From 5a6c084470e441046edd970cb470e83f7cf8cebe Mon Sep 17 00:00:00 2001 From: Yupeng Gou Date: Thu, 6 Jan 2022 14:31:15 -0800 Subject: [PATCH 1/9] Support cusomized metric specification in autoscaling predictive scaling policy. --- internal/service/autoscaling/policy.go | 458 +++++++++++++++++++- internal/service/autoscaling/policy_test.go | 131 +++++- 2 files changed, 573 insertions(+), 16 deletions(-) diff --git a/internal/service/autoscaling/policy.go b/internal/service/autoscaling/policy.go index d11d2f08519..da78a27fcfc 100644 --- a/internal/service/autoscaling/policy.go +++ b/internal/service/autoscaling/policy.go @@ -87,6 +87,264 @@ func ResourcePolicy() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "customized_scaling_metric_specification": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"predictive_scaling_configuration.0.metric_specification.0.predefined_scaling_metric_specification"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric_data_queries": { + Type: schema.TypeList, + Required: true, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "expression": { + Type: schema.TypeString, + Optional: true, + }, + "metric_stat": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric_name": { + Type: schema.TypeString, + Required: true, + }, + "namespace": { + Type: schema.TypeString, + Required: true, + }, + "dimensions": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "stat": { + Type: schema.TypeString, + Required: true, + }, + "unit": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "label": { + Type: schema.TypeString, + Optional: true, + }, + "return_data": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + }, + }, + }, + }, + }, + }, + "customized_load_metric_specification": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"predictive_scaling_configuration.0.metric_specification.0.predefined_load_metric_specification"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric_data_queries": { + Type: schema.TypeList, + Required: true, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "expression": { + Type: schema.TypeString, + Optional: true, + }, + "metric_stat": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric_name": { + Type: schema.TypeString, + Required: true, + }, + "namespace": { + Type: schema.TypeString, + Required: true, + }, + "dimensions": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "stat": { + Type: schema.TypeString, + Required: true, + }, + "unit": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "label": { + Type: schema.TypeString, + Optional: true, + }, + "return_data": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + }, + }, + }, + }, + }, + }, + "customized_capacity_metric_specification": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"predictive_scaling_configuration.0.metric_specification.0.predefined_load_metric_specification"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric_data_queries": { + Type: schema.TypeList, + Required: true, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "expression": { + Type: schema.TypeString, + Optional: true, + }, + "metric_stat": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric_name": { + Type: schema.TypeString, + Required: true, + }, + "namespace": { + Type: schema.TypeString, + Required: true, + }, + "dimensions": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "stat": { + Type: schema.TypeString, + Required: true, + }, + "unit": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "label": { + Type: schema.TypeString, + Optional: true, + }, + "return_data": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + }, + }, + }, + }, + }, + }, "predefined_metric_pair_specification": { Type: schema.TypeList, Optional: true, @@ -111,9 +369,10 @@ func ResourcePolicy() *schema.Resource { }, }, "predefined_scaling_metric_specification": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"predictive_scaling_configuration.0.metric_specification.0.customized_scaling_metric_specification"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "predefined_metric_type": { @@ -134,9 +393,10 @@ func ResourcePolicy() *schema.Resource { }, }, "predefined_load_metric_specification": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"predictive_scaling_configuration.0.metric_specification.0.customized_load_metric_specification"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "predefined_metric_type": { @@ -542,7 +802,6 @@ func getPolicy(d *schema.ResourceData, meta interface{}) (*autoscaling.ScalingPo return resp.ScalingPolicies[idx], nil } } - // policy not found return nil, nil } @@ -637,10 +896,13 @@ func expandPredictiveScalingMetricSpecifications(metricSpecificationsSlice []int } metricSpecificationsFlat := metricSpecificationsSlice[0].(map[string]interface{}) metricSpecification := &autoscaling.PredictiveScalingMetricSpecification{ - PredefinedLoadMetricSpecification: expandPredefinedLoadMetricSpecification(metricSpecificationsFlat["predefined_load_metric_specification"].([]interface{})), - PredefinedMetricPairSpecification: expandPredefinedMetricPairSpecification(metricSpecificationsFlat["predefined_metric_pair_specification"].([]interface{})), - PredefinedScalingMetricSpecification: expandPredefinedScalingMetricSpecification(metricSpecificationsFlat["predefined_scaling_metric_specification"].([]interface{})), - TargetValue: aws.Float64(float64(metricSpecificationsFlat["target_value"].(int))), + PredefinedLoadMetricSpecification: expandPredefinedLoadMetricSpecification(metricSpecificationsFlat["predefined_load_metric_specification"].([]interface{})), + PredefinedMetricPairSpecification: expandPredefinedMetricPairSpecification(metricSpecificationsFlat["predefined_metric_pair_specification"].([]interface{})), + PredefinedScalingMetricSpecification: expandPredefinedScalingMetricSpecification(metricSpecificationsFlat["predefined_scaling_metric_specification"].([]interface{})), + CustomizedScalingMetricSpecification: expandCustomizedScalingMetricSpecification(metricSpecificationsFlat["customized_scaling_metric_specification"].([]interface{})), + CustomizedLoadMetricSpecification: expandCustomizedLoadMetricSpecification(metricSpecificationsFlat["customized_load_metric_specification"].([]interface{})), + CustomizedCapacityMetricSpecification: expandCustomizedCapacityMetricSpecification(metricSpecificationsFlat["customized_capacity_metric_specification"].([]interface{})), + TargetValue: aws.Float64(float64(metricSpecificationsFlat["target_value"].(int))), } return []*autoscaling.PredictiveScalingMetricSpecification{metricSpecification} } @@ -681,6 +943,93 @@ func expandPredefinedScalingMetricSpecification(predefinedScalingMetricSpecifica return predefinedScalingMetricSpecification } +func expandCustomizedScalingMetricSpecification(customizedScalingMetricSpecificationSlice []interface{}) *autoscaling.PredictiveScalingCustomizedScalingMetric { + if customizedScalingMetricSpecificationSlice == nil || len(customizedScalingMetricSpecificationSlice) < 1 { + return nil + } + customizedScalingMetricSpecificationFlat := customizedScalingMetricSpecificationSlice[0].(map[string]interface{}) + customizedScalingMetricSpecification := &autoscaling.PredictiveScalingCustomizedScalingMetric{ + MetricDataQueries: expandMetricDataQueries(customizedScalingMetricSpecificationFlat["metric_data_queries"].([]interface{})), + } + return customizedScalingMetricSpecification +} + +func expandCustomizedLoadMetricSpecification(CustomizedLoadMetricSpecificationSlice []interface{}) *autoscaling.PredictiveScalingCustomizedLoadMetric { + if CustomizedLoadMetricSpecificationSlice == nil || len(CustomizedLoadMetricSpecificationSlice) < 1 { + return nil + } + CustomizedLoadMetricSpecificationSliceFlat := CustomizedLoadMetricSpecificationSlice[0].(map[string]interface{}) + customizedLoadMetricSpecification := &autoscaling.PredictiveScalingCustomizedLoadMetric{ + MetricDataQueries: expandMetricDataQueries(CustomizedLoadMetricSpecificationSliceFlat["metric_data_queries"].([]interface{})), + } + return customizedLoadMetricSpecification +} + +func expandCustomizedCapacityMetricSpecification(CustomizedCapacityMetricSlice []interface{}) *autoscaling.PredictiveScalingCustomizedCapacityMetric { + if CustomizedCapacityMetricSlice == nil || len(CustomizedCapacityMetricSlice) < 1 { + return nil + } + customizedCapacityMetricSliceFlat := CustomizedCapacityMetricSlice[0].(map[string]interface{}) + customizedCapacityMetricSpecification := &autoscaling.PredictiveScalingCustomizedCapacityMetric{ + MetricDataQueries: expandMetricDataQueries(customizedCapacityMetricSliceFlat["metric_data_queries"].([]interface{})), + } + return customizedCapacityMetricSpecification +} + +func expandMetricDataQueries(metricDataQuerySlices []interface{}) []*autoscaling.MetricDataQuery { + if metricDataQuerySlices == nil || len(metricDataQuerySlices) < 1 { + return nil + } + metricDataQueries := make([]*autoscaling.MetricDataQuery, len(metricDataQuerySlices)) + + for i := range metricDataQueries { + metricDataQueryFlat := metricDataQuerySlices[i].(map[string]interface{}) + metricDataQuery := &autoscaling.MetricDataQuery{ + Id: aws.String(metricDataQueryFlat["id"].(string)), + } + if val, ok := metricDataQueryFlat["metric_stat"]; ok && len(val.([]interface{})) > 0 { + metricStatSpec := val.([]interface{})[0].(map[string]interface{}) + metricSpec := metricStatSpec["metric"].([]interface{})[0].(map[string]interface{}) + metric := &autoscaling.Metric{ + MetricName: aws.String(metricSpec["metric_name"].(string)), + Namespace: aws.String(metricSpec["namespace"].(string)), + } + if v, ok := metricSpec["dimensions"]; ok { + dims := v.([]interface{}) + dimList := make([]*autoscaling.MetricDimension, len(dims)) + for i := range dimList { + dim := dims[i].(map[string]interface{}) + md := &autoscaling.MetricDimension{ + Name: aws.String(dim["name"].(string)), + Value: aws.String(dim["value"].(string)), + } + dimList[i] = md + } + metric.Dimensions = dimList + } + metricStat := &autoscaling.MetricStat{ + Metric: metric, + Stat: aws.String(metricStatSpec["stat"].(string)), + } + if v, ok := metricStatSpec["unit"]; ok && len(v.(string)) > 0 { + metricStat.Unit = aws.String(v.(string)) + } + metricDataQuery.MetricStat = metricStat + } + if val, ok := metricDataQueryFlat["expression"]; ok && val.(string) != "" { + metricDataQuery.Expression = aws.String(val.(string)) + } + if val, ok := metricDataQueryFlat["label"]; ok && val.(string) != "" { + metricDataQuery.Label = aws.String(val.(string)) + } + if val, ok := metricDataQueryFlat["return_data"]; ok { + metricDataQuery.ReturnData = aws.Bool(val.(bool)) + } + metricDataQueries[i] = metricDataQuery + } + return metricDataQueries +} + func flattenTargetTrackingConfiguration(config *autoscaling.TargetTrackingConfiguration) []interface{} { if config == nil { return []interface{}{} @@ -761,6 +1110,15 @@ func flattenPredictiveScalingMetricSpecifications(metricSpecification []*autosca if metricSpecification[0].PredefinedScalingMetricSpecification != nil { metricSpecificationFlat["predefined_scaling_metric_specification"] = flattenPredefinedScalingMetricSpecification(metricSpecification[0].PredefinedScalingMetricSpecification) } + if metricSpecification[0].CustomizedScalingMetricSpecification != nil { + metricSpecificationFlat["customized_scaling_metric_specification"] = flattenCustomizedScalingMetricSpecification(metricSpecification[0].CustomizedScalingMetricSpecification) + } + if metricSpecification[0].CustomizedLoadMetricSpecification != nil { + metricSpecificationFlat["customized_load_metric_specification"] = flattenCustomizedLoadMetricSpecification(metricSpecification[0].CustomizedLoadMetricSpecification) + } + if metricSpecification[0].CustomizedCapacityMetricSpecification != nil { + metricSpecificationFlat["customized_capacity_metric_specification"] = flattenCustomizedCapacityMetricSpecification(metricSpecification[0].CustomizedCapacityMetricSpecification) + } return []map[string]interface{}{metricSpecificationFlat} } @@ -793,3 +1151,81 @@ func flattenPredefinedMetricPairSpecification(predefinedMetricPairSpecification predefinedMetricPairSpecificationFlat["resource_label"] = aws.StringValue(predefinedMetricPairSpecification.ResourceLabel) return []map[string]interface{}{predefinedMetricPairSpecificationFlat} } + +func flattenCustomizedScalingMetricSpecification(customizedScalingMetricSpecification *autoscaling.PredictiveScalingCustomizedScalingMetric) []map[string]interface{} { + customizedScalingMetricSpecificationFlat := map[string]interface{}{} + if customizedScalingMetricSpecification == nil { + return []map[string]interface{}{customizedScalingMetricSpecificationFlat} + } + customizedScalingMetricSpecificationFlat["metric_data_queries"] = flattenMetricDataQueries(customizedScalingMetricSpecification.MetricDataQueries) + return []map[string]interface{}{customizedScalingMetricSpecificationFlat} +} + +func flattenCustomizedLoadMetricSpecification(customizedLoadMetricSpecification *autoscaling.PredictiveScalingCustomizedLoadMetric) []map[string]interface{} { + customizedLoadMetricSpecificationFlat := map[string]interface{}{} + if customizedLoadMetricSpecification == nil { + return []map[string]interface{}{customizedLoadMetricSpecificationFlat} + } + customizedLoadMetricSpecificationFlat["metric_data_queries"] = flattenMetricDataQueries(customizedLoadMetricSpecification.MetricDataQueries) + return []map[string]interface{}{customizedLoadMetricSpecificationFlat} +} + +func flattenCustomizedCapacityMetricSpecification(customizedCapacityMetricSpecification *autoscaling.PredictiveScalingCustomizedCapacityMetric) []map[string]interface{} { + customizedCapacityMetricSpecificationFlat := map[string]interface{}{} + if customizedCapacityMetricSpecification == nil { + return []map[string]interface{}{customizedCapacityMetricSpecificationFlat} + } + customizedCapacityMetricSpecificationFlat["metric_data_queries"] = flattenMetricDataQueries(customizedCapacityMetricSpecification.MetricDataQueries) + + return []map[string]interface{}{customizedCapacityMetricSpecificationFlat} +} + +func flattenMetricDataQueries(metricDataQueries []*autoscaling.MetricDataQuery) []interface{} { + metricDataQueriesFlat := map[string]interface{}{} + if metricDataQueriesFlat == nil { + return []interface{}{} + } + + metricDataQueriesSpec := make([]interface{}, len(metricDataQueries)) + for i := range metricDataQueriesSpec { + metricDataQuery := map[string]interface{}{} + rawMetricDataQuery := metricDataQueries[i] + metricDataQuery["id"] = aws.StringValue(rawMetricDataQuery.Id) + if rawMetricDataQuery.Expression != nil { + metricDataQuery["expression"] = aws.StringValue(rawMetricDataQuery.Expression) + } + if rawMetricDataQuery.MetricStat != nil { + metricStatSpec := map[string]interface{}{} + rawMetricStat := rawMetricDataQuery.MetricStat + metricStatSpec["stat"] = aws.StringValue(rawMetricStat.Stat) + if rawMetricStat.Unit != nil { + metricStatSpec["unit"] = aws.StringValue(rawMetricStat.Unit) + } + rawMetric := rawMetricStat.Metric + metricSpec := map[string]interface{}{} + metricSpec["metric_name"] = aws.StringValue(rawMetric.MetricName) + metricSpec["namespace"] = aws.StringValue(rawMetric.Namespace) + if rawMetric.Dimensions != nil { + dimSpec := make([]interface{}, len(rawMetric.Dimensions)) + for i := range dimSpec { + dim := map[string]interface{}{} + rawDim := rawMetric.Dimensions[i] + dim["name"] = aws.StringValue(rawDim.Name) + dim["value"] = aws.StringValue(rawDim.Value) + dimSpec[i] = dim + } + metricSpec["dimensions"] = dimSpec + } + metricStatSpec["metric"] = []map[string]interface{}{metricSpec} + metricDataQuery["metric_stat"] = []map[string]interface{}{metricStatSpec} + } + if rawMetricDataQuery.Label != nil { + metricDataQuery["label"] = aws.StringValue(rawMetricDataQuery.Label) + } + if rawMetricDataQuery.ReturnData != nil { + metricDataQuery["return_data"] = aws.BoolValue(rawMetricDataQuery.ReturnData) + } + metricDataQueriesSpec[i] = metricDataQuery + } + return metricDataQueriesSpec +} diff --git a/internal/service/autoscaling/policy_test.go b/internal/service/autoscaling/policy_test.go index 98e70297401..273d83b5020 100644 --- a/internal/service/autoscaling/policy_test.go +++ b/internal/service/autoscaling/policy_test.go @@ -105,7 +105,7 @@ func TestAccAutoScalingPolicy_basic(t *testing.T) { }) } -func TestAccAutoScalingPolicy_predictiveScaling(t *testing.T) { +func TestAccAutoScalingPolicy_predictiveScaling_Predefined(t *testing.T) { var policy autoscaling.ScalingPolicy resourceSimpleName := "aws_autoscaling_policy.test" @@ -119,7 +119,7 @@ func TestAccAutoScalingPolicy_predictiveScaling(t *testing.T) { CheckDestroy: testAccCheckPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccPolicyConfig_predictiveScaling(name), + Config: testAccPolicyConfig_predictiveScaling_Predefined(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceSimpleName, &policy), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.mode", "ForecastAndScale"), @@ -143,6 +143,61 @@ func TestAccAutoScalingPolicy_predictiveScaling(t *testing.T) { }) } +func TestAccAutoScalingPolicy_predictiveScaling_Custom(t *testing.T) { + var policy autoscaling.ScalingPolicy + + resourceSimpleName := "aws_autoscaling_policy.test" + + name := sdkacctest.RandomWithPrefix("terraform-testacc-asp1") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, autoscaling.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccPolicyConfig_predictiveScaling_Custom(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckScalingPolicyExists(resourceSimpleName, &policy), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.mode", "ForecastOnly"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.scheduling_buffer_time", "10"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.max_capacity_breach_behavior", "IncreaseMaxCapacity"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.max_capacity_buffer", "0"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.target_value", "32"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_scaling_metric_specification.0.metric_data_queries.0.id", "scaling_metric"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_scaling_metric_specification.0.metric_data_queries.0.expression", "TIME_SERIES(1)"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_load_metric_specification.0.metric_data_queries.0.id", "load_metric"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_load_metric_specification.0.metric_data_queries.0.label", "fake_load_metric"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_load_metric_specification.0.metric_data_queries.0.expression", "TIME_SERIES(100)"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.0.id", "weighted_sum"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.0.metric_stat.0.metric.0.namespace", "namespace_foo"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.0.metric_stat.0.metric.0.metric_name", "metric_name_foo"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.0.metric_stat.0.stat", "Sum"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.0.return_data", "false"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.id", "capacity_sum"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.namespace", "namespace_bar"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.metric_name", "metric_name_bar"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.dimensions.0.name", "foo"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.dimensions.0.value", "bar"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.unit", "Percent"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.stat", "Sum"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.return_data", "false"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.2.id", "capacity"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.2.expression", "weighted_sum / capacity_sum"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.2.return_data", "true"), + ), + }, + { + ResourceName: resourceSimpleName, + ImportState: true, + ImportStateIdFunc: testAccPolicyImportStateIdFunc(resourceSimpleName), + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAutoScalingPolicy_predictiveScalingRemoved(t *testing.T) { var policy autoscaling.ScalingPolicy @@ -157,7 +212,7 @@ func TestAccAutoScalingPolicy_predictiveScalingRemoved(t *testing.T) { CheckDestroy: testAccCheckPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccPolicyConfig_predictiveScaling(name), + Config: testAccPolicyConfig_predictiveScaling_Predefined(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceSimpleName, &policy), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.#", "1"), @@ -194,7 +249,7 @@ func TestAccAutoScalingPolicy_predictiveScalingUpdated(t *testing.T) { CheckDestroy: testAccCheckPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccPolicyConfig_predictiveScaling(name), + Config: testAccPolicyConfig_predictiveScaling_Predefined(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceSimpleName, &policy), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.mode", "ForecastAndScale"), @@ -563,7 +618,7 @@ resource "aws_autoscaling_policy" "foobar_target_tracking" { `, name, name, name)) } -func testAccPolicyConfig_predictiveScaling(name string) string { +func testAccPolicyConfig_predictiveScaling_Predefined(name string) string { return acctest.ConfigCompose(testAccPolicyConfig_base(name), fmt.Sprintf(` resource "aws_autoscaling_policy" "test" { name = "%[1]s-policy_predictive" @@ -590,6 +645,72 @@ resource "aws_autoscaling_policy" "test" { `, name)) } +func testAccPolicyConfig_predictiveScaling_Custom(name string) string { + return acctest.ConfigCompose(testAccPolicyConfig_base(name), fmt.Sprintf(` +resource "aws_autoscaling_policy" "test" { + name = "%[1]s-policy_predictive" + policy_type = "PredictiveScaling" + autoscaling_group_name = aws_autoscaling_group.test.name + predictive_scaling_configuration { + metric_specification { + target_value = 32 + customized_scaling_metric_specification { + metric_data_queries { + id = "scaling_metric" + expression = "TIME_SERIES(1)" + } + } + customized_load_metric_specification { + metric_data_queries { + id = "load_metric" + label = "fake_load_metric" + expression = "TIME_SERIES(100)" + } + } + customized_capacity_metric_specification { + metric_data_queries { + id = "weighted_sum" + metric_stat { + metric { + namespace = "namespace_foo" + metric_name = "metric_name_foo" + } + stat = "Sum" + } + return_data = false + } + metric_data_queries { + id = "capacity_sum" + metric_stat { + metric { + namespace = "namespace_bar" + metric_name = "metric_name_bar" + dimensions { + name = "foo" + value = "bar" + } + } + unit = "Percent" + stat = "Sum" + } + return_data = false + } + metric_data_queries { + id = "capacity" + expression = "weighted_sum / capacity_sum" + return_data = true + } + } + } + mode = "ForecastOnly" + scheduling_buffer_time = 10 + max_capacity_breach_behavior = "IncreaseMaxCapacity" + max_capacity_buffer = 0 + } +} +`, name)) +} + func testAccPolicyConfig_predictiveScalingRemoved(name string) string { return acctest.ConfigCompose(testAccPolicyConfig_base(name), fmt.Sprintf(` resource "aws_autoscaling_policy" "test" { From 41bb67cf40784fc428ffe4b0c776f1ea3af7f887 Mon Sep 17 00:00:00 2001 From: Yupeng Gou Date: Tue, 18 Jan 2022 18:44:12 -0800 Subject: [PATCH 2/9] Add change log and website doc --- .changelog/22451.txt | 2 + .../docs/r/autoscaling_policy.html.markdown | 90 ++++++++++++++++++- 2 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 .changelog/22451.txt diff --git a/.changelog/22451.txt b/.changelog/22451.txt new file mode 100644 index 00000000000..baad7816337 --- /dev/null +++ b/.changelog/22451.txt @@ -0,0 +1,2 @@ +```release-note:enhancement +resource/aws_autoscaling_policy: Add customized metric specification in `predictive_scaling_configuration` argument diff --git a/website/docs/r/autoscaling_policy.html.markdown b/website/docs/r/autoscaling_policy.html.markdown index d4098a50075..61000379ab1 100644 --- a/website/docs/r/autoscaling_policy.html.markdown +++ b/website/docs/r/autoscaling_policy.html.markdown @@ -159,9 +159,12 @@ The following arguments are supported: The following arguments are supported: -* `predefined_load_metric_specification` - (Optional) The load metric specification. +* `predefined_load_metric_specification` - (Optional) The predefined load metric specification. * `predefined_metric_pair_specification` - (Optional) The metric pair specification from which Amazon EC2 Auto Scaling determines the appropriate scaling metric and load metric to use. -* `predefined_scaling_metric_specification` - (Optional) The scaling metric specification. +* `predefined_scaling_metric_specification` - (Optional) The predefined scaling metric specification. +* `customized_scaling_metric_specification` - (Optional) The customized scaling metric specification. +* `customized_load_metric_specification` - (Optional) The customized load metric specification. +* `customized_capacity_metric_specification` - (Optional) The customized capacity metric specification. The field is only valid when you use `customized_load_metric_specification` ##### predefined_load_metric_specification @@ -184,6 +187,89 @@ The following arguments are supported: * `predefined_metric_type` - (Required) Describes a scaling metric for a predictive scaling policy. Valid values are `ASGAverageCPUUtilization`, `ASGAverageNetworkIn`, `ASGAverageNetworkOut`, or `ALBRequestCountPerTarget`. * `resource_label` - (Required) A label that uniquely identifies a specific Application Load Balancer target group from which to determine the request count served by your Auto Scaling group. +##### customized_scaling_metric_specification +The following arguments are supported: + +* `metric_data_queries` - (Required) A list of up to 10 structure that defines custom scaling metric in predictive scaling policy + +##### customized_load_metric_specification +The following arguments are supported: +* `metric_data_queries` - (Required) A list of up to 10 structure that defines custom load metric in predictive scaling policy + +##### customized_capacity_metric_specification +The following arguments are supported: +* `metric_data_queries` - (Required) A list of up to 10 structure that defines custom capacity metric in predictive scaling policy + +##### metric_data_queries +The following arguments are supported: +* `id` - (Required) A short name for the metric used in predictive scaling policy. +* `expression` - (Optional) The math expression used on the returned metric. You must specify either `expression` or `metric_stat`, but not both. +* `metric_stat` - (Optional) A structure that defines CloudWatch metric to be used in predictive scaling policy. You must specify either `expression` or `metric_stat`, but not both. +* `label` - (Optional) A human-readable label for this metric or expression. +* `return_data` - (Optional) A boolean that indicates whether to return the timestamps and raw data values of this metric, the default it true + +##### metric_stat +The following arguments are supported: +* `metric` - (Required) A structure that defines the CloudWatch metric to return, including the metric name, namespace, and dimensions. +* `stat` - (Required) The statistic of the metrics to return. +* `unit` - (Optional) The unit of the metrics to return. + +##### metric +* `metric_name` - (Required) The name of the metric. +* `namespace` - (Required) The namespace of the metric. +* `dimensions` - (Optional) The dimensions of the metric. + +### Example predictive scaling policy using custom metric + +```terraform +resource "aws_autoscaling_policy" "example" { + # ... other configuration ... + + predictive_scaling_configuration { + metric_specification { + target_value = 10 + customized_scaling_metric_specification { + metric_data_queries { + id = "scaling" + metric_stat { + metric { + metric_name = "CPUUtilization" + namespace = "AWS/EC2" + dimensions { + name = "AutoScalingGroupName" + value = "ASG-myapp" + } + } + stat = "Average" + } + } + } + customized_load_metric_specification { + metric_data_queries { + id = "load_sum" + expression = "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" ASG-myapp', 'Sum', 3600))" + } + } + customized_capacity_metric_specification { + metric_data_queries { + id = "capacity_sum" + expression = "SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName=\"GroupInServiceIntances\" ASG-myapp', 'Average', 300))" + return_data = false + } + metric_data_queries { + id = "load_sum" + expression = "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" ASG-myapp', 'Sum', 300))" + return_data = false + } + metric_data_queries { + id = "weighted_average" + expression = "load_sum / capacity_sum" + } + } + } + } +} +``` ## Attributes Reference In addition to all arguments above, the following attributes are exported: From 1a300d56c98045e3a751c83b9ca39c0c15750c54 Mon Sep 17 00:00:00 2001 From: Yupeng Gou Date: Thu, 27 Jan 2022 00:21:18 -0800 Subject: [PATCH 3/9] Add attribute validation, refactor namings --- internal/service/autoscaling/policy.go | 68 ++++---- internal/service/autoscaling/policy_test.go | 153 +++++++++--------- .../docs/r/autoscaling_policy.html.markdown | 108 ++++++------- 3 files changed, 172 insertions(+), 157 deletions(-) diff --git a/internal/service/autoscaling/policy.go b/internal/service/autoscaling/policy.go index da78a27fcfc..9a1db2d16ea 100644 --- a/internal/service/autoscaling/policy.go +++ b/internal/service/autoscaling/policy.go @@ -101,12 +101,14 @@ func ResourcePolicy() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, "expression": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1023), }, "metric_stat": { Type: schema.TypeList, @@ -129,7 +131,7 @@ func ResourcePolicy() *schema.Resource { Required: true, }, "dimensions": { - Type: schema.TypeList, + Type: schema.TypeSet, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -148,8 +150,9 @@ func ResourcePolicy() *schema.Resource { }, }, "stat": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 100), }, "unit": { Type: schema.TypeString, @@ -159,8 +162,9 @@ func ResourcePolicy() *schema.Resource { }, }, "label": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 2047), }, "return_data": { Type: schema.TypeBool, @@ -187,12 +191,14 @@ func ResourcePolicy() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, "expression": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1023), }, "metric_stat": { Type: schema.TypeList, @@ -215,7 +221,7 @@ func ResourcePolicy() *schema.Resource { Required: true, }, "dimensions": { - Type: schema.TypeList, + Type: schema.TypeSet, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -234,8 +240,9 @@ func ResourcePolicy() *schema.Resource { }, }, "stat": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 100), }, "unit": { Type: schema.TypeString, @@ -245,8 +252,9 @@ func ResourcePolicy() *schema.Resource { }, }, "label": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 2047), }, "return_data": { Type: schema.TypeBool, @@ -273,12 +281,14 @@ func ResourcePolicy() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, "expression": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1023), }, "metric_stat": { Type: schema.TypeList, @@ -301,7 +311,7 @@ func ResourcePolicy() *schema.Resource { Required: true, }, "dimensions": { - Type: schema.TypeList, + Type: schema.TypeSet, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -320,8 +330,9 @@ func ResourcePolicy() *schema.Resource { }, }, "stat": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 100), }, "unit": { Type: schema.TypeString, @@ -331,8 +342,9 @@ func ResourcePolicy() *schema.Resource { }, }, "label": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 2047), }, "return_data": { Type: schema.TypeBool, @@ -995,7 +1007,7 @@ func expandMetricDataQueries(metricDataQuerySlices []interface{}) []*autoscaling Namespace: aws.String(metricSpec["namespace"].(string)), } if v, ok := metricSpec["dimensions"]; ok { - dims := v.([]interface{}) + dims := v.(*schema.Set).List() dimList := make([]*autoscaling.MetricDimension, len(dims)) for i := range dimList { dim := dims[i].(map[string]interface{}) diff --git a/internal/service/autoscaling/policy_test.go b/internal/service/autoscaling/policy_test.go index 273d83b5020..6de22007c06 100644 --- a/internal/service/autoscaling/policy_test.go +++ b/internal/service/autoscaling/policy_test.go @@ -31,7 +31,7 @@ func TestAccAutoScalingPolicy_basic(t *testing.T) { CheckDestroy: testAccCheckPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccPolicyConfig_basic(name), + Config: testAccPolicyConfigBasic(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceSimpleName, &policy), resource.TestCheckResourceAttr(resourceSimpleName, "adjustment_type", "ChangeInCapacity"), @@ -105,7 +105,7 @@ func TestAccAutoScalingPolicy_basic(t *testing.T) { }) } -func TestAccAutoScalingPolicy_predictiveScaling_Predefined(t *testing.T) { +func TestAccAutoScalingPolicy_predictiveScalingPredefined(t *testing.T) { var policy autoscaling.ScalingPolicy resourceSimpleName := "aws_autoscaling_policy.test" @@ -119,7 +119,7 @@ func TestAccAutoScalingPolicy_predictiveScaling_Predefined(t *testing.T) { CheckDestroy: testAccCheckPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccPolicyConfig_predictiveScaling_Predefined(name), + Config: testAccPolicyConfigPredictiveScalingPredefined(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceSimpleName, &policy), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.mode", "ForecastAndScale"), @@ -143,7 +143,7 @@ func TestAccAutoScalingPolicy_predictiveScaling_Predefined(t *testing.T) { }) } -func TestAccAutoScalingPolicy_predictiveScaling_Custom(t *testing.T) { +func TestAccAutoScalingPolicy_predictiveScalingCustom(t *testing.T) { var policy autoscaling.ScalingPolicy resourceSimpleName := "aws_autoscaling_policy.test" @@ -157,7 +157,7 @@ func TestAccAutoScalingPolicy_predictiveScaling_Custom(t *testing.T) { CheckDestroy: testAccCheckPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccPolicyConfig_predictiveScaling_Custom(name), + Config: testAccPolicyConfigPredictiveScalingCustom(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceSimpleName, &policy), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.mode", "ForecastOnly"), @@ -178,8 +178,7 @@ func TestAccAutoScalingPolicy_predictiveScaling_Custom(t *testing.T) { resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.id", "capacity_sum"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.namespace", "namespace_bar"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.metric_name", "metric_name_bar"), - resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.dimensions.0.name", "foo"), - resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.dimensions.0.value", "bar"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.dimensions.#", "2"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.unit", "Percent"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.stat", "Sum"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.return_data", "false"), @@ -212,14 +211,14 @@ func TestAccAutoScalingPolicy_predictiveScalingRemoved(t *testing.T) { CheckDestroy: testAccCheckPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccPolicyConfig_predictiveScaling_Predefined(name), + Config: testAccPolicyConfigPredictiveScalingPredefined(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceSimpleName, &policy), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.#", "1"), ), }, { - Config: testAccPolicyConfig_predictiveScalingRemoved(name), + Config: testAccPolicyConfigPredictiveScalingRemoved(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceSimpleName, &policy), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.#", "0"), @@ -249,7 +248,7 @@ func TestAccAutoScalingPolicy_predictiveScalingUpdated(t *testing.T) { CheckDestroy: testAccCheckPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccPolicyConfig_predictiveScaling_Predefined(name), + Config: testAccPolicyConfigPredictiveScalingPredefined(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceSimpleName, &policy), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.mode", "ForecastAndScale"), @@ -264,7 +263,7 @@ func TestAccAutoScalingPolicy_predictiveScalingUpdated(t *testing.T) { ), }, { - Config: testAccautoScalingpolicyconfigPredictivescalingUpdated(name), + Config: testAccAutoScalingPolicyConfigPredictiveScalingUpdated(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceSimpleName, &policy), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.mode", "ForecastOnly"), @@ -302,7 +301,7 @@ func TestAccAutoScalingPolicy_disappears(t *testing.T) { CheckDestroy: testAccCheckPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccPolicyConfig_basic(name), + Config: testAccPolicyConfigBasic(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceName, &policy), testAccCheckScalingPolicyDisappears(&policy), @@ -364,7 +363,7 @@ func TestAccAutoScalingPolicy_simpleScalingStepAdjustment(t *testing.T) { CheckDestroy: testAccCheckPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccPolicyConfig_SimpleScalingStepAdjustment(name), + Config: testAccPolicyConfigSimpleScalingStepAdjustment(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceName, &policy), resource.TestCheckResourceAttr(resourceName, "adjustment_type", "ExactCapacity"), @@ -393,7 +392,7 @@ func TestAccAutoScalingPolicy_TargetTrack_predefined(t *testing.T) { CheckDestroy: testAccCheckPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccPolicyConfig_TargetTracking_Predefined(name), + Config: testAccPolicyConfigTargetTrackingPredefined(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists("aws_autoscaling_policy.test", &policy), ), @@ -420,7 +419,7 @@ func TestAccAutoScalingPolicy_TargetTrack_custom(t *testing.T) { CheckDestroy: testAccCheckPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccPolicyConfig_TargetTracking_Custom(name), + Config: testAccPolicyConfigTargetTrackingCustom(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists("aws_autoscaling_policy.test", &policy), ), @@ -449,7 +448,7 @@ func TestAccAutoScalingPolicy_zeroValue(t *testing.T) { CheckDestroy: testAccCheckPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccPolicyConfig_zerovalue(sdkacctest.RandString(5)), + Config: testAccPolicyConfigZeroValue(sdkacctest.RandString(5)), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceSimpleName, &simplepolicy), testAccCheckScalingPolicyExists(resourceStepName, &steppolicy), @@ -538,7 +537,7 @@ func testAccPolicyImportStateIdFunc(resourceName string) resource.ImportStateIdF } } -func testAccPolicyConfig_base(name string) string { +func testAccPolicyConfigBase(name string) string { return fmt.Sprintf(` data "aws_ami" "amzn" { most_recent = true @@ -576,8 +575,8 @@ resource "aws_autoscaling_group" "test" { `, name, name) } -func testAccPolicyConfig_basic(name string) string { - return acctest.ConfigCompose(testAccPolicyConfig_base(name), fmt.Sprintf(` +func testAccPolicyConfigBasic(name string) string { + return acctest.ConfigCompose(testAccPolicyConfigBase(name), fmt.Sprintf(` resource "aws_autoscaling_policy" "foobar_simple" { name = "%s-foobar_simple" adjustment_type = "ChangeInCapacity" @@ -618,8 +617,8 @@ resource "aws_autoscaling_policy" "foobar_target_tracking" { `, name, name, name)) } -func testAccPolicyConfig_predictiveScaling_Predefined(name string) string { - return acctest.ConfigCompose(testAccPolicyConfig_base(name), fmt.Sprintf(` +func testAccPolicyConfigPredictiveScalingPredefined(name string) string { + return acctest.ConfigCompose(testAccPolicyConfigBase(name), fmt.Sprintf(` resource "aws_autoscaling_policy" "test" { name = "%[1]s-policy_predictive" policy_type = "PredictiveScaling" @@ -645,8 +644,8 @@ resource "aws_autoscaling_policy" "test" { `, name)) } -func testAccPolicyConfig_predictiveScaling_Custom(name string) string { - return acctest.ConfigCompose(testAccPolicyConfig_base(name), fmt.Sprintf(` +func testAccPolicyConfigPredictiveScalingCustom(name string) string { + return acctest.ConfigCompose(testAccPolicyConfigBase(name), fmt.Sprintf(` resource "aws_autoscaling_policy" "test" { name = "%[1]s-policy_predictive" policy_type = "PredictiveScaling" @@ -656,50 +655,54 @@ resource "aws_autoscaling_policy" "test" { target_value = 32 customized_scaling_metric_specification { metric_data_queries { - id = "scaling_metric" - expression = "TIME_SERIES(1)" - } + id = "scaling_metric" + expression = "TIME_SERIES(1)" + } } customized_load_metric_specification { metric_data_queries { - id = "load_metric" - label = "fake_load_metric" - expression = "TIME_SERIES(100)" - } + id = "load_metric" + label = "fake_load_metric" + expression = "TIME_SERIES(100)" + } } - customized_capacity_metric_specification { + customized_capacity_metric_specification { metric_data_queries { - id = "weighted_sum" - metric_stat { - metric { - namespace = "namespace_foo" - metric_name = "metric_name_foo" - } - stat = "Sum" - } - return_data = false - } - metric_data_queries { - id = "capacity_sum" - metric_stat { - metric { - namespace = "namespace_bar" - metric_name = "metric_name_bar" - dimensions { - name = "foo" - value = "bar" - } - } - unit = "Percent" - stat = "Sum" - } - return_data = false - } - metric_data_queries { - id = "capacity" - expression = "weighted_sum / capacity_sum" - return_data = true - } + id = "weighted_sum" + metric_stat { + metric { + namespace = "namespace_foo" + metric_name = "metric_name_foo" + } + stat = "Sum" + } + return_data = false + } + metric_data_queries { + id = "capacity_sum" + metric_stat { + metric { + namespace = "namespace_bar" + metric_name = "metric_name_bar" + dimensions { + name = "foo" + value = "bar" + } + dimensions { + name = "bar" + value = "foo" + } + } + unit = "Percent" + stat = "Sum" + } + return_data = false + } + metric_data_queries { + id = "capacity" + expression = "weighted_sum / capacity_sum" + return_data = true + } } } mode = "ForecastOnly" @@ -711,8 +714,8 @@ resource "aws_autoscaling_policy" "test" { `, name)) } -func testAccPolicyConfig_predictiveScalingRemoved(name string) string { - return acctest.ConfigCompose(testAccPolicyConfig_base(name), fmt.Sprintf(` +func testAccPolicyConfigPredictiveScalingRemoved(name string) string { + return acctest.ConfigCompose(testAccPolicyConfigBase(name), fmt.Sprintf(` resource "aws_autoscaling_policy" "test" { name = "%[1]s-foobar_simple" adjustment_type = "ChangeInCapacity" @@ -724,8 +727,8 @@ resource "aws_autoscaling_policy" "test" { `, name)) } -func testAccautoScalingpolicyconfigPredictivescalingUpdated(name string) string { - return testAccPolicyConfig_base(name) + fmt.Sprintf(` +func testAccAutoScalingPolicyConfigPredictiveScalingUpdated(name string) string { + return testAccPolicyConfigBase(name) + fmt.Sprintf(` resource "aws_autoscaling_policy" "test" { name = "%[1]s-policy_predictive" policy_type = "PredictiveScaling" @@ -750,7 +753,7 @@ resource "aws_autoscaling_policy" "test" { } func testAccPolicyConfig_basicUpdate(name string) string { - return testAccPolicyConfig_base(name) + fmt.Sprintf(` + return testAccPolicyConfigBase(name) + fmt.Sprintf(` resource "aws_autoscaling_policy" "foobar_simple" { name = "%s-foobar_simple" adjustment_type = "ChangeInCapacity" @@ -798,8 +801,8 @@ resource "aws_autoscaling_policy" "foobar_target_tracking" { `, name, name, name) } -func testAccPolicyConfig_SimpleScalingStepAdjustment(name string) string { - return testAccPolicyConfig_base(name) + fmt.Sprintf(` +func testAccPolicyConfigSimpleScalingStepAdjustment(name string) string { + return testAccPolicyConfigBase(name) + fmt.Sprintf(` resource "aws_autoscaling_policy" "foobar_simple" { name = "%s-foobar_simple" adjustment_type = "ExactCapacity" @@ -811,8 +814,8 @@ resource "aws_autoscaling_policy" "foobar_simple" { `, name) } -func testAccPolicyConfig_TargetTracking_Predefined(name string) string { - return testAccPolicyConfig_base(name) + fmt.Sprintf(` +func testAccPolicyConfigTargetTrackingPredefined(name string) string { + return testAccPolicyConfigBase(name) + fmt.Sprintf(` resource "aws_autoscaling_policy" "test" { name = "%s-test" policy_type = "TargetTrackingScaling" @@ -829,8 +832,8 @@ resource "aws_autoscaling_policy" "test" { `, name) } -func testAccPolicyConfig_TargetTracking_Custom(name string) string { - return testAccPolicyConfig_base(name) + fmt.Sprintf(` +func testAccPolicyConfigTargetTrackingCustom(name string) string { + return testAccPolicyConfigBase(name) + fmt.Sprintf(` resource "aws_autoscaling_policy" "test" { name = "%s-test" policy_type = "TargetTrackingScaling" @@ -854,8 +857,8 @@ resource "aws_autoscaling_policy" "test" { `, name) } -func testAccPolicyConfig_zerovalue(name string) string { - return testAccPolicyConfig_base(name) + fmt.Sprintf(` +func testAccPolicyConfigZeroValue(name string) string { + return testAccPolicyConfigBase(name) + fmt.Sprintf(` resource "aws_autoscaling_policy" "foobar_simple" { name = "%s-foobar_simple" adjustment_type = "ExactCapacity" diff --git a/website/docs/r/autoscaling_policy.html.markdown b/website/docs/r/autoscaling_policy.html.markdown index 61000379ab1..bd14b5583bc 100644 --- a/website/docs/r/autoscaling_policy.html.markdown +++ b/website/docs/r/autoscaling_policy.html.markdown @@ -39,6 +39,57 @@ resource "aws_autoscaling_group" "bar" { } ``` +### Create predictive scaling policy using custom metrics +```terraform +resource "aws_autoscaling_policy" "example" { + autoscaling_group_name = "my-test-asg" + name = "foo" + policy_type = "PredictiveScaling" + predictive_scaling_configuration { + metric_specification { + target_value = 10 + customized_scaling_metric_specification { + metric_data_queries { + id = "scaling" + metric_stat { + metric { + metric_name = "CPUUtilization" + namespace = "AWS/EC2" + dimensions { + name = "AutoScalingGroupName" + value = "my-test-asg" + } + } + stat = "Average" + } + } + } + customized_load_metric_specification { + metric_data_queries { + id = "load_sum" + expression = "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 3600))" + } + } + customized_capacity_metric_specification { + metric_data_queries { + id = "capacity_sum" + expression = "SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName=\"GroupInServiceIntances\" my-test-asg', 'Average', 300))" + return_data = false + } + metric_data_queries { + id = "load_sum" + expression = "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 300))" + return_data = false + } + metric_data_queries { + id = "weighted_average" + expression = "load_sum / capacity_sum" + } + } + } + } +} +``` ## Argument Reference * `name` - (Required) The name of the policy. @@ -190,15 +241,15 @@ The following arguments are supported: ##### customized_scaling_metric_specification The following arguments are supported: -* `metric_data_queries` - (Required) A list of up to 10 structure that defines custom scaling metric in predictive scaling policy +* `metric_data_queries` - (Required) A list of up to 10 structures that defines custom scaling metric in predictive scaling policy ##### customized_load_metric_specification The following arguments are supported: -* `metric_data_queries` - (Required) A list of up to 10 structure that defines custom load metric in predictive scaling policy +* `metric_data_queries` - (Required) A list of up to 10 structures that defines custom load metric in predictive scaling policy ##### customized_capacity_metric_specification The following arguments are supported: -* `metric_data_queries` - (Required) A list of up to 10 structure that defines custom capacity metric in predictive scaling policy +* `metric_data_queries` - (Required) A list of up to 10 structures that defines custom capacity metric in predictive scaling policy ##### metric_data_queries The following arguments are supported: @@ -219,57 +270,6 @@ The following arguments are supported: * `namespace` - (Required) The namespace of the metric. * `dimensions` - (Optional) The dimensions of the metric. -### Example predictive scaling policy using custom metric - -```terraform -resource "aws_autoscaling_policy" "example" { - # ... other configuration ... - - predictive_scaling_configuration { - metric_specification { - target_value = 10 - customized_scaling_metric_specification { - metric_data_queries { - id = "scaling" - metric_stat { - metric { - metric_name = "CPUUtilization" - namespace = "AWS/EC2" - dimensions { - name = "AutoScalingGroupName" - value = "ASG-myapp" - } - } - stat = "Average" - } - } - } - customized_load_metric_specification { - metric_data_queries { - id = "load_sum" - expression = "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" ASG-myapp', 'Sum', 3600))" - } - } - customized_capacity_metric_specification { - metric_data_queries { - id = "capacity_sum" - expression = "SUM(SEARCH('{AWS/AutoScaling,AutoScalingGroupName} MetricName=\"GroupInServiceIntances\" ASG-myapp', 'Average', 300))" - return_data = false - } - metric_data_queries { - id = "load_sum" - expression = "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" ASG-myapp', 'Sum', 300))" - return_data = false - } - metric_data_queries { - id = "weighted_average" - expression = "load_sum / capacity_sum" - } - } - } - } -} -``` ## Attributes Reference In addition to all arguments above, the following attributes are exported: From 9d928571cb241cc7a95aadc79914f5465f6ce469 Mon Sep 17 00:00:00 2001 From: Yupeng Gou Date: Thu, 3 Feb 2022 01:52:19 -0800 Subject: [PATCH 4/9] Address comments to fix styling issues --- internal/service/autoscaling/policy.go | 99 ++++++++++--------- internal/service/autoscaling/policy_test.go | 48 ++++----- .../docs/r/autoscaling_policy.html.markdown | 30 +++--- 3 files changed, 92 insertions(+), 85 deletions(-) diff --git a/internal/service/autoscaling/policy.go b/internal/service/autoscaling/policy.go index 9a1db2d16ea..4417c3c7b24 100644 --- a/internal/service/autoscaling/policy.go +++ b/internal/service/autoscaling/policy.go @@ -87,11 +87,11 @@ func ResourcePolicy() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "customized_scaling_metric_specification": { + "customized_capacity_metric_specification": { Type: schema.TypeList, Optional: true, MaxItems: 1, - ConflictsWith: []string{"predictive_scaling_configuration.0.metric_specification.0.predefined_scaling_metric_specification"}, + ConflictsWith: []string{"predictive_scaling_configuration.0.metric_specification.0.predefined_load_metric_specification"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "metric_data_queries": { @@ -100,15 +100,20 @@ func ResourcePolicy() *schema.Resource { MaxItems: 10, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "expression": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1023), + }, "id": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringLenBetween(1, 255), }, - "expression": { + "label": { Type: schema.TypeString, Optional: true, - ValidateFunc: validation.StringLenBetween(1, 1023), + ValidateFunc: validation.StringLenBetween(1, 2047), }, "metric_stat": { Type: schema.TypeList, @@ -122,14 +127,6 @@ func ResourcePolicy() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "metric_name": { - Type: schema.TypeString, - Required: true, - }, - "namespace": { - Type: schema.TypeString, - Required: true, - }, "dimensions": { Type: schema.TypeSet, Optional: true, @@ -146,6 +143,14 @@ func ResourcePolicy() *schema.Resource { }, }, }, + "metric_name": { + Type: schema.TypeString, + Required: true, + }, + "namespace": { + Type: schema.TypeString, + Required: true, + }, }, }, }, @@ -161,11 +166,6 @@ func ResourcePolicy() *schema.Resource { }, }, }, - "label": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 2047), - }, "return_data": { Type: schema.TypeBool, Optional: true, @@ -190,15 +190,20 @@ func ResourcePolicy() *schema.Resource { MaxItems: 10, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "expression": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1023), + }, "id": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringLenBetween(1, 255), }, - "expression": { + "label": { Type: schema.TypeString, Optional: true, - ValidateFunc: validation.StringLenBetween(1, 1023), + ValidateFunc: validation.StringLenBetween(1, 2047), }, "metric_stat": { Type: schema.TypeList, @@ -212,14 +217,6 @@ func ResourcePolicy() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "metric_name": { - Type: schema.TypeString, - Required: true, - }, - "namespace": { - Type: schema.TypeString, - Required: true, - }, "dimensions": { Type: schema.TypeSet, Optional: true, @@ -236,6 +233,14 @@ func ResourcePolicy() *schema.Resource { }, }, }, + "metric_name": { + Type: schema.TypeString, + Required: true, + }, + "namespace": { + Type: schema.TypeString, + Required: true, + }, }, }, }, @@ -251,11 +256,6 @@ func ResourcePolicy() *schema.Resource { }, }, }, - "label": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 2047), - }, "return_data": { Type: schema.TypeBool, Optional: true, @@ -267,11 +267,11 @@ func ResourcePolicy() *schema.Resource { }, }, }, - "customized_capacity_metric_specification": { + "customized_scaling_metric_specification": { Type: schema.TypeList, Optional: true, MaxItems: 1, - ConflictsWith: []string{"predictive_scaling_configuration.0.metric_specification.0.predefined_load_metric_specification"}, + ConflictsWith: []string{"predictive_scaling_configuration.0.metric_specification.0.predefined_scaling_metric_specification"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "metric_data_queries": { @@ -280,15 +280,20 @@ func ResourcePolicy() *schema.Resource { MaxItems: 10, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "expression": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1023), + }, "id": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringLenBetween(1, 255), }, - "expression": { + "label": { Type: schema.TypeString, Optional: true, - ValidateFunc: validation.StringLenBetween(1, 1023), + ValidateFunc: validation.StringLenBetween(1, 2047), }, "metric_stat": { Type: schema.TypeList, @@ -302,14 +307,6 @@ func ResourcePolicy() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "metric_name": { - Type: schema.TypeString, - Required: true, - }, - "namespace": { - Type: schema.TypeString, - Required: true, - }, "dimensions": { Type: schema.TypeSet, Optional: true, @@ -326,6 +323,14 @@ func ResourcePolicy() *schema.Resource { }, }, }, + "metric_name": { + Type: schema.TypeString, + Required: true, + }, + "namespace": { + Type: schema.TypeString, + Required: true, + }, }, }, }, @@ -341,11 +346,6 @@ func ResourcePolicy() *schema.Resource { }, }, }, - "label": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 2047), - }, "return_data": { Type: schema.TypeBool, Optional: true, @@ -995,6 +995,7 @@ func expandMetricDataQueries(metricDataQuerySlices []interface{}) []*autoscaling metricDataQueries := make([]*autoscaling.MetricDataQuery, len(metricDataQuerySlices)) for i := range metricDataQueries { + metricDataQueryFlat := metricDataQuerySlices[i].(map[string]interface{}) metricDataQuery := &autoscaling.MetricDataQuery{ Id: aws.String(metricDataQueryFlat["id"].(string)), diff --git a/internal/service/autoscaling/policy_test.go b/internal/service/autoscaling/policy_test.go index 6de22007c06..7327d323b76 100644 --- a/internal/service/autoscaling/policy_test.go +++ b/internal/service/autoscaling/policy_test.go @@ -160,31 +160,31 @@ func TestAccAutoScalingPolicy_predictiveScalingCustom(t *testing.T) { Config: testAccPolicyConfigPredictiveScalingCustom(name), Check: resource.ComposeTestCheckFunc( testAccCheckScalingPolicyExists(resourceSimpleName, &policy), - resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.mode", "ForecastOnly"), - resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.scheduling_buffer_time", "10"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.max_capacity_breach_behavior", "IncreaseMaxCapacity"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.max_capacity_buffer", "0"), - resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.target_value", "32"), - resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_scaling_metric_specification.0.metric_data_queries.0.id", "scaling_metric"), - resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_scaling_metric_specification.0.metric_data_queries.0.expression", "TIME_SERIES(1)"), - resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_load_metric_specification.0.metric_data_queries.0.id", "load_metric"), - resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_load_metric_specification.0.metric_data_queries.0.label", "fake_load_metric"), - resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_load_metric_specification.0.metric_data_queries.0.expression", "TIME_SERIES(100)"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.0.id", "weighted_sum"), - resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.0.metric_stat.0.metric.0.namespace", "namespace_foo"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.0.metric_stat.0.metric.0.metric_name", "metric_name_foo"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.0.metric_stat.0.metric.0.namespace", "namespace_foo"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.0.metric_stat.0.stat", "Sum"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.0.return_data", "false"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.id", "capacity_sum"), - resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.namespace", "namespace_bar"), - resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.metric_name", "metric_name_bar"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.dimensions.#", "2"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.metric_name", "metric_name_bar"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.metric.0.namespace", "namespace_bar"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.unit", "Percent"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.metric_stat.0.stat", "Sum"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.1.return_data", "false"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.2.id", "capacity"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.2.expression", "weighted_sum / capacity_sum"), resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_capacity_metric_specification.0.metric_data_queries.2.return_data", "true"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_scaling_metric_specification.0.metric_data_queries.0.id", "scaling_metric"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_scaling_metric_specification.0.metric_data_queries.0.expression", "TIME_SERIES(1)"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_load_metric_specification.0.metric_data_queries.0.id", "load_metric"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_load_metric_specification.0.metric_data_queries.0.label", "fake_load_metric"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.customized_load_metric_specification.0.metric_data_queries.0.expression", "TIME_SERIES(100)"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.metric_specification.0.target_value", "32"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.mode", "ForecastOnly"), + resource.TestCheckResourceAttr(resourceSimpleName, "predictive_scaling_configuration.0.scheduling_buffer_time", "10"), ), }, { @@ -653,19 +653,6 @@ resource "aws_autoscaling_policy" "test" { predictive_scaling_configuration { metric_specification { target_value = 32 - customized_scaling_metric_specification { - metric_data_queries { - id = "scaling_metric" - expression = "TIME_SERIES(1)" - } - } - customized_load_metric_specification { - metric_data_queries { - id = "load_metric" - label = "fake_load_metric" - expression = "TIME_SERIES(100)" - } - } customized_capacity_metric_specification { metric_data_queries { id = "weighted_sum" @@ -704,6 +691,19 @@ resource "aws_autoscaling_policy" "test" { return_data = true } } + customized_load_metric_specification { + metric_data_queries { + id = "load_metric" + label = "fake_load_metric" + expression = "TIME_SERIES(100)" + } + } + customized_scaling_metric_specification { + metric_data_queries { + id = "scaling_metric" + expression = "TIME_SERIES(1)" + } + } } mode = "ForecastOnly" scheduling_buffer_time = 10 diff --git a/website/docs/r/autoscaling_policy.html.markdown b/website/docs/r/autoscaling_policy.html.markdown index bd14b5583bc..dabca8080bd 100644 --- a/website/docs/r/autoscaling_policy.html.markdown +++ b/website/docs/r/autoscaling_policy.html.markdown @@ -48,6 +48,12 @@ resource "aws_autoscaling_policy" "example" { predictive_scaling_configuration { metric_specification { target_value = 10 + customized_load_metric_specification { + metric_data_queries { + id = "load_sum" + expression = "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 3600))" + } + } customized_scaling_metric_specification { metric_data_queries { id = "scaling" @@ -63,13 +69,7 @@ resource "aws_autoscaling_policy" "example" { stat = "Average" } } - } - customized_load_metric_specification { - metric_data_queries { - id = "load_sum" - expression = "SUM(SEARCH('{AWS/EC2,AutoScalingGroupName} MetricName=\"CPUUtilization\" my-test-asg', 'Sum', 3600))" - } - } + } customized_capacity_metric_specification { metric_data_queries { id = "capacity_sum" @@ -210,12 +210,12 @@ The following arguments are supported: The following arguments are supported: +* `customized_capacity_metric_specification` - (Optional) The customized capacity metric specification. The field is only valid when you use `customized_load_metric_specification` +* `customized_load_metric_specification` - (Optional) The customized load metric specification. +* `customized_scaling_metric_specification` - (Optional) The customized scaling metric specification. * `predefined_load_metric_specification` - (Optional) The predefined load metric specification. * `predefined_metric_pair_specification` - (Optional) The metric pair specification from which Amazon EC2 Auto Scaling determines the appropriate scaling metric and load metric to use. * `predefined_scaling_metric_specification` - (Optional) The predefined scaling metric specification. -* `customized_scaling_metric_specification` - (Optional) The customized scaling metric specification. -* `customized_load_metric_specification` - (Optional) The customized load metric specification. -* `customized_capacity_metric_specification` - (Optional) The customized capacity metric specification. The field is only valid when you use `customized_load_metric_specification` ##### predefined_load_metric_specification @@ -253,8 +253,8 @@ The following arguments are supported: ##### metric_data_queries The following arguments are supported: -* `id` - (Required) A short name for the metric used in predictive scaling policy. * `expression` - (Optional) The math expression used on the returned metric. You must specify either `expression` or `metric_stat`, but not both. +* `id` - (Required) A short name for the metric used in predictive scaling policy. * `metric_stat` - (Optional) A structure that defines CloudWatch metric to be used in predictive scaling policy. You must specify either `expression` or `metric_stat`, but not both. * `label` - (Optional) A human-readable label for this metric or expression. * `return_data` - (Optional) A boolean that indicates whether to return the timestamps and raw data values of this metric, the default it true @@ -266,9 +266,15 @@ The following arguments are supported: * `unit` - (Optional) The unit of the metrics to return. ##### metric +The following arguments are supported: +* `dimensions` - (Optional) The dimensions of the metric. * `metric_name` - (Required) The name of the metric. * `namespace` - (Required) The namespace of the metric. -* `dimensions` - (Optional) The dimensions of the metric. + +##### dimensions +The following arguments are supported: +* `name` - (Required) The name of the dimension. +* `value` - (Required) The value of the dimension. ## Attributes Reference From 11e47e5f48cf8741a0a35c6647f264c6ba9eaaa8 Mon Sep 17 00:00:00 2001 From: Yupeng Gou Date: Thu, 3 Feb 2022 20:26:48 -0800 Subject: [PATCH 5/9] make attribute assignment in alphabetical order --- internal/service/autoscaling/policy.go | 42 +++++++++++++------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/internal/service/autoscaling/policy.go b/internal/service/autoscaling/policy.go index 4417c3c7b24..869796505b3 100644 --- a/internal/service/autoscaling/policy.go +++ b/internal/service/autoscaling/policy.go @@ -908,12 +908,12 @@ func expandPredictiveScalingMetricSpecifications(metricSpecificationsSlice []int } metricSpecificationsFlat := metricSpecificationsSlice[0].(map[string]interface{}) metricSpecification := &autoscaling.PredictiveScalingMetricSpecification{ + CustomizedCapacityMetricSpecification: expandCustomizedCapacityMetricSpecification(metricSpecificationsFlat["customized_capacity_metric_specification"].([]interface{})), + CustomizedLoadMetricSpecification: expandCustomizedLoadMetricSpecification(metricSpecificationsFlat["customized_load_metric_specification"].([]interface{})), + CustomizedScalingMetricSpecification: expandCustomizedScalingMetricSpecification(metricSpecificationsFlat["customized_scaling_metric_specification"].([]interface{})), PredefinedLoadMetricSpecification: expandPredefinedLoadMetricSpecification(metricSpecificationsFlat["predefined_load_metric_specification"].([]interface{})), PredefinedMetricPairSpecification: expandPredefinedMetricPairSpecification(metricSpecificationsFlat["predefined_metric_pair_specification"].([]interface{})), PredefinedScalingMetricSpecification: expandPredefinedScalingMetricSpecification(metricSpecificationsFlat["predefined_scaling_metric_specification"].([]interface{})), - CustomizedScalingMetricSpecification: expandCustomizedScalingMetricSpecification(metricSpecificationsFlat["customized_scaling_metric_specification"].([]interface{})), - CustomizedLoadMetricSpecification: expandCustomizedLoadMetricSpecification(metricSpecificationsFlat["customized_load_metric_specification"].([]interface{})), - CustomizedCapacityMetricSpecification: expandCustomizedCapacityMetricSpecification(metricSpecificationsFlat["customized_capacity_metric_specification"].([]interface{})), TargetValue: aws.Float64(float64(metricSpecificationsFlat["target_value"].(int))), } return []*autoscaling.PredictiveScalingMetricSpecification{metricSpecification} @@ -1114,6 +1114,15 @@ func flattenPredictiveScalingMetricSpecifications(metricSpecification []*autosca if metricSpecification[0].TargetValue != nil { metricSpecificationFlat["target_value"] = aws.Float64Value(metricSpecification[0].TargetValue) } + if metricSpecification[0].CustomizedCapacityMetricSpecification != nil { + metricSpecificationFlat["customized_capacity_metric_specification"] = flattenCustomizedCapacityMetricSpecification(metricSpecification[0].CustomizedCapacityMetricSpecification) + } + if metricSpecification[0].CustomizedLoadMetricSpecification != nil { + metricSpecificationFlat["customized_load_metric_specification"] = flattenCustomizedLoadMetricSpecification(metricSpecification[0].CustomizedLoadMetricSpecification) + } + if metricSpecification[0].CustomizedScalingMetricSpecification != nil { + metricSpecificationFlat["customized_scaling_metric_specification"] = flattenCustomizedScalingMetricSpecification(metricSpecification[0].CustomizedScalingMetricSpecification) + } if metricSpecification[0].PredefinedLoadMetricSpecification != nil { metricSpecificationFlat["predefined_load_metric_specification"] = flattenPredefinedLoadMetricSpecification(metricSpecification[0].PredefinedLoadMetricSpecification) } @@ -1123,15 +1132,6 @@ func flattenPredictiveScalingMetricSpecifications(metricSpecification []*autosca if metricSpecification[0].PredefinedScalingMetricSpecification != nil { metricSpecificationFlat["predefined_scaling_metric_specification"] = flattenPredefinedScalingMetricSpecification(metricSpecification[0].PredefinedScalingMetricSpecification) } - if metricSpecification[0].CustomizedScalingMetricSpecification != nil { - metricSpecificationFlat["customized_scaling_metric_specification"] = flattenCustomizedScalingMetricSpecification(metricSpecification[0].CustomizedScalingMetricSpecification) - } - if metricSpecification[0].CustomizedLoadMetricSpecification != nil { - metricSpecificationFlat["customized_load_metric_specification"] = flattenCustomizedLoadMetricSpecification(metricSpecification[0].CustomizedLoadMetricSpecification) - } - if metricSpecification[0].CustomizedCapacityMetricSpecification != nil { - metricSpecificationFlat["customized_capacity_metric_specification"] = flattenCustomizedCapacityMetricSpecification(metricSpecification[0].CustomizedCapacityMetricSpecification) - } return []map[string]interface{}{metricSpecificationFlat} } @@ -1207,17 +1207,14 @@ func flattenMetricDataQueries(metricDataQueries []*autoscaling.MetricDataQuery) if rawMetricDataQuery.Expression != nil { metricDataQuery["expression"] = aws.StringValue(rawMetricDataQuery.Expression) } + if rawMetricDataQuery.Label != nil { + metricDataQuery["label"] = aws.StringValue(rawMetricDataQuery.Label) + } if rawMetricDataQuery.MetricStat != nil { metricStatSpec := map[string]interface{}{} rawMetricStat := rawMetricDataQuery.MetricStat - metricStatSpec["stat"] = aws.StringValue(rawMetricStat.Stat) - if rawMetricStat.Unit != nil { - metricStatSpec["unit"] = aws.StringValue(rawMetricStat.Unit) - } rawMetric := rawMetricStat.Metric metricSpec := map[string]interface{}{} - metricSpec["metric_name"] = aws.StringValue(rawMetric.MetricName) - metricSpec["namespace"] = aws.StringValue(rawMetric.Namespace) if rawMetric.Dimensions != nil { dimSpec := make([]interface{}, len(rawMetric.Dimensions)) for i := range dimSpec { @@ -1229,12 +1226,15 @@ func flattenMetricDataQueries(metricDataQueries []*autoscaling.MetricDataQuery) } metricSpec["dimensions"] = dimSpec } + metricSpec["metric_name"] = aws.StringValue(rawMetric.MetricName) + metricSpec["namespace"] = aws.StringValue(rawMetric.Namespace) metricStatSpec["metric"] = []map[string]interface{}{metricSpec} + metricStatSpec["stat"] = aws.StringValue(rawMetricStat.Stat) + if rawMetricStat.Unit != nil { + metricStatSpec["unit"] = aws.StringValue(rawMetricStat.Unit) + } metricDataQuery["metric_stat"] = []map[string]interface{}{metricStatSpec} } - if rawMetricDataQuery.Label != nil { - metricDataQuery["label"] = aws.StringValue(rawMetricDataQuery.Label) - } if rawMetricDataQuery.ReturnData != nil { metricDataQuery["return_data"] = aws.BoolValue(rawMetricDataQuery.ReturnData) } From a4e408916231e4cfb830f3c298f9653731860f79 Mon Sep 17 00:00:00 2001 From: Yupeng Gou Date: Fri, 4 Feb 2022 16:22:31 -0800 Subject: [PATCH 6/9] Use method to generate metric data query schema, add examples --- internal/service/autoscaling/policy.go | 405 ++++++------------ internal/service/autoscaling/policy_test.go | 4 - .../docs/r/autoscaling_policy.html.markdown | 36 +- 3 files changed, 155 insertions(+), 290 deletions(-) diff --git a/internal/service/autoscaling/policy.go b/internal/service/autoscaling/policy.go index 869796505b3..78450558e23 100644 --- a/internal/service/autoscaling/policy.go +++ b/internal/service/autoscaling/policy.go @@ -94,86 +94,10 @@ func ResourcePolicy() *schema.Resource { ConflictsWith: []string{"predictive_scaling_configuration.0.metric_specification.0.predefined_load_metric_specification"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "metric_data_queries": { - Type: schema.TypeList, - Required: true, - MaxItems: 10, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "expression": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 1023), - }, - "id": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - "label": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 2047), - }, - "metric_stat": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "metric": { - Type: schema.TypeList, - Required: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "dimensions": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - }, - "value": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - "metric_name": { - Type: schema.TypeString, - Required: true, - }, - "namespace": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - "stat": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 100), - }, - "unit": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - "return_data": { - Type: schema.TypeBool, - Optional: true, - Default: true, - }, - }, - }, - }, + "metric_data_queries": func() *schema.Schema { + schema := customizedMetricDataQuerySchema() + return schema + }(), }, }, }, @@ -184,86 +108,10 @@ func ResourcePolicy() *schema.Resource { ConflictsWith: []string{"predictive_scaling_configuration.0.metric_specification.0.predefined_load_metric_specification"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "metric_data_queries": { - Type: schema.TypeList, - Required: true, - MaxItems: 10, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "expression": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 1023), - }, - "id": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - "label": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 2047), - }, - "metric_stat": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "metric": { - Type: schema.TypeList, - Required: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "dimensions": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - }, - "value": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - "metric_name": { - Type: schema.TypeString, - Required: true, - }, - "namespace": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - "stat": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 100), - }, - "unit": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - "return_data": { - Type: schema.TypeBool, - Optional: true, - Default: true, - }, - }, - }, - }, + "metric_data_queries": func() *schema.Schema { + schema := customizedMetricDataQuerySchema() + return schema + }(), }, }, }, @@ -274,86 +122,10 @@ func ResourcePolicy() *schema.Resource { ConflictsWith: []string{"predictive_scaling_configuration.0.metric_specification.0.predefined_scaling_metric_specification"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "metric_data_queries": { - Type: schema.TypeList, - Required: true, - MaxItems: 10, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "expression": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 1023), - }, - "id": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - "label": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 2047), - }, - "metric_stat": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "metric": { - Type: schema.TypeList, - Required: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "dimensions": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - }, - "value": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - "metric_name": { - Type: schema.TypeString, - Required: true, - }, - "namespace": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - "stat": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 100), - }, - "unit": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - "return_data": { - Type: schema.TypeBool, - Optional: true, - Default: true, - }, - }, - }, - }, + "metric_data_queries": func() *schema.Schema { + schema := customizedMetricDataQuerySchema() + return schema + }(), }, }, }, @@ -364,14 +136,9 @@ func ResourcePolicy() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "predefined_metric_type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - "ASGCPUUtilization", - "ASGNetworkIn", - "ASGNetworkOut", - "ALBRequestCount", - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(autoscaling.PredefinedMetricPairType_Values(), false), }, "resource_label": { Type: schema.TypeString, @@ -388,14 +155,9 @@ func ResourcePolicy() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "predefined_metric_type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - "ASGAverageCPUUtilization", - "ASGAverageNetworkIn", - "ASGAverageNetworkOut", - "ALBRequestCountPerTarget", - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(autoscaling.PredefinedScalingMetricType_Values(), false), }, "resource_label": { Type: schema.TypeString, @@ -412,14 +174,9 @@ func ResourcePolicy() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "predefined_metric_type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - "ASGTotalCPUUtilization", - "ASGTotalNetworkIn", - "ASGTotalNetworkOut", - "ALBTargetGroupRequestCount", - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(autoscaling.PredefinedLoadMetricType_Values(), false), }, "resource_label": { Type: schema.TypeString, @@ -436,13 +193,10 @@ func ResourcePolicy() *schema.Resource { }, }, "max_capacity_breach_behavior": { - Type: schema.TypeString, - Optional: true, - Default: "HonorMaxCapacity", - ValidateFunc: validation.StringInSlice([]string{ - "HonorMaxCapacity", - "IncreaseMaxCapacity", - }, false), + Type: schema.TypeString, + Optional: true, + Default: "HonorMaxCapacity", + ValidateFunc: validation.StringInSlice(autoscaling.PredictiveScalingMaxCapacityBreachBehavior_Values(), false), }, "max_capacity_buffer": { Type: nullable.TypeNullableInt, @@ -450,13 +204,10 @@ func ResourcePolicy() *schema.Resource { ValidateFunc: nullable.ValidateTypeStringNullableIntBetween(0, 100), }, "mode": { - Type: schema.TypeString, - Optional: true, - Default: "ForecastOnly", - ValidateFunc: validation.StringInSlice([]string{ - "ForecastOnly", - "ForecastAndScale", - }, false), + Type: schema.TypeString, + Optional: true, + Default: "ForecastOnly", + ValidateFunc: validation.StringInSlice(autoscaling.PredictiveScalingMode_Values(), false), }, "scheduling_buffer_time": { Type: nullable.TypeNullableInt, @@ -575,6 +326,90 @@ func ResourcePolicy() *schema.Resource { } } +// All predictive scaling customized metrics shares same metric data query schema +func customizedMetricDataQuerySchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Required: true, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "expression": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1023), + }, + "id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "label": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 2047), + }, + "metric_stat": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dimensions": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "metric_name": { + Type: schema.TypeString, + Required: true, + }, + "namespace": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "stat": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 100), + }, + "unit": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "return_data": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + }, + }, + } +} + func resourcePolicyCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).AutoScalingConn @@ -966,22 +801,22 @@ func expandCustomizedScalingMetricSpecification(customizedScalingMetricSpecifica return customizedScalingMetricSpecification } -func expandCustomizedLoadMetricSpecification(CustomizedLoadMetricSpecificationSlice []interface{}) *autoscaling.PredictiveScalingCustomizedLoadMetric { - if CustomizedLoadMetricSpecificationSlice == nil || len(CustomizedLoadMetricSpecificationSlice) < 1 { +func expandCustomizedLoadMetricSpecification(customizedLoadMetricSpecificationSlice []interface{}) *autoscaling.PredictiveScalingCustomizedLoadMetric { + if customizedLoadMetricSpecificationSlice == nil || len(customizedLoadMetricSpecificationSlice) < 1 { return nil } - CustomizedLoadMetricSpecificationSliceFlat := CustomizedLoadMetricSpecificationSlice[0].(map[string]interface{}) + customizedLoadMetricSpecificationSliceFlat := customizedLoadMetricSpecificationSlice[0].(map[string]interface{}) customizedLoadMetricSpecification := &autoscaling.PredictiveScalingCustomizedLoadMetric{ - MetricDataQueries: expandMetricDataQueries(CustomizedLoadMetricSpecificationSliceFlat["metric_data_queries"].([]interface{})), + MetricDataQueries: expandMetricDataQueries(customizedLoadMetricSpecificationSliceFlat["metric_data_queries"].([]interface{})), } return customizedLoadMetricSpecification } -func expandCustomizedCapacityMetricSpecification(CustomizedCapacityMetricSlice []interface{}) *autoscaling.PredictiveScalingCustomizedCapacityMetric { - if CustomizedCapacityMetricSlice == nil || len(CustomizedCapacityMetricSlice) < 1 { +func expandCustomizedCapacityMetricSpecification(customizedCapacityMetricSlice []interface{}) *autoscaling.PredictiveScalingCustomizedCapacityMetric { + if customizedCapacityMetricSlice == nil || len(customizedCapacityMetricSlice) < 1 { return nil } - customizedCapacityMetricSliceFlat := CustomizedCapacityMetricSlice[0].(map[string]interface{}) + customizedCapacityMetricSliceFlat := customizedCapacityMetricSlice[0].(map[string]interface{}) customizedCapacityMetricSpecification := &autoscaling.PredictiveScalingCustomizedCapacityMetric{ MetricDataQueries: expandMetricDataQueries(customizedCapacityMetricSliceFlat["metric_data_queries"].([]interface{})), } diff --git a/internal/service/autoscaling/policy_test.go b/internal/service/autoscaling/policy_test.go index 7327d323b76..82bab2917b7 100644 --- a/internal/service/autoscaling/policy_test.go +++ b/internal/service/autoscaling/policy_test.go @@ -107,9 +107,7 @@ func TestAccAutoScalingPolicy_basic(t *testing.T) { func TestAccAutoScalingPolicy_predictiveScalingPredefined(t *testing.T) { var policy autoscaling.ScalingPolicy - resourceSimpleName := "aws_autoscaling_policy.test" - name := sdkacctest.RandomWithPrefix("terraform-testacc-asp") resource.ParallelTest(t, resource.TestCase{ @@ -145,9 +143,7 @@ func TestAccAutoScalingPolicy_predictiveScalingPredefined(t *testing.T) { func TestAccAutoScalingPolicy_predictiveScalingCustom(t *testing.T) { var policy autoscaling.ScalingPolicy - resourceSimpleName := "aws_autoscaling_policy.test" - name := sdkacctest.RandomWithPrefix("terraform-testacc-asp1") resource.ParallelTest(t, resource.TestCase{ diff --git a/website/docs/r/autoscaling_policy.html.markdown b/website/docs/r/autoscaling_policy.html.markdown index dabca8080bd..4c9c9acd450 100644 --- a/website/docs/r/autoscaling_policy.html.markdown +++ b/website/docs/r/autoscaling_policy.html.markdown @@ -39,7 +39,7 @@ resource "aws_autoscaling_group" "bar" { } ``` -### Create predictive scaling policy using custom metrics +### Create predictive scaling policy using customized metrics ```terraform resource "aws_autoscaling_policy" "example" { autoscaling_group_name = "my-test-asg" @@ -90,6 +90,40 @@ resource "aws_autoscaling_policy" "example" { } } ``` + +### Create predictive scaling policy using customized scaling and predefined load metric +```terraform +resource "aws_autoscaling_policy" "example" { + autoscaling_group_name = "my-test-asg" + name = "foo" + policy_type = "PredictiveScaling" + predictive_scaling_configuration { + metric_specification { + target_value = 10 + predefined_load_metric_specification { + predefined_metric_type = "ASGTotalCPUUtilization" + resource_label = "testLabel" + } + customized_scaling_metric_specification { + metric_data_queries { + id = "scaling" + metric_stat { + metric { + metric_name = "CPUUtilization" + namespace = "AWS/EC2" + dimensions { + name = "AutoScalingGroupName" + value = "my-test-asg" + } + } + stat = "Average" + } + } + } + } + } +} +``` ## Argument Reference * `name` - (Required) The name of the policy. From 4e9bdc74541a983e461f4cd710831e6e8ccb8256 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 3 Mar 2022 08:41:44 -0500 Subject: [PATCH 7/9] Tweak CHANGELOG entry. --- .changelog/22451.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/22451.txt b/.changelog/22451.txt index baad7816337..20f3187cc49 100644 --- a/.changelog/22451.txt +++ b/.changelog/22451.txt @@ -1,2 +1,2 @@ ```release-note:enhancement -resource/aws_autoscaling_policy: Add customized metric specification in `predictive_scaling_configuration` argument +resource/aws_autoscaling_policy: Add `customized_capacity_metric_specification`, `customized_load_metric_specification` and `customized_scaling_metric_specification` to the `predictive_scaling_configuration.metric_specification` argument From 7e7d3ab2fbf6804d4b93b2486956f112dc27c8af Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 3 Mar 2022 08:45:03 -0500 Subject: [PATCH 8/9] Fix markdown-lint errors. --- website/docs/r/autoscaling_policy.html.markdown | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/website/docs/r/autoscaling_policy.html.markdown b/website/docs/r/autoscaling_policy.html.markdown index 4c9c9acd450..4acd459db55 100644 --- a/website/docs/r/autoscaling_policy.html.markdown +++ b/website/docs/r/autoscaling_policy.html.markdown @@ -40,6 +40,7 @@ resource "aws_autoscaling_group" "bar" { ``` ### Create predictive scaling policy using customized metrics + ```terraform resource "aws_autoscaling_policy" "example" { autoscaling_group_name = "my-test-asg" @@ -92,6 +93,7 @@ resource "aws_autoscaling_policy" "example" { ``` ### Create predictive scaling policy using customized scaling and predefined load metric + ```terraform resource "aws_autoscaling_policy" "example" { autoscaling_group_name = "my-test-asg" @@ -124,6 +126,7 @@ resource "aws_autoscaling_policy" "example" { } } ``` + ## Argument Reference * `name` - (Required) The name of the policy. @@ -246,7 +249,7 @@ The following arguments are supported: * `customized_capacity_metric_specification` - (Optional) The customized capacity metric specification. The field is only valid when you use `customized_load_metric_specification` * `customized_load_metric_specification` - (Optional) The customized load metric specification. -* `customized_scaling_metric_specification` - (Optional) The customized scaling metric specification. +* `customized_scaling_metric_specification` - (Optional) The customized scaling metric specification. * `predefined_load_metric_specification` - (Optional) The predefined load metric specification. * `predefined_metric_pair_specification` - (Optional) The metric pair specification from which Amazon EC2 Auto Scaling determines the appropriate scaling metric and load metric to use. * `predefined_scaling_metric_specification` - (Optional) The predefined scaling metric specification. @@ -279,14 +282,17 @@ The following arguments are supported: ##### customized_load_metric_specification The following arguments are supported: + * `metric_data_queries` - (Required) A list of up to 10 structures that defines custom load metric in predictive scaling policy ##### customized_capacity_metric_specification The following arguments are supported: + * `metric_data_queries` - (Required) A list of up to 10 structures that defines custom capacity metric in predictive scaling policy ##### metric_data_queries The following arguments are supported: + * `expression` - (Optional) The math expression used on the returned metric. You must specify either `expression` or `metric_stat`, but not both. * `id` - (Required) A short name for the metric used in predictive scaling policy. * `metric_stat` - (Optional) A structure that defines CloudWatch metric to be used in predictive scaling policy. You must specify either `expression` or `metric_stat`, but not both. @@ -295,18 +301,21 @@ The following arguments are supported: ##### metric_stat The following arguments are supported: + * `metric` - (Required) A structure that defines the CloudWatch metric to return, including the metric name, namespace, and dimensions. * `stat` - (Required) The statistic of the metrics to return. * `unit` - (Optional) The unit of the metrics to return. ##### metric The following arguments are supported: + * `dimensions` - (Optional) The dimensions of the metric. * `metric_name` - (Required) The name of the metric. * `namespace` - (Required) The namespace of the metric. ##### dimensions The following arguments are supported: + * `name` - (Required) The name of the dimension. * `value` - (Required) The value of the dimension. From 44820cea1c7762330bb878e7df6aae07f8956e43 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 3 Mar 2022 08:46:37 -0500 Subject: [PATCH 9/9] Fix terrafmt errors in documentation. --- website/docs/r/autoscaling_policy.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/autoscaling_policy.html.markdown b/website/docs/r/autoscaling_policy.html.markdown index 4acd459db55..d0d7662e893 100644 --- a/website/docs/r/autoscaling_policy.html.markdown +++ b/website/docs/r/autoscaling_policy.html.markdown @@ -70,7 +70,7 @@ resource "aws_autoscaling_policy" "example" { stat = "Average" } } - } + } customized_capacity_metric_specification { metric_data_queries { id = "capacity_sum"