Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 168 additions & 0 deletions apis/bigtable/v1beta1/gcpolicy_identity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v1beta1

import (
"context"
"fmt"

"github.com/GoogleCloudPlatform/k8s-config-connector/apis/common/identity"
refs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/gcpurls"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)

var (
_ identity.IdentityV2 = &BigtableGCPolicyIdentity{}
_ identity.Resource = &BigtableGCPolicy{}
)

var BigtableGCPolicyIdentityFormat = gcpurls.Template[BigtableGCPolicyIdentity]("bigtableadmin.googleapis.com", "projects/{project}/instances/{instance}/tables/{table}/columnFamilies/{columnFamily}")

// +k8s:deepcopy-gen=false
type BigtableGCPolicyIdentity struct {
Project string
Instance string
Table string
ColumnFamily string
}

func (i *BigtableGCPolicyIdentity) String() string {
return BigtableGCPolicyIdentityFormat.ToString(*i)
}

func (i *BigtableGCPolicyIdentity) FromExternal(ref string) error {
parsed, match, err := BigtableGCPolicyIdentityFormat.Parse(ref)
if err != nil {
return fmt.Errorf("format of BigtableGCPolicy external=%q was not known (use %s): %w", ref, BigtableGCPolicyIdentityFormat.CanonicalForm(), err)
}
if !match {
return fmt.Errorf("format of BigtableGCPolicy external=%q was not known (use %s)", ref, BigtableGCPolicyIdentityFormat.CanonicalForm())
}

*i = *parsed
return nil
}

func (i *BigtableGCPolicyIdentity) Host() string {
return BigtableGCPolicyIdentityFormat.Host()
}

func getIdentityFromBigtableGCPolicySpec(ctx context.Context, reader client.Reader, obj client.Object) (*BigtableGCPolicyIdentity, error) {
// 1. Resolve Project ID
projectID, err := refs.ResolveProjectID(ctx, reader, obj)
if err != nil {
return nil, fmt.Errorf("cannot resolve project: %w", err)
}

var instanceRefStr string
var tableRefStr string
var columnFamily string

switch u := obj.(type) {
case *BigtableGCPolicy:
// Direct fields
ref, err := u.Spec.InstanceRef.NormalizedExternal(ctx, reader, u.GetNamespace())
if err != nil {
return nil, fmt.Errorf("cannot resolve instanceRef: %w", err)
}
instanceRefStr = ref

tRef, err := u.Spec.TableRef.NormalizedExternal(ctx, reader, u.GetNamespace())
if err != nil {
return nil, fmt.Errorf("cannot resolve tableRef: %w", err)
}
tableRefStr = tRef

columnFamily = u.Spec.ColumnFamily

default:
// Convert to unstructured
m, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
if err != nil {
return nil, err
}
unstructuredObj := &unstructured.Unstructured{Object: m}

// Resolve InstanceRef
instanceRefObj, found, err := unstructured.NestedFieldCopy(unstructuredObj.Object, "spec", "instanceRef")
if err != nil || !found {
return nil, fmt.Errorf("cannot find spec.instanceRef: %w", err)
}
var instanceRef InstanceRef
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(instanceRefObj.(map[string]interface{}), &instanceRef); err != nil {
return nil, fmt.Errorf("cannot parse spec.instanceRef: %w", err)
}
ref, err := instanceRef.NormalizedExternal(ctx, reader, obj.GetNamespace())
if err != nil {
return nil, fmt.Errorf("cannot resolve instanceRef: %w", err)
}
instanceRefStr = ref

// Resolve TableRef
tableRefObj, found, err := unstructured.NestedFieldCopy(unstructuredObj.Object, "spec", "tableRef")
if err != nil || !found {
return nil, fmt.Errorf("cannot find spec.tableRef: %w", err)
}
var tableRef TableRef
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(tableRefObj.(map[string]interface{}), &tableRef); err != nil {
return nil, fmt.Errorf("cannot parse spec.tableRef: %w", err)
}
tRef, err := tableRef.NormalizedExternal(ctx, reader, obj.GetNamespace())
if err != nil {
return nil, fmt.Errorf("cannot resolve tableRef: %w", err)
}
tableRefStr = tRef

// Resolve ColumnFamily
cf, found, err := unstructured.NestedString(unstructuredObj.Object, "spec", "columnFamily")
if err != nil || !found {
return nil, fmt.Errorf("cannot find spec.columnFamily: %w", err)
}
columnFamily = cf
}

_, instanceID, err := ParseInstanceExternal(instanceRefStr)
if err != nil {
return nil, fmt.Errorf("cannot parse instanceRef external ID: %w", err)
}

_, tableID, err := ParseTableExternal(tableRefStr)
if err != nil {
return nil, fmt.Errorf("cannot parse tableRef external ID: %w", err)
}

if columnFamily == "" {
return nil, fmt.Errorf("columnFamily is empty")
}

identity := &BigtableGCPolicyIdentity{
Project: projectID,
Instance: instanceID,
Table: tableID,
ColumnFamily: columnFamily,
}
return identity, nil
}

func (obj *BigtableGCPolicy) GetIdentity(ctx context.Context, reader client.Reader) (identity.Identity, error) {
specIdentity, err := getIdentityFromBigtableGCPolicySpec(ctx, reader, obj)
if err != nil {
return nil, err
}
return specIdentity, nil
}
118 changes: 118 additions & 0 deletions apis/bigtable/v1beta1/gcpolicy_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v1beta1

import (
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/k8s/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type GcpolicyMaxAge struct {
/* DEPRECATED. Deprecated in favor of duration. Immutable. Number of days before applying GC policy. */
// +optional
Days *int `json:"days,omitempty"`

/* Immutable. Duration before applying GC policy. */
// +optional
Duration *string `json:"duration,omitempty"`
}

type GcpolicyMaxVersion struct {
/* Immutable. Number of version before applying the GC policy. */
Number int `json:"number"`
}

// BigtableGCPolicySpec defines the desired state of BigtableGCPolicy
// +kcc:spec:proto=google.bigtable.admin.v2.GcRule
type BigtableGCPolicySpec struct {
/* Immutable. The name of the column family. */
ColumnFamily string `json:"columnFamily"`

/* The deletion policy for the GC policy. Setting ABANDON allows the resource
to be abandoned rather than deleted. This is useful for GC policy as it cannot be deleted
in a replicated instance. Possible values are: "ABANDON". */
// +optional
DeletionPolicy *string `json:"deletionPolicy,omitempty"`

/* Serialized JSON string for garbage collection policy. Conflicts with "mode", "max_age" and "max_version". */
// +optional
GcRules *string `json:"gcRules,omitempty"`

/* The name of the Bigtable instance. */
InstanceRef InstanceRef `json:"instanceRef"`

/* Immutable. NOTE: 'gc_rules' is more flexible, and should be preferred over this field for new resources. This field may be deprecated in the future. GC policy that applies to all cells older than the given age. */
// +optional
// +kcc:proto:field=google.bigtable.admin.v2.GcRule.max_age
MaxAge []GcpolicyMaxAge `json:"maxAge,omitempty"`

/* Immutable. NOTE: 'gc_rules' is more flexible, and should be preferred over this field for new resources. This field may be deprecated in the future. GC policy that applies to all versions of a cell except for the most recent. */
// +optional
// +kcc:proto:field=google.bigtable.admin.v2.GcRule.max_num_versions
MaxVersion []GcpolicyMaxVersion `json:"maxVersion,omitempty"`

/* Immutable. NOTE: 'gc_rules' is more flexible, and should be preferred over this field for new resources. This field may be deprecated in the future. If multiple policies are set, you should choose between UNION OR INTERSECTION. */
// +optional
Mode *string `json:"mode,omitempty"`

/* The name of the table. */
TableRef TableRef `json:"tableRef"`
}

type BigtableGCPolicyStatus struct {
/* Conditions represent the latest available observations of the
BigtableGCPolicy's current state. */
Conditions []v1alpha1.Condition `json:"conditions,omitempty"`
/* ObservedGeneration is the generation of the resource that was most recently observed by the Config Connector controller. If this is equal to metadata.generation, then that means that the current reported status reflects the most recent desired state of the resource. */
// +optional
ObservedGeneration *int `json:"observedGeneration,omitempty"`
}

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:resource:categories=gcp,shortName=gcpbigtablegcpolicy;gcpbigtablegcpolicies
// +kubebuilder:subresource:status
// +kubebuilder:metadata:labels="cnrm.cloud.google.com/managed-by-kcc=true"
// +kubebuilder:metadata:labels="cnrm.cloud.google.com/stability-level=stable"
// +kubebuilder:metadata:labels="cnrm.cloud.google.com/system=true"
// +kubebuilder:metadata:labels="cnrm.cloud.google.com/tf2crd=true"
// +kubebuilder:printcolumn:name="Age",JSONPath=".metadata.creationTimestamp",type="date"
// +kubebuilder:printcolumn:name="Ready",JSONPath=".status.conditions[?(@.type=='Ready')].status",type="string",description="When 'True', the most recent reconcile of the resource succeeded"
// +kubebuilder:printcolumn:name="Status",JSONPath=".status.conditions[?(@.type=='Ready')].reason",type="string",description="The reason for the value in 'Ready'"
// +kubebuilder:printcolumn:name="Status Age",JSONPath=".status.conditions[?(@.type=='Ready')].lastTransitionTime",type="date",description="The last transition time for the value in 'Status'"

// BigtableGCPolicy is the Schema for the bigtable API
// +k8s:openapi-gen=true
type BigtableGCPolicy struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

// +required
Spec BigtableGCPolicySpec `json:"spec"`
Status BigtableGCPolicyStatus `json:"status,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// BigtableGCPolicyList contains a list of BigtableGCPolicy
type BigtableGCPolicyList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []BigtableGCPolicy `json:"items"`
}

func init() {
SchemeBuilder.Register(&BigtableGCPolicy{}, &BigtableGCPolicyList{})
}
4 changes: 3 additions & 1 deletion apis/bigtable/v1beta1/generate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ go run . generate-types \
--service google.bigtable.admin.v2 \
--api-version bigtable.cnrm.cloud.google.com/v1beta1 \
--resource BigtableAppProfile:AppProfile \
--resource BigtableTable:Table
--resource BigtableTable:Table \
--resource BigtableGCPolicy:GcRule \
--skip-scaffold-files

go run . generate-mapper \
--multiversion \
Expand Down
4 changes: 2 additions & 2 deletions apis/bigtable/v1beta1/table_reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ type TableRef struct {
// A reference to an externally managed BigtableTable resource.
External string `json:"external,omitempty"`

// The name of a BigtableInstance resource.
// The name of a BigtableTable resource.
Name string `json:"name,omitempty"`

// The namespace of a BigtableInstance resource.
// The namespace of a BigtableTable resource.
Namespace string `json:"namespace,omitempty"`
}

Expand Down
Loading
Loading