From a2d730ade7862ff5fef67b8e970de851aaace9eb Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Tue, 5 Sep 2017 20:27:45 +0100 Subject: [PATCH] r/aws_appautoscaling_policy: Nest step scaling policy cfg --- aws/resource_aws_appautoscaling_policy.go | 220 +++++++++++++++--- ...resource_aws_appautoscaling_policy_test.go | 125 ++++++++++ 2 files changed, 312 insertions(+), 33 deletions(-) diff --git a/aws/resource_aws_appautoscaling_policy.go b/aws/resource_aws_appautoscaling_policy.go index e75e76152d7..9ea31f4b490 100644 --- a/aws/resource_aws_appautoscaling_policy.go +++ b/aws/resource_aws_appautoscaling_policy.go @@ -58,21 +58,51 @@ func resourceAwsAppautoscalingPolicy() *schema.Resource { ForceNew: true, ValidateFunc: validateAppautoscalingServiceNamespace, }, - "adjustment_type": &schema.Schema{ - Type: schema.TypeString, - Required: true, - }, - "cooldown": &schema.Schema{ - Type: schema.TypeInt, - Required: true, - }, - "metric_aggregation_type": &schema.Schema{ - Type: schema.TypeString, - Required: true, - }, - "min_adjustment_magnitude": &schema.Schema{ - Type: schema.TypeInt, + "step_scaling_policy_configuration": { + Type: schema.TypeList, Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "adjustment_type": { + Type: schema.TypeString, + Optional: true, + }, + "cooldown": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + }, + "metric_aggregation_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "min_adjustment_magnitude": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + }, + "step_adjustment": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric_interval_lower_bound": &schema.Schema{ + Type: schema.TypeFloat, + Optional: true, + Default: -1, + }, + "metric_interval_upper_bound": &schema.Schema{ + Type: schema.TypeFloat, + Optional: true, + Default: -1, + }, + "scaling_adjustment": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + }, + }, }, "alarms": &schema.Schema{ Type: schema.TypeList, @@ -80,9 +110,32 @@ func resourceAwsAppautoscalingPolicy() *schema.Resource { ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + + "adjustment_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Deprecated: "Use step_scaling_policy_configuration -> adjustment_type instead", + }, + "cooldown": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Deprecated: "Use step_scaling_policy_configuration -> cooldown instead", + }, + "metric_aggregation_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Deprecated: "Use step_scaling_policy_configuration -> metric_aggregation_type instead", + }, + "min_adjustment_magnitude": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Deprecated: "Use step_scaling_policy_configuration -> min_adjustment_magnitude instead", + }, "step_adjustment": &schema.Schema{ - Type: schema.TypeSet, - Optional: true, + Type: schema.TypeSet, + Optional: true, + Deprecated: "Use step_scaling_policy_configuration -> step_adjustment instead", + Set: resourceAwsAppautoscalingAdjustmentHash, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "metric_interval_lower_bound": &schema.Schema{ @@ -99,7 +152,6 @@ func resourceAwsAppautoscalingPolicy() *schema.Resource { }, }, }, - Set: resourceAwsAppautoscalingAdjustmentHash, }, }, } @@ -145,7 +197,7 @@ func resourceAwsAppautoscalingPolicyRead(d *schema.ResourceData, meta interface{ d.Set("scalable_dimension", p.ScalableDimension) d.Set("service_namespace", p.ServiceNamespace) d.Set("alarms", p.Alarms) - d.Set("step_scaling_policy_configuration", p.StepScalingPolicyConfiguration) + d.Set("step_scaling_policy_configuration", flattenStepScalingPolicyConfiguration(p.StepScalingPolicyConfiguration)) return nil } @@ -211,6 +263,10 @@ func expandAppautoscalingStepAdjustments(configured []interface{}) ([]*applicati if data["metric_interval_lower_bound"] != "" { bound := data["metric_interval_lower_bound"] switch bound := bound.(type) { + case float64: + if bound >= 0 { + a.MetricIntervalLowerBound = aws.Float64(bound) + } case string: f, err := strconv.ParseFloat(bound, 64) if err != nil { @@ -226,6 +282,10 @@ func expandAppautoscalingStepAdjustments(configured []interface{}) ([]*applicati if data["metric_interval_upper_bound"] != "" { bound := data["metric_interval_upper_bound"] switch bound := bound.(type) { + case float64: + if bound >= 0 { + a.MetricIntervalUpperBound = aws.Float64(bound) + } case string: f, err := strconv.ParseFloat(bound, 64) if err != nil { @@ -262,25 +322,45 @@ func getAwsAppautoscalingPutScalingPolicyInput(d *schema.ResourceData) (applicat params.ScalableDimension = aws.String(v.(string)) } - var adjustmentSteps []*applicationautoscaling.StepAdjustment - if v, ok := d.GetOk("step_adjustment"); ok { - steps, err := expandAppautoscalingStepAdjustments(v.(*schema.Set).List()) - if err != nil { - return params, fmt.Errorf("metric_interval_lower_bound and metric_interval_upper_bound must be strings!") + // Deprecated fields + // TODO: Remove in next major version + at, atOk := d.GetOk("adjustment_type") + cd, cdOk := d.GetOk("cooldown") + mat, matOk := d.GetOk("metric_aggregation_type") + mam, mamOk := d.GetOk("min_adjustment_magnitude") + sa, saOk := d.GetOk("step_adjustment") + if atOk || cdOk || matOk || mamOk || saOk { + cfg := &applicationautoscaling.StepScalingPolicyConfiguration{} + + if atOk { + cfg.AdjustmentType = aws.String(at.(string)) + } + + if cdOk { + cfg.Cooldown = aws.Int64(int64(cd.(int))) } - adjustmentSteps = steps - } - // build StepScalingPolicyConfiguration - params.StepScalingPolicyConfiguration = &applicationautoscaling.StepScalingPolicyConfiguration{ - AdjustmentType: aws.String(d.Get("adjustment_type").(string)), - Cooldown: aws.Int64(int64(d.Get("cooldown").(int))), - MetricAggregationType: aws.String(d.Get("metric_aggregation_type").(string)), - StepAdjustments: adjustmentSteps, + if matOk { + cfg.MetricAggregationType = aws.String(mat.(string)) + } + + if saOk { + steps, err := expandAppautoscalingStepAdjustments(sa.(*schema.Set).List()) + if err != nil { + return params, fmt.Errorf("metric_interval_lower_bound and metric_interval_upper_bound must be strings!") + } + cfg.StepAdjustments = steps + } + + if mamOk { + cfg.MinAdjustmentMagnitude = aws.Int64(int64(mam.(int))) + } + + params.StepScalingPolicyConfiguration = cfg } - if v, ok := d.GetOk("min_adjustment_magnitude"); ok { - params.StepScalingPolicyConfiguration.MinAdjustmentMagnitude = aws.Int64(int64(v.(int))) + if v, ok := d.GetOk("step_scaling_policy_configuration"); ok { + params.StepScalingPolicyConfiguration = expandStepScalingPolicyConfiguration(v.([]interface{})) } return params, nil @@ -312,6 +392,80 @@ func getAwsAppautoscalingPolicy(d *schema.ResourceData, meta interface{}) (*appl return nil, nil } +func expandStepScalingPolicyConfiguration(cfg []interface{}) *applicationautoscaling.StepScalingPolicyConfiguration { + if len(cfg) < 1 { + return nil + } + + out := &applicationautoscaling.StepScalingPolicyConfiguration{} + + m := cfg[0].(map[string]interface{}) + if v, ok := m["adjustment_type"]; ok { + out.AdjustmentType = aws.String(v.(string)) + } + if v, ok := m["cooldown"]; ok { + out.Cooldown = aws.Int64(int64(v.(int))) + } + if v, ok := m["metric_aggregation_type"]; ok { + out.MetricAggregationType = aws.String(v.(string)) + } + if v, ok := m["min_adjustment_magnitude"].(int); ok && v > 0 { + out.MinAdjustmentMagnitude = aws.Int64(int64(v)) + } + if v, ok := m["step_adjustment"].(*schema.Set); ok && v.Len() > 0 { + out.StepAdjustments, _ = expandAppautoscalingStepAdjustments(v.List()) + } + + return out +} + +func flattenStepScalingPolicyConfiguration(cfg *applicationautoscaling.StepScalingPolicyConfiguration) []interface{} { + if cfg == nil { + return []interface{}{} + } + + m := make(map[string]interface{}, 0) + + if cfg.AdjustmentType != nil { + m["adjustment_type"] = *cfg.AdjustmentType + } + if cfg.Cooldown != nil { + m["cooldown"] = *cfg.Cooldown + } + if cfg.MetricAggregationType != nil { + m["metric_aggregation_type"] = *cfg.MetricAggregationType + } + if cfg.MinAdjustmentMagnitude != nil { + m["min_adjustment_magnitude"] = *cfg.MinAdjustmentMagnitude + } + if cfg.StepAdjustments != nil { + m["step_adjustment"] = flattenAppautoscalingStepAdjustments(cfg.StepAdjustments) + } + + return []interface{}{m} +} + +func flattenAppautoscalingStepAdjustments(adjs []*applicationautoscaling.StepAdjustment) []interface{} { + out := make([]interface{}, len(adjs), len(adjs)) + + for i, adj := range adjs { + m := make(map[string]interface{}, 0) + + m["scaling_adjustment"] = *adj.ScalingAdjustment + + if adj.MetricIntervalLowerBound != nil { + m["metric_interval_lower_bound"] = *adj.MetricIntervalLowerBound + } + if adj.MetricIntervalUpperBound != nil { + m["metric_interval_upper_bound"] = *adj.MetricIntervalUpperBound + } + + out[i] = m + } + + return out +} + func resourceAwsAppautoscalingAdjustmentHash(v interface{}) int { var buf bytes.Buffer m := v.(map[string]interface{}) diff --git a/aws/resource_aws_appautoscaling_policy_test.go b/aws/resource_aws_appautoscaling_policy_test.go index 36abf932cf5..1ec3bbc2891 100644 --- a/aws/resource_aws_appautoscaling_policy_test.go +++ b/aws/resource_aws_appautoscaling_policy_test.go @@ -29,6 +29,9 @@ func TestAccAWSAppautoScalingPolicy_basic(t *testing.T) { resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "adjustment_type", "ChangeInCapacity"), resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "policy_type", "StepScaling"), resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "cooldown", "60"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "step_adjustment.#", "1"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "step_adjustment.2087484785.scaling_adjustment", "1"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "step_adjustment.2087484785.metric_interval_lower_bound", "0"), resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "name", randPolicyName), resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "resource_id", fmt.Sprintf("service/%s/foobar", randClusterName)), resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "service_namespace", "ecs"), @@ -39,6 +42,38 @@ func TestAccAWSAppautoScalingPolicy_basic(t *testing.T) { }) } +func TestAccAWSAppautoScalingPolicy_nestedSchema(t *testing.T) { + var policy applicationautoscaling.ScalingPolicy + + randClusterName := fmt.Sprintf("cluster%s", acctest.RandString(10)) + randPolicyName := fmt.Sprintf("terraform-test-foobar-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAppautoscalingPolicyDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSAppautoscalingPolicyNestedSchemaConfig(randClusterName, randPolicyName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppautoscalingPolicyExists("aws_appautoscaling_policy.foobar_simple", &policy), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "step_scaling_policy_configuration.0.adjustment_type", "PercentChangeInCapacity"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "step_scaling_policy_configuration.0.cooldown", "60"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "step_scaling_policy_configuration.0.step_adjustment.#", "1"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "step_scaling_policy_configuration.0.step_adjustment.2252990027.scaling_adjustment", "1"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "step_scaling_policy_configuration.0.step_adjustment.2252990027.metric_interval_lower_bound", "1"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "step_scaling_policy_configuration.0.step_adjustment.2252990027.metric_interval_upper_bound", "-1"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "name", randPolicyName), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "policy_type", "StepScaling"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "resource_id", fmt.Sprintf("service/%s/foobar", randClusterName)), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "service_namespace", "ecs"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "scalable_dimension", "ecs:service:DesiredCount"), + ), + }, + }, + }) +} + func TestAccAWSAppautoScalingPolicy_spotFleetRequest(t *testing.T) { var policy applicationautoscaling.ScalingPolicy @@ -290,3 +325,93 @@ resource "aws_appautoscaling_policy" "test" { } `, randPolicyName) } + +func testAccAWSAppautoscalingPolicyNestedSchemaConfig( + randClusterName string, + randPolicyName string) string { + return fmt.Sprintf(` +resource "aws_iam_role" "autoscale_role" { + name = "%s" + path = "/" + + assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":[\"sts:AssumeRole\"]}]}" +} + +resource "aws_iam_role_policy" "autoscale_role_policy" { + name = "%s" + role = "${aws_iam_role.autoscale_role.id}" + + policy = <