diff --git a/mmv1/products/spanner/Instance.yaml b/mmv1/products/spanner/Instance.yaml index 0a353ee85dd8..251e3ee20d17 100644 --- a/mmv1/products/spanner/Instance.yaml +++ b/mmv1/products/spanner/Instance.yaml @@ -180,19 +180,49 @@ properties: name: 'autoscalingLimits' description: | Defines scale in controls to reduce the risk of response latency - and outages due to abrupt scale-in events + and outages due to abrupt scale-in events. Users can define the minimum and + maximum compute capacity allocated to the instance, and the autoscaler will + only scale within that range. Users can either use nodes or processing + units to specify the limits, but should use the same unit to set both the + min_limit and max_limit. properties: - !ruby/object:Api::Type::Integer name: 'minProcessingUnits' description: | Specifies minimum number of processing units allocated to the instance. If set, this number should be multiples of 1000. + exactly_one_of: + - min_processing_units + - min_nodes - !ruby/object:Api::Type::Integer name: 'maxProcessingUnits' description: | Specifies maximum number of processing units allocated to the instance. If set, this number should be multiples of 1000 and be greater than or equal to min_processing_units. + exactly_one_of: + - max_processing_units + - max_nodes + - !ruby/object:Api::Type::Integer + name: 'minNodes' + description: | + Specifies number of nodes allocated to the instance. If set, this number + should be greater than or equal to 1. + exactly_one_of: + - min_processing_units + - min_nodes + required_with: + - max_nodes + - !ruby/object:Api::Type::Integer + name: 'maxNodes' + description: | + Specifies maximum number of nodes allocated to the instance. If set, this number + should be greater than or equal to min_nodes. + exactly_one_of: + - max_processing_units + - max_nodes + required_with: + - min_nodes - !ruby/object:Api::Type::NestedObject name: 'autoscalingTargets' description: | diff --git a/mmv1/templates/terraform/encoders/spanner_instance_update.go.erb b/mmv1/templates/terraform/encoders/spanner_instance_update.go.erb index 6c9cc875a3b9..bb917b112ad1 100644 --- a/mmv1/templates/terraform/encoders/spanner_instance_update.go.erb +++ b/mmv1/templates/terraform/encoders/spanner_instance_update.go.erb @@ -24,6 +24,12 @@ if d.HasChange("autoscaling_config.0.autoscaling_limits.0.max_processing_units") if d.HasChange("autoscaling_config.0.autoscaling_limits.0.min_processing_units") { updateMask = append(updateMask, "autoscalingConfig.autoscalingLimits.minProcessingUnits") } +if d.HasChange("autoscaling_config.0.autoscaling_limits.0.max_nodes") { + updateMask = append(updateMask, "autoscalingConfig.autoscalingLimits.maxNodes") +} +if d.HasChange("autoscaling_config.0.autoscaling_limits.0.min_nodes") { + updateMask = append(updateMask, "autoscalingConfig.autoscalingLimits.minNodes") +} if d.HasChange("autoscaling_config.0.autoscaling_targets.0.high_priority_cpu_utilization_percent") { updateMask = append(updateMask, "autoscalingConfig.autoscalingTargets.highPriorityCpuUtilizationPercent") } diff --git a/mmv1/templates/terraform/examples/spanner_instance_with_autoscaling.tf.erb b/mmv1/templates/terraform/examples/spanner_instance_with_autoscaling.tf.erb index 3830a71a70d8..aa541cff768d 100644 --- a/mmv1/templates/terraform/examples/spanner_instance_with_autoscaling.tf.erb +++ b/mmv1/templates/terraform/examples/spanner_instance_with_autoscaling.tf.erb @@ -3,8 +3,11 @@ resource "google_spanner_instance" "example" { display_name = "Test Spanner Instance" autoscaling_config { autoscaling_limits { - max_processing_units = 3000 - min_processing_units = 2000 + // Define the minimum and maximum compute capacity allocated to the instance + // Either use nodes or processing units to specify the limits, + // but should use the same unit to set both the min_limit and max_limit. + max_processing_units = 3000 // OR max_nodes = 3 + min_processing_units = 2000 // OR min_nodes = 2 } autoscaling_targets { high_priority_cpu_utilization_percent = 75 diff --git a/mmv1/third_party/terraform/services/spanner/resource_spanner_instance_test.go b/mmv1/third_party/terraform/services/spanner/resource_spanner_instance_test.go index 07d2e067bd19..562721abe6c7 100644 --- a/mmv1/third_party/terraform/services/spanner/resource_spanner_instance_test.go +++ b/mmv1/third_party/terraform/services/spanner/resource_spanner_instance_test.go @@ -203,6 +203,67 @@ func TestAccSpannerInstance_basicWithAutoscalingUsingProcessingUnitConfigUpdate( }) } +func TestAccSpannerInstance_basicWithAutoscalingUsingNodeConfig(t *testing.T) { + t.Parallel() + + displayName := fmt.Sprintf("spanner-test-%s-dname", acctest.RandString(t, 10)) + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckSpannerInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccSpannerInstance_basicWithAutoscalerConfigUsingNodesAsConfigs(displayName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("google_spanner_instance.basic", "state"), + ), + }, + { + ResourceName: "google_spanner_instance.basic", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccSpannerInstance_basicWithAutoscalingUsingNodeConfigUpdate(t *testing.T) { + t.Parallel() + + displayName := fmt.Sprintf("spanner-test-%s-dname", acctest.RandString(t, 10)) + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckSpannerInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccSpannerInstance_basicWithAutoscalerConfigUsingNodesAsConfigsUpdate(displayName, 1, 2, 65, 95), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("google_spanner_instance.basic", "state"), + ), + }, + { + ResourceName: "google_spanner_instance.basic", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testAccSpannerInstance_basicWithAutoscalerConfigUsingNodesAsConfigsUpdate(displayName, 2, 3, 75, 90), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("google_spanner_instance.basic", "state"), + ), + }, + { + ResourceName: "google_spanner_instance.basic", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + }, + }) +} + func testAccSpannerInstance_basic(name string) string { return fmt.Sprintf(` resource "google_spanner_instance" "basic" { @@ -304,3 +365,43 @@ resource "google_spanner_instance" "basic" { } `, name, name, maxProcessingUnits, minProcessingUnits, cupUtilizationPercent, storageUtilizationPercent) } + +func testAccSpannerInstance_basicWithAutoscalerConfigUsingNodesAsConfigs(name string) string { + return fmt.Sprintf(` +resource "google_spanner_instance" "basic" { + name = "%s" + config = "regional-us-central1" + display_name = "%s" + autoscaling_config { + autoscaling_limits { + max_nodes = 2 + min_nodes = 1 + } + autoscaling_targets { + high_priority_cpu_utilization_percent = 65 + storage_utilization_percent = 95 + } + } +} +`, name, name) +} + +func testAccSpannerInstance_basicWithAutoscalerConfigUsingNodesAsConfigsUpdate(name string, minNodes, maxNodes, cupUtilizationPercent, storageUtilizationPercent int) string { + return fmt.Sprintf(` +resource "google_spanner_instance" "basic" { + name = "%s" + config = "regional-us-central1" + display_name = "%s" + autoscaling_config { + autoscaling_limits { + max_nodes = %v + min_nodes = %v + } + autoscaling_targets { + high_priority_cpu_utilization_percent = %v + storage_utilization_percent = %v + } + } +} +`, name, name, maxNodes, minNodes, cupUtilizationPercent, storageUtilizationPercent) +}