Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(spanner): support defining autoscaling limit as nodes #6748

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/9606.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
spanner: added support for defining autoscaling limit using node count in `google_spanner_instance`
```
90 changes: 89 additions & 1 deletion google-beta/services/spanner/resource_spanner_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,22 +159,44 @@ the instance.`,
Type: schema.TypeList,
Optional: true,
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.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"max_nodes": {
Type: schema.TypeInt,
Optional: true,
Description: `Specifies maximum number of nodes allocated to the instance. If set, this number
should be greater than or equal to min_nodes.`,
ExactlyOneOf: []string{},
RequiredWith: []string{},
},
"max_processing_units": {
Type: schema.TypeInt,
Optional: true,
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.`,
ExactlyOneOf: []string{},
},
"min_nodes": {
Type: schema.TypeInt,
Optional: true,
Description: `Specifies number of nodes allocated to the instance. If set, this number
should be greater than or equal to 1.`,
ExactlyOneOf: []string{},
RequiredWith: []string{},
},
"min_processing_units": {
Type: schema.TypeInt,
Optional: true,
Description: `Specifies minimum number of processing units allocated to the instance.
If set, this number should be multiples of 1000.`,
ExactlyOneOf: []string{},
},
},
},
Expand Down Expand Up @@ -792,6 +814,10 @@ func flattenSpannerInstanceAutoscalingConfigAutoscalingLimits(v interface{}, d *
flattenSpannerInstanceAutoscalingConfigAutoscalingLimitsMinProcessingUnits(original["minProcessingUnits"], d, config)
transformed["max_processing_units"] =
flattenSpannerInstanceAutoscalingConfigAutoscalingLimitsMaxProcessingUnits(original["maxProcessingUnits"], d, config)
transformed["min_nodes"] =
flattenSpannerInstanceAutoscalingConfigAutoscalingLimitsMinNodes(original["minNodes"], d, config)
transformed["max_nodes"] =
flattenSpannerInstanceAutoscalingConfigAutoscalingLimitsMaxNodes(original["maxNodes"], d, config)
return []interface{}{transformed}
}
func flattenSpannerInstanceAutoscalingConfigAutoscalingLimitsMinProcessingUnits(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
Expand Down Expand Up @@ -828,6 +854,40 @@ func flattenSpannerInstanceAutoscalingConfigAutoscalingLimitsMaxProcessingUnits(
return v // let terraform core handle it otherwise
}

func flattenSpannerInstanceAutoscalingConfigAutoscalingLimitsMinNodes(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
// Handles the string fixed64 format
if strVal, ok := v.(string); ok {
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
return intVal
}
}

// number values are represented as float64
if floatVal, ok := v.(float64); ok {
intVal := int(floatVal)
return intVal
}

return v // let terraform core handle it otherwise
}

func flattenSpannerInstanceAutoscalingConfigAutoscalingLimitsMaxNodes(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
// Handles the string fixed64 format
if strVal, ok := v.(string); ok {
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
return intVal
}
}

// number values are represented as float64
if floatVal, ok := v.(float64); ok {
intVal := int(floatVal)
return intVal
}

return v // let terraform core handle it otherwise
}

func flattenSpannerInstanceAutoscalingConfigAutoscalingTargets(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return nil
Expand Down Expand Up @@ -975,6 +1035,20 @@ func expandSpannerInstanceAutoscalingConfigAutoscalingLimits(v interface{}, d tp
transformed["maxProcessingUnits"] = transformedMaxProcessingUnits
}

transformedMinNodes, err := expandSpannerInstanceAutoscalingConfigAutoscalingLimitsMinNodes(original["min_nodes"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedMinNodes); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["minNodes"] = transformedMinNodes
}

transformedMaxNodes, err := expandSpannerInstanceAutoscalingConfigAutoscalingLimitsMaxNodes(original["max_nodes"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedMaxNodes); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["maxNodes"] = transformedMaxNodes
}

return transformed, nil
}

Expand All @@ -986,6 +1060,14 @@ func expandSpannerInstanceAutoscalingConfigAutoscalingLimitsMaxProcessingUnits(v
return v, nil
}

func expandSpannerInstanceAutoscalingConfigAutoscalingLimitsMinNodes(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandSpannerInstanceAutoscalingConfigAutoscalingLimitsMaxNodes(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandSpannerInstanceAutoscalingConfigAutoscalingTargets(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
Expand Down Expand Up @@ -1077,6 +1159,12 @@ func resourceSpannerInstanceUpdateEncoder(d *schema.ResourceData, meta interface
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")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,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
Expand Down
101 changes: 101 additions & 0 deletions google-beta/services/spanner/resource_spanner_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,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" {
Expand Down Expand Up @@ -306,3 +367,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)
}
23 changes: 20 additions & 3 deletions website/docs/r/spanner_instance.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,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
Expand Down Expand Up @@ -181,7 +184,11 @@ This must be set to true if you created a backup manually in the console.
* `autoscaling_limits` -
(Optional)
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.
Structure is [documented below](#nested_autoscaling_limits).

* `autoscaling_targets` -
Expand All @@ -204,6 +211,16 @@ This must be set to true if you created a backup manually in the console.
If set, this number should be multiples of 1000 and be greater than or equal to
min_processing_units.

* `min_nodes` -
(Optional)
Specifies number of nodes allocated to the instance. If set, this number
should be greater than or equal to 1.

* `max_nodes` -
(Optional)
Specifies maximum number of nodes allocated to the instance. If set, this number
should be greater than or equal to min_nodes.

<a name="nested_autoscaling_targets"></a>The `autoscaling_targets` block supports:

* `high_priority_cpu_utilization_percent` -
Expand Down