Skip to content

Commit

Permalink
Add mode enum and scale down controls for Compute AutoScaler (#3693) (#…
Browse files Browse the repository at this point in the history
…2214)

* Add mode enum and scale down controls for Compute AutoScaler

* Add mode enum for Compute AutoScaler in the correct API block

* Add defaults for mode and default_from_api for scale down controls

* Add tests for scale_down_controls and set at_least_one_of for it

Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
modular-magician authored Jun 23, 2020
1 parent 8b7de6e commit f9c6591
Show file tree
Hide file tree
Showing 7 changed files with 322 additions and 7 deletions.
6 changes: 6 additions & 0 deletions .changelog/3693.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
```release-note:enhancement
compute: Added `mode` to `google_compute_autoscaler` `autoscaling_policy`
```
```release-note:enhancement
compute: Added `scale_down_control` for `google_compute_autoscaler` `autoscaling_policy` (beta only)
```
220 changes: 220 additions & 0 deletions google-beta/resource_compute_autoscaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,55 @@ Stackdriver Monitoring metric. Possible values: ["GAUGE", "DELTA_PER_SECOND", "D
},
},
},
"mode": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{"OFF", "ONLY_UP", "ON", ""}, false),
Description: `Defines operating mode for this policy. Default value: "ON" Possible values: ["OFF", "ONLY_UP", "ON"]`,
Default: "ON",
},
"scale_down_control": {
Type: schema.TypeList,
Computed: true,
Optional: true,
Description: `Defines scale down controls to reduce the risk of response latency
and outages due to abrupt scale-in events`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"max_scaled_down_replicas": {
Type: schema.TypeList,
Optional: true,
Description: `A nested object resource`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"fixed": {
Type: schema.TypeInt,
Optional: true,
Description: `Specifies a fixed number of VM instances. This must be a positive
integer.`,
},
"percent": {
Type: schema.TypeInt,
Optional: true,
Description: `Specifies a percentage of instances between 0 to 100%, inclusive.
For example, specify 80 for 80%.`,
},
},
},
AtLeastOneOf: []string{},
},
"time_window_sec": {
Type: schema.TypeInt,
Optional: true,
Description: `How long back autoscaling should look when computing recommendations
to include directives regarding slower scale down, as described above.`,
},
},
},
AtLeastOneOf: []string{},
},
},
},
},
Expand Down Expand Up @@ -540,6 +589,10 @@ func flattenComputeAutoscalerAutoscalingPolicy(v interface{}, d *schema.Resource
flattenComputeAutoscalerAutoscalingPolicyMaxReplicas(original["maxNumReplicas"], d, config)
transformed["cooldown_period"] =
flattenComputeAutoscalerAutoscalingPolicyCooldownPeriod(original["coolDownPeriodSec"], d, config)
transformed["mode"] =
flattenComputeAutoscalerAutoscalingPolicyMode(original["mode"], d, config)
transformed["scale_down_control"] =
flattenComputeAutoscalerAutoscalingPolicyScaleDownControl(original["scaleDownControl"], d, config)
transformed["cpu_utilization"] =
flattenComputeAutoscalerAutoscalingPolicyCpuUtilization(original["cpuUtilization"], d, config)
transformed["metric"] =
Expand Down Expand Up @@ -599,6 +652,91 @@ func flattenComputeAutoscalerAutoscalingPolicyCooldownPeriod(v interface{}, d *s
return v // let terraform core handle it otherwise
}

func flattenComputeAutoscalerAutoscalingPolicyMode(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}

func flattenComputeAutoscalerAutoscalingPolicyScaleDownControl(v interface{}, d *schema.ResourceData, config *Config) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["max_scaled_down_replicas"] =
flattenComputeAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicas(original["maxScaledDownReplicas"], d, config)
transformed["time_window_sec"] =
flattenComputeAutoscalerAutoscalingPolicyScaleDownControlTimeWindowSec(original["timeWindowSec"], d, config)
return []interface{}{transformed}
}
func flattenComputeAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicas(v interface{}, d *schema.ResourceData, config *Config) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["fixed"] =
flattenComputeAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasFixed(original["fixed"], d, config)
transformed["percent"] =
flattenComputeAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasPercent(original["percent"], d, config)
return []interface{}{transformed}
}
func flattenComputeAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasFixed(v interface{}, d *schema.ResourceData, config *Config) interface{} {
// Handles the string fixed64 format
if strVal, ok := v.(string); ok {
if intVal, err := strconv.ParseInt(strVal, 10, 64); 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 flattenComputeAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasPercent(v interface{}, d *schema.ResourceData, config *Config) interface{} {
// Handles the string fixed64 format
if strVal, ok := v.(string); ok {
if intVal, err := strconv.ParseInt(strVal, 10, 64); 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 flattenComputeAutoscalerAutoscalingPolicyScaleDownControlTimeWindowSec(v interface{}, d *schema.ResourceData, config *Config) interface{} {
// Handles the string fixed64 format
if strVal, ok := v.(string); ok {
if intVal, err := strconv.ParseInt(strVal, 10, 64); 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 flattenComputeAutoscalerAutoscalingPolicyCpuUtilization(v interface{}, d *schema.ResourceData, config *Config) interface{} {
if v == nil {
return nil
Expand Down Expand Up @@ -727,6 +865,20 @@ func expandComputeAutoscalerAutoscalingPolicy(v interface{}, d TerraformResource
transformed["coolDownPeriodSec"] = transformedCooldownPeriod
}

transformedMode, err := expandComputeAutoscalerAutoscalingPolicyMode(original["mode"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedMode); val.IsValid() && !isEmptyValue(val) {
transformed["mode"] = transformedMode
}

transformedScaleDownControl, err := expandComputeAutoscalerAutoscalingPolicyScaleDownControl(original["scale_down_control"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedScaleDownControl); val.IsValid() && !isEmptyValue(val) {
transformed["scaleDownControl"] = transformedScaleDownControl
}

transformedCpuUtilization, err := expandComputeAutoscalerAutoscalingPolicyCpuUtilization(original["cpu_utilization"], d, config)
if err != nil {
return nil, err
Expand Down Expand Up @@ -763,6 +915,74 @@ func expandComputeAutoscalerAutoscalingPolicyCooldownPeriod(v interface{}, d Ter
return v, nil
}

func expandComputeAutoscalerAutoscalingPolicyMode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandComputeAutoscalerAutoscalingPolicyScaleDownControl(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedMaxScaledDownReplicas, err := expandComputeAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicas(original["max_scaled_down_replicas"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedMaxScaledDownReplicas); val.IsValid() && !isEmptyValue(val) {
transformed["maxScaledDownReplicas"] = transformedMaxScaledDownReplicas
}

transformedTimeWindowSec, err := expandComputeAutoscalerAutoscalingPolicyScaleDownControlTimeWindowSec(original["time_window_sec"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedTimeWindowSec); val.IsValid() && !isEmptyValue(val) {
transformed["timeWindowSec"] = transformedTimeWindowSec
}

return transformed, nil
}

func expandComputeAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicas(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedFixed, err := expandComputeAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasFixed(original["fixed"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedFixed); val.IsValid() && !isEmptyValue(val) {
transformed["fixed"] = transformedFixed
}

transformedPercent, err := expandComputeAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasPercent(original["percent"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedPercent); val.IsValid() && !isEmptyValue(val) {
transformed["percent"] = transformedPercent
}

return transformed, nil
}

func expandComputeAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasFixed(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandComputeAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasPercent(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandComputeAutoscalerAutoscalingPolicyScaleDownControlTimeWindowSec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandComputeAutoscalerAutoscalingPolicyCpuUtilization(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
Expand Down
50 changes: 50 additions & 0 deletions google-beta/resource_compute_autoscaler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,31 @@ func TestAccComputeAutoscaler_multicondition(t *testing.T) {
})
}

func TestAccComputeAutoscaler_scaleDownControl(t *testing.T) {
t.Parallel()

var it_name = fmt.Sprintf("autoscaler-test-%s", randString(t, 10))
var tp_name = fmt.Sprintf("autoscaler-test-%s", randString(t, 10))
var igm_name = fmt.Sprintf("autoscaler-test-%s", randString(t, 10))
var autoscaler_name = fmt.Sprintf("autoscaler-test-%s", randString(t, 10))

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeAutoscalerDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccComputeAutoscaler_scaleDownControl(it_name, tp_name, igm_name, autoscaler_name),
},
{
ResourceName: "google_compute_autoscaler.foobar",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccComputeAutoscaler_scaffolding(it_name, tp_name, igm_name string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
Expand Down Expand Up @@ -183,3 +208,28 @@ resource "google_compute_autoscaler" "foobar" {
}
`, autoscaler_name)
}

func testAccComputeAutoscaler_scaleDownControl(it_name, tp_name, igm_name, autoscaler_name string) string {
return testAccComputeAutoscaler_scaffolding(it_name, tp_name, igm_name) + fmt.Sprintf(`
resource "google_compute_autoscaler" "foobar" {
description = "Resource created for Terraform acceptance testing"
name = "%s"
zone = "us-central1-a"
target = google_compute_instance_group_manager.foobar.self_link
autoscaling_policy {
max_replicas = 10
min_replicas = 1
cooldown_period = 60
cpu_utilization {
target = 0.5
}
scale_down_control {
max_scaled_down_replicas {
percent = 80
}
time_window_sec = 300
}
}
}
`, autoscaler_name)
}
6 changes: 3 additions & 3 deletions google-beta/resource_compute_node_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,16 @@ to 100 and greater than or equal to min-nodes.`,
Description: `The autoscaling mode. Set to one of the following:
- OFF: Disables the autoscaler.
- ON: Enables scaling in and scaling out.
- ONLY_SCALE_OUT: Enables only scaling out.
You must use this mode if your node groups are configured to
- ONLY_SCALE_OUT: Enables only scaling out.
You must use this mode if your node groups are configured to
restart their hosted VMs on minimal servers. Possible values: ["OFF", "ON", "ONLY_SCALE_OUT"]`,
},
"min_nodes": {
Type: schema.TypeInt,
Computed: true,
Optional: true,
ForceNew: true,
Description: `Minimum size of the node group. Must be less
Description: `Minimum size of the node group. Must be less
than or equal to max-nodes. The default value is 0.`,
},
},
Expand Down
39 changes: 39 additions & 0 deletions website/docs/r/compute_autoscaler.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,21 @@ The `autoscaling_policy` block supports:
instance may take to initialize. To do this, create an instance
and time the startup process.

* `mode` -
(Optional)
Defines operating mode for this policy.

Default value: `ON`
Possible values are:
* `OFF`
* `ONLY_UP`
* `ON`

* `scale_down_control` -
(Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html))
Defines scale down controls to reduce the risk of response latency
and outages due to abrupt scale-in events Structure is documented below.

* `cpu_utilization` -
(Optional)
Defines the CPU utilization policy that allows the autoscaler to
Expand All @@ -264,6 +279,30 @@ The `autoscaling_policy` block supports:
Configuration parameters of autoscaling based on a load balancer. Structure is documented below.


The `scale_down_control` block supports:

* `max_scaled_down_replicas` -
(Optional)
A nested object resource Structure is documented below.

* `time_window_sec` -
(Optional)
How long back autoscaling should look when computing recommendations
to include directives regarding slower scale down, as described above.


The `max_scaled_down_replicas` block supports:

* `fixed` -
(Optional)
Specifies a fixed number of VM instances. This must be a positive
integer.

* `percent` -
(Optional)
Specifies a percentage of instances between 0 to 100%, inclusive.
For example, specify 80 for 80%.

The `cpu_utilization` block supports:

* `target` -
Expand Down
Loading

0 comments on commit f9c6591

Please sign in to comment.