From 230a0fdce4f9d698a908f53a93c7aafa1d2cca3f Mon Sep 17 00:00:00 2001 From: Joyce Ma Date: Thu, 28 Nov 2024 07:48:19 +0000 Subject: [PATCH] Support AlloyDBInstance type, mapper and direct controller --- apis/alloydb/v1alpha1/doc.go | 16 + apis/alloydb/v1alpha1/groupversion_info.go | 33 + apis/alloydb/v1alpha1/instance_identity.go | 123 ++++ apis/alloydb/v1alpha1/instance_reference.go | 83 +++ apis/alloydb/v1alpha1/instance_types.go | 196 ++++++ apis/alloydb/v1alpha1/types.generated.go | 181 +++++ .../alloydb/v1alpha1/zz_generated.deepcopy.go | 630 ++++++++++++++++++ apis/alloydb/v1beta1/doc.go | 16 + apis/alloydb/v1beta1/groupversion_info.go | 33 + apis/alloydb/v1beta1/instance_identity.go | 123 ++++ apis/alloydb/v1beta1/instance_reference.go | 83 +++ apis/alloydb/v1beta1/instance_types.go | 195 ++++++ apis/alloydb/v1beta1/types.generated.go | 181 +++++ apis/alloydb/v1beta1/zz_generated.deepcopy.go | 630 ++++++++++++++++++ apis/refs/v1beta1/alloydbref.go | 283 ++++++++ apis/refs/v1beta1/helper.go | 8 + ...stances.alloydb.cnrm.cloud.google.com.yaml | 193 +++--- .../template/controller/controller.go | 4 +- go.mod | 1 + go.sum | 2 + .../direct/alloydb/instance_controller.go | 402 +++++++++++ .../direct/alloydb/instance_mappings.go | 124 ++++ .../direct/alloydb/mapper.generated.go | 255 +++++++ pkg/gvks/supportedgvks/gvks_generated.go | 4 +- .../resource-docs/alloydb/alloydbinstance.md | 47 +- 25 files changed, 3736 insertions(+), 110 deletions(-) create mode 100644 apis/alloydb/v1alpha1/doc.go create mode 100644 apis/alloydb/v1alpha1/groupversion_info.go create mode 100644 apis/alloydb/v1alpha1/instance_identity.go create mode 100644 apis/alloydb/v1alpha1/instance_reference.go create mode 100644 apis/alloydb/v1alpha1/instance_types.go create mode 100644 apis/alloydb/v1alpha1/types.generated.go create mode 100644 apis/alloydb/v1alpha1/zz_generated.deepcopy.go create mode 100644 apis/alloydb/v1beta1/doc.go create mode 100644 apis/alloydb/v1beta1/groupversion_info.go create mode 100644 apis/alloydb/v1beta1/instance_identity.go create mode 100644 apis/alloydb/v1beta1/instance_reference.go create mode 100644 apis/alloydb/v1beta1/instance_types.go create mode 100644 apis/alloydb/v1beta1/types.generated.go create mode 100644 apis/alloydb/v1beta1/zz_generated.deepcopy.go create mode 100644 apis/refs/v1beta1/alloydbref.go create mode 100644 pkg/controller/direct/alloydb/instance_controller.go create mode 100644 pkg/controller/direct/alloydb/instance_mappings.go create mode 100644 pkg/controller/direct/alloydb/mapper.generated.go diff --git a/apis/alloydb/v1alpha1/doc.go b/apis/alloydb/v1alpha1/doc.go new file mode 100644 index 0000000000..4dd8f835c1 --- /dev/null +++ b/apis/alloydb/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.alloydb.v1beta +package v1alpha1 diff --git a/apis/alloydb/v1alpha1/groupversion_info.go b/apis/alloydb/v1alpha1/groupversion_info.go new file mode 100644 index 0000000000..fa8c1c21bb --- /dev/null +++ b/apis/alloydb/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=alloydb.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: "alloydb.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/alloydb/v1alpha1/instance_identity.go b/apis/alloydb/v1alpha1/instance_identity.go new file mode 100644 index 0000000000..16542ff1ec --- /dev/null +++ b/apis/alloydb/v1alpha1/instance_identity.go @@ -0,0 +1,123 @@ +// 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" +) + +const serviceDomain = "//alloydb.googleapis.com" + +// InstanceIdentity defines the resource reference to AlloyDBInstance, which "External" field +// holds the GCP identifier for the KRM object. +type InstanceIdentity struct { + parent *InstanceParent + id string +} + +func (i *InstanceIdentity) String() string { + return i.parent.String() + "/instances/" + i.id +} + +func (i *InstanceIdentity) ID() string { + return i.id +} + +func (i *InstanceIdentity) Parent() *InstanceParent { + return i.parent +} + +// AsExternalRef builds a externalRef from a PrivilegedAccessManagerEntitlement. +func (i *InstanceIdentity) AsExternalRef() *string { + er := serviceDomain + "/" + i.String() + return &er +} + +type InstanceParent struct { + clusterName string +} + +func (p *InstanceParent) String() string { + return p.clusterName +} + +// New builds a InstanceIdentity from the Config Connector Instance object. +func NewInstanceIdentity(ctx context.Context, reader client.Reader, obj *AlloyDBInstance) (*InstanceIdentity, error) { + + // Get Parent + clusterRef, err := refsv1beta1.ResolveAlloyDBCluster(ctx, reader, obj, obj.Spec.ClusterRef) + if err != nil { + return nil, fmt.Errorf("cannot resolve AlloyDBCluster ref: %w", err) + } + + // 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 ExternalRef + externalRef := common.ValueOf(obj.Status.ExternalRef) + if externalRef != "" { + // Validate desired with actual + actualParent, actualResourceID, err := ParseInstanceExternalRef(externalRef) + if err != nil { + return nil, err + } + if actualParent.clusterName != clusterRef.String() { + return nil, fmt.Errorf("spec.clusterRef changed, expect %s, got %s", actualParent.clusterName, clusterRef) + } + 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 &InstanceIdentity{ + parent: &InstanceParent{ + clusterName: clusterRef.String(), + }, + id: resourceID, + }, nil +} + +func ParseInstanceExternalRef(externalRef string) (parent *InstanceParent, resourceID string, err error) { + if !strings.HasPrefix(externalRef, serviceDomain) { + return nil, "", fmt.Errorf("externalRef should have prefix %s, got %s", serviceDomain, externalRef) + } + path := strings.TrimPrefix(externalRef, serviceDomain+"/") + return ParseInstanceExternal(path) +} + +func ParseInstanceExternal(external string) (parent *InstanceParent, resourceID string, err error) { + tokens := strings.Split(external, "/") + if len(tokens) != 8 || tokens[0] != "projects" || tokens[2] != "locations" || tokens[4] != "clusters" || tokens[6] != "instances" { + return nil, "", fmt.Errorf("format of AlloyDBInstance external=%q was not known (use projects//locations//clusters//instances/)", external) + } + parent = &InstanceParent{ + clusterName: fmt.Sprintf("%s/%s/%s/%s/%s/%s", tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]), + } + resourceID = tokens[7] + return parent, resourceID, nil +} diff --git a/apis/alloydb/v1alpha1/instance_reference.go b/apis/alloydb/v1alpha1/instance_reference.go new file mode 100644 index 0000000000..e2b6055c6b --- /dev/null +++ b/apis/alloydb/v1alpha1/instance_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 = &InstanceRef{} + +// InstanceRef defines the resource reference to AlloyDBInstance, which "External" field +// holds the GCP identifier for the KRM object. +type InstanceRef struct { + // A reference to an externally managed AlloyDBInstance resource. + // Should be in the format "projects//locations//instances/". + External string `json:"external,omitempty"` + + // The name of a AlloyDBInstance resource. + Name string `json:"name,omitempty"` + + // The namespace of a AlloyDBInstance resource. + Namespace string `json:"namespace,omitempty"` +} + +// NormalizedExternal provision the "External" value for other resource that depends on AlloyDBInstance. +// If the "External" is given in the other resource's spec.AlloyDBInstanceRef, the given value will be used. +// Otherwise, the "Name" and "Namespace" will be used to query the actual AlloyDBInstance object from the cluster. +func (r *InstanceRef) 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", AlloyDBInstanceGVK.Kind) + } + // From given External + if r.External != "" { + if _, _, err := ParseInstanceExternal(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(AlloyDBInstanceGVK) + 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", AlloyDBInstanceGVK, 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/alloydb/v1alpha1/instance_types.go b/apis/alloydb/v1alpha1/instance_types.go new file mode 100644 index 0000000000..5210a86ba3 --- /dev/null +++ b/apis/alloydb/v1alpha1/instance_types.go @@ -0,0 +1,196 @@ +// 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" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/k8s/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var AlloyDBInstanceGVK = GroupVersion.WithKind("AlloyDBInstance") + +// AlloyDBInstanceSpec defines the desired state of AlloyDBInstance +// +kcc:proto=google.cloud.alloydb.v1beta.Instance +type AlloyDBInstanceSpec struct { + + // The AlloyDBInstance cluster that this resource belongs to. + // +required + ClusterRef *refs.AlloyDBClusterRef `json:"clusterRef,omitempty"` + + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="ResourceID field is immutable" + // Immutable. + // Optional. The instanceId of the resource. If not given, the metadata.name will be used. + ResourceID *string `json:"resourceID,omitempty"` + + // Annotations to allow client tools to store small amount + // of arbitrary data. This is distinct from labels. + Annotations map[string]string `json:"annotations,omitempty"` + + // Availability type of an Instance. Defaults to REGIONAL for both primary and read instances. + // + // Note that primary and read instances can have different availability types. + // Only READ_POOL instance supports ZONAL type. Users can't specify the zone for READ_POOL instance. + // Zone is automatically chosen from the list of zones in the region specified. + // Read pool of size 1 can only have zonal availability. Read pools with node count of 2 or more + // can have regional availability (nodes are present in 2 or more zones in a region). Possible values: ["AVAILABILITY_TYPE_UNSPECIFIED", "ZONAL", "REGIONAL"]. + AvailabilityType *string `json:"availabilityType,omitempty"` + + // Database flags. Set at instance level. * They are copied + // from primary instance on read instance creation. * Read instances + // can set new or override existing flags that are relevant for reads, + // e.g. for enabling columnar cache on a read instance. Flags set on + // read instance may or may not be present on primary. + DatabaseFlags map[string]string `json:"databaseFlags,omitempty"` + + // User-settable and human-readable display name for the + // Instance. + DisplayName *string `json:"displayName,omitempty"` + + // The Compute Engine zone that the instance should serve + // from, per https://cloud.google.com/compute/docs/regions-zones This + // can ONLY be specified for ZONAL instances. If present for a REGIONAL + // instance, an error will be thrown. If this is absent for a ZONAL + // instance, instance is created in a random zone with available capacity. + GceZone *string `json:"gceZone,omitempty"` + + // We recommend that you use `instanceTypeRef` instead. + // The type of the instance. Possible values: [PRIMARY, READ_POOL, SECONDARY] + InstanceType *string `json:"instanceType,omitempty"` + + // The type of instance. + // Possible values: ["PRIMARY", "READ_POOL", "SECONDARY"] + // + // For PRIMARY and SECONDARY instances, set the value to refer to the name of the associated cluster. + // This is recommended because the instance type of primary and secondary instances is tied to the cluster type of the associated cluster. + // If the secondary cluster is promoted to primary cluster, then the associated secondary instance also becomes primary instance. + // Example: + // instanceTypeRef: + // name: clusterName + // For instances of type READ_POOL, set the value using external keyword. + // Example: + // instanceTypeRef: + // external: READ_POOL + // If the instance type is SECONDARY, the delete instance operation does not delete the secondary instance but abandons it instead. + // Use deletionPolicy = "FORCE" in the associated secondary cluster and delete the cluster forcefully to delete the secondary cluster as well its associated secondary instance. + InstanceTypeRef *refs.AlloyDBClusterTypeRef `json:"instanceTypeRef,omitempty"` + + // Configurations for the machines that host the underlying + // database engine. + MachineConfig *Instance_MachineConfig `json:"machineConfig,omitempty"` + + // Instance level network configuration. + NetworkConfig *Instance_InstanceNetworkConfig `json:"networkConfig,omitempty"` + + // Read pool specific config. If the instance type is READ_POOL, + // this configuration must be provided. + ReadPoolConfig *Instance_ReadPoolConfig `json:"readPoolConfig,omitempty"` +} + +// AlloyDBInstanceStatus defines the config connector machine state of AlloyDBInstance +type AlloyDBInstanceStatus 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 AlloyDBInstance resource in GCP. + ExternalRef *string `json:"externalRef,omitempty"` + + /* NOTYET + // ObservedState is the state of the resource as most recently observed in GCP. + ObservedState *AlloyDBInstanceObservedState `json:"observedState,omitempty"` + */ + + // Time the Instance was created in UTC. + CreateTime *string `json:"createTime,omitempty"` + + // The IP address for the Instance. This is the connection + // endpoint for an end-user application. + IpAddress *string `json:"ipAddress,omitempty"` + + // The name of the instance resource. + Name *string `json:"name,omitempty"` + + // The outbound public IP addresses for the instance. This is available ONLY when + // networkConfig.enableOutboundPublicIp is set to true. These IP addresses are used + // for outbound connections. + OutboundPublicIpAddresses []string `json:"outboundPublicIpAddresses,omitempty"` + + // The public IP addresses for the Instance. This is available + // ONLY when networkConfig.enablePublicIp is set to true. This is the + // connection endpoint for an end-user application. + PublicIpAddress *string `json:"publicIpAddress,omitempty"` + + // Set to true if the current state of Instance does not + // match the user's intended state, and the service is actively updating + // the resource to reconcile them. This can happen due to user-triggered + // updates or system actions like failover or maintenance. + Reconciling *bool `json:"reconciling,omitempty"` + + // The current state of the alloydb instance. + State *string `json:"state,omitempty"` + + // The system-generated UID of the resource. + Uid *string `json:"uid,omitempty"` + + // Time the Instance was updated in UTC. + UpdateTime *string `json:"updateTime,omitempty"` +} + +/* NOTYET +// AlloyDBInstanceSpec defines the desired state of AlloyDBInstance +// +kcc:proto=google.cloud.alloydb.v1beta.Instance +// AlloyDBInstanceObservedState is the state of the AlloyDBInstance resource as most recently observed in GCP. +type AlloyDBInstanceObservedState struct { +} +*/ + +// +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=gcpalloydbinstance;gcpalloydbinstances +// +kubebuilder:subresource:status +// +kubebuilder:metadata:labels="cnrm.cloud.google.com/tf2crd=true";"cnrm.cloud.google.com/managed-by-kcc=true";"cnrm.cloud.google.com/stability-level=stable";"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'" + +// AlloyDBInstance is the Schema for the AlloyDBInstance API +// +k8s:openapi-gen=true +// +kubebuilder:storageversion +type AlloyDBInstance struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // +required + Spec AlloyDBInstanceSpec `json:"spec,omitempty"` + Status AlloyDBInstanceStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// AlloyDBInstanceList contains a list of AlloyDBInstance +type AlloyDBInstanceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AlloyDBInstance `json:"items"` +} + +func init() { + SchemeBuilder.Register(&AlloyDBInstance{}, &AlloyDBInstanceList{}) +} diff --git a/apis/alloydb/v1alpha1/types.generated.go b/apis/alloydb/v1alpha1/types.generated.go new file mode 100644 index 0000000000..fac1677e73 --- /dev/null +++ b/apis/alloydb/v1alpha1/types.generated.go @@ -0,0 +1,181 @@ +// 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 + +// +kcc:proto=google.cloud.alloydb.v1beta.GeminiInstanceConfig +type GeminiInstanceConfig struct { + // Output only. Whether the Gemini in Databases add-on is enabled for the + // instance. It will be true only if the add-on has been enabled for the + // billing account corresponding to the instance. Its status is toggled from + // the Admin Control Center (ACC) and cannot be toggled using AlloyDBInstance's APIs. + Entitled *bool `json:"entitled,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.ClientConnectionConfig +type Instance_ClientConnectionConfig struct { + // Optional. Configuration to enforce connectors only (ex: AuthProxy) + // connections to the database. + RequireConnectors *bool `json:"requireConnectors,omitempty"` + + // Optional. SSL configuration option for this instance. + SslConfig *SslConfig `json:"sslConfig,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.InstanceNetworkConfig +type Instance_InstanceNetworkConfig struct { + // Optional. A list of external network authorized to access this instance. + // This field is only allowed to be set when 'enablePublicIp' is set to true. + AuthorizedExternalNetworks []Instance_InstanceNetworkConfig_AuthorizedNetwork `json:"authorizedExternalNetworks,omitempty"` + + // Optional. Enabling public ip for the instance. If a user wishes + // to disable this, please also clear the list of the authorized + // external networks set on the same instance. + EnablePublicIp *bool `json:"enablePublicIp,omitempty"` + + // Optional. Enabling an outbound public IP address to support a database + // server sending requests out into the internet. + EnableOutboundPublicIp *bool `json:"enableOutboundPublicIp,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.InstanceNetworkConfig.AuthorizedNetwork +type Instance_InstanceNetworkConfig_AuthorizedNetwork struct { + // CIDR range for one authorzied network of the instance. + CidrRange *string `json:"cidrRange,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.MachineConfig +type Instance_MachineConfig struct { + // The number of CPU's in the VM instance. + CpuCount *int32 `json:"cpuCount,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.Node +type Instance_Node struct { + // The Compute Engine zone of the VM e.g. "us-central1-b". + ZoneID *string `json:"zoneID,omitempty"` + + // The identifier of the VM e.g. "test-read-0601-407e52be-ms3l". + ID *string `json:"id,omitempty"` + + // The private IP address of the VM e.g. "10.57.0.34". + Ip *string `json:"ip,omitempty"` + + // Determined by state of the compute VM and postgres-service health. + // Compute VM state can have values listed in + // https://cloud.google.com/compute/docs/instances/instance-life-cycle and + // postgres-service health can have values: HEALTHY and UNHEALTHY. + State *string `json:"state,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.ObservabilityInstanceConfig +type Instance_ObservabilityInstanceConfig struct { + // Observability feature status for an instance. + // This flag is turned "off" by default. + Enabled *bool `json:"enabled,omitempty"` + + // Preserve comments in query string for an instance. + // This flag is turned "off" by default. + PreserveComments *bool `json:"preserveComments,omitempty"` + + // Track wait events during query execution for an instance. + // This flag is turned "on" by default but tracking is enabled only after + // observability enabled flag is also turned on. + TrackWaitEvents *bool `json:"trackWaitEvents,omitempty"` + + // Output only. Track wait event types during query execution for an + // instance. This flag is turned "on" by default but tracking is enabled + // only after observability enabled flag is also turned on. This is + // read-only flag and only modifiable by producer API. + TrackWaitEventTypes *bool `json:"trackWaitEventTypes,omitempty"` + + // Query string length. The default value is 10k. + MaxQueryStringLength *int32 `json:"maxQueryStringLength,omitempty"` + + // Record application tags for an instance. + // This flag is turned "off" by default. + RecordApplicationTags *bool `json:"recordApplicationTags,omitempty"` + + // Number of query execution plans captured by Insights per minute + // for all queries combined. The default value is 200. + // Any integer between 0 to 200 is considered valid. + QueryPlansPerMinute *int32 `json:"queryPlansPerMinute,omitempty"` + + // Track actively running queries on the instance. + // If not set, this flag is "off" by default. + TrackActiveQueries *bool `json:"trackActiveQueries,omitempty"` + + // Track client address for an instance. + // If not set, default value is "off". + TrackClientAddress *bool `json:"trackClientAddress,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.PscInstanceConfig +type Instance_PscInstanceConfig struct { + // Output only. The service attachment created when Private + // Service Connect (PSC) is enabled for the instance. + // The name of the resource will be in the format of + // `projects//regions//serviceAttachments/` + ServiceAttachmentLink *string `json:"serviceAttachmentLink,omitempty"` + + // Optional. List of consumer projects that are allowed to create + // PSC endpoints to service-attachments to this instance. + AllowedConsumerProjects []string `json:"allowedConsumerProjects,omitempty"` + + // Output only. The DNS name of the instance for PSC connectivity. + // Name convention: ...alloydb-psc.goog + PscDnsName *string `json:"pscDnsName,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.QueryInsightsInstanceConfig +type Instance_QueryInsightsInstanceConfig struct { + // Record application tags for an instance. + // This flag is turned "on" by default. + RecordApplicationTags *bool `json:"recordApplicationTags,omitempty"` + + // Record client address for an instance. Client address is PII information. + // This flag is turned "on" by default. + RecordClientAddress *bool `json:"recordClientAddress,omitempty"` + + // Query string length. The default value is 1024. + // Any integer between 256 and 4500 is considered valid. + QueryStringLength *uint32 `json:"queryStringLength,omitempty"` + + // Number of query execution plans captured by Insights per minute + // for all queries combined. The default value is 5. + // Any integer between 0 and 20 is considered valid. + QueryPlansPerMinute *uint32 `json:"queryPlansPerMinute,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.ReadPoolConfig +type Instance_ReadPoolConfig struct { + // Read capacity, i.e. number of nodes in a read pool instance. + NodeCount *int32 `json:"nodeCount,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.UpdatePolicy +type Instance_UpdatePolicy struct { + // Mode for updating the instance. + Mode *string `json:"mode,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.SslConfig +type SslConfig struct { + // Optional. SSL mode. Specifies client-server SSL/TLS connection behavior. + SslMode *string `json:"sslMode,omitempty"` + + // Optional. Certificate Authority (CA) source. Only CA_SOURCE_MANAGED is + // supported currently, and is the default value. + CaSource *string `json:"caSource,omitempty"` +} diff --git a/apis/alloydb/v1alpha1/zz_generated.deepcopy.go b/apis/alloydb/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..c9fc8953f9 --- /dev/null +++ b/apis/alloydb/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,630 @@ +//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 *AlloyDBInstance) DeepCopyInto(out *AlloyDBInstance) { + *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 AlloyDBInstance. +func (in *AlloyDBInstance) DeepCopy() *AlloyDBInstance { + if in == nil { + return nil + } + out := new(AlloyDBInstance) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AlloyDBInstance) 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 *AlloyDBInstanceList) DeepCopyInto(out *AlloyDBInstanceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AlloyDBInstance, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlloyDBInstanceList. +func (in *AlloyDBInstanceList) DeepCopy() *AlloyDBInstanceList { + if in == nil { + return nil + } + out := new(AlloyDBInstanceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AlloyDBInstanceList) 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 *AlloyDBInstanceSpec) DeepCopyInto(out *AlloyDBInstanceSpec) { + *out = *in + if in.ClusterRef != nil { + in, out := &in.ClusterRef, &out.ClusterRef + *out = new(v1beta1.AlloyDBClusterRef) + **out = **in + } + if in.ResourceID != nil { + in, out := &in.ResourceID, &out.ResourceID + *out = new(string) + **out = **in + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.AvailabilityType != nil { + in, out := &in.AvailabilityType, &out.AvailabilityType + *out = new(string) + **out = **in + } + if in.DatabaseFlags != nil { + in, out := &in.DatabaseFlags, &out.DatabaseFlags + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.DisplayName != nil { + in, out := &in.DisplayName, &out.DisplayName + *out = new(string) + **out = **in + } + if in.GceZone != nil { + in, out := &in.GceZone, &out.GceZone + *out = new(string) + **out = **in + } + if in.InstanceType != nil { + in, out := &in.InstanceType, &out.InstanceType + *out = new(string) + **out = **in + } + if in.InstanceTypeRef != nil { + in, out := &in.InstanceTypeRef, &out.InstanceTypeRef + *out = new(v1beta1.AlloyDBClusterTypeRef) + **out = **in + } + if in.MachineConfig != nil { + in, out := &in.MachineConfig, &out.MachineConfig + *out = new(Instance_MachineConfig) + (*in).DeepCopyInto(*out) + } + if in.NetworkConfig != nil { + in, out := &in.NetworkConfig, &out.NetworkConfig + *out = new(Instance_InstanceNetworkConfig) + (*in).DeepCopyInto(*out) + } + if in.ReadPoolConfig != nil { + in, out := &in.ReadPoolConfig, &out.ReadPoolConfig + *out = new(Instance_ReadPoolConfig) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlloyDBInstanceSpec. +func (in *AlloyDBInstanceSpec) DeepCopy() *AlloyDBInstanceSpec { + if in == nil { + return nil + } + out := new(AlloyDBInstanceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AlloyDBInstanceStatus) DeepCopyInto(out *AlloyDBInstanceStatus) { + *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.CreateTime != nil { + in, out := &in.CreateTime, &out.CreateTime + *out = new(string) + **out = **in + } + if in.IpAddress != nil { + in, out := &in.IpAddress, &out.IpAddress + *out = new(string) + **out = **in + } + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.OutboundPublicIpAddresses != nil { + in, out := &in.OutboundPublicIpAddresses, &out.OutboundPublicIpAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.PublicIpAddress != nil { + in, out := &in.PublicIpAddress, &out.PublicIpAddress + *out = new(string) + **out = **in + } + if in.Reconciling != nil { + in, out := &in.Reconciling, &out.Reconciling + *out = new(bool) + **out = **in + } + if in.State != nil { + in, out := &in.State, &out.State + *out = new(string) + **out = **in + } + if in.Uid != nil { + in, out := &in.Uid, &out.Uid + *out = new(string) + **out = **in + } + if in.UpdateTime != nil { + in, out := &in.UpdateTime, &out.UpdateTime + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlloyDBInstanceStatus. +func (in *AlloyDBInstanceStatus) DeepCopy() *AlloyDBInstanceStatus { + if in == nil { + return nil + } + out := new(AlloyDBInstanceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeminiInstanceConfig) DeepCopyInto(out *GeminiInstanceConfig) { + *out = *in + if in.Entitled != nil { + in, out := &in.Entitled, &out.Entitled + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeminiInstanceConfig. +func (in *GeminiInstanceConfig) DeepCopy() *GeminiInstanceConfig { + if in == nil { + return nil + } + out := new(GeminiInstanceConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InstanceIdentity) DeepCopyInto(out *InstanceIdentity) { + *out = *in + if in.parent != nil { + in, out := &in.parent, &out.parent + *out = new(InstanceParent) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceIdentity. +func (in *InstanceIdentity) DeepCopy() *InstanceIdentity { + if in == nil { + return nil + } + out := new(InstanceIdentity) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InstanceParent) DeepCopyInto(out *InstanceParent) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceParent. +func (in *InstanceParent) DeepCopy() *InstanceParent { + if in == nil { + return nil + } + out := new(InstanceParent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InstanceRef) DeepCopyInto(out *InstanceRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceRef. +func (in *InstanceRef) DeepCopy() *InstanceRef { + if in == nil { + return nil + } + out := new(InstanceRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_ClientConnectionConfig) DeepCopyInto(out *Instance_ClientConnectionConfig) { + *out = *in + if in.RequireConnectors != nil { + in, out := &in.RequireConnectors, &out.RequireConnectors + *out = new(bool) + **out = **in + } + if in.SslConfig != nil { + in, out := &in.SslConfig, &out.SslConfig + *out = new(SslConfig) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_ClientConnectionConfig. +func (in *Instance_ClientConnectionConfig) DeepCopy() *Instance_ClientConnectionConfig { + if in == nil { + return nil + } + out := new(Instance_ClientConnectionConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_InstanceNetworkConfig) DeepCopyInto(out *Instance_InstanceNetworkConfig) { + *out = *in + if in.AuthorizedExternalNetworks != nil { + in, out := &in.AuthorizedExternalNetworks, &out.AuthorizedExternalNetworks + *out = make([]Instance_InstanceNetworkConfig_AuthorizedNetwork, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.EnablePublicIp != nil { + in, out := &in.EnablePublicIp, &out.EnablePublicIp + *out = new(bool) + **out = **in + } + if in.EnableOutboundPublicIp != nil { + in, out := &in.EnableOutboundPublicIp, &out.EnableOutboundPublicIp + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_InstanceNetworkConfig. +func (in *Instance_InstanceNetworkConfig) DeepCopy() *Instance_InstanceNetworkConfig { + if in == nil { + return nil + } + out := new(Instance_InstanceNetworkConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_InstanceNetworkConfig_AuthorizedNetwork) DeepCopyInto(out *Instance_InstanceNetworkConfig_AuthorizedNetwork) { + *out = *in + if in.CidrRange != nil { + in, out := &in.CidrRange, &out.CidrRange + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_InstanceNetworkConfig_AuthorizedNetwork. +func (in *Instance_InstanceNetworkConfig_AuthorizedNetwork) DeepCopy() *Instance_InstanceNetworkConfig_AuthorizedNetwork { + if in == nil { + return nil + } + out := new(Instance_InstanceNetworkConfig_AuthorizedNetwork) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_MachineConfig) DeepCopyInto(out *Instance_MachineConfig) { + *out = *in + if in.CpuCount != nil { + in, out := &in.CpuCount, &out.CpuCount + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_MachineConfig. +func (in *Instance_MachineConfig) DeepCopy() *Instance_MachineConfig { + if in == nil { + return nil + } + out := new(Instance_MachineConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_Node) DeepCopyInto(out *Instance_Node) { + *out = *in + if in.ZoneID != nil { + in, out := &in.ZoneID, &out.ZoneID + *out = new(string) + **out = **in + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Ip != nil { + in, out := &in.Ip, &out.Ip + *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 Instance_Node. +func (in *Instance_Node) DeepCopy() *Instance_Node { + if in == nil { + return nil + } + out := new(Instance_Node) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_ObservabilityInstanceConfig) DeepCopyInto(out *Instance_ObservabilityInstanceConfig) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in + } + if in.PreserveComments != nil { + in, out := &in.PreserveComments, &out.PreserveComments + *out = new(bool) + **out = **in + } + if in.TrackWaitEvents != nil { + in, out := &in.TrackWaitEvents, &out.TrackWaitEvents + *out = new(bool) + **out = **in + } + if in.TrackWaitEventTypes != nil { + in, out := &in.TrackWaitEventTypes, &out.TrackWaitEventTypes + *out = new(bool) + **out = **in + } + if in.MaxQueryStringLength != nil { + in, out := &in.MaxQueryStringLength, &out.MaxQueryStringLength + *out = new(int32) + **out = **in + } + if in.RecordApplicationTags != nil { + in, out := &in.RecordApplicationTags, &out.RecordApplicationTags + *out = new(bool) + **out = **in + } + if in.QueryPlansPerMinute != nil { + in, out := &in.QueryPlansPerMinute, &out.QueryPlansPerMinute + *out = new(int32) + **out = **in + } + if in.TrackActiveQueries != nil { + in, out := &in.TrackActiveQueries, &out.TrackActiveQueries + *out = new(bool) + **out = **in + } + if in.TrackClientAddress != nil { + in, out := &in.TrackClientAddress, &out.TrackClientAddress + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_ObservabilityInstanceConfig. +func (in *Instance_ObservabilityInstanceConfig) DeepCopy() *Instance_ObservabilityInstanceConfig { + if in == nil { + return nil + } + out := new(Instance_ObservabilityInstanceConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_PscInstanceConfig) DeepCopyInto(out *Instance_PscInstanceConfig) { + *out = *in + if in.ServiceAttachmentLink != nil { + in, out := &in.ServiceAttachmentLink, &out.ServiceAttachmentLink + *out = new(string) + **out = **in + } + if in.AllowedConsumerProjects != nil { + in, out := &in.AllowedConsumerProjects, &out.AllowedConsumerProjects + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.PscDnsName != nil { + in, out := &in.PscDnsName, &out.PscDnsName + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_PscInstanceConfig. +func (in *Instance_PscInstanceConfig) DeepCopy() *Instance_PscInstanceConfig { + if in == nil { + return nil + } + out := new(Instance_PscInstanceConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_QueryInsightsInstanceConfig) DeepCopyInto(out *Instance_QueryInsightsInstanceConfig) { + *out = *in + if in.RecordApplicationTags != nil { + in, out := &in.RecordApplicationTags, &out.RecordApplicationTags + *out = new(bool) + **out = **in + } + if in.RecordClientAddress != nil { + in, out := &in.RecordClientAddress, &out.RecordClientAddress + *out = new(bool) + **out = **in + } + if in.QueryStringLength != nil { + in, out := &in.QueryStringLength, &out.QueryStringLength + *out = new(uint32) + **out = **in + } + if in.QueryPlansPerMinute != nil { + in, out := &in.QueryPlansPerMinute, &out.QueryPlansPerMinute + *out = new(uint32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_QueryInsightsInstanceConfig. +func (in *Instance_QueryInsightsInstanceConfig) DeepCopy() *Instance_QueryInsightsInstanceConfig { + if in == nil { + return nil + } + out := new(Instance_QueryInsightsInstanceConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_ReadPoolConfig) DeepCopyInto(out *Instance_ReadPoolConfig) { + *out = *in + if in.NodeCount != nil { + in, out := &in.NodeCount, &out.NodeCount + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_ReadPoolConfig. +func (in *Instance_ReadPoolConfig) DeepCopy() *Instance_ReadPoolConfig { + if in == nil { + return nil + } + out := new(Instance_ReadPoolConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_UpdatePolicy) DeepCopyInto(out *Instance_UpdatePolicy) { + *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 Instance_UpdatePolicy. +func (in *Instance_UpdatePolicy) DeepCopy() *Instance_UpdatePolicy { + if in == nil { + return nil + } + out := new(Instance_UpdatePolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SslConfig) DeepCopyInto(out *SslConfig) { + *out = *in + if in.SslMode != nil { + in, out := &in.SslMode, &out.SslMode + *out = new(string) + **out = **in + } + if in.CaSource != nil { + in, out := &in.CaSource, &out.CaSource + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SslConfig. +func (in *SslConfig) DeepCopy() *SslConfig { + if in == nil { + return nil + } + out := new(SslConfig) + in.DeepCopyInto(out) + return out +} diff --git a/apis/alloydb/v1beta1/doc.go b/apis/alloydb/v1beta1/doc.go new file mode 100644 index 0000000000..c08dd82333 --- /dev/null +++ b/apis/alloydb/v1beta1/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.alloydb.v1beta +package v1beta1 diff --git a/apis/alloydb/v1beta1/groupversion_info.go b/apis/alloydb/v1beta1/groupversion_info.go new file mode 100644 index 0000000000..331999fe7c --- /dev/null +++ b/apis/alloydb/v1beta1/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=alloydb.cnrm.cloud.google.com +package v1beta1 + +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: "alloydb.cnrm.cloud.google.com", Version: "v1beta1"} + + // 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/alloydb/v1beta1/instance_identity.go b/apis/alloydb/v1beta1/instance_identity.go new file mode 100644 index 0000000000..9ee7c11a1a --- /dev/null +++ b/apis/alloydb/v1beta1/instance_identity.go @@ -0,0 +1,123 @@ +// 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 v1beta1 + +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" +) + +const serviceDomain = "//alloydb.googleapis.com" + +// InstanceIdentity defines the resource reference to AlloyDBInstance, which "External" field +// holds the GCP identifier for the KRM object. +type InstanceIdentity struct { + parent *InstanceParent + id string +} + +func (i *InstanceIdentity) String() string { + return i.parent.String() + "/instances/" + i.id +} + +func (i *InstanceIdentity) ID() string { + return i.id +} + +func (i *InstanceIdentity) Parent() *InstanceParent { + return i.parent +} + +// AsExternalRef builds a externalRef from a PrivilegedAccessManagerEntitlement. +func (i *InstanceIdentity) AsExternalRef() *string { + er := serviceDomain + "/" + i.String() + return &er +} + +type InstanceParent struct { + clusterName string +} + +func (p *InstanceParent) String() string { + return p.clusterName +} + +// New builds a InstanceIdentity from the Config Connector Instance object. +func NewInstanceIdentity(ctx context.Context, reader client.Reader, obj *AlloyDBInstance) (*InstanceIdentity, error) { + + // Get Parent + clusterRef, err := refsv1beta1.ResolveAlloyDBCluster(ctx, reader, obj, obj.Spec.ClusterRef) + if err != nil { + return nil, fmt.Errorf("cannot resolve AlloyDBCluster ref: %w", err) + } + + // 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 ExternalRef + externalRef := common.ValueOf(obj.Status.ExternalRef) + if externalRef != "" { + // Validate desired with actual + actualParent, actualResourceID, err := ParseInstanceExternalRef(externalRef) + if err != nil { + return nil, err + } + if actualParent.clusterName != clusterRef.String() { + return nil, fmt.Errorf("spec.clusterRef changed, expect %s, got %s", actualParent.clusterName, clusterRef) + } + 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 &InstanceIdentity{ + parent: &InstanceParent{ + clusterName: clusterRef.String(), + }, + id: resourceID, + }, nil +} + +func ParseInstanceExternalRef(externalRef string) (parent *InstanceParent, resourceID string, err error) { + if !strings.HasPrefix(externalRef, serviceDomain) { + return nil, "", fmt.Errorf("externalRef should have prefix %s, got %s", serviceDomain, externalRef) + } + path := strings.TrimPrefix(externalRef, serviceDomain+"/") + return ParseInstanceExternal(path) +} + +func ParseInstanceExternal(external string) (parent *InstanceParent, resourceID string, err error) { + tokens := strings.Split(external, "/") + if len(tokens) != 8 || tokens[0] != "projects" || tokens[2] != "locations" || tokens[4] != "clusters" || tokens[6] != "instances" { + return nil, "", fmt.Errorf("format of AlloyDBInstance external=%q was not known (use projects//locations//clusters//instances/)", external) + } + parent = &InstanceParent{ + clusterName: fmt.Sprintf("%s/%s/%s/%s/%s/%s", tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]), + } + resourceID = tokens[7] + return parent, resourceID, nil +} diff --git a/apis/alloydb/v1beta1/instance_reference.go b/apis/alloydb/v1beta1/instance_reference.go new file mode 100644 index 0000000000..0518e62537 --- /dev/null +++ b/apis/alloydb/v1beta1/instance_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 v1beta1 + +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 = &InstanceRef{} + +// InstanceRef defines the resource reference to AlloyDBInstance, which "External" field +// holds the GCP identifier for the KRM object. +type InstanceRef struct { + // A reference to an externally managed AlloyDBInstance resource. + // Should be in the format "projects//locations//instances/". + External string `json:"external,omitempty"` + + // The name of a AlloyDBInstance resource. + Name string `json:"name,omitempty"` + + // The namespace of a AlloyDBInstance resource. + Namespace string `json:"namespace,omitempty"` +} + +// NormalizedExternal provision the "External" value for other resource that depends on AlloyDBInstance. +// If the "External" is given in the other resource's spec.AlloyDBInstanceRef, the given value will be used. +// Otherwise, the "Name" and "Namespace" will be used to query the actual AlloyDBInstance object from the cluster. +func (r *InstanceRef) 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", AlloyDBInstanceGVK.Kind) + } + // From given External + if r.External != "" { + if _, _, err := ParseInstanceExternal(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(AlloyDBInstanceGVK) + 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", AlloyDBInstanceGVK, 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/alloydb/v1beta1/instance_types.go b/apis/alloydb/v1beta1/instance_types.go new file mode 100644 index 0000000000..78ac8ad533 --- /dev/null +++ b/apis/alloydb/v1beta1/instance_types.go @@ -0,0 +1,195 @@ +// 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 v1beta1 + +import ( + refs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/k8s/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var AlloyDBInstanceGVK = GroupVersion.WithKind("AlloyDBInstance") + +// AlloyDBInstanceSpec defines the desired state of AlloyDBInstance +// +kcc:proto=google.cloud.alloydb.v1beta.Instance +type AlloyDBInstanceSpec struct { + + // The AlloyDBInstance cluster that this resource belongs to. + // +required + ClusterRef *refs.AlloyDBClusterRef `json:"clusterRef,omitempty"` + + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="ResourceID field is immutable" + // Immutable. + // Optional. The instanceId of the resource. If not given, the metadata.name will be used. + ResourceID *string `json:"resourceID,omitempty"` + + // Annotations to allow client tools to store small amount + // of arbitrary data. This is distinct from labels. + Annotations map[string]string `json:"annotations,omitempty"` + + // Availability type of an Instance. Defaults to REGIONAL for both primary and read instances. + // + // Note that primary and read instances can have different availability types. + // Only READ_POOL instance supports ZONAL type. Users can't specify the zone for READ_POOL instance. + // Zone is automatically chosen from the list of zones in the region specified. + // Read pool of size 1 can only have zonal availability. Read pools with node count of 2 or more + // can have regional availability (nodes are present in 2 or more zones in a region). Possible values: ["AVAILABILITY_TYPE_UNSPECIFIED", "ZONAL", "REGIONAL"]. + AvailabilityType *string `json:"availabilityType,omitempty"` + + // Database flags. Set at instance level. * They are copied + // from primary instance on read instance creation. * Read instances + // can set new or override existing flags that are relevant for reads, + // e.g. for enabling columnar cache on a read instance. Flags set on + // read instance may or may not be present on primary. + DatabaseFlags map[string]string `json:"databaseFlags,omitempty"` + + // User-settable and human-readable display name for the + // Instance. + DisplayName *string `json:"displayName,omitempty"` + + // The Compute Engine zone that the instance should serve + // from, per https://cloud.google.com/compute/docs/regions-zones This + // can ONLY be specified for ZONAL instances. If present for a REGIONAL + // instance, an error will be thrown. If this is absent for a ZONAL + // instance, instance is created in a random zone with available capacity. + GceZone *string `json:"gceZone,omitempty"` + + // We recommend that you use `instanceTypeRef` instead. + // The type of the instance. Possible values: [PRIMARY, READ_POOL, SECONDARY] + InstanceType *string `json:"instanceType,omitempty"` + + // The type of instance. + // Possible values: ["PRIMARY", "READ_POOL", "SECONDARY"] + // + // For PRIMARY and SECONDARY instances, set the value to refer to the name of the associated cluster. + // This is recommended because the instance type of primary and secondary instances is tied to the cluster type of the associated cluster. + // If the secondary cluster is promoted to primary cluster, then the associated secondary instance also becomes primary instance. + // Example: + // instanceTypeRef: + // name: clusterName + // For instances of type READ_POOL, set the value using external keyword. + // Example: + // instanceTypeRef: + // external: READ_POOL + // If the instance type is SECONDARY, the delete instance operation does not delete the secondary instance but abandons it instead. + // Use deletionPolicy = "FORCE" in the associated secondary cluster and delete the cluster forcefully to delete the secondary cluster as well its associated secondary instance. + InstanceTypeRef *refs.AlloyDBClusterTypeRef `json:"instanceTypeRef,omitempty"` + + // Configurations for the machines that host the underlying + // database engine. + MachineConfig *Instance_MachineConfig `json:"machineConfig,omitempty"` + + // Instance level network configuration. + NetworkConfig *Instance_InstanceNetworkConfig `json:"networkConfig,omitempty"` + + // Read pool specific config. If the instance type is READ_POOL, + // this configuration must be provided. + ReadPoolConfig *Instance_ReadPoolConfig `json:"readPoolConfig,omitempty"` +} + +// AlloyDBInstanceStatus defines the config connector machine state of AlloyDBInstance +type AlloyDBInstanceStatus 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 AlloyDBInstance resource in GCP. + ExternalRef *string `json:"externalRef,omitempty"` + + /* NOTYET + // ObservedState is the state of the resource as most recently observed in GCP. + ObservedState *AlloyDBInstanceObservedState `json:"observedState,omitempty"` + */ + + // Time the Instance was created in UTC. + CreateTime *string `json:"createTime,omitempty"` + + // The IP address for the Instance. This is the connection + // endpoint for an end-user application. + IpAddress *string `json:"ipAddress,omitempty"` + + // The name of the instance resource. + Name *string `json:"name,omitempty"` + + // The outbound public IP addresses for the instance. This is available ONLY when + // networkConfig.enableOutboundPublicIp is set to true. These IP addresses are used + // for outbound connections. + OutboundPublicIpAddresses []string `json:"outboundPublicIpAddresses,omitempty"` + + // The public IP addresses for the Instance. This is available + // ONLY when networkConfig.enablePublicIp is set to true. This is the + // connection endpoint for an end-user application. + PublicIpAddress *string `json:"publicIpAddress,omitempty"` + + // Set to true if the current state of Instance does not + // match the user's intended state, and the service is actively updating + // the resource to reconcile them. This can happen due to user-triggered + // updates or system actions like failover or maintenance. + Reconciling *bool `json:"reconciling,omitempty"` + + // The current state of the alloydb instance. + State *string `json:"state,omitempty"` + + // The system-generated UID of the resource. + Uid *string `json:"uid,omitempty"` + + // Time the Instance was updated in UTC. + UpdateTime *string `json:"updateTime,omitempty"` +} + +/* NOTYET +// AlloyDBInstanceSpec defines the desired state of AlloyDBInstance +// +kcc:proto=google.cloud.alloydb.v1beta.Instance +// AlloyDBInstanceObservedState is the state of the AlloyDBInstance resource as most recently observed in GCP. +type AlloyDBInstanceObservedState struct { +} +*/ + +// +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=gcpalloydbinstance;gcpalloydbinstances +// +kubebuilder:subresource:status +// +kubebuilder:metadata:labels="cnrm.cloud.google.com/tf2crd=true";"cnrm.cloud.google.com/managed-by-kcc=true";"cnrm.cloud.google.com/stability-level=stable";"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'" + +// AlloyDBInstance is the Schema for the AlloyDBInstance API +// +k8s:openapi-gen=true +type AlloyDBInstance struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // +required + Spec AlloyDBInstanceSpec `json:"spec,omitempty"` + Status AlloyDBInstanceStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// AlloyDBInstanceList contains a list of AlloyDBInstance +type AlloyDBInstanceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AlloyDBInstance `json:"items"` +} + +func init() { + SchemeBuilder.Register(&AlloyDBInstance{}, &AlloyDBInstanceList{}) +} diff --git a/apis/alloydb/v1beta1/types.generated.go b/apis/alloydb/v1beta1/types.generated.go new file mode 100644 index 0000000000..2185dbf809 --- /dev/null +++ b/apis/alloydb/v1beta1/types.generated.go @@ -0,0 +1,181 @@ +// 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 v1beta1 + +// +kcc:proto=google.cloud.alloydb.v1beta.GeminiInstanceConfig +type GeminiInstanceConfig struct { + // Output only. Whether the Gemini in Databases add-on is enabled for the + // instance. It will be true only if the add-on has been enabled for the + // billing account corresponding to the instance. Its status is toggled from + // the Admin Control Center (ACC) and cannot be toggled using AlloyDBInstance's APIs. + Entitled *bool `json:"entitled,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.ClientConnectionConfig +type Instance_ClientConnectionConfig struct { + // Optional. Configuration to enforce connectors only (ex: AuthProxy) + // connections to the database. + RequireConnectors *bool `json:"requireConnectors,omitempty"` + + // Optional. SSL configuration option for this instance. + SslConfig *SslConfig `json:"sslConfig,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.InstanceNetworkConfig +type Instance_InstanceNetworkConfig struct { + // Optional. A list of external network authorized to access this instance. + // This field is only allowed to be set when 'enablePublicIp' is set to true. + AuthorizedExternalNetworks []Instance_InstanceNetworkConfig_AuthorizedNetwork `json:"authorizedExternalNetworks,omitempty"` + + // Optional. Enabling public ip for the instance. If a user wishes + // to disable this, please also clear the list of the authorized + // external networks set on the same instance. + EnablePublicIp *bool `json:"enablePublicIp,omitempty"` + + // Optional. Enabling an outbound public IP address to support a database + // server sending requests out into the internet. + EnableOutboundPublicIp *bool `json:"enableOutboundPublicIp,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.InstanceNetworkConfig.AuthorizedNetwork +type Instance_InstanceNetworkConfig_AuthorizedNetwork struct { + // CIDR range for one authorzied network of the instance. + CidrRange *string `json:"cidrRange,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.MachineConfig +type Instance_MachineConfig struct { + // The number of CPU's in the VM instance. + CpuCount *int32 `json:"cpuCount,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.Node +type Instance_Node struct { + // The Compute Engine zone of the VM e.g. "us-central1-b". + ZoneID *string `json:"zoneID,omitempty"` + + // The identifier of the VM e.g. "test-read-0601-407e52be-ms3l". + ID *string `json:"id,omitempty"` + + // The private IP address of the VM e.g. "10.57.0.34". + Ip *string `json:"ip,omitempty"` + + // Determined by state of the compute VM and postgres-service health. + // Compute VM state can have values listed in + // https://cloud.google.com/compute/docs/instances/instance-life-cycle and + // postgres-service health can have values: HEALTHY and UNHEALTHY. + State *string `json:"state,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.ObservabilityInstanceConfig +type Instance_ObservabilityInstanceConfig struct { + // Observability feature status for an instance. + // This flag is turned "off" by default. + Enabled *bool `json:"enabled,omitempty"` + + // Preserve comments in query string for an instance. + // This flag is turned "off" by default. + PreserveComments *bool `json:"preserveComments,omitempty"` + + // Track wait events during query execution for an instance. + // This flag is turned "on" by default but tracking is enabled only after + // observability enabled flag is also turned on. + TrackWaitEvents *bool `json:"trackWaitEvents,omitempty"` + + // Output only. Track wait event types during query execution for an + // instance. This flag is turned "on" by default but tracking is enabled + // only after observability enabled flag is also turned on. This is + // read-only flag and only modifiable by producer API. + TrackWaitEventTypes *bool `json:"trackWaitEventTypes,omitempty"` + + // Query string length. The default value is 10k. + MaxQueryStringLength *int32 `json:"maxQueryStringLength,omitempty"` + + // Record application tags for an instance. + // This flag is turned "off" by default. + RecordApplicationTags *bool `json:"recordApplicationTags,omitempty"` + + // Number of query execution plans captured by Insights per minute + // for all queries combined. The default value is 200. + // Any integer between 0 to 200 is considered valid. + QueryPlansPerMinute *int32 `json:"queryPlansPerMinute,omitempty"` + + // Track actively running queries on the instance. + // If not set, this flag is "off" by default. + TrackActiveQueries *bool `json:"trackActiveQueries,omitempty"` + + // Track client address for an instance. + // If not set, default value is "off". + TrackClientAddress *bool `json:"trackClientAddress,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.PscInstanceConfig +type Instance_PscInstanceConfig struct { + // Output only. The service attachment created when Private + // Service Connect (PSC) is enabled for the instance. + // The name of the resource will be in the format of + // `projects//regions//serviceAttachments/` + ServiceAttachmentLink *string `json:"serviceAttachmentLink,omitempty"` + + // Optional. List of consumer projects that are allowed to create + // PSC endpoints to service-attachments to this instance. + AllowedConsumerProjects []string `json:"allowedConsumerProjects,omitempty"` + + // Output only. The DNS name of the instance for PSC connectivity. + // Name convention: ...alloydb-psc.goog + PscDnsName *string `json:"pscDnsName,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.QueryInsightsInstanceConfig +type Instance_QueryInsightsInstanceConfig struct { + // Record application tags for an instance. + // This flag is turned "on" by default. + RecordApplicationTags *bool `json:"recordApplicationTags,omitempty"` + + // Record client address for an instance. Client address is PII information. + // This flag is turned "on" by default. + RecordClientAddress *bool `json:"recordClientAddress,omitempty"` + + // Query string length. The default value is 1024. + // Any integer between 256 and 4500 is considered valid. + QueryStringLength *uint32 `json:"queryStringLength,omitempty"` + + // Number of query execution plans captured by Insights per minute + // for all queries combined. The default value is 5. + // Any integer between 0 and 20 is considered valid. + QueryPlansPerMinute *uint32 `json:"queryPlansPerMinute,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.ReadPoolConfig +type Instance_ReadPoolConfig struct { + // Read capacity, i.e. number of nodes in a read pool instance. + NodeCount *int32 `json:"nodeCount,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.Instance.UpdatePolicy +type Instance_UpdatePolicy struct { + // Mode for updating the instance. + Mode *string `json:"mode,omitempty"` +} + +// +kcc:proto=google.cloud.alloydb.v1beta.SslConfig +type SslConfig struct { + // Optional. SSL mode. Specifies client-server SSL/TLS connection behavior. + SslMode *string `json:"sslMode,omitempty"` + + // Optional. Certificate Authority (CA) source. Only CA_SOURCE_MANAGED is + // supported currently, and is the default value. + CaSource *string `json:"caSource,omitempty"` +} diff --git a/apis/alloydb/v1beta1/zz_generated.deepcopy.go b/apis/alloydb/v1beta1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..1f5bade33e --- /dev/null +++ b/apis/alloydb/v1beta1/zz_generated.deepcopy.go @@ -0,0 +1,630 @@ +//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 v1beta1 + +import ( + refsv1beta1 "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" + "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 *AlloyDBInstance) DeepCopyInto(out *AlloyDBInstance) { + *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 AlloyDBInstance. +func (in *AlloyDBInstance) DeepCopy() *AlloyDBInstance { + if in == nil { + return nil + } + out := new(AlloyDBInstance) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AlloyDBInstance) 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 *AlloyDBInstanceList) DeepCopyInto(out *AlloyDBInstanceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AlloyDBInstance, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlloyDBInstanceList. +func (in *AlloyDBInstanceList) DeepCopy() *AlloyDBInstanceList { + if in == nil { + return nil + } + out := new(AlloyDBInstanceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AlloyDBInstanceList) 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 *AlloyDBInstanceSpec) DeepCopyInto(out *AlloyDBInstanceSpec) { + *out = *in + if in.ClusterRef != nil { + in, out := &in.ClusterRef, &out.ClusterRef + *out = new(refsv1beta1.AlloyDBClusterRef) + **out = **in + } + if in.ResourceID != nil { + in, out := &in.ResourceID, &out.ResourceID + *out = new(string) + **out = **in + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.AvailabilityType != nil { + in, out := &in.AvailabilityType, &out.AvailabilityType + *out = new(string) + **out = **in + } + if in.DatabaseFlags != nil { + in, out := &in.DatabaseFlags, &out.DatabaseFlags + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.DisplayName != nil { + in, out := &in.DisplayName, &out.DisplayName + *out = new(string) + **out = **in + } + if in.GceZone != nil { + in, out := &in.GceZone, &out.GceZone + *out = new(string) + **out = **in + } + if in.InstanceType != nil { + in, out := &in.InstanceType, &out.InstanceType + *out = new(string) + **out = **in + } + if in.InstanceTypeRef != nil { + in, out := &in.InstanceTypeRef, &out.InstanceTypeRef + *out = new(refsv1beta1.AlloyDBClusterTypeRef) + **out = **in + } + if in.MachineConfig != nil { + in, out := &in.MachineConfig, &out.MachineConfig + *out = new(Instance_MachineConfig) + (*in).DeepCopyInto(*out) + } + if in.NetworkConfig != nil { + in, out := &in.NetworkConfig, &out.NetworkConfig + *out = new(Instance_InstanceNetworkConfig) + (*in).DeepCopyInto(*out) + } + if in.ReadPoolConfig != nil { + in, out := &in.ReadPoolConfig, &out.ReadPoolConfig + *out = new(Instance_ReadPoolConfig) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlloyDBInstanceSpec. +func (in *AlloyDBInstanceSpec) DeepCopy() *AlloyDBInstanceSpec { + if in == nil { + return nil + } + out := new(AlloyDBInstanceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AlloyDBInstanceStatus) DeepCopyInto(out *AlloyDBInstanceStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1alpha1.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.CreateTime != nil { + in, out := &in.CreateTime, &out.CreateTime + *out = new(string) + **out = **in + } + if in.IpAddress != nil { + in, out := &in.IpAddress, &out.IpAddress + *out = new(string) + **out = **in + } + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.OutboundPublicIpAddresses != nil { + in, out := &in.OutboundPublicIpAddresses, &out.OutboundPublicIpAddresses + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.PublicIpAddress != nil { + in, out := &in.PublicIpAddress, &out.PublicIpAddress + *out = new(string) + **out = **in + } + if in.Reconciling != nil { + in, out := &in.Reconciling, &out.Reconciling + *out = new(bool) + **out = **in + } + if in.State != nil { + in, out := &in.State, &out.State + *out = new(string) + **out = **in + } + if in.Uid != nil { + in, out := &in.Uid, &out.Uid + *out = new(string) + **out = **in + } + if in.UpdateTime != nil { + in, out := &in.UpdateTime, &out.UpdateTime + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlloyDBInstanceStatus. +func (in *AlloyDBInstanceStatus) DeepCopy() *AlloyDBInstanceStatus { + if in == nil { + return nil + } + out := new(AlloyDBInstanceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeminiInstanceConfig) DeepCopyInto(out *GeminiInstanceConfig) { + *out = *in + if in.Entitled != nil { + in, out := &in.Entitled, &out.Entitled + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeminiInstanceConfig. +func (in *GeminiInstanceConfig) DeepCopy() *GeminiInstanceConfig { + if in == nil { + return nil + } + out := new(GeminiInstanceConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InstanceIdentity) DeepCopyInto(out *InstanceIdentity) { + *out = *in + if in.parent != nil { + in, out := &in.parent, &out.parent + *out = new(InstanceParent) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceIdentity. +func (in *InstanceIdentity) DeepCopy() *InstanceIdentity { + if in == nil { + return nil + } + out := new(InstanceIdentity) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InstanceParent) DeepCopyInto(out *InstanceParent) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceParent. +func (in *InstanceParent) DeepCopy() *InstanceParent { + if in == nil { + return nil + } + out := new(InstanceParent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InstanceRef) DeepCopyInto(out *InstanceRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceRef. +func (in *InstanceRef) DeepCopy() *InstanceRef { + if in == nil { + return nil + } + out := new(InstanceRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_ClientConnectionConfig) DeepCopyInto(out *Instance_ClientConnectionConfig) { + *out = *in + if in.RequireConnectors != nil { + in, out := &in.RequireConnectors, &out.RequireConnectors + *out = new(bool) + **out = **in + } + if in.SslConfig != nil { + in, out := &in.SslConfig, &out.SslConfig + *out = new(SslConfig) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_ClientConnectionConfig. +func (in *Instance_ClientConnectionConfig) DeepCopy() *Instance_ClientConnectionConfig { + if in == nil { + return nil + } + out := new(Instance_ClientConnectionConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_InstanceNetworkConfig) DeepCopyInto(out *Instance_InstanceNetworkConfig) { + *out = *in + if in.AuthorizedExternalNetworks != nil { + in, out := &in.AuthorizedExternalNetworks, &out.AuthorizedExternalNetworks + *out = make([]Instance_InstanceNetworkConfig_AuthorizedNetwork, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.EnablePublicIp != nil { + in, out := &in.EnablePublicIp, &out.EnablePublicIp + *out = new(bool) + **out = **in + } + if in.EnableOutboundPublicIp != nil { + in, out := &in.EnableOutboundPublicIp, &out.EnableOutboundPublicIp + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_InstanceNetworkConfig. +func (in *Instance_InstanceNetworkConfig) DeepCopy() *Instance_InstanceNetworkConfig { + if in == nil { + return nil + } + out := new(Instance_InstanceNetworkConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_InstanceNetworkConfig_AuthorizedNetwork) DeepCopyInto(out *Instance_InstanceNetworkConfig_AuthorizedNetwork) { + *out = *in + if in.CidrRange != nil { + in, out := &in.CidrRange, &out.CidrRange + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_InstanceNetworkConfig_AuthorizedNetwork. +func (in *Instance_InstanceNetworkConfig_AuthorizedNetwork) DeepCopy() *Instance_InstanceNetworkConfig_AuthorizedNetwork { + if in == nil { + return nil + } + out := new(Instance_InstanceNetworkConfig_AuthorizedNetwork) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_MachineConfig) DeepCopyInto(out *Instance_MachineConfig) { + *out = *in + if in.CpuCount != nil { + in, out := &in.CpuCount, &out.CpuCount + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_MachineConfig. +func (in *Instance_MachineConfig) DeepCopy() *Instance_MachineConfig { + if in == nil { + return nil + } + out := new(Instance_MachineConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_Node) DeepCopyInto(out *Instance_Node) { + *out = *in + if in.ZoneID != nil { + in, out := &in.ZoneID, &out.ZoneID + *out = new(string) + **out = **in + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Ip != nil { + in, out := &in.Ip, &out.Ip + *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 Instance_Node. +func (in *Instance_Node) DeepCopy() *Instance_Node { + if in == nil { + return nil + } + out := new(Instance_Node) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_ObservabilityInstanceConfig) DeepCopyInto(out *Instance_ObservabilityInstanceConfig) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in + } + if in.PreserveComments != nil { + in, out := &in.PreserveComments, &out.PreserveComments + *out = new(bool) + **out = **in + } + if in.TrackWaitEvents != nil { + in, out := &in.TrackWaitEvents, &out.TrackWaitEvents + *out = new(bool) + **out = **in + } + if in.TrackWaitEventTypes != nil { + in, out := &in.TrackWaitEventTypes, &out.TrackWaitEventTypes + *out = new(bool) + **out = **in + } + if in.MaxQueryStringLength != nil { + in, out := &in.MaxQueryStringLength, &out.MaxQueryStringLength + *out = new(int32) + **out = **in + } + if in.RecordApplicationTags != nil { + in, out := &in.RecordApplicationTags, &out.RecordApplicationTags + *out = new(bool) + **out = **in + } + if in.QueryPlansPerMinute != nil { + in, out := &in.QueryPlansPerMinute, &out.QueryPlansPerMinute + *out = new(int32) + **out = **in + } + if in.TrackActiveQueries != nil { + in, out := &in.TrackActiveQueries, &out.TrackActiveQueries + *out = new(bool) + **out = **in + } + if in.TrackClientAddress != nil { + in, out := &in.TrackClientAddress, &out.TrackClientAddress + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_ObservabilityInstanceConfig. +func (in *Instance_ObservabilityInstanceConfig) DeepCopy() *Instance_ObservabilityInstanceConfig { + if in == nil { + return nil + } + out := new(Instance_ObservabilityInstanceConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_PscInstanceConfig) DeepCopyInto(out *Instance_PscInstanceConfig) { + *out = *in + if in.ServiceAttachmentLink != nil { + in, out := &in.ServiceAttachmentLink, &out.ServiceAttachmentLink + *out = new(string) + **out = **in + } + if in.AllowedConsumerProjects != nil { + in, out := &in.AllowedConsumerProjects, &out.AllowedConsumerProjects + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.PscDnsName != nil { + in, out := &in.PscDnsName, &out.PscDnsName + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_PscInstanceConfig. +func (in *Instance_PscInstanceConfig) DeepCopy() *Instance_PscInstanceConfig { + if in == nil { + return nil + } + out := new(Instance_PscInstanceConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_QueryInsightsInstanceConfig) DeepCopyInto(out *Instance_QueryInsightsInstanceConfig) { + *out = *in + if in.RecordApplicationTags != nil { + in, out := &in.RecordApplicationTags, &out.RecordApplicationTags + *out = new(bool) + **out = **in + } + if in.RecordClientAddress != nil { + in, out := &in.RecordClientAddress, &out.RecordClientAddress + *out = new(bool) + **out = **in + } + if in.QueryStringLength != nil { + in, out := &in.QueryStringLength, &out.QueryStringLength + *out = new(uint32) + **out = **in + } + if in.QueryPlansPerMinute != nil { + in, out := &in.QueryPlansPerMinute, &out.QueryPlansPerMinute + *out = new(uint32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_QueryInsightsInstanceConfig. +func (in *Instance_QueryInsightsInstanceConfig) DeepCopy() *Instance_QueryInsightsInstanceConfig { + if in == nil { + return nil + } + out := new(Instance_QueryInsightsInstanceConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_ReadPoolConfig) DeepCopyInto(out *Instance_ReadPoolConfig) { + *out = *in + if in.NodeCount != nil { + in, out := &in.NodeCount, &out.NodeCount + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance_ReadPoolConfig. +func (in *Instance_ReadPoolConfig) DeepCopy() *Instance_ReadPoolConfig { + if in == nil { + return nil + } + out := new(Instance_ReadPoolConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Instance_UpdatePolicy) DeepCopyInto(out *Instance_UpdatePolicy) { + *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 Instance_UpdatePolicy. +func (in *Instance_UpdatePolicy) DeepCopy() *Instance_UpdatePolicy { + if in == nil { + return nil + } + out := new(Instance_UpdatePolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SslConfig) DeepCopyInto(out *SslConfig) { + *out = *in + if in.SslMode != nil { + in, out := &in.SslMode, &out.SslMode + *out = new(string) + **out = **in + } + if in.CaSource != nil { + in, out := &in.CaSource, &out.CaSource + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SslConfig. +func (in *SslConfig) DeepCopy() *SslConfig { + if in == nil { + return nil + } + out := new(SslConfig) + in.DeepCopyInto(out) + return out +} diff --git a/apis/refs/v1beta1/alloydbref.go b/apis/refs/v1beta1/alloydbref.go new file mode 100644 index 0000000000..5f58ac7677 --- /dev/null +++ b/apis/refs/v1beta1/alloydbref.go @@ -0,0 +1,283 @@ +// 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 v1beta1 + +import ( + "context" + "fmt" + "strings" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type AlloyDBClusterRef struct { + // If provided must be in the format `projects/[projectId]/locations/[location]/clusters/[clusterId]`. + External string `json:"external,omitempty"` + // The `metadata.name` field of a `AlloyDBCluster` resource. + Name string `json:"name,omitempty"` + // The `metadata.namespace` field of a `AlloyDBCluster` resource. + Namespace string `json:"namespace,omitempty"` +} + +type AlloyDBCluster struct { + projectID string + location string + clusterID string +} + +func ResolveAlloyDBCluster(ctx context.Context, reader client.Reader, src client.Object, ref *AlloyDBClusterRef) (*AlloyDBCluster, error) { + if ref == nil { + return nil, nil + } + + if ref.Name == "" && ref.External == "" { + return nil, fmt.Errorf("must specify either name or external on AlloyDBClusterRef") + } + if ref.Name != "" && ref.External != "" { + return nil, fmt.Errorf("cannot specify both name and external on AlloyDBClusterRef") + } + + // External is provided. + if ref.External != "" { + // External should be in the `projects/[projectId]/locations/[location]/clusters/[clusterId]` format. + tokens := strings.Split(ref.External, "/") + if len(tokens) == 6 && tokens[0] == "projects" && tokens[2] == "locations" && tokens[4] == "clusters" { + return &AlloyDBCluster{ + projectID: tokens[1], + location: tokens[3], + clusterID: tokens[5], + }, nil + } + return nil, fmt.Errorf("format of AlloyDBClusterRef external=%q was not known (use projects/[projectId]/locations/[location]/clusters/[clusterId])", ref.External) + + } + + // Fetch AlloyDBCluster object to construct the external form. + cluster := &unstructured.Unstructured{} + cluster.SetGroupVersionKind(schema.GroupVersionKind{ + Group: "alloydb.cnrm.cloud.google.com", + Version: "v1beta1", + Kind: "AlloyDBCluster", + }) + nn := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + if nn.Namespace == "" { + nn.Namespace = src.GetNamespace() + } + if err := reader.Get(ctx, nn, cluster); err != nil { + if apierrors.IsNotFound(err) { + return nil, fmt.Errorf("referenced AlloyDBCluster %v not found", nn) + } + return nil, fmt.Errorf("error reading referenced AlloyDBCluster %v: %w", nn, err) + } + projectID, err := ResolveProjectID(ctx, reader, cluster) + if err != nil { + return nil, err + } + location, err := GetLocation(cluster) + if err != nil { + return nil, err + } + clusterID, err := GetResourceID(cluster) + if err != nil { + return nil, err + } + return &AlloyDBCluster{ + projectID: projectID, + location: location, + clusterID: clusterID, + }, nil +} + +type AlloyDBClusterTypeRef struct { + // The type of instance. Possible values: ["PRIMARY", "READ_POOL", "SECONDARY"] + External string `json:"external,omitempty"` + // The `metadata.name` field of a `AlloyDBCluster` resource. + Name string `json:"name,omitempty"` + // The `metadata.namespace` field of a `AlloyDBCluster` resource. + Namespace string `json:"namespace,omitempty"` +} + +func ResolveAlloyDBClusterType(ctx context.Context, reader client.Reader, src client.Object, ref *AlloyDBClusterTypeRef) (*string, error) { + if ref == nil { + return nil, nil + } + + if ref.Name == "" && ref.External == "" { + return nil, fmt.Errorf("must specify either name or external on AlloyDBClusterRef") + } + if ref.Name != "" && ref.External != "" { + return nil, fmt.Errorf("cannot specify both name and external on AlloyDBClusterRef") + } + + // External is provided. + if ref.External != "" { + return lazyPtr(ref.External), nil + } + + // Fetch AlloyDBCluster object to construct the external form. + cluster := &unstructured.Unstructured{} + cluster.SetGroupVersionKind(schema.GroupVersionKind{ + Group: "alloydb.cnrm.cloud.google.com", + Version: "v1beta1", + Kind: "AlloyDBCluster", + }) + nn := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + if nn.Namespace == "" { + nn.Namespace = src.GetNamespace() + } + if err := reader.Get(ctx, nn, cluster); err != nil { + if apierrors.IsNotFound(err) { + return nil, fmt.Errorf("referenced AlloyDBCluster %v not found", nn) + } + return nil, fmt.Errorf("error reading referenced AlloyDBCluster %v: %w", nn, err) + } + clusterType, _, err := unstructured.NestedString(cluster.Object, "spec", "clusterType") + if err != nil { + return nil, fmt.Errorf("reading spec.clusterType from %v %v/%v: %w", cluster.GroupVersionKind().Kind, cluster.GetNamespace(), cluster.GetName(), err) + } + if clusterType == "" { + // clusterType is defaulted to "PRIMARY" when not set. + clusterType = "PRIMARY" + } + return lazyPtr(clusterType), nil +} + +func ResolveAlloyDBClusterName(ctx context.Context, reader client.Reader, obj *unstructured.Unstructured) (string, error) { + clusterRefExternal, _, _ := unstructured.NestedString(obj.Object, "spec", "clusterRef", "external") + if clusterRefExternal != "" { + clusterRef := AlloyDBClusterRef{ + External: clusterRefExternal, + } + + cluster, err := ResolveAlloyDBCluster(ctx, reader, obj, &clusterRef) + if err != nil { + return "", fmt.Errorf("cannot parse clusterRef.external %q in %v %v/%v: %w", clusterRefExternal, obj.GetKind(), obj.GetNamespace(), obj.GetName(), err) + } + return cluster.String(), nil + } + + clusterRefName, _, _ := unstructured.NestedString(obj.Object, "spec", "clusterRef", "name") + if clusterRefName != "" { + clusterRefNamespace, _, _ := unstructured.NestedString(obj.Object, "spec", "clusterRef", "namespace") + + clusterRef := AlloyDBClusterRef{ + Name: clusterRefName, + Namespace: clusterRefNamespace, + } + if clusterRef.Namespace == "" { + clusterRef.Namespace = obj.GetNamespace() + } + + cluster, err := ResolveAlloyDBCluster(ctx, reader, obj, &clusterRef) + if err != nil { + return "", fmt.Errorf("cannot parse clusterRef in %v %v/%v: %w", obj.GetKind(), obj.GetNamespace(), obj.GetName(), err) + } + return cluster.String(), nil + } + + return "", fmt.Errorf("cannot find AlloyDB cluster name for %v %v/%v", obj.GetKind(), obj.GetNamespace(), obj.GetName()) +} + +func (c *AlloyDBCluster) String() string { + return fmt.Sprintf("projects/%s/locations/%s/clusters/%s", c.projectID, c.location, c.clusterID) +} + +type AlloyDBInstanceRef struct { + // If provided must be in the format `projects/[projectId]/locations/[location]/clusters/[clusterId]/instances/[instanceId]`. + External string `json:"external,omitempty"` + // The `metadata.name` field of a `AlloyDBInstance` resource. + Name string `json:"name,omitempty"` + // The `metadata.namespace` field of a `AlloyDBInstance` resource. + Namespace string `json:"namespace,omitempty"` +} + +type AlloyDBInstance struct { + clusterName string + instanceID string +} + +func ResolveAlloyDBInstance(ctx context.Context, reader client.Reader, src client.Object, ref *AlloyDBInstanceRef) (*AlloyDBInstance, error) { + if ref == nil { + return nil, nil + } + + if ref.Name == "" && ref.External == "" { + return nil, fmt.Errorf("must specify either name or external on AlloyDBInstanceRef") + } + if ref.Name != "" && ref.External != "" { + return nil, fmt.Errorf("cannot specify both name and external on AlloyDBInstanceRef") + } + + // External is provided. + if ref.External != "" { + // External should be in the `projects/[projectId]/locations/[location]/clusters/[clusterId]/instances/[instanceId]` format. + tokens := strings.Split(ref.External, "/") + if len(tokens) == 6 && tokens[0] == "projects" && tokens[2] == "locations" && tokens[4] == "clusters" && tokens[6] == "instances" { + return &AlloyDBInstance{ + clusterName: fmt.Sprintf("%s/%s/%s/%s/%s/%s", tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]), + instanceID: tokens[7], + }, nil + } + return nil, fmt.Errorf("format of AlloyDBInstanceRef external=%q was not known (use projects/[projectId]/locations/[location]/clusters/[clusterId]/instances/[instanceId])", ref.External) + + } + + // Fetch AlloyDBInstance object to construct the external form. + instance := &unstructured.Unstructured{} + instance.SetGroupVersionKind(schema.GroupVersionKind{ + Group: "alloydb.cnrm.cloud.google.com", + Version: "v1beta1", + Kind: "AlloyDBInstance", + }) + nn := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + if nn.Namespace == "" { + nn.Namespace = src.GetNamespace() + } + if err := reader.Get(ctx, nn, instance); err != nil { + if apierrors.IsNotFound(err) { + return nil, fmt.Errorf("referenced AlloyDBInstance %v not found", nn) + } + return nil, fmt.Errorf("error reading referenced AlloyDBInstance %v: %w", nn, err) + } + clusterName, err := ResolveAlloyDBClusterName(ctx, reader, instance) + if err != nil { + return nil, err + } + instanceID, err := GetResourceID(instance) + if err != nil { + return nil, err + } + return &AlloyDBInstance{ + clusterName: clusterName, + instanceID: instanceID, + }, nil +} + +func (i *AlloyDBInstance) String() string { + return fmt.Sprintf("%s/instances/%s", i.clusterName, i.instanceID) +} diff --git a/apis/refs/v1beta1/helper.go b/apis/refs/v1beta1/helper.go index df6733442b..0d0b81b732 100644 --- a/apis/refs/v1beta1/helper.go +++ b/apis/refs/v1beta1/helper.go @@ -41,3 +41,11 @@ func GetLocation(u *unstructured.Unstructured) (string, error) { } return location, nil } + +func lazyPtr[V comparable](v V) *V { + var defaultV V + if v == defaultV { + return nil + } + return &v +} diff --git a/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_alloydbinstances.alloydb.cnrm.cloud.google.com.yaml b/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_alloydbinstances.alloydb.cnrm.cloud.google.com.yaml index d5ba9d6474..b32deca361 100644 --- a/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_alloydbinstances.alloydb.cnrm.cloud.google.com.yaml +++ b/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_alloydbinstances.alloydb.cnrm.cloud.google.com.yaml @@ -16,6 +16,7 @@ spec: categories: - gcp kind: AlloyDBInstance + listKind: AlloyDBInstanceList plural: alloydbinstances shortNames: - gcpalloydbinstance @@ -40,28 +41,25 @@ spec: jsonPath: .status.conditions[?(@.type=='Ready')].lastTransitionTime name: Status Age type: date - name: v1beta1 + name: v1alpha1 schema: openAPIV3Schema: + description: AlloyDBInstance is the Schema for the AlloyDBInstance API properties: apiVersion: - description: 'apiVersion defines the versioned schema of this representation + 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/api-conventions.md#resources' + 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 + 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/api-conventions.md#types-kinds' + 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: - oneOf: - - required: - - instanceType - - required: - - instanceTypeRef + description: AlloyDBInstanceSpec defines the desired state of AlloyDBInstance properties: annotations: additionalProperties: @@ -71,14 +69,17 @@ spec: type: object availabilityType: description: |- - 'Availability type of an Instance. Defaults to REGIONAL for both primary and read instances. + Availability type of an Instance. Defaults to REGIONAL for both primary and read instances. + Note that primary and read instances can have different availability types. Only READ_POOL instance supports ZONAL type. Users can't specify the zone for READ_POOL instance. Zone is automatically chosen from the list of zones in the region specified. Read pool of size 1 can only have zonal availability. Read pools with node count of 2 or more - can have regional availability (nodes are present in 2 or more zones in a region).' Possible values: ["AVAILABILITY_TYPE_UNSPECIFIED", "ZONAL", "REGIONAL"]. + can have regional availability (nodes are present in 2 or more zones in a region). Possible values: ["AVAILABILITY_TYPE_UNSPECIFIED", "ZONAL", "REGIONAL"]. type: string clusterRef: + description: The AlloyDBInstance cluster that this resource belongs + to. oneOf: - not: required: @@ -95,14 +96,14 @@ spec: - external properties: external: - description: 'Allowed value: The `name` field of an `AlloyDBCluster` - resource.' + description: If provided must be in the format `projects/[projectId]/locations/[location]/clusters/[clusterId]`. type: string name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: The `metadata.name` field of a `AlloyDBCluster` resource. type: string namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + description: The `metadata.namespace` field of a `AlloyDBCluster` + resource. type: string type: object databaseFlags: @@ -126,14 +127,15 @@ spec: instance, instance is created in a random zone with available capacity. type: string instanceType: - description: |- - We recommend that you use `instanceTypeRef` instead. - The type of the instance. Possible values: [PRIMARY, READ_POOL, SECONDARY] + description: 'We recommend that you use `instanceTypeRef` instead. + The type of the instance. Possible values: [PRIMARY, READ_POOL, + SECONDARY]' type: string instanceTypeRef: description: |- The type of instance. Possible values: ["PRIMARY", "READ_POOL", "SECONDARY"] + For PRIMARY and SECONDARY instances, set the value to refer to the name of the associated cluster. This is recommended because the instance type of primary and secondary instances is tied to the cluster type of the associated cluster. If the secondary cluster is promoted to primary cluster, then the associated secondary instance also becomes primary instance. @@ -162,14 +164,15 @@ spec: - external properties: external: - description: 'Allowed value: The `clusterType` field of an `AlloyDBCluster` - resource.' + description: 'The type of instance. Possible values: ["PRIMARY", + "READ_POOL", "SECONDARY"]' type: string name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: The `metadata.name` field of a `AlloyDBCluster` resource. type: string namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + description: The `metadata.namespace` field of a `AlloyDBCluster` + resource. type: string type: object machineConfig: @@ -178,30 +181,32 @@ spec: properties: cpuCount: description: The number of CPU's in the VM instance. + format: int32 type: integer type: object networkConfig: description: Instance level network configuration. properties: authorizedExternalNetworks: - description: A list of external networks authorized to access - this instance. This field is only allowed to be set when 'enable_public_ip' - is set to true. + description: Optional. A list of external network authorized to + access this instance. This field is only allowed to be set when + 'enablePublicIp' is set to true. items: properties: cidrRange: - description: CIDR range for one authorized network of the + description: CIDR range for one authorzied network of the instance. type: string type: object type: array enableOutboundPublicIp: - description: Enabling outbound public ip for the instance. + description: Optional. Enabling an outbound public IP address + to support a database server sending requests out into the internet. type: boolean enablePublicIp: - description: Enabling public ip for the instance. If a user wishes - to disable this, please also clear the list of the authorized - external networks set on the same instance. + description: Optional. Enabling public ip for the instance. If + a user wishes to disable this, please also clear the list of + the authorized external networks set on the same instance. type: boolean type: object readPoolConfig: @@ -211,21 +216,26 @@ spec: nodeCount: description: Read capacity, i.e. number of nodes in a read pool instance. + format: int32 type: integer type: object resourceID: description: Immutable. Optional. The instanceId of the resource. - Used for creation and acquisition. When unset, the value of `metadata.name` - is used as the default. + If not given, the metadata.name will be used. type: string + x-kubernetes-validations: + - message: ResourceID field is immutable + rule: self == oldSelf required: - clusterRef type: object status: + description: AlloyDBInstanceStatus defines the config connector machine + state of AlloyDBInstance properties: conditions: - description: Conditions represent the latest available observation - of the resource's current state. + description: Conditions represent the latest available observations + of the object's current state. items: properties: lastTransitionTime: @@ -252,6 +262,10 @@ spec: createTime: description: Time the Instance was created in UTC. type: string + externalRef: + description: A unique specifier for the AlloyDBInstance resource in + GCP. + type: string ipAddress: description: The IP address for the Instance. This is the connection endpoint for an end-user application. @@ -265,12 +279,12 @@ spec: 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 outboundPublicIpAddresses: - description: |- - The outbound public IP addresses for the instance. This is available ONLY when - networkConfig.enableOutboundPublicIp is set to true. These IP addresses are used - for outbound connections. + description: The outbound public IP addresses for the instance. This + is available ONLY when networkConfig.enableOutboundPublicIp is set + to true. These IP addresses are used for outbound connections. items: type: string type: array @@ -299,7 +313,7 @@ spec: - spec type: object served: true - storage: false + storage: true subresources: status: {} - additionalPrinterColumns: @@ -318,28 +332,25 @@ spec: jsonPath: .status.conditions[?(@.type=='Ready')].lastTransitionTime name: Status Age type: date - name: v1alpha1 + name: v1beta1 schema: openAPIV3Schema: + description: AlloyDBInstance is the Schema for the AlloyDBInstance API properties: apiVersion: - description: 'apiVersion defines the versioned schema of this representation + 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/api-conventions.md#resources' + 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 + 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/api-conventions.md#types-kinds' + 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: - oneOf: - - required: - - instanceType - - required: - - instanceTypeRef + description: AlloyDBInstanceSpec defines the desired state of AlloyDBInstance properties: annotations: additionalProperties: @@ -349,14 +360,17 @@ spec: type: object availabilityType: description: |- - 'Availability type of an Instance. Defaults to REGIONAL for both primary and read instances. + Availability type of an Instance. Defaults to REGIONAL for both primary and read instances. + Note that primary and read instances can have different availability types. Only READ_POOL instance supports ZONAL type. Users can't specify the zone for READ_POOL instance. Zone is automatically chosen from the list of zones in the region specified. Read pool of size 1 can only have zonal availability. Read pools with node count of 2 or more - can have regional availability (nodes are present in 2 or more zones in a region).' Possible values: ["AVAILABILITY_TYPE_UNSPECIFIED", "ZONAL", "REGIONAL"]. + can have regional availability (nodes are present in 2 or more zones in a region). Possible values: ["AVAILABILITY_TYPE_UNSPECIFIED", "ZONAL", "REGIONAL"]. type: string clusterRef: + description: The AlloyDBInstance cluster that this resource belongs + to. oneOf: - not: required: @@ -373,14 +387,14 @@ spec: - external properties: external: - description: 'Allowed value: The `name` field of an `AlloyDBCluster` - resource.' + description: If provided must be in the format `projects/[projectId]/locations/[location]/clusters/[clusterId]`. type: string name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: The `metadata.name` field of a `AlloyDBCluster` resource. type: string namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + description: The `metadata.namespace` field of a `AlloyDBCluster` + resource. type: string type: object databaseFlags: @@ -404,14 +418,15 @@ spec: instance, instance is created in a random zone with available capacity. type: string instanceType: - description: |- - We recommend that you use `instanceTypeRef` instead. - The type of the instance. Possible values: [PRIMARY, READ_POOL, SECONDARY] + description: 'We recommend that you use `instanceTypeRef` instead. + The type of the instance. Possible values: [PRIMARY, READ_POOL, + SECONDARY]' type: string instanceTypeRef: description: |- The type of instance. Possible values: ["PRIMARY", "READ_POOL", "SECONDARY"] + For PRIMARY and SECONDARY instances, set the value to refer to the name of the associated cluster. This is recommended because the instance type of primary and secondary instances is tied to the cluster type of the associated cluster. If the secondary cluster is promoted to primary cluster, then the associated secondary instance also becomes primary instance. @@ -440,14 +455,15 @@ spec: - external properties: external: - description: 'Allowed value: The `clusterType` field of an `AlloyDBCluster` - resource.' + description: 'The type of instance. Possible values: ["PRIMARY", + "READ_POOL", "SECONDARY"]' type: string name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: The `metadata.name` field of a `AlloyDBCluster` resource. type: string namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + description: The `metadata.namespace` field of a `AlloyDBCluster` + resource. type: string type: object machineConfig: @@ -456,30 +472,32 @@ spec: properties: cpuCount: description: The number of CPU's in the VM instance. + format: int32 type: integer type: object networkConfig: description: Instance level network configuration. properties: authorizedExternalNetworks: - description: A list of external networks authorized to access - this instance. This field is only allowed to be set when 'enable_public_ip' - is set to true. + description: Optional. A list of external network authorized to + access this instance. This field is only allowed to be set when + 'enablePublicIp' is set to true. items: properties: cidrRange: - description: CIDR range for one authorized network of the + description: CIDR range for one authorzied network of the instance. type: string type: object type: array enableOutboundPublicIp: - description: Enabling outbound public ip for the instance. + description: Optional. Enabling an outbound public IP address + to support a database server sending requests out into the internet. type: boolean enablePublicIp: - description: Enabling public ip for the instance. If a user wishes - to disable this, please also clear the list of the authorized - external networks set on the same instance. + description: Optional. Enabling public ip for the instance. If + a user wishes to disable this, please also clear the list of + the authorized external networks set on the same instance. type: boolean type: object readPoolConfig: @@ -489,21 +507,26 @@ spec: nodeCount: description: Read capacity, i.e. number of nodes in a read pool instance. + format: int32 type: integer type: object resourceID: description: Immutable. Optional. The instanceId of the resource. - Used for creation and acquisition. When unset, the value of `metadata.name` - is used as the default. + If not given, the metadata.name will be used. type: string + x-kubernetes-validations: + - message: ResourceID field is immutable + rule: self == oldSelf required: - clusterRef type: object status: + description: AlloyDBInstanceStatus defines the config connector machine + state of AlloyDBInstance properties: conditions: - description: Conditions represent the latest available observation - of the resource's current state. + description: Conditions represent the latest available observations + of the object's current state. items: properties: lastTransitionTime: @@ -530,6 +553,10 @@ spec: createTime: description: Time the Instance was created in UTC. type: string + externalRef: + description: A unique specifier for the AlloyDBInstance resource in + GCP. + type: string ipAddress: description: The IP address for the Instance. This is the connection endpoint for an end-user application. @@ -543,12 +570,12 @@ spec: 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 outboundPublicIpAddresses: - description: |- - The outbound public IP addresses for the instance. This is available ONLY when - networkConfig.enableOutboundPublicIp is set to true. These IP addresses are used - for outbound connections. + description: The outbound public IP addresses for the instance. This + is available ONLY when networkConfig.enableOutboundPublicIp is set + to true. These IP addresses are used for outbound connections. items: type: string type: array @@ -577,12 +604,6 @@ spec: - spec type: object served: true - storage: true + storage: false subresources: status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/dev/tools/controllerbuilder/template/controller/controller.go b/dev/tools/controllerbuilder/template/controller/controller.go index 9ddd54f465..e008d59ff1 100644 --- a/dev/tools/controllerbuilder/template/controller/controller.go +++ b/dev/tools/controllerbuilder/template/controller/controller.go @@ -138,8 +138,8 @@ type {{.ProtoResource}}Adapter struct { var _ directbase.Adapter = &{{.ProtoResource}}Adapter{} // Find retrieves the GCP resource. -// Return true means the object is found. This triggers Adapter ` + "`" + `Update` + "`" + ` call. -// Return true means the object is not found. This triggers Adapter ` + "`" + `Create` + "`" + ` call. +// Return true means the object is found. This triggers Adapter ` + "`" + `Update` + "`" + ` call. +// Return true means the object is not found. This triggers Adapter ` + "`" + `Create` + "`" + ` call. // Return a non-nil error requeues the requests. func (a *{{.ProtoResource}}Adapter) Find(ctx context.Context) (bool, error) { log := klog.FromContext(ctx) diff --git a/go.mod b/go.mod index db15dbd7f7..444dacd015 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ toolchain go1.23.2 replace github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp => ./mockgcp require ( + cloud.google.com/go/alloydb v1.14.0 cloud.google.com/go/apikeys v1.1.12 cloud.google.com/go/bigquery v1.63.1 cloud.google.com/go/certificatemanager v1.9.1 diff --git a/go.sum b/go.sum index c715574541..f7682aa11c 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,8 @@ cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= +cloud.google.com/go/alloydb v1.14.0 h1:aEmmIHmiHDs46wTr/YqXuumuUGNc5QKYA7317nEFj2Y= +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.9.9 h1:BmtbpNQozo8ZwW2t7QJjnrQtdganSdmqeIBxHxNkEZQ= diff --git a/pkg/controller/direct/alloydb/instance_controller.go b/pkg/controller/direct/alloydb/instance_controller.go new file mode 100644 index 0000000000..abb031d971 --- /dev/null +++ b/pkg/controller/direct/alloydb/instance_controller.go @@ -0,0 +1,402 @@ +// 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 alloydb + +import ( + "context" + "fmt" + "reflect" + + krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/alloydb/v1beta1" + refsv1beta1 "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/directbase" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/registry" + + gcp "cloud.google.com/go/alloydb/apiv1beta" + alloydbpb "cloud.google.com/go/alloydb/apiv1beta/alloydbpb" + "github.com/google/go-cmp/cmp" + "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/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func init() { + registry.RegisterModel(krm.AlloyDBInstanceGVK, NewInstanceModel) +} + +func NewInstanceModel(ctx context.Context, config *config.ControllerConfig) (directbase.Model, error) { + return &instanceModel{config: *config}, nil +} + +var _ directbase.Model = &instanceModel{} + +type instanceModel struct { + config config.ControllerConfig +} + +func (m *instanceModel) client(ctx context.Context) (*gcp.AlloyDBAdminClient, error) { + var opts []option.ClientOption + opts, err := m.config.RESTClientOptions() + if err != nil { + return nil, err + } + gcpClient, err := gcp.NewAlloyDBAdminRESTClient(ctx, opts...) + if err != nil { + return nil, fmt.Errorf("error building AlloyDB client for Instance: %w", err) + } + return gcpClient, err +} + +func (m *instanceModel) AdapterForObject(ctx context.Context, reader client.Reader, u *unstructured.Unstructured) (directbase.Adapter, error) { + obj := &krm.AlloyDBInstance{} + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &obj); err != nil { + return nil, fmt.Errorf("error converting to %T: %w", obj, err) + } + + id, err := krm.NewInstanceIdentity(ctx, reader, obj) + if err != nil { + return nil, err + } + + if obj.Spec.InstanceType != nil && obj.Spec.InstanceTypeRef != nil { + return nil, fmt.Errorf("one and only one of 'spec.InstanceTypeRef' " + + "and 'spec.InstanceType' should be configured: both are configured") + } + if obj.Spec.InstanceType == nil && obj.Spec.InstanceTypeRef == nil { + return nil, fmt.Errorf("one and only one of 'spec.InstanceTypeRef' " + + "and 'spec.InstanceType' should be configured: neither is configured") + } + + var instanceType *string + if obj.Spec.InstanceType != nil { + if *instanceType == "" { + return nil, fmt.Errorf("'spec.InstanceType' should be configured with a non-empty string") + } + instanceType = obj.Spec.InstanceType + } + if obj.Spec.InstanceTypeRef != nil { + instanceType, err = refsv1beta1.ResolveAlloyDBClusterType(ctx, reader, obj, obj.Spec.InstanceTypeRef) + if err != nil { + return nil, fmt.Errorf("cannot resolve `spec.InstanceTypeRef`: %w", err) + } + } + obj.Spec.InstanceType = instanceType + + // Get alloydb GCP client + gcpClient, err := m.client(ctx) + if err != nil { + return nil, err + } + return &instanceAdapter{ + id: id, + gcpClient: gcpClient, + desired: obj, + }, nil +} + +func (m *instanceModel) AdapterForURL(ctx context.Context, url string) (directbase.Adapter, error) { + // TODO: Support URLs + return nil, nil +} + +type instanceAdapter struct { + id *krm.InstanceIdentity + gcpClient *gcp.AlloyDBAdminClient + desired *krm.AlloyDBInstance + actual *alloydbpb.Instance +} + +var _ directbase.Adapter = &instanceAdapter{} + +// Find retrieves the GCP resource. +// Return true means the object is found. This triggers Adapter `Update` call. +// Return true means the object is not found. This triggers Adapter `Create` call. +// Return a non-nil error requeues the requests. +func (a *instanceAdapter) Find(ctx context.Context) (bool, error) { + log := klog.FromContext(ctx) + log.V(2).Info("getting instance", "name", a.id) + fmt.Printf("getting instance: %v\n", a.id) + + req := &alloydbpb.GetInstanceRequest{Name: a.id.String()} + instancepb, err := a.gcpClient.GetInstance(ctx, req) + if err != nil { + log.V(2).Info("error getting instance", "name", a.id, "error", err) + fmt.Printf("instance error: %+v\n", err) + if direct.IsNotFound(err) { + return false, nil + } + + return false, fmt.Errorf("getting instance %q: %w", a.id, err) + } + + fmt.Printf("retrieved instance: %+v\n", instancepb) + a.actual = instancepb + 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 *instanceAdapter) Create(ctx context.Context, createOp *directbase.CreateOperation) error { + log := klog.FromContext(ctx) + log.V(2).Info("creating instance", "name", a.id) + fmt.Printf("creating instance: %v\n", a.id) + mapCtx := &direct.MapContext{} + + desired := a.desired.DeepCopy() + resource := AlloyDBInstanceSpec_ToProto(mapCtx, &desired.Spec) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + resource.Labels = make(map[string]string) + for k, v := range a.desired.GetObjectMeta().GetLabels() { + resource.Labels[k] = v + } + resource.Labels["managed-by-cnrm"] = "true" + + var created *alloydbpb.Instance + instanceType := a.desired.Spec.InstanceType + if instanceType != nil && *instanceType == "SECONDARY" { + req := &alloydbpb.CreateSecondaryInstanceRequest{ + Parent: a.id.Parent().String(), + InstanceId: a.id.ID(), + Instance: resource, + } + op, err := a.gcpClient.CreateSecondaryInstance(ctx, req) + if err != nil { + log.V(2).Info("error creating secondary instance", "name", a.id, "error", err) + return fmt.Errorf("creating secondary instance %s: %w", a.id, err) + } + created, err = op.Wait(ctx) + if err != nil { + log.V(2).Info("error waiting secondary instance creation", "name", a.id, "error", err) + return fmt.Errorf("secondary instance %s waiting creation: %w", a.id, err) + } + log.V(2).Info("successfully created secondary instance", "name", a.id) + } else { + req := &alloydbpb.CreateInstanceRequest{ + Parent: a.id.Parent().String(), + InstanceId: a.id.ID(), + Instance: resource, + } + op, err := a.gcpClient.CreateInstance(ctx, req) + if err != nil { + log.V(2).Info("error creating instance", "name", a.id, "error", err) + return fmt.Errorf("creating instance %s: %w", a.id, err) + } + created, err = op.Wait(ctx) + if err != nil { + log.V(2).Info("error waiting instance creation", "name", a.id, "error", err) + return fmt.Errorf("instance %s waiting creation: %w", a.id, err) + } + log.V(2).Info("successfully created instance", "name", a.id) + } + + status := AlloyDBInstanceStatus_FromProto(mapCtx, created) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + status.ExternalRef = a.id.AsExternalRef() + 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 *instanceAdapter) Update(ctx context.Context, updateOp *directbase.UpdateOperation) error { + log := klog.FromContext(ctx) + log.V(2).Info("updating instance", "name", a.id) + mapCtx := &direct.MapContext{} + + parsedActual := AlloyDBInstanceSpec_FromProto(mapCtx, a.actual) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + + updatePaths, err := compareInstance(ctx, parsedActual, &a.desired.Spec) + if err != nil { + return err + } + desiredLabels := a.desired.GetObjectMeta().GetLabels() + desiredLabels["managed-by-cnrm"] = "true" + if !reflect.DeepEqual(a.actual.GetLabels(), desiredLabels) { + log.V(2).Info("'metadata.labels' field is updated (-old +new)", cmp.Diff(a.actual.GetLabels(), desiredLabels)) + updatePaths = append(updatePaths, "availability_type") + } + + if len(updatePaths) == 0 { + log.V(2).Info("no field needs update", "name", a.id) + return nil + } + fmt.Printf("maqiuyu... updateMasks: %+v\n", updatePaths) + updateMask := &fieldmaskpb.FieldMask{ + Paths: updatePaths, + } + desiredPb := AlloyDBInstanceSpec_ToProto(mapCtx, &a.desired.DeepCopy().Spec) + desiredPb.Labels = desiredLabels + desiredPb.Name = a.id.String() + req := &alloydbpb.UpdateInstanceRequest{ + UpdateMask: updateMask, + Instance: desiredPb, + } + op, err := a.gcpClient.UpdateInstance(ctx, req) + if err != nil { + log.V(2).Info("error updating instance", "name", a.id, "error", err) + return fmt.Errorf("updating instance %s: %w", a.id, err) + } + updated, err := op.Wait(ctx) + if err != nil { + log.V(2).Info("error waiting instance update", "name", a.id, "error", err) + return fmt.Errorf("instance %s waiting update: %w", a.id, err) + } + log.V(2).Info("successfully updated instance", "name", a.id) + + status := AlloyDBInstanceStatus_FromProto(mapCtx, updated) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + return updateOp.UpdateStatus(ctx, status, nil) +} + +func compareInstance(ctx context.Context, actual, desired *krm.AlloyDBInstanceSpec) (updatePaths []string, err error) { + log := klog.FromContext(ctx) + updatePaths = make([]string, 0) + if !reflect.DeepEqual(actual.Annotations, desired.Annotations) { + log.V(2).Info("'spec.annotations' field is updated (-old +new)", cmp.Diff(actual.Annotations, desired.Annotations)) + updatePaths = append(updatePaths, "annotations") + } + // TODO: Test case with availability type unset. + if desired.AvailabilityType != nil && !reflect.DeepEqual(actual.AvailabilityType, desired.AvailabilityType) { + log.V(2).Info("'spec.availabilityType' field is updated (-old +new)", cmp.Diff(actual.AvailabilityType, desired.AvailabilityType)) + updatePaths = append(updatePaths, "availability_type") + } + // TODO: Test "copied" behavior for read pool + // TODO: Test "overridden" behavior for read pool + // Default value of databaseFlags is unknown for a read instance unless we + // make API calls to get the database flags of the primary instance. + if desired.DatabaseFlags != nil && !reflect.DeepEqual(actual.DatabaseFlags, desired.DatabaseFlags) { + log.V(2).Info("'spec.databaseFlags' field is updated (-old +new)", cmp.Diff(actual.DatabaseFlags, desired.DatabaseFlags)) + updatePaths = append(updatePaths, "database_flags") + } + if desired.DisplayName != nil && !reflect.DeepEqual(actual.DisplayName, desired.DisplayName) { + log.V(2).Info("'spec.displayName' field is updated (-old +new)", cmp.Diff(actual.DisplayName, desired.DisplayName)) + updatePaths = append(updatePaths, "display_name") + } + if desired.GceZone != nil && !reflect.DeepEqual(actual.GceZone, desired.GceZone) { + log.V(2).Info("'spec.gceZone' field is updated (-old +new)", cmp.Diff(actual.GceZone, desired.GceZone)) + updatePaths = append(updatePaths, "gce_zone") + } + if desired.InstanceType != nil && !reflect.DeepEqual(actual.InstanceType, desired.InstanceType) { + log.V(2).Info("'spec.instanceType' field is updated (-old +new)", cmp.Diff(actual.InstanceType, desired.InstanceType)) + return nil, fmt.Errorf("cannot change immutable field %s from %v to %v", "'spec.instanceType'", actual.InstanceType, desired.InstanceType) + } + // TODO: Test machineConfig unset and empty struct + if desired.MachineConfig != nil { + if desired.MachineConfig.CpuCount != nil && !reflect.DeepEqual(actual.MachineConfig.CpuCount, desired.MachineConfig.CpuCount) { + log.V(2).Info("'spec.machineConfig.cpuCount' field is updated (-old +new)", cmp.Diff(actual.MachineConfig.CpuCount, desired.MachineConfig.CpuCount)) + updatePaths = append(updatePaths, "machine_config.cpu_count") + } + } + if desired.NetworkConfig != nil { + if desired.NetworkConfig.EnablePublicIp != nil && !reflect.DeepEqual(actual.NetworkConfig.EnablePublicIp, desired.NetworkConfig.EnablePublicIp) { + log.V(2).Info("'spec.networkConfig.enablePublicIp' field is updated (-old +new)", cmp.Diff(actual.NetworkConfig.EnablePublicIp, desired.NetworkConfig.EnablePublicIp)) + updatePaths = append(updatePaths, "network_config.enable_public_ip") + } + if desired.NetworkConfig.EnableOutboundPublicIp != nil && !reflect.DeepEqual(actual.NetworkConfig.EnableOutboundPublicIp, desired.NetworkConfig.EnableOutboundPublicIp) { + log.V(2).Info("'spec.networkConfig.enableOutboundPublicIp' field is updated (-old +new)", cmp.Diff(actual.NetworkConfig.EnableOutboundPublicIp, desired.NetworkConfig.EnableOutboundPublicIp)) + updatePaths = append(updatePaths, "network_config.enable_outbound_public_ip") + } + if desired.NetworkConfig.AuthorizedExternalNetworks != nil && !reflect.DeepEqual(actual.NetworkConfig.AuthorizedExternalNetworks, desired.NetworkConfig.AuthorizedExternalNetworks) { + log.V(2).Info("'spec.networkConfig.authorizedExternalNetworks' field is updated (-old +new)", cmp.Diff(actual.NetworkConfig.AuthorizedExternalNetworks, desired.NetworkConfig.AuthorizedExternalNetworks)) + updatePaths = append(updatePaths, "network_config.authorized_external_networks") + } + } + if desired.ReadPoolConfig != nil { + if desired.ReadPoolConfig.NodeCount != nil && !reflect.DeepEqual(actual.ReadPoolConfig.NodeCount, desired.ReadPoolConfig.NodeCount) { + log.V(2).Info("'spec.readPoolConfig.nodeCount' field is updated (-old +new)", cmp.Diff(actual.ReadPoolConfig.NodeCount, desired.ReadPoolConfig.NodeCount)) + updatePaths = append(updatePaths, "read_pool_config.node_count") + } + } + return updatePaths, nil +} + +// Export maps the GCP object to a Config Connector resource `spec`. +func (a *instanceAdapter) Export(ctx context.Context) (*unstructured.Unstructured, error) { + if a.actual == nil { + return nil, fmt.Errorf("Find() not called") + } + u := &unstructured.Unstructured{} + + obj := &krm.AlloyDBInstance{} + mapCtx := &direct.MapContext{} + obj.Spec = direct.ValueOf(AlloyDBInstanceSpec_FromProto(mapCtx, a.actual)) + if mapCtx.Err() != nil { + return nil, mapCtx.Err() + } + uObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + if err != nil { + return nil, err + } + + // Split name into tokens and use ID. + u.SetName(a.actual.Name) + u.SetGroupVersionKind(krm.AlloyDBInstanceGVK) + + u.Object = uObj + return u, nil +} + +// Delete the resource from GCP service when the corresponding Config Connector resource is deleted. +func (a *instanceAdapter) Delete(ctx context.Context, deleteOp *directbase.DeleteOperation) (bool, error) { + log := klog.FromContext(ctx) + log.V(2).Info("deleting instance", "name", a.id) + + // Returning true directly if it is to delete a secondary instance. + // Technically the secondary instance is only abandoned but not deleted. + // This is because deletion of secondary instance is not supported. Instead, + // users should delete the secondary cluster which will forcefully delete + // the associated secondary instance. + instanceType := a.desired.Spec.InstanceType + if instanceType != nil && *instanceType == "SECONDARY" { + log.V(2).Info("This operation didn't delete the secondary instance. You need to delete the associated secondary cluster to delete the secondary instance (and the entire secondary cluster).", "name", a.id) + return true, nil + } + + req := &alloydbpb.DeleteInstanceRequest{Name: a.id.String()} + op, err := a.gcpClient.DeleteInstance(ctx, req) + if op != nil { + opMetadata, opErr := op.Metadata() + fmt.Printf("maqiuyu... delete operation: %v\n%v\nMetadata:\n%+v\nErr while getting metadata\n%v\n", op.Name(), op.Done(), opMetadata, opErr) + } else { + fmt.Printf("maqiuyu... delete operation not triggered. Maybe there is an error? %+v\n", err) + } + if err != nil { + log.V(2).Info("error deleting instance", "name", a.id, "error", err) + if direct.IsNotFound(err) { + return false, nil + } + return false, fmt.Errorf("deleting instance %s: %w", a.id, err) + } + + err = op.Wait(ctx) + if err != nil { + log.V(2).Info("error waiting instance delete", "name", a.id, "error", err) + return false, fmt.Errorf("waiting delete instance %s: %w", a.id, err) + } + + log.V(2).Info("successfully deleted instance", "name", a.id) + return true, nil +} diff --git a/pkg/controller/direct/alloydb/instance_mappings.go b/pkg/controller/direct/alloydb/instance_mappings.go new file mode 100644 index 0000000000..c5b40b0e12 --- /dev/null +++ b/pkg/controller/direct/alloydb/instance_mappings.go @@ -0,0 +1,124 @@ +// 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 alloydb + +import ( + "fmt" + + pb "cloud.google.com/go/alloydb/apiv1beta/alloydbpb" + + krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/alloydb/v1beta1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct" +) + +func AlloyDBInstanceSpec_FromProto(mapCtx *direct.MapContext, in *pb.Instance) *krm.AlloyDBInstanceSpec { + if in == nil { + return nil + } + out := &krm.AlloyDBInstanceSpec{} + out.Annotations = in.GetAnnotations() + //out.AvailabilityType = direct.LazyPtr(in.GetAvailabilityType().String()) + out.AvailabilityType = direct.Enum_FromProto(mapCtx, in.GetAvailabilityType()) + out.DatabaseFlags = in.GetDatabaseFlags() + out.DisplayName = direct.LazyPtr(in.GetDisplayName()) + out.GceZone = direct.LazyPtr(in.GetGceZone()) + //out.InstanceType = direct.LazyPtr(in.GetInstanceType().String()) + out.InstanceType = direct.Enum_FromProto(mapCtx, in.GetInstanceType()) + // how to handle the labels? + out.MachineConfig = Instance_MachineConfig_FromProto(mapCtx, in.GetMachineConfig()) + out.NetworkConfig = Instance_InstanceNetworkConfig_FromProto(mapCtx, in.GetNetworkConfig()) + out.ReadPoolConfig = Instance_ReadPoolConfig_FromProto(mapCtx, in.GetReadPoolConfig()) + + // MISSING: Uid + // MISSING: CreateTime + // MISSING: UpdateTime + // MISSING: DeleteTime + // MISSING: Labels??? + // MISSING: State + // MISSING: WritableNode + // MISSING: Nodes + // MISSING: QueryInsightsConfig + // MISSING: ObservabilityConfig + // MISSING: IpAddress + // MISSING: PublicIpAddress + // MISSING: Reconciling + // MISSING: Etag + // MISSING: UpdatePolicy + // MISSING: ClientConnectionConfig + // MISSING: SatisfiesPzs + // MISSING: PscInstanceConfig + // MISSING: GeminiConfig + // MISSING: OutboundPublicIpAddresses + fmt.Printf("maqiuyu...AlloyDBInstanceSpec_FromProto: %+v\n", out) + return out +} + +func AlloyDBInstanceSpec_ToProto(mapCtx *direct.MapContext, in *krm.AlloyDBInstanceSpec) *pb.Instance { + if in == nil { + return nil + } + out := &pb.Instance{} + out.Annotations = in.Annotations + out.AvailabilityType = direct.Enum_ToProto[pb.Instance_AvailabilityType](mapCtx, in.AvailabilityType) + out.DatabaseFlags = in.DatabaseFlags + out.DisplayName = direct.ValueOf(in.DisplayName) + out.GceZone = direct.ValueOf(in.GceZone) + out.InstanceType = direct.Enum_ToProto[pb.Instance_InstanceType](mapCtx, in.InstanceType) + // how to handle the labels? + out.MachineConfig = Instance_MachineConfig_ToProto(mapCtx, in.MachineConfig) + out.NetworkConfig = Instance_InstanceNetworkConfig_ToProto(mapCtx, in.NetworkConfig) + out.ReadPoolConfig = Instance_ReadPoolConfig_ToProto(mapCtx, in.ReadPoolConfig) + // MISSING: Uid + // MISSING: CreateTime + // MISSING: UpdateTime + // MISSING: DeleteTime + // MISSING: Labels should be an internal field for to map metadata.labels + // MISSING: State + // MISSING: WritableNode + // MISSING: Nodes + // MISSING: QueryInsightsConfig + // MISSING: ObservabilityConfig + // MISSING: IpAddress + // MISSING: PublicIpAddress + // MISSING: Reconciling + // MISSING: Etag + // MISSING: UpdatePolicy + // MISSING: ClientConnectionConfig + // MISSING: SatisfiesPzs + // MISSING: PscInstanceConfig + // MISSING: GeminiConfig + // MISSING: OutboundPublicIpAddresses + fmt.Printf("maqiuyu...AlloyDBInstanceSpec_ToProto: %+v\n", out) + return out +} + +func AlloyDBInstanceStatus_FromProto(mapCtx *direct.MapContext, in *pb.Instance) *krm.AlloyDBInstanceStatus { + if in == nil { + return nil + } + out := &krm.AlloyDBInstanceStatus{} + out.CreateTime = direct.StringTimestamp_FromProto(mapCtx, in.GetCreateTime()) + out.IpAddress = direct.LazyPtr(in.GetIpAddress()) + out.Name = direct.LazyPtr(in.GetName()) + out.OutboundPublicIpAddresses = in.GetOutboundPublicIpAddresses() + out.PublicIpAddress = direct.LazyPtr(in.GetPublicIpAddress()) + out.Reconciling = direct.LazyPtr(in.Reconciling) + out.State = direct.Enum_FromProto(mapCtx, in.GetState()) + out.Uid = direct.LazyPtr(in.Uid) + out.UpdateTime = direct.StringTimestamp_FromProto(mapCtx, in.GetUpdateTime()) + + fmt.Printf("maqiuyu...AlloyDBInstanceStatus_FromProto: %+v", out) + return out +} diff --git a/pkg/controller/direct/alloydb/mapper.generated.go b/pkg/controller/direct/alloydb/mapper.generated.go new file mode 100644 index 0000000000..1aaa1efb95 --- /dev/null +++ b/pkg/controller/direct/alloydb/mapper.generated.go @@ -0,0 +1,255 @@ +// 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 alloydb + +import ( + pb "cloud.google.com/go/alloydb/apiv1beta/alloydbpb" + + krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/alloydb/v1beta1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct" +) + +func GeminiInstanceConfig_FromProto(mapCtx *direct.MapContext, in *pb.GeminiInstanceConfig) *krm.GeminiInstanceConfig { + if in == nil { + return nil + } + out := &krm.GeminiInstanceConfig{} + out.Entitled = direct.LazyPtr(in.GetEntitled()) + return out +} +func GeminiInstanceConfig_ToProto(mapCtx *direct.MapContext, in *krm.GeminiInstanceConfig) *pb.GeminiInstanceConfig { + if in == nil { + return nil + } + out := &pb.GeminiInstanceConfig{} + out.Entitled = direct.ValueOf(in.Entitled) + return out +} +func Instance_ClientConnectionConfig_FromProto(mapCtx *direct.MapContext, in *pb.Instance_ClientConnectionConfig) *krm.Instance_ClientConnectionConfig { + if in == nil { + return nil + } + out := &krm.Instance_ClientConnectionConfig{} + out.RequireConnectors = direct.LazyPtr(in.GetRequireConnectors()) + out.SslConfig = SslConfig_FromProto(mapCtx, in.GetSslConfig()) + return out +} +func Instance_ClientConnectionConfig_ToProto(mapCtx *direct.MapContext, in *krm.Instance_ClientConnectionConfig) *pb.Instance_ClientConnectionConfig { + if in == nil { + return nil + } + out := &pb.Instance_ClientConnectionConfig{} + out.RequireConnectors = direct.ValueOf(in.RequireConnectors) + out.SslConfig = SslConfig_ToProto(mapCtx, in.SslConfig) + return out +} +func Instance_InstanceNetworkConfig_FromProto(mapCtx *direct.MapContext, in *pb.Instance_InstanceNetworkConfig) *krm.Instance_InstanceNetworkConfig { + if in == nil { + return nil + } + out := &krm.Instance_InstanceNetworkConfig{} + out.AuthorizedExternalNetworks = direct.Slice_FromProto(mapCtx, in.AuthorizedExternalNetworks, Instance_InstanceNetworkConfig_AuthorizedNetwork_FromProto) + out.EnablePublicIp = direct.LazyPtr(in.GetEnablePublicIp()) + out.EnableOutboundPublicIp = direct.LazyPtr(in.GetEnableOutboundPublicIp()) + return out +} +func Instance_InstanceNetworkConfig_ToProto(mapCtx *direct.MapContext, in *krm.Instance_InstanceNetworkConfig) *pb.Instance_InstanceNetworkConfig { + if in == nil { + return nil + } + out := &pb.Instance_InstanceNetworkConfig{} + out.AuthorizedExternalNetworks = direct.Slice_ToProto(mapCtx, in.AuthorizedExternalNetworks, Instance_InstanceNetworkConfig_AuthorizedNetwork_ToProto) + out.EnablePublicIp = direct.ValueOf(in.EnablePublicIp) + out.EnableOutboundPublicIp = direct.ValueOf(in.EnableOutboundPublicIp) + return out +} +func Instance_InstanceNetworkConfig_AuthorizedNetwork_FromProto(mapCtx *direct.MapContext, in *pb.Instance_InstanceNetworkConfig_AuthorizedNetwork) *krm.Instance_InstanceNetworkConfig_AuthorizedNetwork { + if in == nil { + return nil + } + out := &krm.Instance_InstanceNetworkConfig_AuthorizedNetwork{} + out.CidrRange = direct.LazyPtr(in.GetCidrRange()) + return out +} +func Instance_InstanceNetworkConfig_AuthorizedNetwork_ToProto(mapCtx *direct.MapContext, in *krm.Instance_InstanceNetworkConfig_AuthorizedNetwork) *pb.Instance_InstanceNetworkConfig_AuthorizedNetwork { + if in == nil { + return nil + } + out := &pb.Instance_InstanceNetworkConfig_AuthorizedNetwork{} + out.CidrRange = direct.ValueOf(in.CidrRange) + return out +} +func Instance_MachineConfig_FromProto(mapCtx *direct.MapContext, in *pb.Instance_MachineConfig) *krm.Instance_MachineConfig { + if in == nil { + return nil + } + out := &krm.Instance_MachineConfig{} + out.CpuCount = direct.LazyPtr(in.GetCpuCount()) + return out +} +func Instance_MachineConfig_ToProto(mapCtx *direct.MapContext, in *krm.Instance_MachineConfig) *pb.Instance_MachineConfig { + if in == nil { + return nil + } + out := &pb.Instance_MachineConfig{} + out.CpuCount = direct.ValueOf(in.CpuCount) + return out +} +func Instance_Node_FromProto(mapCtx *direct.MapContext, in *pb.Instance_Node) *krm.Instance_Node { + if in == nil { + return nil + } + out := &krm.Instance_Node{} + out.ZoneID = direct.LazyPtr(in.GetZoneId()) + out.ID = direct.LazyPtr(in.GetId()) + out.Ip = direct.LazyPtr(in.GetIp()) + out.State = direct.LazyPtr(in.GetState()) + return out +} +func Instance_Node_ToProto(mapCtx *direct.MapContext, in *krm.Instance_Node) *pb.Instance_Node { + if in == nil { + return nil + } + out := &pb.Instance_Node{} + out.ZoneId = direct.ValueOf(in.ZoneID) + out.Id = direct.ValueOf(in.ID) + out.Ip = direct.ValueOf(in.Ip) + out.State = direct.ValueOf(in.State) + return out +} +func Instance_ObservabilityInstanceConfig_FromProto(mapCtx *direct.MapContext, in *pb.Instance_ObservabilityInstanceConfig) *krm.Instance_ObservabilityInstanceConfig { + if in == nil { + return nil + } + out := &krm.Instance_ObservabilityInstanceConfig{} + out.Enabled = in.Enabled + out.PreserveComments = in.PreserveComments + out.TrackWaitEvents = in.TrackWaitEvents + out.TrackWaitEventTypes = in.TrackWaitEventTypes + out.MaxQueryStringLength = in.MaxQueryStringLength + out.RecordApplicationTags = in.RecordApplicationTags + out.QueryPlansPerMinute = in.QueryPlansPerMinute + out.TrackActiveQueries = in.TrackActiveQueries + out.TrackClientAddress = in.TrackClientAddress + return out +} +func Instance_ObservabilityInstanceConfig_ToProto(mapCtx *direct.MapContext, in *krm.Instance_ObservabilityInstanceConfig) *pb.Instance_ObservabilityInstanceConfig { + if in == nil { + return nil + } + out := &pb.Instance_ObservabilityInstanceConfig{} + out.Enabled = in.Enabled + out.PreserveComments = in.PreserveComments + out.TrackWaitEvents = in.TrackWaitEvents + out.TrackWaitEventTypes = in.TrackWaitEventTypes + out.MaxQueryStringLength = in.MaxQueryStringLength + out.RecordApplicationTags = in.RecordApplicationTags + out.QueryPlansPerMinute = in.QueryPlansPerMinute + out.TrackActiveQueries = in.TrackActiveQueries + out.TrackClientAddress = in.TrackClientAddress + return out +} +func Instance_PscInstanceConfig_FromProto(mapCtx *direct.MapContext, in *pb.Instance_PscInstanceConfig) *krm.Instance_PscInstanceConfig { + if in == nil { + return nil + } + out := &krm.Instance_PscInstanceConfig{} + out.ServiceAttachmentLink = direct.LazyPtr(in.GetServiceAttachmentLink()) + out.AllowedConsumerProjects = in.AllowedConsumerProjects + out.PscDnsName = direct.LazyPtr(in.GetPscDnsName()) + return out +} +func Instance_PscInstanceConfig_ToProto(mapCtx *direct.MapContext, in *krm.Instance_PscInstanceConfig) *pb.Instance_PscInstanceConfig { + if in == nil { + return nil + } + out := &pb.Instance_PscInstanceConfig{} + out.ServiceAttachmentLink = direct.ValueOf(in.ServiceAttachmentLink) + out.AllowedConsumerProjects = in.AllowedConsumerProjects + out.PscDnsName = direct.ValueOf(in.PscDnsName) + return out +} +func Instance_QueryInsightsInstanceConfig_FromProto(mapCtx *direct.MapContext, in *pb.Instance_QueryInsightsInstanceConfig) *krm.Instance_QueryInsightsInstanceConfig { + if in == nil { + return nil + } + out := &krm.Instance_QueryInsightsInstanceConfig{} + out.RecordApplicationTags = in.RecordApplicationTags + out.RecordClientAddress = in.RecordClientAddress + out.QueryStringLength = direct.LazyPtr(in.GetQueryStringLength()) + out.QueryPlansPerMinute = in.QueryPlansPerMinute + return out +} +func Instance_QueryInsightsInstanceConfig_ToProto(mapCtx *direct.MapContext, in *krm.Instance_QueryInsightsInstanceConfig) *pb.Instance_QueryInsightsInstanceConfig { + if in == nil { + return nil + } + out := &pb.Instance_QueryInsightsInstanceConfig{} + out.RecordApplicationTags = in.RecordApplicationTags + out.RecordClientAddress = in.RecordClientAddress + out.QueryStringLength = direct.ValueOf(in.QueryStringLength) + out.QueryPlansPerMinute = in.QueryPlansPerMinute + return out +} +func Instance_ReadPoolConfig_FromProto(mapCtx *direct.MapContext, in *pb.Instance_ReadPoolConfig) *krm.Instance_ReadPoolConfig { + if in == nil { + return nil + } + out := &krm.Instance_ReadPoolConfig{} + out.NodeCount = direct.LazyPtr(in.GetNodeCount()) + return out +} +func Instance_ReadPoolConfig_ToProto(mapCtx *direct.MapContext, in *krm.Instance_ReadPoolConfig) *pb.Instance_ReadPoolConfig { + if in == nil { + return nil + } + out := &pb.Instance_ReadPoolConfig{} + out.NodeCount = direct.ValueOf(in.NodeCount) + return out +} +func Instance_UpdatePolicy_FromProto(mapCtx *direct.MapContext, in *pb.Instance_UpdatePolicy) *krm.Instance_UpdatePolicy { + if in == nil { + return nil + } + out := &krm.Instance_UpdatePolicy{} + out.Mode = direct.Enum_FromProto(mapCtx, in.GetMode()) + return out +} +func Instance_UpdatePolicy_ToProto(mapCtx *direct.MapContext, in *krm.Instance_UpdatePolicy) *pb.Instance_UpdatePolicy { + if in == nil { + return nil + } + out := &pb.Instance_UpdatePolicy{} + out.Mode = direct.Enum_ToProto[pb.Instance_UpdatePolicy_Mode](mapCtx, in.Mode) + return out +} +func SslConfig_FromProto(mapCtx *direct.MapContext, in *pb.SslConfig) *krm.SslConfig { + if in == nil { + return nil + } + out := &krm.SslConfig{} + out.SslMode = direct.Enum_FromProto(mapCtx, in.GetSslMode()) + out.CaSource = direct.Enum_FromProto(mapCtx, in.GetCaSource()) + return out +} +func SslConfig_ToProto(mapCtx *direct.MapContext, in *krm.SslConfig) *pb.SslConfig { + if in == nil { + return nil + } + out := &pb.SslConfig{} + out.SslMode = direct.Enum_ToProto[pb.SslConfig_SslMode](mapCtx, in.SslMode) + out.CaSource = direct.Enum_ToProto[pb.SslConfig_CaSource](mapCtx, in.CaSource) + return out +} diff --git a/pkg/gvks/supportedgvks/gvks_generated.go b/pkg/gvks/supportedgvks/gvks_generated.go index a7d44d8495..e5b495eb1b 100644 --- a/pkg/gvks/supportedgvks/gvks_generated.go +++ b/pkg/gvks/supportedgvks/gvks_generated.go @@ -157,7 +157,7 @@ var SupportedGVKs = map[schema.GroupVersionKind]GVKMetadata{ }, { Group: "alloydb.cnrm.cloud.google.com", - Version: "v1beta1", + Version: "v1alpha1", Kind: "AlloyDBInstance", }: { Labels: map[string]string{ @@ -169,7 +169,7 @@ var SupportedGVKs = map[schema.GroupVersionKind]GVKMetadata{ }, { Group: "alloydb.cnrm.cloud.google.com", - Version: "v1alpha1", + Version: "v1beta1", Kind: "AlloyDBInstance", }: { Labels: map[string]string{ diff --git a/scripts/generate-google3-docs/resource-reference/generated/resource-docs/alloydb/alloydbinstance.md b/scripts/generate-google3-docs/resource-reference/generated/resource-docs/alloydb/alloydbinstance.md index 79e59bcc1b..3770dd32b6 100644 --- a/scripts/generate-google3-docs/resource-reference/generated/resource-docs/alloydb/alloydbinstance.md +++ b/scripts/generate-google3-docs/resource-reference/generated/resource-docs/alloydb/alloydbinstance.md @@ -119,12 +119,13 @@ resourceID: string

string

-

{% verbatim %}'Availability type of an Instance. Defaults to REGIONAL for both primary and read instances. +

{% verbatim %}Availability type of an Instance. Defaults to REGIONAL for both primary and read instances. + Note that primary and read instances can have different availability types. Only READ_POOL instance supports ZONAL type. Users can't specify the zone for READ_POOL instance. Zone is automatically chosen from the list of zones in the region specified. Read pool of size 1 can only have zonal availability. Read pools with node count of 2 or more -can have regional availability (nodes are present in 2 or more zones in a region).' Possible values: ["AVAILABILITY_TYPE_UNSPECIFIED", "ZONAL", "REGIONAL"].{% endverbatim %}

+can have regional availability (nodes are present in 2 or more zones in a region). Possible values: ["AVAILABILITY_TYPE_UNSPECIFIED", "ZONAL", "REGIONAL"].{% endverbatim %}

@@ -134,7 +135,7 @@ can have regional availability (nodes are present in 2 or more zones in a region

object

-

{% verbatim %}{% endverbatim %}

+

{% verbatim %}The AlloyDBInstance cluster that this resource belongs to.{% endverbatim %}

@@ -144,7 +145,7 @@ can have regional availability (nodes are present in 2 or more zones in a region

string

-

{% verbatim %}Allowed value: The `name` field of an `AlloyDBCluster` resource.{% endverbatim %}

+

{% verbatim %}If provided must be in the format `projects/[projectId]/locations/[location]/clusters/[clusterId]`.{% endverbatim %}

@@ -154,7 +155,7 @@ can have regional availability (nodes are present in 2 or more zones in a region

string

-

{% verbatim %}Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names{% endverbatim %}

+

{% verbatim %}The `metadata.name` field of a `AlloyDBCluster` resource.{% endverbatim %}

@@ -164,7 +165,7 @@ can have regional availability (nodes are present in 2 or more zones in a region

string

-

{% verbatim %}Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/{% endverbatim %}

+

{% verbatim %}The `metadata.namespace` field of a `AlloyDBCluster` resource.{% endverbatim %}

@@ -204,8 +205,7 @@ can have regional availability (nodes are present in 2 or more zones in a region

string

-

{% verbatim %}We recommend that you use `instanceTypeRef` instead. -The type of the instance. Possible values: [PRIMARY, READ_POOL, SECONDARY]{% endverbatim %}

+

{% verbatim %}We recommend that you use `instanceTypeRef` instead. The type of the instance. Possible values: [PRIMARY, READ_POOL, SECONDARY]{% endverbatim %}

@@ -217,6 +217,7 @@ The type of the instance. Possible values: [PRIMARY, READ_POOL, SECONDARY]{% end

object

{% verbatim %}The type of instance. Possible values: ["PRIMARY", "READ_POOL", "SECONDARY"] + For PRIMARY and SECONDARY instances, set the value to refer to the name of the associated cluster. This is recommended because the instance type of primary and secondary instances is tied to the cluster type of the associated cluster. If the secondary cluster is promoted to primary cluster, then the associated secondary instance also becomes primary instance. @@ -238,7 +239,7 @@ Use deletionPolicy = "FORCE" in the associated secondary cluster and delete the

string

-

{% verbatim %}Allowed value: The `clusterType` field of an `AlloyDBCluster` resource.{% endverbatim %}

+

{% verbatim %}The type of instance. Possible values: ["PRIMARY", "READ_POOL", "SECONDARY"]{% endverbatim %}

@@ -248,7 +249,7 @@ Use deletionPolicy = "FORCE" in the associated secondary cluster and delete the

string

-

{% verbatim %}Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names{% endverbatim %}

+

{% verbatim %}The `metadata.name` field of a `AlloyDBCluster` resource.{% endverbatim %}

@@ -258,7 +259,7 @@ Use deletionPolicy = "FORCE" in the associated secondary cluster and delete the

string

-

{% verbatim %}Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/{% endverbatim %}

+

{% verbatim %}The `metadata.namespace` field of a `AlloyDBCluster` resource.{% endverbatim %}

@@ -298,7 +299,7 @@ Use deletionPolicy = "FORCE" in the associated secondary cluster and delete the

list (object)

-

{% verbatim %}A list of external networks authorized to access this instance. This field is only allowed to be set when 'enable_public_ip' is set to true.{% endverbatim %}

+

{% verbatim %}Optional. A list of external network authorized to access this instance. This field is only allowed to be set when 'enablePublicIp' is set to true.{% endverbatim %}

@@ -318,7 +319,7 @@ Use deletionPolicy = "FORCE" in the associated secondary cluster and delete the

string

-

{% verbatim %}CIDR range for one authorized network of the instance.{% endverbatim %}

+

{% verbatim %}CIDR range for one authorzied network of the instance.{% endverbatim %}

@@ -328,7 +329,7 @@ Use deletionPolicy = "FORCE" in the associated secondary cluster and delete the

boolean

-

{% verbatim %}Enabling outbound public ip for the instance.{% endverbatim %}

+

{% verbatim %}Optional. Enabling an outbound public IP address to support a database server sending requests out into the internet.{% endverbatim %}

@@ -338,7 +339,7 @@ Use deletionPolicy = "FORCE" in the associated secondary cluster and delete the

boolean

-

{% verbatim %}Enabling public ip for the instance. If a user wishes to disable this, please also clear the list of the authorized external networks set on the same instance.{% endverbatim %}

+

{% verbatim %}Optional. Enabling public ip for the instance. If a user wishes to disable this, please also clear the list of the authorized external networks set on the same instance.{% endverbatim %}

@@ -368,7 +369,7 @@ Use deletionPolicy = "FORCE" in the associated secondary cluster and delete the

string

-

{% verbatim %}Immutable. Optional. The instanceId of the resource. Used for creation and acquisition. When unset, the value of `metadata.name` is used as the default.{% endverbatim %}

+

{% verbatim %}Immutable. Optional. The instanceId of the resource. If not given, the metadata.name will be used.{% endverbatim %}

@@ -386,6 +387,7 @@ conditions: status: string type: string createTime: string +externalRef: string ipAddress: string name: string observedGeneration: integer @@ -409,7 +411,7 @@ updateTime: string conditions

list (object)

-

{% verbatim %}Conditions represent the latest available observation of the resource's current state.{% endverbatim %}

+

{% verbatim %}Conditions represent the latest available observations of the object's current state.{% endverbatim %}

@@ -461,6 +463,13 @@ updateTime: string

{% verbatim %}Time the Instance was created in UTC.{% endverbatim %}

+ + externalRef + +

string

+

{% verbatim %}A unique specifier for the AlloyDBInstance resource in GCP.{% endverbatim %}

+ + ipAddress @@ -486,9 +495,7 @@ updateTime: string outboundPublicIpAddresses

list (string)

-

{% verbatim %}The outbound public IP addresses for the instance. This is available ONLY when -networkConfig.enableOutboundPublicIp is set to true. These IP addresses are used -for outbound connections.{% endverbatim %}

+

{% verbatim %}The outbound public IP addresses for the instance. This is available ONLY when networkConfig.enableOutboundPublicIp is set to true. These IP addresses are used for outbound connections.{% endverbatim %}