From dc25bc462fd91708857a5694a4f1ba511d472d78 Mon Sep 17 00:00:00 2001 From: Anh Le Date: Fri, 13 Dec 2024 20:23:06 +0000 Subject: [PATCH] Add swap compute field for spanner instance --- mockgcp/mockspanner/admin/instance.go | 30 +- ...erinstance-swap-compute-fields.golden.yaml | 31 ++ .../_http.log | 335 ++++++++++++++++++ .../create.yaml | 24 ++ .../update.yaml | 24 ++ 5 files changed, 435 insertions(+), 9 deletions(-) create mode 100644 pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/_generated_object_spannerinstance-swap-compute-fields.golden.yaml create mode 100644 pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/_http.log create mode 100644 pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/create.yaml create mode 100644 pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/update.yaml diff --git a/mockgcp/mockspanner/admin/instance.go b/mockgcp/mockspanner/admin/instance.go index cda1379f49..578c6e4a22 100644 --- a/mockgcp/mockspanner/admin/instance.go +++ b/mockgcp/mockspanner/admin/instance.go @@ -17,11 +17,13 @@ package mockspanner import ( "context" "reflect" + "slices" "strings" "cloud.google.com/go/longrunning/autogen/longrunningpb" "github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp/common/projects" pb "github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp/generated/mockgcp/spanner/admin/instance/v1" + "google.golang.org/genproto/protobuf/field_mask" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" @@ -69,7 +71,7 @@ func (s *SpannerInstanceV1) CreateInstance(ctx context.Context, req *pb.CreateIn obj := proto.Clone(req.GetInstance()).(*pb.Instance) obj.Name = fqn - s.populateDefaultsForSpannerInstance(obj, obj) + s.populateDefaultsForSpannerInstance(obj, obj, nil) obj.State = pb.Instance_READY // Metadata instance include ReplicaComputeCapacity even if not specify @@ -96,16 +98,27 @@ func (s *SpannerInstanceV1) CreateInstance(ctx context.Context, req *pb.CreateIn }) } -func (s *SpannerInstanceV1) populateDefaultsForSpannerInstance(update, obj *pb.Instance) { +func (s *SpannerInstanceV1) populateDefaultsForSpannerInstance(update, obj *pb.Instance, f *field_mask.FieldMask) { // At most one of either node_count or processing_units should be present. // https://cloud.google.com/spanner/docs/compute-capacity // 1 nodeCount equals 1000 processingUnits - if 1000*update.NodeCount > update.ProcessingUnits { - obj.ProcessingUnits = 1000 * update.NodeCount - obj.NodeCount = update.NodeCount + if f != nil && len(f.Paths) > 0 { + if slices.Contains[[]string](f.Paths, "node_count") { + obj.NodeCount = update.NodeCount + obj.ProcessingUnits = update.NodeCount * 1000 + } + if slices.Contains[[]string](f.Paths, "processing_units") { + obj.ProcessingUnits = update.ProcessingUnits + obj.NodeCount = update.ProcessingUnits / 1000 + } } else { - obj.ProcessingUnits = update.ProcessingUnits - obj.NodeCount = update.ProcessingUnits / 1000 + if 1000*update.NodeCount > update.ProcessingUnits { + obj.ProcessingUnits = 1000 * update.NodeCount + obj.NodeCount = update.NodeCount + } else { + obj.ProcessingUnits = update.ProcessingUnits + obj.NodeCount = update.ProcessingUnits / 1000 + } } } @@ -152,8 +165,7 @@ func (s *SpannerInstanceV1) UpdateInstance(ctx context.Context, req *pb.UpdateIn } } - - s.populateDefaultsForSpannerInstance(req.Instance, obj) + s.populateDefaultsForSpannerInstance(req.Instance, obj, req.FieldMask) // Metadata instance include ReplicaComputeCapacity even if not specify cloneObj := proto.Clone(obj).(*pb.Instance) s.populateReplicaComputeCapacityForSpannerInstance(cloneObj) diff --git a/pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/_generated_object_spannerinstance-swap-compute-fields.golden.yaml b/pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/_generated_object_spannerinstance-swap-compute-fields.golden.yaml new file mode 100644 index 0000000000..98efdcc7ed --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/_generated_object_spannerinstance-swap-compute-fields.golden.yaml @@ -0,0 +1,31 @@ +apiVersion: spanner.cnrm.cloud.google.com/v1beta1 +kind: SpannerInstance +metadata: + annotations: + cnrm.cloud.google.com/management-conflict-prevention-policy: none + cnrm.cloud.google.com/project-id: ${projectId} + cnrm.cloud.google.com/state-into-spec: absent + finalizers: + - cnrm.cloud.google.com/finalizer + - cnrm.cloud.google.com/deletion-defender + generation: 3 + labels: + cnrm-test: "true" + label-one: value-one + name: spannerinstance-sample-${uniqueId} + namespace: ${uniqueId} +spec: + config: regional-us-west1 + displayName: New spanner Instance Sample + numNodes: 2 + processingUnits: 900 + resourceID: spannerinstance-sample-${uniqueId} +status: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: The resource is up to date + reason: UpToDate + status: "True" + type: Ready + observedGeneration: 3 + state: READY diff --git a/pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/_http.log b/pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/_http.log new file mode 100644 index 0000000000..72c96cb3d8 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/_http.log @@ -0,0 +1,335 @@ +GET https://spanner.googleapis.com/v1/projects/${projectId}/instances/spannerinstance-sample-${uniqueId}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "message": "Instance not found: projects/${projectId}/instances/spannerinstance-sample-${uniqueId}", + "status": "NOT_FOUND" + } +} + +--- + +POST https://spanner.googleapis.com/v1/projects/${projectId}/instances?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +{ + "instance": { + "config": "projects/${projectId}/instanceConfigs/regional-us-west1", + "displayName": "Spanner Instance Sample", + "labels": { + "cnrm-test": "true", + "label-one": "value-one", + "managed-by-cnrm": "true" + }, + "nodeCount": 2 + }, + "instanceId": "spannerinstance-sample-${uniqueId}" +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "metadata": { + "@type": "type.googleapis.com/google.spanner.admin.instance.v1.CreateInstanceMetadata", + "instance": { + "config": "projects/${projectId}/instanceConfigs/regional-us-west1", + "displayName": "Spanner Instance Sample", + "labels": { + "cnrm-test": "true", + "label-one": "value-one", + "managed-by-cnrm": "true" + }, + "name": "projects/${projectId}/instances/spannerinstance-sample-${uniqueId}", + "nodeCount": 2, + "processingUnits": 2000, + "replicaComputeCapacity": [ + { + "nodeCount": 2, + "replicaSelection": { + "location": "us-west1" + } + } + ], + "state": "READY" + }, + "startTime": "2024-04-01T12:34:56.123456Z" + }, + "name": "projects/${projectId}/instances/spannerinstance-sample-${uniqueId}/operations/${operationID}" +} + +--- + +GET https://spanner.googleapis.com/v1/projects/${projectId}/instances/spannerinstance-sample-${uniqueId}/operations/${operationID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.spanner.admin.instance.v1.CreateInstanceMetadata", + "endTime": "2024-04-01T12:34:56.123456Z", + "expectedFulfillmentPeriod": "FULFILLMENT_PERIOD_NORMAL", + "instance": { + "config": "projects/${projectId}/instanceConfigs/regional-us-west1", + "displayName": "Spanner Instance Sample", + "labels": { + "cnrm-test": "true", + "label-one": "value-one", + "managed-by-cnrm": "true" + }, + "name": "projects/${projectId}/instances/spannerinstance-sample-${uniqueId}", + "nodeCount": 2, + "processingUnits": 2000, + "state": "READY", + "updateTime": "2024-04-01T12:34:56.123456Z" + }, + "startTime": "2024-04-01T12:34:56.123456Z" + }, + "name": "projects/${projectId}/instances/spannerinstance-sample-${uniqueId}/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.spanner.admin.instance.v1.Instance", + "config": "projects/${projectId}/instanceConfigs/regional-us-west1", + "createTime": "2024-04-01T12:34:56.123456Z", + "displayName": "Spanner Instance Sample", + "labels": { + "cnrm-test": "true", + "label-one": "value-one", + "managed-by-cnrm": "true" + }, + "name": "projects/${projectId}/instances/spannerinstance-sample-${uniqueId}", + "nodeCount": 2, + "processingUnits": 2000, + "state": "READY", + "updateTime": "2024-04-01T12:34:56.123456Z" + } +} + +--- + +GET https://spanner.googleapis.com/v1/projects/${projectId}/instances/spannerinstance-sample-${uniqueId}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "config": "projects/${projectId}/instanceConfigs/regional-us-west1", + "createTime": "2024-04-01T12:34:56.123456Z", + "displayName": "Spanner Instance Sample", + "labels": { + "cnrm-test": "true", + "label-one": "value-one", + "managed-by-cnrm": "true" + }, + "name": "projects/${projectId}/instances/spannerinstance-sample-${uniqueId}", + "nodeCount": 2, + "processingUnits": 2000, + "state": "READY", + "updateTime": "2024-04-01T12:34:56.123456Z" +} + +--- + +PATCH https://spanner.googleapis.com/v1/projects/${projectId}/instances/spannerinstance-sample-${uniqueId}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +{ + "fieldMask": "displayName,processingUnits", + "instance": { + "displayName": "New spanner Instance Sample", + "labels": { + "cnrm-test": "true", + "label-one": "value-one", + "managed-by-cnrm": "true" + }, + "name": "projects/${projectId}/instances/%!s(\u003cnil\u003e)", + "nodeCount": 2, + "processingUnits": 900 + } +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "metadata": { + "@type": "type.googleapis.com/google.spanner.admin.instance.v1.UpdateInstanceMetadata", + "instance": { + "config": "projects/${projectId}/instanceConfigs/regional-us-west1", + "createTime": "2024-04-01T12:34:56.123456Z", + "displayName": "Spanner Instance Sample", + "labels": { + "cnrm-test": "true", + "label-one": "value-one", + "managed-by-cnrm": "true" + }, + "name": "projects/${projectId}/instances/spannerinstance-sample-${uniqueId}", + "processingUnits": 900, + "replicaComputeCapacity": [ + { + "nodeCount": 0, + "replicaSelection": { + "location": "us-west1" + } + } + ], + "state": "READY", + "updateTime": "2024-04-01T12:34:56.123456Z" + }, + "startTime": "2024-04-01T12:34:56.123456Z" + }, + "name": "projects/${projectId}/instances/spannerinstance-sample-${uniqueId}/operations/${operationID}" +} + +--- + +GET https://spanner.googleapis.com/v1/projects/${projectId}/instances/spannerinstance-sample-${uniqueId}/operations/${operationID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.spanner.admin.instance.v1.UpdateInstanceMetadata", + "endTime": "2024-04-01T12:34:56.123456Z", + "expectedFulfillmentPeriod": "FULFILLMENT_PERIOD_NORMAL", + "instance": { + "config": "projects/${projectId}/instanceConfigs/regional-us-west1", + "createTime": "2024-04-01T12:34:56.123456Z", + "displayName": "Spanner Instance Sample", + "labels": { + "cnrm-test": "true", + "label-one": "value-one", + "managed-by-cnrm": "true" + }, + "name": "projects/${projectId}/instances/spannerinstance-sample-${uniqueId}", + "processingUnits": 900, + "state": "READY", + "updateTime": "2024-04-01T12:34:56.123456Z" + }, + "startTime": "2024-04-01T12:34:56.123456Z" + }, + "name": "projects/${projectId}/instances/spannerinstance-sample-${uniqueId}/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.spanner.admin.instance.v1.Instance", + "config": "projects/${projectId}/instanceConfigs/regional-us-west1", + "createTime": "2024-04-01T12:34:56.123456Z", + "displayName": "Spanner Instance Sample", + "labels": { + "cnrm-test": "true", + "label-one": "value-one", + "managed-by-cnrm": "true" + }, + "name": "projects/${projectId}/instances/spannerinstance-sample-${uniqueId}", + "processingUnits": 900, + "state": "READY", + "updateTime": "2024-04-01T12:34:56.123456Z" + } +} + +--- + +GET https://spanner.googleapis.com/v1/projects/${projectId}/instances/spannerinstance-sample-${uniqueId}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "config": "projects/${projectId}/instanceConfigs/regional-us-west1", + "createTime": "2024-04-01T12:34:56.123456Z", + "displayName": "Spanner Instance Sample", + "labels": { + "cnrm-test": "true", + "label-one": "value-one", + "managed-by-cnrm": "true" + }, + "name": "projects/${projectId}/instances/spannerinstance-sample-${uniqueId}", + "processingUnits": 900, + "state": "READY", + "updateTime": "2024-04-01T12:34:56.123456Z" +} + +--- + +DELETE https://spanner.googleapis.com/v1/projects/${projectId}/instances/spannerinstance-sample-${uniqueId}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{} \ No newline at end of file diff --git a/pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/create.yaml b/pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/create.yaml new file mode 100644 index 0000000000..8bfec22047 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/create.yaml @@ -0,0 +1,24 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: spanner.cnrm.cloud.google.com/v1beta1 +kind: SpannerInstance +metadata: + labels: + label-one: "value-one" + name: spannerinstance-sample-${uniqueId} +spec: + config: regional-us-west1 + displayName: Spanner Instance Sample + numNodes: 2 diff --git a/pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/update.yaml b/pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/update.yaml new file mode 100644 index 0000000000..ec8ffa88a6 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/spanner/v1beta1/spannerinstance-swap-compute-fields/update.yaml @@ -0,0 +1,24 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: spanner.cnrm.cloud.google.com/v1beta1 +kind: SpannerInstance +metadata: + labels: + label-one: "value-one" + name: spannerinstance-sample-${uniqueId} +spec: + config: regional-us-west1 + displayName: New spanner Instance Sample + processingUnits: 900