diff --git a/apis/managedkafka/v1alpha1/cluster_identity.go b/apis/managedkafka/v1alpha1/cluster_identity.go new file mode 100644 index 0000000000..c9a5f81c37 --- /dev/null +++ b/apis/managedkafka/v1alpha1/cluster_identity.go @@ -0,0 +1,116 @@ +// Copyright 2024 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 v1alpha1 + +import ( + "context" + "fmt" + "strings" + + "github.com/GoogleCloudPlatform/k8s-config-connector/apis/common" + refsv1beta1 "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// ClusterIdentity defines the resource reference to ManagedKafkaCluster, which "External" field +// holds the GCP identifier for the KRM object. +type ClusterIdentity struct { + parent *ClusterParent + id string +} + +func (i *ClusterIdentity) String() string { + return i.parent.String() + "/clusters/" + i.id +} + +func (i *ClusterIdentity) ID() string { + return i.id +} + +func (i *ClusterIdentity) Parent() *ClusterParent { + return i.parent +} + +type ClusterParent struct { + ProjectID string + Location string +} + +func (p *ClusterParent) String() string { + return "projects/" + p.ProjectID + "/locations/" + p.Location +} + +// New builds a ClusterIdentity from the Config Connector Cluster object. +func NewClusterIdentity(ctx context.Context, reader client.Reader, obj *ManagedKafkaCluster) (*ClusterIdentity, error) { + // Get Parent + projectRef, err := refsv1beta1.ResolveProject(ctx, reader, obj.GetNamespace(), obj.Spec.ProjectRef) + if err != nil { + return nil, err + } + projectID := projectRef.ProjectID + if projectID == "" { + return nil, fmt.Errorf("cannot resolve project") + } + location := obj.Spec.Location + + // Get desired ID + resourceID := common.ValueOf(obj.Spec.ResourceID) + if resourceID == "" { + resourceID = obj.GetName() + } + if resourceID == "" { + return nil, fmt.Errorf("cannot resolve resource ID") + } + + // Use approved External + externalRef := common.ValueOf(obj.Status.ExternalRef) + if externalRef != "" { + // Validate desired with actual + actualParent, actualResourceID, err := ParseClusterExternal(externalRef) + if err != nil { + return nil, err + } + if actualParent.ProjectID != projectID { + return nil, fmt.Errorf("spec.projectRef changed, expect %s, got %s", actualParent.ProjectID, projectID) + } + if actualParent.Location != location { + return nil, fmt.Errorf("spec.location changed, expect %s, got %s", actualParent.Location, location) + } + if actualResourceID != resourceID { + return nil, fmt.Errorf("cannot reset `metadata.name` or `spec.resourceID` to %s, since it has already assigned to %s", + resourceID, actualResourceID) + } + } + return &ClusterIdentity{ + parent: &ClusterParent{ + ProjectID: projectID, + Location: location, + }, + id: resourceID, + }, nil +} + +func ParseClusterExternal(external string) (parent *ClusterParent, resourceID string, err error) { + tokens := strings.Split(external, "/") + if len(tokens) != 6 || tokens[0] != "projects" || tokens[2] != "locations" || tokens[4] != "clusters" { + return nil, "", fmt.Errorf("format of ManagedKafkaCluster external=%q was not known (use projects/{{projectID}}/locations/{{location}}/clusters/{{clusterID}})", external) + } + parent = &ClusterParent{ + ProjectID: tokens[1], + Location: tokens[3], + } + resourceID = tokens[5] + return parent, resourceID, nil +} diff --git a/apis/managedkafka/v1alpha1/cluster_reference.go b/apis/managedkafka/v1alpha1/cluster_reference.go new file mode 100644 index 0000000000..b68a33676c --- /dev/null +++ b/apis/managedkafka/v1alpha1/cluster_reference.go @@ -0,0 +1,83 @@ +// Copyright 2024 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 v1alpha1 + +import ( + "context" + "fmt" + + refsv1beta1 "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ refsv1beta1.ExternalNormalizer = &ClusterRef{} + +// ClusterRef defines the resource reference to ManagedKafkaCluster, which "External" field +// holds the GCP identifier for the KRM object. +type ClusterRef struct { + // A reference to an externally managed ManagedKafkaCluster resource. + // Should be in the format "projects/{{projectID}}/locations/{{location}}/clusters/{{clusterID}}". + External string `json:"external,omitempty"` + + // The name of a ManagedKafkaCluster resource. + Name string `json:"name,omitempty"` + + // The namespace of a ManagedKafkaCluster resource. + Namespace string `json:"namespace,omitempty"` +} + +// NormalizedExternal provision the "External" value for other resource that depends on ManagedKafkaCluster. +// If the "External" is given in the other resource's spec.ManagedKafkaClusterRef, the given value will be used. +// Otherwise, the "Name" and "Namespace" will be used to query the actual ManagedKafkaCluster object from the cluster. +func (r *ClusterRef) NormalizedExternal(ctx context.Context, reader client.Reader, otherNamespace string) (string, error) { + if r.External != "" && r.Name != "" { + return "", fmt.Errorf("cannot specify both name and external on %s reference", ManagedKafkaClusterGVK.Kind) + } + // From given External + if r.External != "" { + if _, _, err := ParseClusterExternal(r.External); err != nil { + return "", err + } + return r.External, nil + } + + // From the Config Connector object + if r.Namespace == "" { + r.Namespace = otherNamespace + } + key := types.NamespacedName{Name: r.Name, Namespace: r.Namespace} + u := &unstructured.Unstructured{} + u.SetGroupVersionKind(ManagedKafkaClusterGVK) + if err := reader.Get(ctx, key, u); err != nil { + if apierrors.IsNotFound(err) { + return "", k8s.NewReferenceNotFoundError(u.GroupVersionKind(), key) + } + return "", fmt.Errorf("reading referenced %s %s: %w", ManagedKafkaClusterGVK, key, err) + } + // Get external from status.externalRef. This is the most trustworthy place. + actualExternalRef, _, err := unstructured.NestedString(u.Object, "status", "externalRef") + if err != nil { + return "", fmt.Errorf("reading status.externalRef: %w", err) + } + if actualExternalRef == "" { + return "", k8s.NewReferenceNotReadyError(u.GroupVersionKind(), key) + } + r.External = actualExternalRef + return r.External, nil +} diff --git a/apis/managedkafka/v1alpha1/cluster_types.go b/apis/managedkafka/v1alpha1/cluster_types.go new file mode 100644 index 0000000000..f754ac1838 --- /dev/null +++ b/apis/managedkafka/v1alpha1/cluster_types.go @@ -0,0 +1,192 @@ +// Copyright 2024 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 v1alpha1 + +import ( + refs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" + commonv1alpha1 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/common/v1alpha1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/k8s/v1alpha1" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var ManagedKafkaClusterGVK = GroupVersion.WithKind("ManagedKafkaCluster") + +// +kcc:proto=google.cloud.managedkafka.v1.AccessConfig +type AccessConfig struct { + // Required. Virtual Private Cloud (VPC) networks that must be granted direct + // access to the Kafka cluster. Minimum of 1 network is required. Maximum 10 + // networks can be specified. + // +kcc:proto:field=google.cloud.managedkafka.v1.AccessConfig.network_configs + // +required + NetworkConfigs []NetworkConfig `json:"networkConfigs,omitempty"` +} + +// +kcc:proto=google.cloud.managedkafka.v1.CapacityConfig +type CapacityConfig struct { + // Required. The number of vCPUs to provision for the cluster. Minimum: 3. + // +kcc:proto:field=google.cloud.managedkafka.v1.CapacityConfig.vcpu_count + // +required + VcpuCount *int64 `json:"vcpuCount,omitempty"` + + // Required. The memory to provision for the cluster in bytes. + // The CPU:memory ratio (vCPU:GiB) must be between 1:1 and 1:8. + // Minimum: 3221225472 (3 GiB). + // +kcc:proto:field=google.cloud.managedkafka.v1.CapacityConfig.memory_bytes + // +required + MemoryBytes *int64 `json:"memoryBytes,omitempty"` +} + +// +kcc:proto=google.cloud.managedkafka.v1.NetworkConfig +type NetworkConfig struct { + // Required. Reference to the VPC subnet in which to create Private Service Connect + // (PSC) endpoints for the Kafka brokers and bootstrap address. + // + // The subnet must be located in the same region as the Kafka cluster. The + // project may differ. Multiple subnets from the same parent network must not + // be specified. + // + // The CIDR range of the subnet must be within the IPv4 address ranges for + // private networks, as specified in RFC 1918. + // +kcc:proto:field=google.cloud.managedkafka.v1.NetworkConfig.subnet + // +required + SubnetworkRef *refs.ComputeSubnetworkRef `json:"subnetworkRef"` +} + +// +kcc:proto=google.cloud.managedkafka.v1.GcpConfig +type GcpConfig struct { + // Required. Access configuration for the Kafka cluster. + // +kcc:proto:field=google.cloud.managedkafka.v1.GcpConfig.access_config + // +required + AccessConfig *AccessConfig `json:"accessConfig,omitempty"` + + // Optional. Immutable. The Cloud KMS Key name to use for encryption. The key + // must be located in the same region as the cluster and cannot be changed. + // +kcc:proto:field=google.cloud.managedkafka.v1.GcpConfig.kms_key + KmsKeyRef *refs.KMSCryptoKeyRef `json:"kmsKeyRef,omitempty"` +} + +// ManagedKafkaClusterSpec defines the desired state of ManagedKafkaCluster +// +kcc:proto=google.cloud.managedkafka.v1.Cluster +type ManagedKafkaClusterSpec struct { + commonv1alpha1.CommonSpec `json:",inline"` + + // +required + Location string `json:"location"` + + // The ManagedKafkaCluster name. If not given, the metadata.name will be used. + ResourceID *string `json:"resourceID,omitempty"` + + // Required. Configuration properties for a Kafka cluster deployed to Google + // Cloud Platform. + // +kcc:proto:field=google.cloud.managedkafka.v1.Cluster.gcp_config + // +required + GcpConfig *GcpConfig `json:"gcpConfig,omitempty"` + + // Optional. Labels as key value pairs. + // +kcc:proto:field=google.cloud.managedkafka.v1.Cluster.labels + Labels map[string]string `json:"labels,omitempty"` + + // Required. Capacity configuration for the Kafka cluster. + // +kcc:proto:field=google.cloud.managedkafka.v1.Cluster.capacity_config + // +required + CapacityConfig *CapacityConfig `json:"capacityConfig,omitempty"` + + // Optional. Rebalance configuration for the Kafka cluster. + // +kcc:proto:field=google.cloud.managedkafka.v1.Cluster.rebalance_config + RebalanceConfig *RebalanceConfig `json:"rebalanceConfig,omitempty"` +} + +// ManagedKafkaClusterStatus defines the config connector machine state of ManagedKafkaCluster +type ManagedKafkaClusterStatus struct { + /* Conditions represent the latest available observations of the + object'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. + ObservedGeneration *int64 `json:"observedGeneration,omitempty"` + + // A unique specifier for the ManagedKafkaCluster resource in GCP. + ExternalRef *string `json:"externalRef,omitempty"` + + // ObservedState is the state of the resource as most recently observed in GCP. + ObservedState *ManagedKafkaClusterObservedState `json:"observedState,omitempty"` +} + +// ManagedKafkaClusterSpec defines the desired state of ManagedKafkaCluster +// +kcc:proto=google.cloud.managedkafka.v1.Cluster +// ManagedKafkaClusterObservedState is the state of the ManagedKafkaCluster resource as most recently observed in GCP. +type ManagedKafkaClusterObservedState struct { + // Identifier. The name of the cluster. Structured like: + // projects/{project_number}/locations/{location}/clusters/{cluster_id} + // +kcc:proto:field=google.cloud.managedkafka.v1.Cluster.name + Name *string `json:"name,omitempty"` + + // Output only. The time when the cluster was created. + // +kcc:proto:field=google.cloud.managedkafka.v1.Cluster.create_time + CreateTime *string `json:"createTime,omitempty"` + + // Output only. The time when the cluster was last updated. + // +kcc:proto:field=google.cloud.managedkafka.v1.Cluster.update_time + UpdateTime *string `json:"updateTime,omitempty"` + + // Output only. The current state of the cluster. + // +kcc:proto:field=google.cloud.managedkafka.v1.Cluster.state + State *string `json:"state,omitempty"` + + // NOTYET + // Output only. Reserved for future use. + // +kcc:proto:field=google.cloud.managedkafka.v1.Cluster.satisfies_pzi + // SatisfiesPzi *bool `json:"satisfiesPzi,omitempty"` + + // NOTYET + // Output only. Reserved for future use. + // +kcc:proto:field=google.cloud.managedkafka.v1.Cluster.satisfies_pzs + // SatisfiesPzs *bool `json:"satisfiesPzs,omitempty"` +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// TODO(user): make sure the pluralizaiton below is correct +// +kubebuilder:resource:categories=gcp,shortName=gcpmanagedkafkacluster;gcpmanagedkafkaclusters +// +kubebuilder:subresource:status +// +kubebuilder:metadata:labels="cnrm.cloud.google.com/managed-by-kcc=true";"cnrm.cloud.google.com/system=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'" + +// ManagedKafkaCluster is the Schema for the ManagedKafkaCluster API +// +k8s:openapi-gen=true +type ManagedKafkaCluster struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // +required + Spec ManagedKafkaClusterSpec `json:"spec,omitempty"` + Status ManagedKafkaClusterStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// ManagedKafkaClusterList contains a list of ManagedKafkaCluster +type ManagedKafkaClusterList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ManagedKafkaCluster `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ManagedKafkaCluster{}, &ManagedKafkaClusterList{}) +} diff --git a/apis/managedkafka/v1alpha1/doc.go b/apis/managedkafka/v1alpha1/doc.go new file mode 100644 index 0000000000..afadd01abf --- /dev/null +++ b/apis/managedkafka/v1alpha1/doc.go @@ -0,0 +1,16 @@ +// Copyright 2024 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. + +// +kcc:proto=google.cloud.managedkafka.v1 +package v1alpha1 diff --git a/apis/managedkafka/v1alpha1/groupversion_info.go b/apis/managedkafka/v1alpha1/groupversion_info.go new file mode 100644 index 0000000000..1ab510ee82 --- /dev/null +++ b/apis/managedkafka/v1alpha1/groupversion_info.go @@ -0,0 +1,33 @@ +// Copyright 2024 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. + +// +kubebuilder:object:generate=true +// +groupName=managedkafka.cnrm.cloud.google.com +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "managedkafka.cnrm.cloud.google.com", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/apis/managedkafka/v1alpha1/types.generated.go b/apis/managedkafka/v1alpha1/types.generated.go new file mode 100644 index 0000000000..aedc5bd93a --- /dev/null +++ b/apis/managedkafka/v1alpha1/types.generated.go @@ -0,0 +1,23 @@ +// Copyright 2025 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 v1alpha1 + +// +kcc:proto=google.cloud.managedkafka.v1.RebalanceConfig +type RebalanceConfig struct { + // Optional. The rebalance behavior for the cluster. + // When not specified, defaults to `NO_REBALANCE`. + // +kcc:proto:field=google.cloud.managedkafka.v1.RebalanceConfig.mode + Mode *string `json:"mode,omitempty"` +} diff --git a/apis/managedkafka/v1alpha1/zz_generated.deepcopy.go b/apis/managedkafka/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..6172b91a69 --- /dev/null +++ b/apis/managedkafka/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,359 @@ +//go:build !ignore_autogenerated + +// Copyright 2020 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. + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" + k8sv1alpha1 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/k8s/v1alpha1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AccessConfig) DeepCopyInto(out *AccessConfig) { + *out = *in + if in.NetworkConfigs != nil { + in, out := &in.NetworkConfigs, &out.NetworkConfigs + *out = make([]NetworkConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AccessConfig. +func (in *AccessConfig) DeepCopy() *AccessConfig { + if in == nil { + return nil + } + out := new(AccessConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CapacityConfig) DeepCopyInto(out *CapacityConfig) { + *out = *in + if in.VcpuCount != nil { + in, out := &in.VcpuCount, &out.VcpuCount + *out = new(int64) + **out = **in + } + if in.MemoryBytes != nil { + in, out := &in.MemoryBytes, &out.MemoryBytes + *out = new(int64) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CapacityConfig. +func (in *CapacityConfig) DeepCopy() *CapacityConfig { + if in == nil { + return nil + } + out := new(CapacityConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterIdentity) DeepCopyInto(out *ClusterIdentity) { + *out = *in + if in.parent != nil { + in, out := &in.parent, &out.parent + *out = new(ClusterParent) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterIdentity. +func (in *ClusterIdentity) DeepCopy() *ClusterIdentity { + if in == nil { + return nil + } + out := new(ClusterIdentity) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterParent) DeepCopyInto(out *ClusterParent) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterParent. +func (in *ClusterParent) DeepCopy() *ClusterParent { + if in == nil { + return nil + } + out := new(ClusterParent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterRef) DeepCopyInto(out *ClusterRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRef. +func (in *ClusterRef) DeepCopy() *ClusterRef { + if in == nil { + return nil + } + out := new(ClusterRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GcpConfig) DeepCopyInto(out *GcpConfig) { + *out = *in + if in.AccessConfig != nil { + in, out := &in.AccessConfig, &out.AccessConfig + *out = new(AccessConfig) + (*in).DeepCopyInto(*out) + } + if in.KmsKeyRef != nil { + in, out := &in.KmsKeyRef, &out.KmsKeyRef + *out = new(v1beta1.KMSCryptoKeyRef) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GcpConfig. +func (in *GcpConfig) DeepCopy() *GcpConfig { + if in == nil { + return nil + } + out := new(GcpConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagedKafkaCluster) DeepCopyInto(out *ManagedKafkaCluster) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedKafkaCluster. +func (in *ManagedKafkaCluster) DeepCopy() *ManagedKafkaCluster { + if in == nil { + return nil + } + out := new(ManagedKafkaCluster) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ManagedKafkaCluster) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagedKafkaClusterList) DeepCopyInto(out *ManagedKafkaClusterList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ManagedKafkaCluster, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedKafkaClusterList. +func (in *ManagedKafkaClusterList) DeepCopy() *ManagedKafkaClusterList { + if in == nil { + return nil + } + out := new(ManagedKafkaClusterList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ManagedKafkaClusterList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagedKafkaClusterObservedState) DeepCopyInto(out *ManagedKafkaClusterObservedState) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.CreateTime != nil { + in, out := &in.CreateTime, &out.CreateTime + *out = new(string) + **out = **in + } + if in.UpdateTime != nil { + in, out := &in.UpdateTime, &out.UpdateTime + *out = new(string) + **out = **in + } + if in.State != nil { + in, out := &in.State, &out.State + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedKafkaClusterObservedState. +func (in *ManagedKafkaClusterObservedState) DeepCopy() *ManagedKafkaClusterObservedState { + if in == nil { + return nil + } + out := new(ManagedKafkaClusterObservedState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagedKafkaClusterSpec) DeepCopyInto(out *ManagedKafkaClusterSpec) { + *out = *in + in.CommonSpec.DeepCopyInto(&out.CommonSpec) + if in.ResourceID != nil { + in, out := &in.ResourceID, &out.ResourceID + *out = new(string) + **out = **in + } + if in.GcpConfig != nil { + in, out := &in.GcpConfig, &out.GcpConfig + *out = new(GcpConfig) + (*in).DeepCopyInto(*out) + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.CapacityConfig != nil { + in, out := &in.CapacityConfig, &out.CapacityConfig + *out = new(CapacityConfig) + (*in).DeepCopyInto(*out) + } + if in.RebalanceConfig != nil { + in, out := &in.RebalanceConfig, &out.RebalanceConfig + *out = new(RebalanceConfig) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedKafkaClusterSpec. +func (in *ManagedKafkaClusterSpec) DeepCopy() *ManagedKafkaClusterSpec { + if in == nil { + return nil + } + out := new(ManagedKafkaClusterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagedKafkaClusterStatus) DeepCopyInto(out *ManagedKafkaClusterStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]k8sv1alpha1.Condition, len(*in)) + copy(*out, *in) + } + if in.ObservedGeneration != nil { + in, out := &in.ObservedGeneration, &out.ObservedGeneration + *out = new(int64) + **out = **in + } + if in.ExternalRef != nil { + in, out := &in.ExternalRef, &out.ExternalRef + *out = new(string) + **out = **in + } + if in.ObservedState != nil { + in, out := &in.ObservedState, &out.ObservedState + *out = new(ManagedKafkaClusterObservedState) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedKafkaClusterStatus. +func (in *ManagedKafkaClusterStatus) DeepCopy() *ManagedKafkaClusterStatus { + if in == nil { + return nil + } + out := new(ManagedKafkaClusterStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkConfig) DeepCopyInto(out *NetworkConfig) { + *out = *in + if in.SubnetworkRef != nil { + in, out := &in.SubnetworkRef, &out.SubnetworkRef + *out = new(v1beta1.ComputeSubnetworkRef) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkConfig. +func (in *NetworkConfig) DeepCopy() *NetworkConfig { + if in == nil { + return nil + } + out := new(NetworkConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RebalanceConfig) DeepCopyInto(out *RebalanceConfig) { + *out = *in + if in.Mode != nil { + in, out := &in.Mode, &out.Mode + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RebalanceConfig. +func (in *RebalanceConfig) DeepCopy() *RebalanceConfig { + if in == nil { + return nil + } + out := new(RebalanceConfig) + in.DeepCopyInto(out) + return out +} diff --git a/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_managedkafkaclusters.managedkafka.cnrm.cloud.google.com.yaml b/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_managedkafkaclusters.managedkafka.cnrm.cloud.google.com.yaml new file mode 100644 index 0000000000..7e10db0b56 --- /dev/null +++ b/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_managedkafkaclusters.managedkafka.cnrm.cloud.google.com.yaml @@ -0,0 +1,299 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cnrm.cloud.google.com/version: 0.0.0-dev + creationTimestamp: null + labels: + cnrm.cloud.google.com/managed-by-kcc: "true" + cnrm.cloud.google.com/system: "true" + name: managedkafkaclusters.managedkafka.cnrm.cloud.google.com +spec: + group: managedkafka.cnrm.cloud.google.com + names: + categories: + - gcp + kind: ManagedKafkaCluster + listKind: ManagedKafkaClusterList + plural: managedkafkaclusters + shortNames: + - gcpmanagedkafkacluster + - gcpmanagedkafkaclusters + singular: managedkafkacluster + preserveUnknownFields: false + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: When 'True', the most recent reconcile of the resource succeeded + jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - description: The reason for the value in 'Ready' + jsonPath: .status.conditions[?(@.type=='Ready')].reason + name: Status + type: string + - description: The last transition time for the value in 'Status' + jsonPath: .status.conditions[?(@.type=='Ready')].lastTransitionTime + name: Status Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: ManagedKafkaCluster is the Schema for the ManagedKafkaCluster + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ManagedKafkaClusterSpec defines the desired state of ManagedKafkaCluster + properties: + capacityConfig: + description: Required. Capacity configuration for the Kafka cluster. + properties: + memoryBytes: + description: 'Required. The memory to provision for the cluster + in bytes. The CPU:memory ratio (vCPU:GiB) must be between 1:1 + and 1:8. Minimum: 3221225472 (3 GiB).' + format: int64 + type: integer + vcpuCount: + description: 'Required. The number of vCPUs to provision for the + cluster. Minimum: 3.' + format: int64 + type: integer + required: + - memoryBytes + - vcpuCount + type: object + gcpConfig: + description: Required. Configuration properties for a Kafka cluster + deployed to Google Cloud Platform. + properties: + accessConfig: + description: Required. Access configuration for the Kafka cluster. + properties: + networkConfigs: + description: Required. Virtual Private Cloud (VPC) networks + that must be granted direct access to the Kafka cluster. + Minimum of 1 network is required. Maximum 10 networks can + be specified. + items: + properties: + subnetworkRef: + description: |- + Required. Reference to the VPC subnet in which to create Private Service Connect + (PSC) endpoints for the Kafka brokers and bootstrap address. + + The subnet must be located in the same region as the Kafka cluster. The + project may differ. Multiple subnets from the same parent network must not + be specified. + + The CIDR range of the subnet must be within the IPv4 address ranges for + private networks, as specified in RFC 1918. + oneOf: + - not: + required: + - external + required: + - name + - not: + anyOf: + - required: + - name + - required: + - namespace + required: + - external + properties: + external: + description: The ComputeSubnetwork selflink of form + "projects/{{project}}/regions/{{region}}/subnetworks/{{name}}", + when not managed by Config Connector. + type: string + name: + description: The `name` field of a `ComputeSubnetwork` + resource. + type: string + namespace: + description: The `namespace` field of a `ComputeSubnetwork` + resource. + type: string + type: object + required: + - subnetworkRef + type: object + type: array + required: + - networkConfigs + type: object + kmsKeyRef: + description: Optional. Immutable. The Cloud KMS Key name to use + for encryption. The key must be located in the same region as + the cluster and cannot be changed. + oneOf: + - not: + required: + - external + required: + - name + - not: + anyOf: + - required: + - name + - required: + - namespace + required: + - external + properties: + external: + description: A reference to an externally managed KMSCryptoKey. + Should be in the format `projects/[kms_project_id]/locations/[region]/keyRings/[key_ring_id]/cryptoKeys/[key]`. + type: string + name: + description: The `name` of a `KMSCryptoKey` resource. + type: string + namespace: + description: The `namespace` of a `KMSCryptoKey` resource. + type: string + type: object + required: + - accessConfig + type: object + labels: + additionalProperties: + type: string + description: Optional. Labels as key value pairs. + type: object + location: + type: string + projectRef: + description: The Project that this resource belongs to. + oneOf: + - not: + required: + - external + required: + - name + - not: + anyOf: + - required: + - name + - required: + - namespace + required: + - external + properties: + external: + description: The `projectID` field of a project, when not managed + by Config Connector. + type: string + kind: + description: The kind of the Project resource; optional but must + be `Project` if provided. + type: string + name: + description: The `name` field of a `Project` resource. + type: string + namespace: + description: The `namespace` field of a `Project` resource. + type: string + type: object + rebalanceConfig: + description: Optional. Rebalance configuration for the Kafka cluster. + properties: + mode: + description: Optional. The rebalance behavior for the cluster. + When not specified, defaults to `NO_REBALANCE`. + type: string + type: object + resourceID: + description: The GCP resource identifier. If not given, the metadata.name + will be used. + type: string + required: + - capacityConfig + - gcpConfig + - location + - projectRef + type: object + status: + description: ManagedKafkaClusterStatus defines the config connector machine + state of ManagedKafkaCluster + properties: + conditions: + description: Conditions represent the latest available observations + of the object's current state. + items: + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + type: string + message: + description: Human-readable message indicating details about + last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's + last transition. + type: string + status: + description: Status is the status of the condition. Can be True, + False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + type: array + externalRef: + description: A unique specifier for the ManagedKafkaCluster resource + in GCP. + type: string + observedGeneration: + description: 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. + format: int64 + type: integer + observedState: + description: ObservedState is the state of the resource as most recently + observed in GCP. + properties: + createTime: + description: Output only. The time when the cluster was created. + type: string + name: + description: 'Identifier. The name of the cluster. Structured + like: projects/{project_number}/locations/{location}/clusters/{cluster_id}' + type: string + state: + description: Output only. The current state of the cluster. + type: string + updateTime: + description: Output only. The time when the cluster was last updated. + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/installbundle/components/clusterroles/cnrm_admin.yaml b/config/installbundle/components/clusterroles/cnrm_admin.yaml index a515fc7ddd..b91eebfe49 100644 --- a/config/installbundle/components/clusterroles/cnrm_admin.yaml +++ b/config/installbundle/components/clusterroles/cnrm_admin.yaml @@ -775,6 +775,18 @@ rules: - update - patch - delete +- apiGroups: + - managedkafka.cnrm.cloud.google.com + resources: + - '*' + verbs: + - get + - list + - watch + - create + - update + - patch + - delete - apiGroups: - memcache.cnrm.cloud.google.com resources: diff --git a/config/installbundle/components/clusterroles/cnrm_viewer.yaml b/config/installbundle/components/clusterroles/cnrm_viewer.yaml index e34e7d98eb..d31542680d 100644 --- a/config/installbundle/components/clusterroles/cnrm_viewer.yaml +++ b/config/installbundle/components/clusterroles/cnrm_viewer.yaml @@ -518,6 +518,14 @@ rules: - get - list - watch +- apiGroups: + - managedkafka.cnrm.cloud.google.com + resources: + - '*' + verbs: + - get + - list + - watch - apiGroups: - memcache.cnrm.cloud.google.com resources: diff --git a/dev/tools/controllerbuilder/generate.sh b/dev/tools/controllerbuilder/generate.sh index ba30914e0f..8910eff290 100755 --- a/dev/tools/controllerbuilder/generate.sh +++ b/dev/tools/controllerbuilder/generate.sh @@ -188,11 +188,15 @@ go run . generate-mapper \ --service google.cloud.iap.v1 \ --api-version iap.cnrm.cloud.google.com/v1alpha1 -# $ go run . generate-controller \ -# --service google.cloud.iap.v1 \ -# --api-version iap.cnrm.cloud.google.com/v1alpha1 \ -# --kind IAPSettings \ -# --proto-resource IapSettings +# ManagedKafka +go run . generate-types \ + --service google.cloud.managedkafka.v1 \ + --api-version managedkafka.cnrm.cloud.google.com/v1alpha1 \ + --resource ManagedKafkaCluster:Cluster + +go run . generate-mapper \ + --service google.cloud.managedkafka.v1 \ + --api-version managedkafka.cnrm.cloud.google.com/v1alpha1 # PrivilegedAccessManager go run . generate-mapper \ diff --git a/go.mod b/go.mod index c59c797836..35d24e65f3 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( cloud.google.com/go/iam v1.2.2 cloud.google.com/go/iap v1.10.2 cloud.google.com/go/kms v1.20.1 + cloud.google.com/go/managedkafka v0.4.0 cloud.google.com/go/monitoring v1.21.2 cloud.google.com/go/privilegedaccessmanager v0.2.1 cloud.google.com/go/profiler v0.4.1 @@ -69,11 +70,11 @@ require ( golang.org/x/oauth2 v0.25.0 golang.org/x/sync v0.10.0 golang.org/x/time v0.9.0 - google.golang.org/api v0.210.0 + google.golang.org/api v0.214.0 google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 - google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f - google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 - google.golang.org/grpc v1.67.1 + google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 + google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 + google.golang.org/grpc v1.67.3 google.golang.org/protobuf v1.35.2 gopkg.in/dnaeon/go-vcr.v3 v3.2.0 gopkg.in/yaml.v2 v2.4.0 @@ -94,10 +95,10 @@ require ( bitbucket.org/creachadair/stringset v0.0.8 // indirect cel.dev/expr v0.16.0 // indirect cloud.google.com/go v0.116.0 // indirect - cloud.google.com/go/auth v0.11.0 // indirect + cloud.google.com/go/auth v0.13.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect cloud.google.com/go/bigtable v1.33.0 // indirect - cloud.google.com/go/compute/metadata v0.5.2 // indirect + cloud.google.com/go/compute/metadata v0.6.0 // indirect cloud.google.com/go/longrunning v0.6.2 // indirect dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect diff --git a/go.sum b/go.sum index 471b926bbb..acb70ff959 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ cloud.google.com/go/alloydb v1.14.0 h1:aEmmIHmiHDs46wTr/YqXuumuUGNc5QKYA7317nEFj cloud.google.com/go/alloydb v1.14.0/go.mod h1:OTBY1HoL0Z8PsHoMMVhkaUPKyY8oP7hzIAe/Dna6UHk= cloud.google.com/go/apikeys v1.1.12 h1:ZTFWJ1ibGjiIrIhhtdWOm7AGJd+y9R17dVujlgU//6E= cloud.google.com/go/apikeys v1.1.12/go.mod h1:3tqZUj8CmCJm0maQyLufgyO5Ghf3AZQ6hcSkIqsSIm4= -cloud.google.com/go/auth v0.11.0 h1:Ic5SZz2lsvbYcWT5dfjNWgw6tTlGi2Wc8hyQSC9BstA= -cloud.google.com/go/auth v0.11.0/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= +cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs= +cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= @@ -48,8 +48,8 @@ cloud.google.com/go/cloudbuild v1.19.0 h1:Uo0bL251yvyWsNtO3Og9m5Z4S48cgGf3IUX7xz cloud.google.com/go/cloudbuild v1.19.0/go.mod h1:ZGRqbNMrVGhknIIjwASa6MqoRTOpXIVMSI+Ew5DMPuY= cloud.google.com/go/compute v1.29.0 h1:Lph6d8oPi38NHkOr6S55Nus/Pbbcp37m/J0ohgKAefs= cloud.google.com/go/compute v1.29.0/go.mod h1:HFlsDurE5DpQZClAGf/cYh+gxssMhBxBovZDYkEn/Og= -cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= -cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= +cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= cloud.google.com/go/dataflow v0.10.2 h1:o9P5/zR2mOYJmCnfp9/7RprKFZCwmSu3TvemQSmCaFM= cloud.google.com/go/dataflow v0.10.2/go.mod h1:+HIb4HJxDCZYuCqDGnBHZEglh5I0edi/mLgVbxDf0Ag= cloud.google.com/go/dataform v0.10.2 h1:t16DoejuOHoxJR88qrpdmFFlCXA9+x5PKrqI9qiDYz0= @@ -71,6 +71,8 @@ cloud.google.com/go/kms v1.20.1 h1:og29Wv59uf2FVaZlesaiDAqHFzHaoUyHI3HYp9VUHVg= cloud.google.com/go/kms v1.20.1/go.mod h1:LywpNiVCvzYNJWS9JUcGJSVTNSwPwi0vBAotzDqn2nc= cloud.google.com/go/longrunning v0.6.2 h1:xjDfh1pQcWPEvnfjZmwjKQEcHnpz6lHjfy7Fo0MK+hc= cloud.google.com/go/longrunning v0.6.2/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI= +cloud.google.com/go/managedkafka v0.4.0 h1:/snDok/h6TZKw0ubmfj/LYIwSn16mWBoBI2OEl7ldIA= +cloud.google.com/go/managedkafka v0.4.0/go.mod h1:AUCV9FeT5IbuIf4ctH6TsnovE/KuIPE6Mp/YowkTyx0= cloud.google.com/go/monitoring v1.21.2 h1:FChwVtClH19E7pJ+e0xUhJPGksctZNVOk2UhMmblmdU= cloud.google.com/go/monitoring v1.21.2/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+WFX8g2hqVEZU= cloud.google.com/go/privilegedaccessmanager v0.2.1 h1:8a9N5vXTVaEUsTOVxpY7bI354vjS9jVOY8FjwMRfWTI= @@ -1382,8 +1384,8 @@ google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjR google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= -google.golang.org/api v0.210.0 h1:HMNffZ57OoZCRYSbdWVRoqOa8V8NIHLL0CzdBPLztWk= -google.golang.org/api v0.210.0/go.mod h1:B9XDZGnx2NtyjzVkOVTGrFSAVZgPcbedzKg/gTLwqBs= +google.golang.org/api v0.214.0 h1:h2Gkq07OYi6kusGOaT/9rnNljuXmqPnaig7WGPmKbwA= +google.golang.org/api v0.214.0/go.mod h1:bYPpLG8AyeMWwDU6NXoB00xC0DFkikVvd5MfwoxjLqE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1439,10 +1441,10 @@ google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxH google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk= google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc= -google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f h1:M65LEviCfuZTfrfzwwEoxVtgvfkFkBUbFnRbxCXuXhU= -google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f/go.mod h1:Yo94eF2nj7igQt+TiJ49KxjIH8ndLYPZMIRSiRcEbg0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 h1:pgr/4QbFyktUv9CtQ/Fq4gzEE6/Xs7iCXbktaGzLHbQ= +google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1464,8 +1466,8 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/grpc v1.67.3 h1:OgPcDAFKHnH8X3O4WcO4XUc8GRDeKsKReqbQtiCj7N8= +google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/pkg/controller/direct/managedkafka/cluster_controller.go b/pkg/controller/direct/managedkafka/cluster_controller.go new file mode 100644 index 0000000000..70eb70c09f --- /dev/null +++ b/pkg/controller/direct/managedkafka/cluster_controller.go @@ -0,0 +1,298 @@ +// Copyright 2024 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 managedkafka + +import ( + "context" + "fmt" + + krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/managedkafka/v1alpha1" + refs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/config" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/common" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/directbase" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/registry" + + gcp "cloud.google.com/go/managedkafka/apiv1" + pb "cloud.google.com/go/managedkafka/apiv1/managedkafkapb" + "google.golang.org/api/option" + "google.golang.org/protobuf/types/known/fieldmaskpb" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func init() { + registry.RegisterModel(krm.ManagedKafkaClusterGVK, NewClusterModel) +} + +func NewClusterModel(ctx context.Context, config *config.ControllerConfig) (directbase.Model, error) { + return &modelCluster{config: *config}, nil +} + +var _ directbase.Model = &modelCluster{} + +type modelCluster struct { + config config.ControllerConfig +} + +func (m *modelCluster) client(ctx context.Context) (*gcp.Client, error) { + var opts []option.ClientOption + opts, err := m.config.RESTClientOptions() + if err != nil { + return nil, err + } + gcpClient, err := gcp.NewRESTClient(ctx, opts...) + if err != nil { + return nil, fmt.Errorf("building Cluster client: %w", err) + } + return gcpClient, err +} + +func (m *modelCluster) AdapterForObject(ctx context.Context, reader client.Reader, u *unstructured.Unstructured) (directbase.Adapter, error) { + obj := &krm.ManagedKafkaCluster{} + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &obj); err != nil { + return nil, fmt.Errorf("error converting to %T: %w", obj, err) + } + + id, err := krm.NewClusterIdentity(ctx, reader, obj) + if err != nil { + return nil, err + } + + // Get managedkafka GCP client + gcpClient, err := m.client(ctx) + if err != nil { + return nil, err + } + return &ClusterAdapter{ + id: id, + gcpClient: gcpClient, + desired: obj, + reader: reader, + }, nil +} + +func (m *modelCluster) AdapterForURL(ctx context.Context, url string) (directbase.Adapter, error) { + // TODO: Support URLs + return nil, nil +} + +type ClusterAdapter struct { + id *krm.ClusterIdentity + gcpClient *gcp.Client + desired *krm.ManagedKafkaCluster + actual *pb.Cluster + reader client.Reader +} + +var _ directbase.Adapter = &ClusterAdapter{} + +// Find retrieves the GCP resource. +// Return true means the object is found. This triggers Adapter `Update` call. +// Return false means the object is not found. This triggers Adapter `Create` call. +// Return a non-nil error requeues the requests. +func (a *ClusterAdapter) Find(ctx context.Context) (bool, error) { + log := klog.FromContext(ctx) + log.V(2).Info("getting Cluster", "name", a.id) + + req := &pb.GetClusterRequest{Name: a.id.String()} + clusterpb, err := a.gcpClient.GetCluster(ctx, req) + if err != nil { + if direct.IsNotFound(err) { + return false, nil + } + return false, fmt.Errorf("getting Cluster %q: %w", a.id, err) + } + + a.actual = clusterpb + return true, nil +} + +// Create creates the resource in GCP based on `spec` and update the Config Connector object `status` based on the GCP response. +func (a *ClusterAdapter) Create(ctx context.Context, createOp *directbase.CreateOperation) error { + log := klog.FromContext(ctx) + log.V(2).Info("creating Cluster", "name", a.id) + + if err := a.normalizeReference(ctx); err != nil { + return err + } + + mapCtx := &direct.MapContext{} + desired := a.desired.DeepCopy() + resource := ManagedKafkaClusterSpec_ToProto(mapCtx, &desired.Spec) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + + // TODO(contributor): Complete the gcp "CREATE" or "INSERT" request. + req := &pb.CreateClusterRequest{ + Parent: a.id.Parent().String(), + ClusterId: a.id.ID(), // Note: this is not the fully qualified name for this resource, it is just the resource ID + Cluster: resource, + } + op, err := a.gcpClient.CreateCluster(ctx, req) + if err != nil { + return fmt.Errorf("creating Cluster %s: %w", a.id, err) + } + created, err := op.Wait(ctx) + if err != nil { + return fmt.Errorf("waiting for creation of Cluster %s: %w", a.id, err) + } + log.V(2).Info("successfully created Cluster", "name", a.id) + + status := &krm.ManagedKafkaClusterStatus{} + status.ObservedState = ManagedKafkaClusterObservedState_FromProto(mapCtx, created) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + status.ExternalRef = &created.Name // populate externalRef + return createOp.UpdateStatus(ctx, status, nil) +} + +// Update updates the resource in GCP based on `spec` and update the Config Connector object `status` based on the GCP response. +func (a *ClusterAdapter) Update(ctx context.Context, updateOp *directbase.UpdateOperation) error { + log := klog.FromContext(ctx) + log.V(2).Info("updating Cluster", "name", a.id) + + if err := a.normalizeReference(ctx); err != nil { + return err + } + + mapCtx := &direct.MapContext{} + desiredPb := ManagedKafkaClusterSpec_ToProto(mapCtx, &a.desired.DeepCopy().Spec) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + + paths, err := common.CompareProtoMessage(desiredPb, a.actual, common.BasicDiff) + if err != nil { + return err + } + + if len(paths) == 0 { + log.V(2).Info("no field needs update", "name", a.id.String()) + status := &krm.ManagedKafkaClusterStatus{} + status.ObservedState = ManagedKafkaClusterObservedState_FromProto(mapCtx, a.actual) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + return updateOp.UpdateStatus(ctx, status, nil) + } + updateMask := &fieldmaskpb.FieldMask{ + Paths: sets.List(paths)} + + desiredPb.Name = a.id.String() // populate the name field so that the GCP API can identify the resource + req := &pb.UpdateClusterRequest{ + UpdateMask: updateMask, + Cluster: desiredPb, + } + op, err := a.gcpClient.UpdateCluster(ctx, req) + if err != nil { + return fmt.Errorf("updating Cluster %s: %w", a.id.String(), err) + } + updated, err := op.Wait(ctx) + if err != nil { + return fmt.Errorf("waiting update for Cluster %s: %w", a.id.String(), err) + } + log.V(2).Info("successfully updated Cluster", "name", a.id.String()) + + status := &krm.ManagedKafkaClusterStatus{} + status.ExternalRef = &updated.Name // populate externalRef + status.ObservedState = ManagedKafkaClusterObservedState_FromProto(mapCtx, updated) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + return updateOp.UpdateStatus(ctx, status, nil) +} + +// Export maps the GCP object to a Config Connector resource `spec`. +func (a *ClusterAdapter) Export(ctx context.Context) (*unstructured.Unstructured, error) { + if a.actual == nil { + return nil, fmt.Errorf("Find() not called") + } + u := &unstructured.Unstructured{} + + obj := &krm.ManagedKafkaCluster{} + mapCtx := &direct.MapContext{} + obj.Spec = direct.ValueOf(ManagedKafkaClusterSpec_FromProto(mapCtx, a.actual)) + if mapCtx.Err() != nil { + return nil, mapCtx.Err() + } + obj.Spec.ProjectRef = &refs.ProjectRef{External: a.id.Parent().ProjectID} + obj.Spec.Location = a.id.Parent().Location + uObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + if err != nil { + return nil, err + } + + u.SetName(a.actual.Name) + u.SetGroupVersionKind(krm.ManagedKafkaClusterGVK) + + u.Object = uObj + return u, nil +} + +// Delete the resource from GCP service when the corresponding Config Connector resource is deleted. +func (a *ClusterAdapter) Delete(ctx context.Context, deleteOp *directbase.DeleteOperation) (bool, error) { + log := klog.FromContext(ctx) + log.V(2).Info("deleting Cluster", "name", a.id) + + req := &pb.DeleteClusterRequest{Name: a.id.String()} + op, err := a.gcpClient.DeleteCluster(ctx, req) + if err != nil { + return false, fmt.Errorf("deleting Cluster %s: %w", a.id, err) + } + log.V(2).Info("successfully deleted Cluster", "name", a.id) + + err = op.Wait(ctx) + if err != nil { + return false, fmt.Errorf("waiting delete Cluster %s: %w", a.id, err) + } + return true, nil +} + +func (a *ClusterAdapter) normalizeReference(ctx context.Context) error { + obj := a.desired + + // Normalize the subnetworkRef in the accessConfig.networkConfigs + if obj.Spec.GcpConfig != nil && obj.Spec.GcpConfig.AccessConfig != nil && obj.Spec.GcpConfig.AccessConfig.NetworkConfigs != nil { + for i := range obj.Spec.GcpConfig.AccessConfig.NetworkConfigs { + networkConfig := &obj.Spec.GcpConfig.AccessConfig.NetworkConfigs[i] + if networkConfig.SubnetworkRef != nil { + subnet, err := refs.ResolveComputeSubnetwork(ctx, a.reader, obj, networkConfig.SubnetworkRef) + if err != nil { + return err + } + networkConfig.SubnetworkRef = subnet + } + } + } + + // Normalize the kmsKeyRef in the gcpConfig + if obj.Spec.GcpConfig != nil && obj.Spec.GcpConfig.KmsKeyRef != nil { + kmsKey, err := refs.ResolveKMSCryptoKeyRef(ctx, a.reader, obj, obj.Spec.GcpConfig.KmsKeyRef) + if err != nil { + return err + } + obj.Spec.GcpConfig.KmsKeyRef = kmsKey + } + + return nil +} diff --git a/pkg/controller/direct/managedkafka/cluster_mappings.go b/pkg/controller/direct/managedkafka/cluster_mappings.go new file mode 100644 index 0000000000..16e2d41514 --- /dev/null +++ b/pkg/controller/direct/managedkafka/cluster_mappings.go @@ -0,0 +1,65 @@ +// Copyright 2025 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 managedkafka + +import ( + pb "cloud.google.com/go/managedkafka/apiv1/managedkafkapb" + krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/managedkafka/v1alpha1" + refs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct" +) + +func GcpConfig_FromProto(mapCtx *direct.MapContext, in *pb.GcpConfig) *krm.GcpConfig { + if in == nil { + return nil + } + out := &krm.GcpConfig{} + out.AccessConfig = AccessConfig_FromProto(mapCtx, in.GetAccessConfig()) + if in.GetKmsKey() != "" { + out.KmsKeyRef = &refs.KMSCryptoKeyRef{External: in.GetKmsKey()} + } + return out +} +func GcpConfig_ToProto(mapCtx *direct.MapContext, in *krm.GcpConfig) *pb.GcpConfig { + if in == nil { + return nil + } + out := &pb.GcpConfig{} + out.AccessConfig = AccessConfig_ToProto(mapCtx, in.AccessConfig) + if in.KmsKeyRef != nil { + out.KmsKey = in.KmsKeyRef.External + } + return out +} +func NetworkConfig_FromProto(mapCtx *direct.MapContext, in *pb.NetworkConfig) *krm.NetworkConfig { + if in == nil { + return nil + } + out := &krm.NetworkConfig{} + if in.GetSubnet() != "" { + out.SubnetworkRef = &refs.ComputeSubnetworkRef{External: in.GetSubnet()} + } + return out +} +func NetworkConfig_ToProto(mapCtx *direct.MapContext, in *krm.NetworkConfig) *pb.NetworkConfig { + if in == nil { + return nil + } + out := &pb.NetworkConfig{} + if in.SubnetworkRef != nil { + out.Subnet = in.SubnetworkRef.External + } + return out +} diff --git a/pkg/controller/direct/managedkafka/mapper.generated.go b/pkg/controller/direct/managedkafka/mapper.generated.go new file mode 100644 index 0000000000..b84f7e9f7c --- /dev/null +++ b/pkg/controller/direct/managedkafka/mapper.generated.go @@ -0,0 +1,118 @@ +// Copyright 2025 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 managedkafka + +import ( + pb "cloud.google.com/go/managedkafka/apiv1/managedkafkapb" + krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/managedkafka/v1alpha1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct" +) + +func AccessConfig_FromProto(mapCtx *direct.MapContext, in *pb.AccessConfig) *krm.AccessConfig { + if in == nil { + return nil + } + out := &krm.AccessConfig{} + out.NetworkConfigs = direct.Slice_FromProto(mapCtx, in.NetworkConfigs, NetworkConfig_FromProto) + return out +} +func AccessConfig_ToProto(mapCtx *direct.MapContext, in *krm.AccessConfig) *pb.AccessConfig { + if in == nil { + return nil + } + out := &pb.AccessConfig{} + out.NetworkConfigs = direct.Slice_ToProto(mapCtx, in.NetworkConfigs, NetworkConfig_ToProto) + return out +} +func CapacityConfig_FromProto(mapCtx *direct.MapContext, in *pb.CapacityConfig) *krm.CapacityConfig { + if in == nil { + return nil + } + out := &krm.CapacityConfig{} + out.VcpuCount = direct.LazyPtr(in.GetVcpuCount()) + out.MemoryBytes = direct.LazyPtr(in.GetMemoryBytes()) + return out +} +func CapacityConfig_ToProto(mapCtx *direct.MapContext, in *krm.CapacityConfig) *pb.CapacityConfig { + if in == nil { + return nil + } + out := &pb.CapacityConfig{} + out.VcpuCount = direct.ValueOf(in.VcpuCount) + out.MemoryBytes = direct.ValueOf(in.MemoryBytes) + return out +} +func ManagedKafkaClusterObservedState_FromProto(mapCtx *direct.MapContext, in *pb.Cluster) *krm.ManagedKafkaClusterObservedState { + if in == nil { + return nil + } + out := &krm.ManagedKafkaClusterObservedState{} + out.Name = direct.LazyPtr(in.GetName()) + out.CreateTime = direct.StringTimestamp_FromProto(mapCtx, in.GetCreateTime()) + out.UpdateTime = direct.StringTimestamp_FromProto(mapCtx, in.GetUpdateTime()) + out.State = direct.Enum_FromProto(mapCtx, in.GetState()) + return out +} +func ManagedKafkaClusterObservedState_ToProto(mapCtx *direct.MapContext, in *krm.ManagedKafkaClusterObservedState) *pb.Cluster { + if in == nil { + return nil + } + out := &pb.Cluster{} + out.Name = direct.ValueOf(in.Name) + out.CreateTime = direct.StringTimestamp_ToProto(mapCtx, in.CreateTime) + out.UpdateTime = direct.StringTimestamp_ToProto(mapCtx, in.UpdateTime) + out.State = direct.Enum_ToProto[pb.Cluster_State](mapCtx, in.State) + return out +} +func ManagedKafkaClusterSpec_FromProto(mapCtx *direct.MapContext, in *pb.Cluster) *krm.ManagedKafkaClusterSpec { + if in == nil { + return nil + } + out := &krm.ManagedKafkaClusterSpec{} + out.GcpConfig = GcpConfig_FromProto(mapCtx, in.GetGcpConfig()) + out.Labels = in.Labels + out.CapacityConfig = CapacityConfig_FromProto(mapCtx, in.GetCapacityConfig()) + out.RebalanceConfig = RebalanceConfig_FromProto(mapCtx, in.GetRebalanceConfig()) + return out +} +func ManagedKafkaClusterSpec_ToProto(mapCtx *direct.MapContext, in *krm.ManagedKafkaClusterSpec) *pb.Cluster { + if in == nil { + return nil + } + out := &pb.Cluster{} + if oneof := GcpConfig_ToProto(mapCtx, in.GcpConfig); oneof != nil { + out.PlatformConfig = &pb.Cluster_GcpConfig{GcpConfig: oneof} + } + out.Labels = in.Labels + out.CapacityConfig = CapacityConfig_ToProto(mapCtx, in.CapacityConfig) + out.RebalanceConfig = RebalanceConfig_ToProto(mapCtx, in.RebalanceConfig) + return out +} +func RebalanceConfig_FromProto(mapCtx *direct.MapContext, in *pb.RebalanceConfig) *krm.RebalanceConfig { + if in == nil { + return nil + } + out := &krm.RebalanceConfig{} + out.Mode = direct.Enum_FromProto(mapCtx, in.GetMode()) + return out +} +func RebalanceConfig_ToProto(mapCtx *direct.MapContext, in *krm.RebalanceConfig) *pb.RebalanceConfig { + if in == nil { + return nil + } + out := &pb.RebalanceConfig{} + out.Mode = direct.Enum_ToProto[pb.RebalanceConfig_Mode](mapCtx, in.Mode) + return out +} diff --git a/pkg/controller/direct/register/register.go b/pkg/controller/direct/register/register.go index 78cd411129..9dce92703d 100644 --- a/pkg/controller/direct/register/register.go +++ b/pkg/controller/direct/register/register.go @@ -36,6 +36,7 @@ import ( _ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/kms/autokeyconfig" _ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/kms/keyhandle" _ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/logging" + _ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/managedkafka" _ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/monitoring" _ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/networkconnectivity" _ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/privateca" diff --git a/pkg/gvks/supportedgvks/gvks_generated.go b/pkg/gvks/supportedgvks/gvks_generated.go index f4c29d24dc..db40fc9da2 100644 --- a/pkg/gvks/supportedgvks/gvks_generated.go +++ b/pkg/gvks/supportedgvks/gvks_generated.go @@ -3306,6 +3306,16 @@ var SupportedGVKs = map[schema.GroupVersionKind]GVKMetadata{ "cnrm.cloud.google.com/system": "true", }, }, + { + Group: "managedkafka.cnrm.cloud.google.com", + Version: "v1alpha1", + Kind: "ManagedKafkaCluster", + }: { + Labels: map[string]string{ + "cnrm.cloud.google.com/managed-by-kcc": "true", + "cnrm.cloud.google.com/system": "true", + }, + }, { Group: "memcache.cnrm.cloud.google.com", Version: "v1beta1", diff --git a/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/_generated_object_managedkafkacluster.golden.yaml b/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/_generated_object_managedkafkacluster.golden.yaml new file mode 100644 index 0000000000..f6703147a7 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/_generated_object_managedkafkacluster.golden.yaml @@ -0,0 +1,41 @@ +apiVersion: managedkafka.cnrm.cloud.google.com/v1alpha1 +kind: ManagedKafkaCluster +metadata: + finalizers: + - cnrm.cloud.google.com/finalizer + - cnrm.cloud.google.com/deletion-defender + generation: 2 + labels: + cnrm-test: "true" + name: managedkafkacluster-${uniqueId} + namespace: ${uniqueId} +spec: + capacityConfig: + memoryBytes: 4294967296 + vcpuCount: 4 + gcpConfig: + accessConfig: + networkConfigs: + - subnetworkRef: + name: computesubnetwork-${uniqueId}-1 + - subnetworkRef: + name: computesubnetwork-${uniqueId}-2 + location: us-central1 + projectRef: + external: ${projectId} + rebalanceConfig: + mode: AUTO_REBALANCE_ON_SCALE_UP +status: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: The resource is up to date + reason: UpToDate + status: "True" + type: Ready + externalRef: projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId} + observedGeneration: 2 + observedState: + createTime: "1970-01-01T00:00:00Z" + name: projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId} + state: ACTIVE + updateTime: "1970-01-01T00:00:00Z" diff --git a/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/_http.log b/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/_http.log new file mode 100644 index 0000000000..e82dbf8c5c --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/_http.log @@ -0,0 +1,1466 @@ +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +404 Not Found +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "errors": [ + { + "domain": "global", + "message": "The resource 'projects/${projectId}/global/networks/computenetwork-${uniqueId}-1' was not found", + "reason": "notFound" + } + ], + "message": "The resource 'projects/${projectId}/global/networks/computenetwork-${uniqueId}-1' was not found" + } +} + +--- + +POST https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +{ + "autoCreateSubnetworks": false, + "name": "computenetwork-${uniqueId}-1", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL" +} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-1", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-1", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}-1", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "REGIONAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-1", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +404 Not Found +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "errors": [ + { + "domain": "global", + "message": "The resource 'projects/${projectId}/global/networks/computenetwork-${uniqueId}-2' was not found", + "reason": "notFound" + } + ], + "message": "The resource 'projects/${projectId}/global/networks/computenetwork-${uniqueId}-2' was not found" + } +} + +--- + +POST https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +{ + "autoCreateSubnetworks": false, + "name": "computenetwork-${uniqueId}-2", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL" +} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-2", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-2", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}-2", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "REGIONAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-2", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +404 Not Found +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "errors": [ + { + "domain": "global", + "message": "The resource 'projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1' was not found", + "reason": "notFound" + } + ], + "message": "The resource 'projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1' was not found" + } +} + +--- + +POST https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +{ + "ipCidrRange": "10.0.0.0/24", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}-1", + "network": "projects/${projectId}/global/networks/computenetwork-${uniqueId}-1", + "region": "projects/${projectId}/global/regions/us-central1" +} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 0, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 100, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.0.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.0.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}-1", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-1", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1", + "stackType": "IPV4_ONLY" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +404 Not Found +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "errors": [ + { + "domain": "global", + "message": "The resource 'projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-2' was not found", + "reason": "notFound" + } + ], + "message": "The resource 'projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-2' was not found" + } +} + +--- + +POST https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +{ + "ipCidrRange": "10.0.1.0/24", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}-2", + "network": "projects/${projectId}/global/networks/computenetwork-${uniqueId}-2", + "region": "projects/${projectId}/global/regions/us-central1" +} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 0, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-2", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 100, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-2", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.1.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.1.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}-2", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-2", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-2", + "stackType": "IPV4_ONLY" +} + +--- + +GET https://managedkafka.googleapis.com/v1/projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} +X-Goog-Request-Params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Fclusters%2Fmanagedkafkacluster-${uniqueId} + +404 Not Found +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "message": "Resource 'projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}' was not found", + "status": "NOT_FOUND" + } +} + +--- + +POST https://managedkafka.googleapis.com/v1/projects/${projectId}/locations/us-central1/clusters?%24alt=json%3Benum-encoding%3Dint&clusterId=managedkafkacluster-${uniqueId} +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} +X-Goog-Request-Params: parent=projects%2F${projectId}%2Flocations%2Fus-central1 + +{ + "capacityConfig": { + "memoryBytes": "3221225472", + "vcpuCount": "3" + }, + "gcpConfig": { + "accessConfig": { + "networkConfigs": [ + { + "subnet": "projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1" + } + ] + } + }, + "rebalanceConfig": { + "mode": 1 + } +} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.managedkafka.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}-1", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "REGIONAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-1", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", + "subnetworks": [ + "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1" + ] +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}-2", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "REGIONAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-2", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", + "subnetworks": [ + "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-2" + ] +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.1.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.1.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}-2", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-2", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-2", + "stackType": "IPV4_ONLY" +} + +--- + +GET https://managedkafka.googleapis.com/v1/projects/${projectId}/locations/us-central1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} +X-Goog-Request-Params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Foperations%2F${operationID} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.managedkafka.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.managedkafka.v1.Cluster", + "capacityConfig": { + "memoryBytes": "3221225472", + "vcpuCount": "3" + }, + "createTime": "2024-04-01T12:34:56.123456Z", + "gcpConfig": { + "accessConfig": { + "networkConfigs": [ + { + "subnet": "projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1" + } + ] + } + }, + "name": "projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}", + "rebalanceConfig": { + "mode": "NO_REBALANCE" + }, + "satisfiesPzi": false, + "satisfiesPzs": false, + "state": "ACTIVE", + "updateTime": "2024-04-01T12:34:56.123456Z" + } +} + +--- + +GET https://managedkafka.googleapis.com/v1/projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} +X-Goog-Request-Params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Fclusters%2Fmanagedkafkacluster-${uniqueId} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "capacityConfig": { + "memoryBytes": "3221225472", + "vcpuCount": "3" + }, + "createTime": "2024-04-01T12:34:56.123456Z", + "gcpConfig": { + "accessConfig": { + "networkConfigs": [ + { + "subnet": "projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1" + } + ] + } + }, + "name": "projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}", + "rebalanceConfig": { + "mode": 1 + }, + "satisfiesPzi": false, + "satisfiesPzs": false, + "state": 2, + "updateTime": "2024-04-01T12:34:56.123456Z" +} + +--- + +PATCH https://managedkafka.googleapis.com/v1/projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}?%24alt=json%3Benum-encoding%3Dint&updateMask=capacityConfig.memoryBytes%2CcapacityConfig.vcpuCount%2CgcpConfig.accessConfig.networkConfigs%2Cname%2CrebalanceConfig.mode +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} +X-Goog-Request-Params: cluster.name=projects%2F${projectId}%2Flocations%2Fus-central1%2Fclusters%2Fmanagedkafkacluster-${uniqueId} + +{ + "capacityConfig": { + "memoryBytes": "4294967296", + "vcpuCount": "4" + }, + "gcpConfig": { + "accessConfig": { + "networkConfigs": [ + { + "subnet": "projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1" + }, + { + "subnet": "projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-2" + } + ] + } + }, + "name": "projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}", + "rebalanceConfig": { + "mode": 2 + } +} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.managedkafka.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}", + "verb": "update" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}" +} + +--- + +GET https://managedkafka.googleapis.com/v1/projects/${projectId}/locations/us-central1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} +X-Goog-Request-Params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Foperations%2F${operationID} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.managedkafka.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}", + "verb": "update" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.managedkafka.v1.Cluster", + "capacityConfig": { + "memoryBytes": "4294967296", + "vcpuCount": "4" + }, + "createTime": "2024-04-01T12:34:56.123456Z", + "gcpConfig": { + "accessConfig": { + "networkConfigs": [ + { + "subnet": "projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1" + }, + { + "subnet": "projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-2" + } + ] + } + }, + "name": "projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}", + "rebalanceConfig": { + "mode": "AUTO_REBALANCE_ON_SCALE_UP" + }, + "satisfiesPzi": false, + "satisfiesPzs": false, + "state": "ACTIVE", + "updateTime": "2024-04-01T12:34:56.123456Z" + } +} + +--- + +GET https://managedkafka.googleapis.com/v1/projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} +X-Goog-Request-Params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Fclusters%2Fmanagedkafkacluster-${uniqueId} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "capacityConfig": { + "memoryBytes": "4294967296", + "vcpuCount": "4" + }, + "createTime": "2024-04-01T12:34:56.123456Z", + "gcpConfig": { + "accessConfig": { + "networkConfigs": [ + { + "subnet": "projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1" + }, + { + "subnet": "projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-2" + } + ] + } + }, + "name": "projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}", + "rebalanceConfig": { + "mode": 2 + }, + "satisfiesPzi": false, + "satisfiesPzs": false, + "state": 2, + "updateTime": "2024-04-01T12:34:56.123456Z" +} + +--- + +DELETE https://managedkafka.googleapis.com/v1/projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} +X-Goog-Request-Params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Fclusters%2Fmanagedkafkacluster-${uniqueId} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.managedkafka.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.0.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.0.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}-1", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-1", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1", + "stackType": "IPV4_ONLY" +} + +--- + +GET https://managedkafka.googleapis.com/v1/projects/${projectId}/locations/us-central1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} +X-Goog-Request-Params: name=projects%2F${projectId}%2Flocations%2Fus-central1%2Foperations%2F${operationID} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.managedkafka.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-central1/clusters/managedkafkacluster-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-central1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.protobuf.Empty" + } +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.1.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.1.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}-2", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-2", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-2", + "stackType": "IPV4_ONLY" +} + +--- + +DELETE https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 0, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-2", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 100, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-2", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.0.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.0.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}-1", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-1", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1", + "stackType": "IPV4_ONLY" +} + +--- + +DELETE https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 0, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 100, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-central1/subnetworks/computesubnetwork-${uniqueId}-1", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}-2", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "REGIONAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-2", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}" +} + +--- + +DELETE https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-2", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-2", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}-1", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "REGIONAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-1", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}" +} + +--- + +DELETE https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-1", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 kcc/${kccVersion} (+https://github.com/GoogleCloudPlatform/k8s-config-connector) kcc/controller-manager/${kccVersion} + +200 OK +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}-1", + "user": "user@example.com" +} \ No newline at end of file diff --git a/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/create.yaml b/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/create.yaml new file mode 100644 index 0000000000..7a890ef576 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/create.yaml @@ -0,0 +1,32 @@ +# Copyright 2025 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. + +apiVersion: managedkafka.cnrm.cloud.google.com/v1alpha1 +kind: ManagedKafkaCluster +metadata: + name: managedkafkacluster-${uniqueId} +spec: + projectRef: + external: ${projectId} + location: us-central1 + capacityConfig: + vcpuCount: 3 + memoryBytes: 3221225472 # 3GB + gcpConfig: + accessConfig: + networkConfigs: + - subnetworkRef: + name: computesubnetwork-${uniqueId}-1 + rebalanceConfig: + mode: NO_REBALANCE diff --git a/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/dependencies.yaml b/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/dependencies.yaml new file mode 100644 index 0000000000..cf56c4c07a --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/dependencies.yaml @@ -0,0 +1,47 @@ +# Copyright 2025 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. + +apiVersion: compute.cnrm.cloud.google.com/v1beta1 +kind: ComputeNetwork +metadata: + name: computenetwork-${uniqueId}-1 +spec: + autoCreateSubnetworks: false +--- +apiVersion: compute.cnrm.cloud.google.com/v1beta1 +kind: ComputeNetwork +metadata: + name: computenetwork-${uniqueId}-2 +spec: + autoCreateSubnetworks: false +--- +apiVersion: compute.cnrm.cloud.google.com/v1beta1 +kind: ComputeSubnetwork +metadata: + name: computesubnetwork-${uniqueId}-1 +spec: + region: us-central1 + networkRef: + name: computenetwork-${uniqueId}-1 + ipCidrRange: 10.0.0.0/24 +--- +apiVersion: compute.cnrm.cloud.google.com/v1beta1 +kind: ComputeSubnetwork +metadata: + name: computesubnetwork-${uniqueId}-2 +spec: + region: us-central1 + networkRef: + name: computenetwork-${uniqueId}-2 + ipCidrRange: 10.0.1.0/24 diff --git a/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/update.yaml b/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/update.yaml new file mode 100644 index 0000000000..3cc236ef22 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/managedkafka/v1alpha1/managedkafkacluster/update.yaml @@ -0,0 +1,34 @@ +# Copyright 2025 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. + +apiVersion: managedkafka.cnrm.cloud.google.com/v1alpha1 +kind: ManagedKafkaCluster +metadata: + name: managedkafkacluster-${uniqueId} +spec: + projectRef: + external: ${projectId} + location: us-central1 + capacityConfig: + vcpuCount: 4 # 3 -> 4 + memoryBytes: 4294967296 # 3GB -> 4GB + gcpConfig: + accessConfig: + networkConfigs: + - subnetworkRef: + name: computesubnetwork-${uniqueId}-1 + - subnetworkRef: + name: computesubnetwork-${uniqueId}-2 # 1 subnetwork -> 2 subnetworks + rebalanceConfig: + mode: AUTO_REBALANCE_ON_SCALE_UP # NO_REBALANCE -> AUTO_REBALANCE_ON_SCALE_UP