Skip to content

Commit 44ecb78

Browse files
feat(spanner): add instance autoscaling attributes to spanner instance resource (#9403) (#16473)
* feat(spanner): add instance autoscaling attributed to spanner instance resource * add update tests * fix tests * fix tests * fix lint [upstream:445f283acc877fe918cf30d77db69f9a734c8589] Signed-off-by: Modular Magician <[email protected]>
1 parent 478fda5 commit 44ecb78

File tree

4 files changed

+456
-5
lines changed

4 files changed

+456
-5
lines changed

.changelog/9403.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
spanner: added `autoscaling_config` field to `google_spanner_instance`
3+
```

google/services/spanner/resource_spanner_instance.go

+301-4
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,69 @@ in length.
145145
146146
If not provided, a random string starting with 'tf-' will be selected.`,
147147
},
148+
"autoscaling_config": {
149+
Type: schema.TypeList,
150+
Optional: true,
151+
Description: `The autoscaling configuration. Autoscaling is enabled if this field is set.
152+
When autoscaling is enabled, num_nodes and processing_units are treated as,
153+
OUTPUT_ONLY fields and reflect the current compute capacity allocated to
154+
the instance.`,
155+
MaxItems: 1,
156+
Elem: &schema.Resource{
157+
Schema: map[string]*schema.Schema{
158+
"autoscaling_limits": {
159+
Type: schema.TypeList,
160+
Optional: true,
161+
Description: `Defines scale in controls to reduce the risk of response latency
162+
and outages due to abrupt scale-in events`,
163+
MaxItems: 1,
164+
Elem: &schema.Resource{
165+
Schema: map[string]*schema.Schema{
166+
"max_processing_units": {
167+
Type: schema.TypeInt,
168+
Optional: true,
169+
Description: `Specifies maximum number of processing units allocated to the instance.
170+
If set, this number should be multiples of 1000 and be greater than or equal to
171+
min_processing_units.`,
172+
},
173+
"min_processing_units": {
174+
Type: schema.TypeInt,
175+
Optional: true,
176+
Description: `Specifies minimum number of processing units allocated to the instance.
177+
If set, this number should be multiples of 1000.`,
178+
},
179+
},
180+
},
181+
},
182+
"autoscaling_targets": {
183+
Type: schema.TypeList,
184+
Optional: true,
185+
Description: `Defines scale in controls to reduce the risk of response latency
186+
and outages due to abrupt scale-in events`,
187+
MaxItems: 1,
188+
Elem: &schema.Resource{
189+
Schema: map[string]*schema.Schema{
190+
"high_priority_cpu_utilization_percent": {
191+
Type: schema.TypeInt,
192+
Optional: true,
193+
Description: `Specifies the target high priority cpu utilization percentage that the autoscaler
194+
should be trying to achieve for the instance.
195+
This number is on a scale from 0 (no utilization) to 100 (full utilization)..`,
196+
},
197+
"storage_utilization_percent": {
198+
Type: schema.TypeInt,
199+
Optional: true,
200+
Description: `Specifies the target storage utilization percentage that the autoscaler
201+
should be trying to achieve for the instance.
202+
This number is on a scale from 0 (no utilization) to 100 (full utilization).`,
203+
},
204+
},
205+
},
206+
},
207+
},
208+
},
209+
ExactlyOneOf: []string{"num_nodes", "processing_units", "autoscaling_config"},
210+
},
148211
"labels": {
149212
Type: schema.TypeMap,
150213
Optional: true,
@@ -162,15 +225,15 @@ Please refer to the field 'effective_labels' for all of the labels present on th
162225
Optional: true,
163226
Description: `The number of nodes allocated to this instance. Exactly one of either node_count or processing_units
164227
must be present in terraform.`,
165-
ExactlyOneOf: []string{"num_nodes", "processing_units"},
228+
ExactlyOneOf: []string{"num_nodes", "processing_units", "autoscaling_config"},
166229
},
167230
"processing_units": {
168231
Type: schema.TypeInt,
169232
Computed: true,
170233
Optional: true,
171234
Description: `The number of processing units allocated to this instance. Exactly one of processing_units
172235
or node_count must be present in terraform.`,
173-
ExactlyOneOf: []string{"num_nodes", "processing_units"},
236+
ExactlyOneOf: []string{"num_nodes", "processing_units", "autoscaling_config"},
174237
},
175238
"effective_labels": {
176239
Type: schema.TypeMap,
@@ -246,6 +309,12 @@ func resourceSpannerInstanceCreate(d *schema.ResourceData, meta interface{}) err
246309
} else if v, ok := d.GetOkExists("processing_units"); !tpgresource.IsEmptyValue(reflect.ValueOf(processingUnitsProp)) && (ok || !reflect.DeepEqual(v, processingUnitsProp)) {
247310
obj["processingUnits"] = processingUnitsProp
248311
}
312+
autoscalingConfigProp, err := expandSpannerInstanceAutoscalingConfig(d.Get("autoscaling_config"), d, config)
313+
if err != nil {
314+
return err
315+
} else if v, ok := d.GetOkExists("autoscaling_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(autoscalingConfigProp)) && (ok || !reflect.DeepEqual(v, autoscalingConfigProp)) {
316+
obj["autoscalingConfig"] = autoscalingConfigProp
317+
}
249318
labelsProp, err := expandSpannerInstanceEffectiveLabels(d.Get("effective_labels"), d, config)
250319
if err != nil {
251320
return err
@@ -418,6 +487,9 @@ func resourceSpannerInstanceRead(d *schema.ResourceData, meta interface{}) error
418487
if err := d.Set("state", flattenSpannerInstanceState(res["state"], d, config)); err != nil {
419488
return fmt.Errorf("Error reading Instance: %s", err)
420489
}
490+
if err := d.Set("autoscaling_config", flattenSpannerInstanceAutoscalingConfig(res["autoscalingConfig"], d, config)); err != nil {
491+
return fmt.Errorf("Error reading Instance: %s", err)
492+
}
421493
if err := d.Set("terraform_labels", flattenSpannerInstanceTerraformLabels(res["labels"], d, config)); err != nil {
422494
return fmt.Errorf("Error reading Instance: %s", err)
423495
}
@@ -462,6 +534,12 @@ func resourceSpannerInstanceUpdate(d *schema.ResourceData, meta interface{}) err
462534
} else if v, ok := d.GetOkExists("processing_units"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, processingUnitsProp)) {
463535
obj["processingUnits"] = processingUnitsProp
464536
}
537+
autoscalingConfigProp, err := expandSpannerInstanceAutoscalingConfig(d.Get("autoscaling_config"), d, config)
538+
if err != nil {
539+
return err
540+
} else if v, ok := d.GetOkExists("autoscaling_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, autoscalingConfigProp)) {
541+
obj["autoscalingConfig"] = autoscalingConfigProp
542+
}
465543
labelsProp, err := expandSpannerInstanceEffectiveLabels(d.Get("effective_labels"), d, config)
466544
if err != nil {
467545
return err
@@ -686,6 +764,119 @@ func flattenSpannerInstanceState(v interface{}, d *schema.ResourceData, config *
686764
return v
687765
}
688766

767+
func flattenSpannerInstanceAutoscalingConfig(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
768+
if v == nil {
769+
return nil
770+
}
771+
original := v.(map[string]interface{})
772+
if len(original) == 0 {
773+
return nil
774+
}
775+
transformed := make(map[string]interface{})
776+
transformed["autoscaling_limits"] =
777+
flattenSpannerInstanceAutoscalingConfigAutoscalingLimits(original["autoscalingLimits"], d, config)
778+
transformed["autoscaling_targets"] =
779+
flattenSpannerInstanceAutoscalingConfigAutoscalingTargets(original["autoscalingTargets"], d, config)
780+
return []interface{}{transformed}
781+
}
782+
func flattenSpannerInstanceAutoscalingConfigAutoscalingLimits(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
783+
if v == nil {
784+
return nil
785+
}
786+
original := v.(map[string]interface{})
787+
if len(original) == 0 {
788+
return nil
789+
}
790+
transformed := make(map[string]interface{})
791+
transformed["min_processing_units"] =
792+
flattenSpannerInstanceAutoscalingConfigAutoscalingLimitsMinProcessingUnits(original["minProcessingUnits"], d, config)
793+
transformed["max_processing_units"] =
794+
flattenSpannerInstanceAutoscalingConfigAutoscalingLimitsMaxProcessingUnits(original["maxProcessingUnits"], d, config)
795+
return []interface{}{transformed}
796+
}
797+
func flattenSpannerInstanceAutoscalingConfigAutoscalingLimitsMinProcessingUnits(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
798+
// Handles the string fixed64 format
799+
if strVal, ok := v.(string); ok {
800+
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
801+
return intVal
802+
}
803+
}
804+
805+
// number values are represented as float64
806+
if floatVal, ok := v.(float64); ok {
807+
intVal := int(floatVal)
808+
return intVal
809+
}
810+
811+
return v // let terraform core handle it otherwise
812+
}
813+
814+
func flattenSpannerInstanceAutoscalingConfigAutoscalingLimitsMaxProcessingUnits(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
815+
// Handles the string fixed64 format
816+
if strVal, ok := v.(string); ok {
817+
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
818+
return intVal
819+
}
820+
}
821+
822+
// number values are represented as float64
823+
if floatVal, ok := v.(float64); ok {
824+
intVal := int(floatVal)
825+
return intVal
826+
}
827+
828+
return v // let terraform core handle it otherwise
829+
}
830+
831+
func flattenSpannerInstanceAutoscalingConfigAutoscalingTargets(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
832+
if v == nil {
833+
return nil
834+
}
835+
original := v.(map[string]interface{})
836+
if len(original) == 0 {
837+
return nil
838+
}
839+
transformed := make(map[string]interface{})
840+
transformed["high_priority_cpu_utilization_percent"] =
841+
flattenSpannerInstanceAutoscalingConfigAutoscalingTargetsHighPriorityCpuUtilizationPercent(original["highPriorityCpuUtilizationPercent"], d, config)
842+
transformed["storage_utilization_percent"] =
843+
flattenSpannerInstanceAutoscalingConfigAutoscalingTargetsStorageUtilizationPercent(original["storageUtilizationPercent"], d, config)
844+
return []interface{}{transformed}
845+
}
846+
func flattenSpannerInstanceAutoscalingConfigAutoscalingTargetsHighPriorityCpuUtilizationPercent(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
847+
// Handles the string fixed64 format
848+
if strVal, ok := v.(string); ok {
849+
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
850+
return intVal
851+
}
852+
}
853+
854+
// number values are represented as float64
855+
if floatVal, ok := v.(float64); ok {
856+
intVal := int(floatVal)
857+
return intVal
858+
}
859+
860+
return v // let terraform core handle it otherwise
861+
}
862+
863+
func flattenSpannerInstanceAutoscalingConfigAutoscalingTargetsStorageUtilizationPercent(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
864+
// Handles the string fixed64 format
865+
if strVal, ok := v.(string); ok {
866+
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
867+
return intVal
868+
}
869+
}
870+
871+
// number values are represented as float64
872+
if floatVal, ok := v.(float64); ok {
873+
intVal := int(floatVal)
874+
return intVal
875+
}
876+
877+
return v // let terraform core handle it otherwise
878+
}
879+
689880
func flattenSpannerInstanceTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
690881
if v == nil {
691882
return v
@@ -735,6 +926,100 @@ func expandSpannerInstanceProcessingUnits(v interface{}, d tpgresource.Terraform
735926
return v, nil
736927
}
737928

929+
func expandSpannerInstanceAutoscalingConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
930+
l := v.([]interface{})
931+
if len(l) == 0 || l[0] == nil {
932+
return nil, nil
933+
}
934+
raw := l[0]
935+
original := raw.(map[string]interface{})
936+
transformed := make(map[string]interface{})
937+
938+
transformedAutoscalingLimits, err := expandSpannerInstanceAutoscalingConfigAutoscalingLimits(original["autoscaling_limits"], d, config)
939+
if err != nil {
940+
return nil, err
941+
} else if val := reflect.ValueOf(transformedAutoscalingLimits); val.IsValid() && !tpgresource.IsEmptyValue(val) {
942+
transformed["autoscalingLimits"] = transformedAutoscalingLimits
943+
}
944+
945+
transformedAutoscalingTargets, err := expandSpannerInstanceAutoscalingConfigAutoscalingTargets(original["autoscaling_targets"], d, config)
946+
if err != nil {
947+
return nil, err
948+
} else if val := reflect.ValueOf(transformedAutoscalingTargets); val.IsValid() && !tpgresource.IsEmptyValue(val) {
949+
transformed["autoscalingTargets"] = transformedAutoscalingTargets
950+
}
951+
952+
return transformed, nil
953+
}
954+
955+
func expandSpannerInstanceAutoscalingConfigAutoscalingLimits(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
956+
l := v.([]interface{})
957+
if len(l) == 0 || l[0] == nil {
958+
return nil, nil
959+
}
960+
raw := l[0]
961+
original := raw.(map[string]interface{})
962+
transformed := make(map[string]interface{})
963+
964+
transformedMinProcessingUnits, err := expandSpannerInstanceAutoscalingConfigAutoscalingLimitsMinProcessingUnits(original["min_processing_units"], d, config)
965+
if err != nil {
966+
return nil, err
967+
} else if val := reflect.ValueOf(transformedMinProcessingUnits); val.IsValid() && !tpgresource.IsEmptyValue(val) {
968+
transformed["minProcessingUnits"] = transformedMinProcessingUnits
969+
}
970+
971+
transformedMaxProcessingUnits, err := expandSpannerInstanceAutoscalingConfigAutoscalingLimitsMaxProcessingUnits(original["max_processing_units"], d, config)
972+
if err != nil {
973+
return nil, err
974+
} else if val := reflect.ValueOf(transformedMaxProcessingUnits); val.IsValid() && !tpgresource.IsEmptyValue(val) {
975+
transformed["maxProcessingUnits"] = transformedMaxProcessingUnits
976+
}
977+
978+
return transformed, nil
979+
}
980+
981+
func expandSpannerInstanceAutoscalingConfigAutoscalingLimitsMinProcessingUnits(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
982+
return v, nil
983+
}
984+
985+
func expandSpannerInstanceAutoscalingConfigAutoscalingLimitsMaxProcessingUnits(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
986+
return v, nil
987+
}
988+
989+
func expandSpannerInstanceAutoscalingConfigAutoscalingTargets(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
990+
l := v.([]interface{})
991+
if len(l) == 0 || l[0] == nil {
992+
return nil, nil
993+
}
994+
raw := l[0]
995+
original := raw.(map[string]interface{})
996+
transformed := make(map[string]interface{})
997+
998+
transformedHighPriorityCpuUtilizationPercent, err := expandSpannerInstanceAutoscalingConfigAutoscalingTargetsHighPriorityCpuUtilizationPercent(original["high_priority_cpu_utilization_percent"], d, config)
999+
if err != nil {
1000+
return nil, err
1001+
} else if val := reflect.ValueOf(transformedHighPriorityCpuUtilizationPercent); val.IsValid() && !tpgresource.IsEmptyValue(val) {
1002+
transformed["highPriorityCpuUtilizationPercent"] = transformedHighPriorityCpuUtilizationPercent
1003+
}
1004+
1005+
transformedStorageUtilizationPercent, err := expandSpannerInstanceAutoscalingConfigAutoscalingTargetsStorageUtilizationPercent(original["storage_utilization_percent"], d, config)
1006+
if err != nil {
1007+
return nil, err
1008+
} else if val := reflect.ValueOf(transformedStorageUtilizationPercent); val.IsValid() && !tpgresource.IsEmptyValue(val) {
1009+
transformed["storageUtilizationPercent"] = transformedStorageUtilizationPercent
1010+
}
1011+
1012+
return transformed, nil
1013+
}
1014+
1015+
func expandSpannerInstanceAutoscalingConfigAutoscalingTargetsHighPriorityCpuUtilizationPercent(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
1016+
return v, nil
1017+
}
1018+
1019+
func expandSpannerInstanceAutoscalingConfigAutoscalingTargetsStorageUtilizationPercent(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
1020+
return v, nil
1021+
}
1022+
7381023
func expandSpannerInstanceEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
7391024
if v == nil {
7401025
return map[string]string{}, nil
@@ -747,8 +1032,8 @@ func expandSpannerInstanceEffectiveLabels(v interface{}, d tpgresource.Terraform
7471032
}
7481033

7491034
func resourceSpannerInstanceEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
750-
// Temp Logic to accommodate processing_units and num_nodes
751-
if obj["processingUnits"] == nil && obj["nodeCount"] == nil {
1035+
// Temp Logic to accommodate autoscaling_config, processing_units and num_nodes
1036+
if obj["processingUnits"] == nil && obj["nodeCount"] == nil && obj["autoscalingConfig"] == nil {
7521037
obj["nodeCount"] = 1
7531038
}
7541039
newObj := make(map[string]interface{})
@@ -786,6 +1071,18 @@ func resourceSpannerInstanceUpdateEncoder(d *schema.ResourceData, meta interface
7861071
if d.HasChange("processing_units") {
7871072
updateMask = append(updateMask, "processingUnits")
7881073
}
1074+
if d.HasChange("autoscaling_config.0.autoscaling_limits.0.max_processing_units") {
1075+
updateMask = append(updateMask, "autoscalingConfig.autoscalingLimits.maxProcessingUnits")
1076+
}
1077+
if d.HasChange("autoscaling_config.0.autoscaling_limits.0.min_processing_units") {
1078+
updateMask = append(updateMask, "autoscalingConfig.autoscalingLimits.minProcessingUnits")
1079+
}
1080+
if d.HasChange("autoscaling_config.0.autoscaling_targets.0.high_priority_cpu_utilization_percent") {
1081+
updateMask = append(updateMask, "autoscalingConfig.autoscalingTargets.highPriorityCpuUtilizationPercent")
1082+
}
1083+
if d.HasChange("autoscaling_config.0.autoscaling_targets.0.storage_utilization_percent") {
1084+
updateMask = append(updateMask, "autoscalingConfig.autoscalingTargets.storageUtilizationPercent")
1085+
}
7891086
newObj["fieldMask"] = strings.Join(updateMask, ",")
7901087
return newObj, nil
7911088
}

0 commit comments

Comments
 (0)