From d3eb4da6c8258ea116e956aca6885cbf7e9938f4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 12 Jun 2019 12:34:44 -0400 Subject: [PATCH 01/19] Add 'aws_autoscalingplans_scaling_plan' resource. --- aws/provider.go | 1 + ...ource_aws_autoscalingplans_scaling_plan.go | 1081 +++++++++++++++++ ..._aws_autoscalingplans_scaling_plan_test.go | 521 ++++++++ aws/validators.go | 20 + aws/validators_test.go | 28 + ...utoscalingplans_scaling_plan.html.markdown | 229 ++++ 6 files changed, 1880 insertions(+) create mode 100644 aws/resource_aws_autoscalingplans_scaling_plan.go create mode 100644 aws/resource_aws_autoscalingplans_scaling_plan_test.go create mode 100644 website/docs/r/autoscalingplans_scaling_plan.html.markdown diff --git a/aws/provider.go b/aws/provider.go index 34e5c2925841..8c3df08879a0 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -430,6 +430,7 @@ func Provider() *schema.Provider { "aws_autoscaling_notification": resourceAwsAutoscalingNotification(), "aws_autoscaling_policy": resourceAwsAutoscalingPolicy(), "aws_autoscaling_schedule": resourceAwsAutoscalingSchedule(), + "aws_autoscalingplans_scaling_plan": resourceAwsAutoScalingPlansScalingPlan(), "aws_backup_plan": resourceAwsBackupPlan(), "aws_backup_selection": resourceAwsBackupSelection(), "aws_backup_vault": resourceAwsBackupVault(), diff --git a/aws/resource_aws_autoscalingplans_scaling_plan.go b/aws/resource_aws_autoscalingplans_scaling_plan.go new file mode 100644 index 000000000000..9039288b8e3a --- /dev/null +++ b/aws/resource_aws_autoscalingplans_scaling_plan.go @@ -0,0 +1,1081 @@ +package aws + +import ( + "bytes" + "fmt" + "log" + "regexp" + "sort" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/autoscalingplans" + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" +) + +const ( + autoscalingplansScalingPlanStatusDeleted = "Deleted" +) + +func resourceAwsAutoScalingPlansScalingPlan() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAutoScalingPlansScalingPlanCreate, + Read: resourceAwsAutoScalingPlansScalingPlanRead, + Update: resourceAwsAutoScalingPlansScalingPlanUpdate, + Delete: resourceAwsAutoScalingPlansScalingPlanDelete, + Importer: &schema.ResourceImporter{ + State: resourceAwsAutoScalingPlansScalingPlanImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 128), + validation.StringMatch(regexp.MustCompile(`^[[:print:]]+$`), "must be printable"), + validateStringDoesNotContainAny("|:/"), + ), + }, + + "application_source": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cloudformation_stack_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, + ConflictsWith: []string{"application_source.0.tag_filter"}, + }, + + "tag_filter": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + MaxItems: 50, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + }, + + "values": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + MaxItems: 50, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + }, + }, + Set: autoScalingPlansTagFilterHash, + ConflictsWith: []string{"application_source.0.cloudformation_stack_arn"}, + }, + }, + }, + }, + + "scaling_instruction": { + Type: schema.TypeSet, + Required: true, + MinItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "customized_load_metric_specification": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dimensions": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "metric_name": { + Type: schema.TypeString, + Required: true, + }, + + "namespace": { + Type: schema.TypeString, + Required: true, + }, + + "statistic": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + autoscalingplans.MetricStatisticSum, + }, false), + }, + + "unit": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + + "disable_dynamic_scaling": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "max_capacity": { + Type: schema.TypeInt, + Required: true, + }, + + "min_capacity": { + Type: schema.TypeInt, + Required: true, + }, + + "predefined_load_metric_specification": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "predefined_load_metric_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + autoscalingplans.LoadMetricTypeAlbtargetGroupRequestCount, + autoscalingplans.LoadMetricTypeAsgtotalCpuutilization, + autoscalingplans.LoadMetricTypeAsgtotalNetworkIn, + autoscalingplans.LoadMetricTypeAsgtotalNetworkOut, + }, false), + }, + + "resource_label": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1023), + }, + }, + }, + }, + + "predictive_scaling_max_capacity_behavior": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + autoscalingplans.PredictiveScalingMaxCapacityBehaviorSetForecastCapacityToMaxCapacity, + autoscalingplans.PredictiveScalingMaxCapacityBehaviorSetMaxCapacityAboveForecastCapacity, + autoscalingplans.PredictiveScalingMaxCapacityBehaviorSetMaxCapacityToForecastCapacity, + }, false), + }, + + "predictive_scaling_max_capacity_buffer": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 100), + }, + + "predictive_scaling_mode": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + autoscalingplans.PredictiveScalingModeForecastAndScale, + autoscalingplans.PredictiveScalingModeForecastOnly, + }, false), + }, + + "resource_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 1600), + }, + + "scalable_dimension": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + autoscalingplans.ScalableDimensionAutoscalingAutoScalingGroupDesiredCapacity, + autoscalingplans.ScalableDimensionDynamodbIndexReadCapacityUnits, + autoscalingplans.ScalableDimensionDynamodbIndexWriteCapacityUnits, + autoscalingplans.ScalableDimensionDynamodbTableReadCapacityUnits, + autoscalingplans.ScalableDimensionDynamodbTableWriteCapacityUnits, + autoscalingplans.ScalableDimensionEcsServiceDesiredCount, + autoscalingplans.ScalableDimensionEc2SpotFleetRequestTargetCapacity, + autoscalingplans.ScalableDimensionRdsClusterReadReplicaCount, + }, false), + }, + + "scaling_policy_update_behavior": { + Type: schema.TypeString, + Optional: true, + Default: autoscalingplans.ScalingPolicyUpdateBehaviorKeepExternalPolicies, + ValidateFunc: validation.StringInSlice([]string{ + autoscalingplans.ScalingPolicyUpdateBehaviorKeepExternalPolicies, + autoscalingplans.ScalingPolicyUpdateBehaviorReplaceExternalPolicies, + }, false), + }, + + "scheduled_action_buffer_time": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(0), + }, + + "service_namespace": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + autoscalingplans.ServiceNamespaceAutoscaling, + autoscalingplans.ServiceNamespaceDynamodb, + autoscalingplans.ServiceNamespaceEcs, + autoscalingplans.ServiceNamespaceEc2, + autoscalingplans.ServiceNamespaceRds, + }, false), + }, + + "target_tracking_configuration": { + Type: schema.TypeSet, + Required: true, + MinItems: 1, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "customized_scaling_metric_specification": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dimensions": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "metric_name": { + Type: schema.TypeString, + Required: true, + }, + + "namespace": { + Type: schema.TypeString, + Required: true, + }, + + "statistic": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + autoscalingplans.MetricStatisticAverage, + autoscalingplans.MetricStatisticMaximum, + autoscalingplans.MetricStatisticMinimum, + autoscalingplans.MetricStatisticSampleCount, + autoscalingplans.MetricStatisticSum, + }, false), + }, + + "unit": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + + "disable_scale_in": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "estimated_instance_warmup": { + Type: schema.TypeInt, + Optional: true, + }, + + "predefined_scaling_metric_specification": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "predefined_scaling_metric_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + autoscalingplans.ScalingMetricTypeAlbrequestCountPerTarget, + autoscalingplans.ScalingMetricTypeAsgaverageCpuutilization, + autoscalingplans.ScalingMetricTypeAsgaverageNetworkIn, + autoscalingplans.ScalingMetricTypeAsgaverageNetworkOut, + autoscalingplans.ScalingMetricTypeDynamoDbreadCapacityUtilization, + autoscalingplans.ScalingMetricTypeDynamoDbwriteCapacityUtilization, + autoscalingplans.ScalingMetricTypeEcsserviceAverageCpuutilization, + autoscalingplans.ScalingMetricTypeEcsserviceAverageMemoryUtilization, + autoscalingplans.ScalingMetricTypeEc2spotFleetRequestAverageCpuutilization, + autoscalingplans.ScalingMetricTypeEc2spotFleetRequestAverageNetworkIn, + autoscalingplans.ScalingMetricTypeEc2spotFleetRequestAverageNetworkOut, + autoscalingplans.ScalingMetricTypeRdsreaderAverageCpuutilization, + autoscalingplans.ScalingMetricTypeRdsreaderAverageDatabaseConnections, + }, false), + }, + + "resource_label": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1023), + }, + }, + }, + }, + + "scale_in_cooldown": { + Type: schema.TypeInt, + Optional: true, + }, + + "scale_out_cooldown": { + Type: schema.TypeInt, + Optional: true, + }, + + "target_value": { + Type: schema.TypeFloat, + Required: true, + ValidateFunc: validation.FloatBetween(8.515920e-109, 1.174271e+108), + }, + }, + }, + Set: autoScalingPlansTargetTrackingConfigurationHash, + }, + }, + }, + Set: autoScalingPlansScalingInstructionHash, + }, + + "scaling_plan_version": { + Type: schema.TypeInt, + Computed: true, + }, + }, + } +} + +func resourceAwsAutoScalingPlansScalingPlanCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).autoscalingplansconn + + scalingPlanName := d.Get("name").(string) + req := &autoscalingplans.CreateScalingPlanInput{ + ApplicationSource: expandAutoScalingPlansApplicationSource(d.Get("application_source").([]interface{})), + ScalingInstructions: expandAutoScalingPlansScalingInstructions(d.Get("scaling_instruction").(*schema.Set)), + ScalingPlanName: aws.String(scalingPlanName), + } + + log.Printf("[DEBUG] Creating Auto Scaling scaling plan: %s", req) + resp, err := conn.CreateScalingPlan(req) + if err != nil { + return fmt.Errorf("error creating Auto Scaling scaling plan: %s", err) + } + + scalingPlanVersion := int(aws.Int64Value(resp.ScalingPlanVersion)) + d.SetId(autoScalingPlansScalingPlanId(scalingPlanName, scalingPlanVersion)) + d.Set("scaling_plan_version", scalingPlanVersion) + + if err := waitForAutoScalingPlansScalingPlanAvailabilityOnCreate(conn, scalingPlanName, scalingPlanVersion, d.Timeout(schema.TimeoutCreate)); err != nil { + return fmt.Errorf("error waiting for Auto Scaling scaling plan (%s) to become available: %s", d.Id(), err) + } + + return resourceAwsAutoScalingPlansScalingPlanRead(d, meta) +} + +func resourceAwsAutoScalingPlansScalingPlanRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).autoscalingplansconn + + scalingPlanName := d.Get("name").(string) + scalingPlanVersion := d.Get("scaling_plan_version").(int) + + scalingPlanRaw, state, err := autoScalingPlansScalingPlanRefresh(conn, scalingPlanName, scalingPlanVersion)() + if err != nil { + return fmt.Errorf("error reading Auto Scaling scaling plan (%s): %s", d.Id(), err) + } + + if state == autoscalingplansScalingPlanStatusDeleted { + log.Printf("[WARN] Auto Scaling scaling plan (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + scalingPlan := scalingPlanRaw.(*autoscalingplans.ScalingPlan) + err = d.Set("application_source", flattenAutoScalingPlansApplicationSource(scalingPlan.ApplicationSource)) + if err != nil { + return fmt.Errorf("error setting application_source: %s", err) + } + d.Set("name", scalingPlan.ScalingPlanName) + err = d.Set("scaling_instruction", flattenAutoScalingPlansScalingInstructions(scalingPlan.ScalingInstructions)) + if err != nil { + return fmt.Errorf("error setting application_source: %s", err) + } + d.Set("scaling_plan_version", int(aws.Int64Value(scalingPlan.ScalingPlanVersion))) + + return nil +} + +func resourceAwsAutoScalingPlansScalingPlanUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).autoscalingplansconn + + scalingPlanName := d.Get("name").(string) + scalingPlanVersion := d.Get("scaling_plan_version").(int) + + req := &autoscalingplans.UpdateScalingPlanInput{ + ApplicationSource: expandAutoScalingPlansApplicationSource(d.Get("application_source").([]interface{})), + ScalingInstructions: expandAutoScalingPlansScalingInstructions(d.Get("scaling_instruction").(*schema.Set)), + ScalingPlanName: aws.String(scalingPlanName), + ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), + } + + log.Printf("[DEBUG] Updating Auto Scaling scaling plan: %s", req) + _, err := conn.UpdateScalingPlan(req) + if err != nil { + return fmt.Errorf("error updating Auto Scaling scaling plan (%s): %s", d.Id(), err) + } + + if err := waitForAutoScalingPlansScalingPlanAvailabilityOnUpdate(conn, scalingPlanName, scalingPlanVersion, d.Timeout(schema.TimeoutUpdate)); err != nil { + return fmt.Errorf("error waiting for Auto Scaling scaling plan (%s) to become available: %s", d.Id(), err) + } + + return resourceAwsAutoScalingPlansScalingPlanRead(d, meta) +} + +func resourceAwsAutoScalingPlansScalingPlanDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).autoscalingplansconn + + scalingPlanName := d.Get("name").(string) + scalingPlanVersion := d.Get("scaling_plan_version").(int) + + log.Printf("[DEBUG] Deleting Auto Scaling scaling plan: %s", d.Id()) + _, err := conn.DeleteScalingPlan(&autoscalingplans.DeleteScalingPlanInput{ + ScalingPlanName: aws.String(scalingPlanName), + ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), + }) + if isAWSErr(err, autoscalingplans.ErrCodeObjectNotFoundException, "") { + return nil + } + if err != nil { + return fmt.Errorf("error deleting Auto Scaling scaling plan (%s): %s", d.Id(), err) + } + + if err := waitForAutoScalingPlansScalingPlanDeletion(conn, scalingPlanName, scalingPlanVersion, d.Timeout(schema.TimeoutDelete)); err != nil { + return fmt.Errorf("error waiting for Auto Scaling scaling plan (%s) to be deleted: %s", d.Id(), err) + } + + return nil +} + +func resourceAwsAutoScalingPlansScalingPlanImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + scalingPlanName := d.Id() + scalingPlanVersion := 1 + + d.SetId(autoScalingPlansScalingPlanId(scalingPlanName, scalingPlanVersion)) + d.Set("name", scalingPlanName) + d.Set("scaling_plan_version", scalingPlanVersion) + + return []*schema.ResourceData{d}, nil +} + +// Terraform resource ID. +func autoScalingPlansScalingPlanId(scalingPlanName string, scalingPlanVersion int) string { + return fmt.Sprintf("%s/%d", scalingPlanName, scalingPlanVersion) +} + +func autoScalingPlansScalingPlanRefresh(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + resp, err := conn.DescribeScalingPlans(&autoscalingplans.DescribeScalingPlansInput{ + ScalingPlanNames: aws.StringSlice([]string{scalingPlanName}), + ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), + }) + if err != nil { + return nil, "", err + } + + if n := len(resp.ScalingPlans); n == 0 { + return "", autoscalingplansScalingPlanStatusDeleted, nil + } else if n > 1 { + return nil, "", fmt.Errorf("Found %d Auto Scaling scaling plans for %s, expected 1", n, scalingPlanName) + } + + scalingPlan := resp.ScalingPlans[0] + if statusMessage := aws.StringValue(scalingPlan.StatusMessage); statusMessage != "" { + log.Printf("[INFO] Auto Scaling scaling plan (%s) status message: %s", scalingPlanName, statusMessage) + } + + return scalingPlan, aws.StringValue(scalingPlan.StatusCode), nil + } +} + +func waitForAutoScalingPlansScalingPlanAvailabilityOnCreate(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int, timeout time.Duration) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{autoscalingplans.ScalingPlanStatusCodeCreationInProgress}, + Target: []string{autoscalingplans.ScalingPlanStatusCodeActive, autoscalingplans.ScalingPlanStatusCodeActiveWithProblems}, + Refresh: autoScalingPlansScalingPlanRefresh(conn, scalingPlanName, scalingPlanVersion), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 5 * time.Second, + } + + _, err := stateConf.WaitForState() + + return err +} + +func waitForAutoScalingPlansScalingPlanAvailabilityOnUpdate(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int, timeout time.Duration) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{autoscalingplans.ScalingPlanStatusCodeUpdateInProgress}, + Target: []string{autoscalingplans.ScalingPlanStatusCodeActive, autoscalingplans.ScalingPlanStatusCodeActiveWithProblems}, + Refresh: autoScalingPlansScalingPlanRefresh(conn, scalingPlanName, scalingPlanVersion), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 5 * time.Second, + } + + _, err := stateConf.WaitForState() + + return err +} + +func waitForAutoScalingPlansScalingPlanDeletion(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int, timeout time.Duration) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{autoscalingplans.ScalingPlanStatusCodeDeletionInProgress}, + Target: []string{autoscalingplansScalingPlanStatusDeleted}, + Refresh: autoScalingPlansScalingPlanRefresh(conn, scalingPlanName, scalingPlanVersion), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 5 * time.Second, + } + + _, err := stateConf.WaitForState() + + return err +} + +// +// ApplicationSource functions. +// + +func expandAutoScalingPlansApplicationSource(vApplicationSource []interface{}) *autoscalingplans.ApplicationSource { + if len(vApplicationSource) == 0 || vApplicationSource[0] == nil { + return nil + } + mApplicationSource := vApplicationSource[0].(map[string]interface{}) + + applicationSource := &autoscalingplans.ApplicationSource{} + + if v, ok := mApplicationSource["cloudformation_stack_arn"].(string); ok && v != "" { + applicationSource.CloudFormationStackARN = aws.String(v) + } + + if vTagFilters, ok := mApplicationSource["tag_filter"].(*schema.Set); ok && vTagFilters.Len() > 0 { + tagFilters := []*autoscalingplans.TagFilter{} + + for _, vTagFilter := range vTagFilters.List() { + tagFilter := &autoscalingplans.TagFilter{} + + mTagFilter := vTagFilter.(map[string]interface{}) + + if v, ok := mTagFilter["key"].(string); ok && v != "" { + tagFilter.Key = aws.String(v) + } + + if vValues, ok := mTagFilter["values"].(*schema.Set); ok && vValues.Len() > 0 { + tagFilter.Values = expandStringSet(vValues) + } + + tagFilters = append(tagFilters, tagFilter) + } + + applicationSource.TagFilters = tagFilters + } + + return applicationSource +} + +func flattenAutoScalingPlansApplicationSource(applicationSource *autoscalingplans.ApplicationSource) []interface{} { + if applicationSource == nil { + return []interface{}{} + } + + mApplicationSource := map[string]interface{}{ + "cloudformation_stack_arn": aws.StringValue(applicationSource.CloudFormationStackARN), + } + + if tagFilters := applicationSource.TagFilters; tagFilters != nil { + vTagFilters := []interface{}{} + + for _, tagFilter := range tagFilters { + mTagFilter := map[string]interface{}{ + "key": aws.StringValue(tagFilter.Key), + "values": flattenStringSet(tagFilter.Values), + } + + vTagFilters = append(vTagFilters, mTagFilter) + } + + mApplicationSource["tag_filter"] = schema.NewSet(autoScalingPlansTagFilterHash, vTagFilters) + } + + return []interface{}{mApplicationSource} +} + +func autoScalingPlansTagFilterHash(vTagFilter interface{}) int { + var buf bytes.Buffer + + mTagFilter := vTagFilter.(map[string]interface{}) + if v, ok := mTagFilter["key"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if vValues, ok := mTagFilter["values"].(*schema.Set); ok { + // The order of the returned elements is deterministic. + for _, v := range vValues.List() { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + } + + return hashcode.String(buf.String()) +} + +// +// ScalingInstruction functions. +// + +func expandAutoScalingPlansScalingInstructions(vScalingInstructions *schema.Set) []*autoscalingplans.ScalingInstruction { + scalingInstructions := []*autoscalingplans.ScalingInstruction{} + + for _, vScalingInstruction := range vScalingInstructions.List() { + mScalingInstruction := vScalingInstruction.(map[string]interface{}) + + scalingInstruction := &autoscalingplans.ScalingInstruction{} + + if v, ok := mScalingInstruction["disable_dynamic_scaling"].(bool); ok { + scalingInstruction.DisableDynamicScaling = aws.Bool(v) + } + if v, ok := mScalingInstruction["max_capacity"].(int); ok { + scalingInstruction.MaxCapacity = aws.Int64(int64(v)) + } + if v, ok := mScalingInstruction["min_capacity"].(int); ok { + scalingInstruction.MinCapacity = aws.Int64(int64(v)) + } + if v, ok := mScalingInstruction["predictive_scaling_max_capacity_behavior"].(string); ok && v != "" { + scalingInstruction.PredictiveScalingMaxCapacityBehavior = aws.String(v) + } + if v, ok := mScalingInstruction["predictive_scaling_max_capacity_buffer"].(int); ok && v > 0 { + scalingInstruction.PredictiveScalingMaxCapacityBuffer = aws.Int64(int64(v)) + } + if v, ok := mScalingInstruction["predictive_scaling_mode"].(string); ok && v != "" { + scalingInstruction.PredictiveScalingMode = aws.String(v) + } + if v, ok := mScalingInstruction["resource_id"].(string); ok && v != "" { + scalingInstruction.ResourceId = aws.String(v) + } + if v, ok := mScalingInstruction["scalable_dimension"].(string); ok && v != "" { + scalingInstruction.ScalableDimension = aws.String(v) + } + if v, ok := mScalingInstruction["scaling_policy_update_behavior"].(string); ok && v != "" { + scalingInstruction.ScalingPolicyUpdateBehavior = aws.String(v) + } + if v, ok := mScalingInstruction["scheduled_action_buffer_time"].(int); ok && v > 0 { + scalingInstruction.ScheduledActionBufferTime = aws.Int64(int64(v)) + } + if v, ok := mScalingInstruction["service_namespace"].(string); ok && v != "" { + scalingInstruction.ServiceNamespace = aws.String(v) + } + + if vCustomizedLoadMetricSpecification, ok := mScalingInstruction["customized_load_metric_specification"].([]interface{}); ok && len(vCustomizedLoadMetricSpecification) > 0 && vCustomizedLoadMetricSpecification[0] != nil { + mCustomizedLoadMetricSpecification := vCustomizedLoadMetricSpecification[0].(map[string]interface{}) + + customizedLoadMetricSpecification := &autoscalingplans.CustomizedLoadMetricSpecification{} + + if v, ok := mCustomizedLoadMetricSpecification["dimensions"].(map[string]interface{}); ok { + dimensions := []*autoscalingplans.MetricDimension{} + + for key, value := range v { + dimension := &autoscalingplans.MetricDimension{} + + dimension.Name = aws.String(key) + dimension.Value = aws.String(value.(string)) + + dimensions = append(dimensions, dimension) + } + + customizedLoadMetricSpecification.Dimensions = dimensions + } + if v, ok := mCustomizedLoadMetricSpecification["metric_name"].(string); ok && v != "" { + customizedLoadMetricSpecification.MetricName = aws.String(v) + } + if v, ok := mCustomizedLoadMetricSpecification["namespace"].(string); ok && v != "" { + customizedLoadMetricSpecification.Namespace = aws.String(v) + } + if v, ok := mCustomizedLoadMetricSpecification["statistic"].(string); ok && v != "" { + customizedLoadMetricSpecification.Statistic = aws.String(v) + } + if v, ok := mCustomizedLoadMetricSpecification["unit"].(string); ok && v != "" { + customizedLoadMetricSpecification.Unit = aws.String(v) + } + + scalingInstruction.CustomizedLoadMetricSpecification = customizedLoadMetricSpecification + } + + if vPredefinedLoadMetricSpecification, ok := mScalingInstruction["predefined_load_metric_specification"].([]interface{}); ok && len(vPredefinedLoadMetricSpecification) > 0 && vPredefinedLoadMetricSpecification[0] != nil { + mPredefinedLoadMetricSpecification := vPredefinedLoadMetricSpecification[0].(map[string]interface{}) + + predefinedLoadMetricSpecification := &autoscalingplans.PredefinedLoadMetricSpecification{} + + if v, ok := mPredefinedLoadMetricSpecification["predefined_load_metric_type"].(string); ok && v != "" { + predefinedLoadMetricSpecification.PredefinedLoadMetricType = aws.String(v) + } + if v, ok := mPredefinedLoadMetricSpecification["resource_label"].(string); ok && v != "" { + predefinedLoadMetricSpecification.ResourceLabel = aws.String(v) + } + + scalingInstruction.PredefinedLoadMetricSpecification = predefinedLoadMetricSpecification + } + + if vTargetTrackingConfigurations, ok := mScalingInstruction["target_tracking_configuration"].(*schema.Set); ok && vTargetTrackingConfigurations.Len() > 0 { + targetTrackingConfigurations := []*autoscalingplans.TargetTrackingConfiguration{} + + for _, vTargetTrackingConfiguration := range vTargetTrackingConfigurations.List() { + targetTrackingConfiguration := &autoscalingplans.TargetTrackingConfiguration{} + + mTargetTrackingConfiguration := vTargetTrackingConfiguration.(map[string]interface{}) + + if v, ok := mTargetTrackingConfiguration["disable_scale_in"].(bool); ok { + targetTrackingConfiguration.DisableScaleIn = aws.Bool(v) + } + if v, ok := mTargetTrackingConfiguration["estimated_instance_warmup"].(int); ok && v > 0 { + targetTrackingConfiguration.EstimatedInstanceWarmup = aws.Int64(int64(v)) + } + if v, ok := mTargetTrackingConfiguration["scale_in_cooldown"].(int); ok && v > 0 { + targetTrackingConfiguration.ScaleInCooldown = aws.Int64(int64(v)) + } + if v, ok := mTargetTrackingConfiguration["scale_out_cooldown"].(int); ok && v > 0 { + targetTrackingConfiguration.ScaleOutCooldown = aws.Int64(int64(v)) + } + if v, ok := mTargetTrackingConfiguration["target_value"].(float64); ok && v > 0.0 { + targetTrackingConfiguration.TargetValue = aws.Float64(v) + } + + if vCustomizedScalingMetricSpecification, ok := mTargetTrackingConfiguration["customized_scaling_metric_specification"].([]interface{}); ok && len(vCustomizedScalingMetricSpecification) > 0 && vCustomizedScalingMetricSpecification[0] != nil { + mCustomizedScalingMetricSpecification := vCustomizedScalingMetricSpecification[0].(map[string]interface{}) + + customizedScalingMetricSpecification := &autoscalingplans.CustomizedScalingMetricSpecification{} + + if v, ok := mCustomizedScalingMetricSpecification["dimensions"].(map[string]interface{}); ok { + dimensions := []*autoscalingplans.MetricDimension{} + + for key, value := range v { + dimension := &autoscalingplans.MetricDimension{} + + dimension.Name = aws.String(key) + dimension.Value = aws.String(value.(string)) + + dimensions = append(dimensions, dimension) + } + + customizedScalingMetricSpecification.Dimensions = dimensions + } + if v, ok := mCustomizedScalingMetricSpecification["metric_name"].(string); ok && v != "" { + customizedScalingMetricSpecification.MetricName = aws.String(v) + } + if v, ok := mCustomizedScalingMetricSpecification["namespace"].(string); ok && v != "" { + customizedScalingMetricSpecification.Namespace = aws.String(v) + } + if v, ok := mCustomizedScalingMetricSpecification["statistic"].(string); ok && v != "" { + customizedScalingMetricSpecification.Statistic = aws.String(v) + } + if v, ok := mCustomizedScalingMetricSpecification["unit"].(string); ok && v != "" { + customizedScalingMetricSpecification.Unit = aws.String(v) + } + + targetTrackingConfiguration.CustomizedScalingMetricSpecification = customizedScalingMetricSpecification + } + + if vPredefinedScalingMetricSpecification, ok := mTargetTrackingConfiguration["predefined_scaling_metric_specification"].([]interface{}); ok && len(vPredefinedScalingMetricSpecification) > 0 && vPredefinedScalingMetricSpecification[0] != nil { + mPredefinedScalingMetricSpecification := vPredefinedScalingMetricSpecification[0].(map[string]interface{}) + + predefinedScalingMetricSpecification := &autoscalingplans.PredefinedScalingMetricSpecification{} + + if v, ok := mPredefinedScalingMetricSpecification["predefined_scaling_metric_type"].(string); ok && v != "" { + predefinedScalingMetricSpecification.PredefinedScalingMetricType = aws.String(v) + } + if v, ok := mPredefinedScalingMetricSpecification["resource_label"].(string); ok && v != "" { + predefinedScalingMetricSpecification.ResourceLabel = aws.String(v) + } + + targetTrackingConfiguration.PredefinedScalingMetricSpecification = predefinedScalingMetricSpecification + } + + targetTrackingConfigurations = append(targetTrackingConfigurations, targetTrackingConfiguration) + } + + scalingInstruction.TargetTrackingConfigurations = targetTrackingConfigurations + } + + scalingInstructions = append(scalingInstructions, scalingInstruction) + } + + return scalingInstructions +} + +func flattenAutoScalingPlansScalingInstructions(scalingInstructions []*autoscalingplans.ScalingInstruction) *schema.Set { + vScalingInstructions := []interface{}{} + + for _, scalingInstruction := range scalingInstructions { + mScalingInstruction := map[string]interface{}{ + "disable_dynamic_scaling": aws.BoolValue(scalingInstruction.DisableDynamicScaling), + "max_capacity": int(aws.Int64Value(scalingInstruction.MaxCapacity)), + "min_capacity": int(aws.Int64Value(scalingInstruction.MinCapacity)), + "predictive_scaling_max_capacity_behavior": aws.StringValue(scalingInstruction.PredictiveScalingMaxCapacityBehavior), + "predictive_scaling_max_capacity_buffer": int(aws.Int64Value(scalingInstruction.PredictiveScalingMaxCapacityBuffer)), + "predictive_scaling_mode": aws.StringValue(scalingInstruction.PredictiveScalingMode), + "resource_id": aws.StringValue(scalingInstruction.ResourceId), + "scalable_dimension": aws.StringValue(scalingInstruction.ScalableDimension), + "scaling_policy_update_behavior": aws.StringValue(scalingInstruction.ScalingPolicyUpdateBehavior), + "scheduled_action_buffer_time": int(aws.Int64Value(scalingInstruction.ScheduledActionBufferTime)), + "service_namespace": aws.StringValue(scalingInstruction.ServiceNamespace), + } + + if customizedLoadMetricSpecification := scalingInstruction.CustomizedLoadMetricSpecification; customizedLoadMetricSpecification != nil { + mDimensions := map[string]interface{}{} + for _, dimension := range customizedLoadMetricSpecification.Dimensions { + mDimensions[aws.StringValue(dimension.Name)] = aws.StringValue(dimension.Value) + } + + mScalingInstruction["customized_load_metric_specification"] = []interface{}{ + map[string]interface{}{ + "dimensions": mDimensions, + "metric_name": aws.StringValue(customizedLoadMetricSpecification.MetricName), + "namespace": aws.StringValue(customizedLoadMetricSpecification.Namespace), + "statistic": aws.StringValue(customizedLoadMetricSpecification.Statistic), + "unit": aws.StringValue(customizedLoadMetricSpecification.Unit), + }, + } + } + + if predefinedLoadMetricSpecification := scalingInstruction.PredefinedLoadMetricSpecification; predefinedLoadMetricSpecification != nil { + mScalingInstruction["predefined_load_metric_specification"] = []interface{}{ + map[string]interface{}{ + "predefined_load_metric_type": aws.StringValue(predefinedLoadMetricSpecification.PredefinedLoadMetricType), + "resource_label": aws.StringValue(predefinedLoadMetricSpecification.ResourceLabel), + }, + } + } + + if targetTrackingConfigurations := scalingInstruction.TargetTrackingConfigurations; targetTrackingConfigurations != nil { + vTargetTrackingConfigurations := []interface{}{} + + for _, targetTrackingConfiguration := range targetTrackingConfigurations { + mTargetTrackingConfiguration := map[string]interface{}{ + "disable_scale_in": aws.BoolValue(targetTrackingConfiguration.DisableScaleIn), + "estimated_instance_warmup": int(aws.Int64Value(targetTrackingConfiguration.EstimatedInstanceWarmup)), + "scale_in_cooldown": int(aws.Int64Value(targetTrackingConfiguration.ScaleInCooldown)), + "scale_out_cooldown": int(aws.Int64Value(targetTrackingConfiguration.ScaleOutCooldown)), + "target_value": aws.Float64Value(targetTrackingConfiguration.TargetValue), + } + + if customizedScalingMetricSpecification := targetTrackingConfiguration.CustomizedScalingMetricSpecification; customizedScalingMetricSpecification != nil { + mDimensions := map[string]interface{}{} + for _, dimension := range customizedScalingMetricSpecification.Dimensions { + mDimensions[aws.StringValue(dimension.Name)] = aws.StringValue(dimension.Value) + } + + mTargetTrackingConfiguration["customized_scaling_metric_specification"] = []interface{}{ + map[string]interface{}{ + "dimensions": mDimensions, + "metric_name": aws.StringValue(customizedScalingMetricSpecification.MetricName), + "namespace": aws.StringValue(customizedScalingMetricSpecification.Namespace), + "statistic": aws.StringValue(customizedScalingMetricSpecification.Statistic), + "unit": aws.StringValue(customizedScalingMetricSpecification.Unit), + }, + } + } + + if predefinedScalingMetricSpecification := targetTrackingConfiguration.PredefinedScalingMetricSpecification; predefinedScalingMetricSpecification != nil { + mTargetTrackingConfiguration["predefined_scaling_metric_specification"] = []interface{}{ + map[string]interface{}{ + "predefined_scaling_metric_type": aws.StringValue(predefinedScalingMetricSpecification.PredefinedScalingMetricType), + "resource_label": aws.StringValue(predefinedScalingMetricSpecification.ResourceLabel), + }, + } + } + + vTargetTrackingConfigurations = append(vTargetTrackingConfigurations, mTargetTrackingConfiguration) + } + + mScalingInstruction["target_tracking_configuration"] = schema.NewSet(autoScalingPlansTargetTrackingConfigurationHash, vTargetTrackingConfigurations) + } + + vScalingInstructions = append(vScalingInstructions, mScalingInstruction) + } + + return schema.NewSet(autoScalingPlansScalingInstructionHash, vScalingInstructions) +} + +func autoScalingPlansScalingInstructionHash(vScalingInstruction interface{}) int { + var buf bytes.Buffer + + mScalingInstruction := vScalingInstruction.(map[string]interface{}) + if vCustomizedLoadMetricSpecification, ok := mScalingInstruction["customized_load_metric_specification"].([]interface{}); ok && len(vCustomizedLoadMetricSpecification) > 0 && vCustomizedLoadMetricSpecification[0] != nil { + mCustomizedLoadMetricSpecification := vCustomizedLoadMetricSpecification[0].(map[string]interface{}) + if v, ok := mCustomizedLoadMetricSpecification["dimensions"].(map[string]interface{}); ok { + buf.WriteString(fmt.Sprintf("%d-", stableMapHash(v))) + } + if v, ok := mCustomizedLoadMetricSpecification["metric_name"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if v, ok := mCustomizedLoadMetricSpecification["namespace"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if v, ok := mCustomizedLoadMetricSpecification["statistic"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if v, ok := mCustomizedLoadMetricSpecification["unit"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + } + if v, ok := mScalingInstruction["disable_dynamic_scaling"].(bool); ok { + buf.WriteString(fmt.Sprintf("%t-", v)) + } + if v, ok := mScalingInstruction["max_capacity"].(int); ok { + buf.WriteString(fmt.Sprintf("%d-", v)) + } + if v, ok := mScalingInstruction["min_capacity"].(int); ok { + buf.WriteString(fmt.Sprintf("%d-", v)) + } + if vPredefinedLoadMetricSpecification, ok := mScalingInstruction["predefined_load_metric_specification"].([]interface{}); ok && len(vPredefinedLoadMetricSpecification) > 0 && vPredefinedLoadMetricSpecification[0] != nil { + mPredefinedLoadMetricSpecification := vPredefinedLoadMetricSpecification[0].(map[string]interface{}) + if v, ok := mPredefinedLoadMetricSpecification["predefined_load_metric_type"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if v, ok := mPredefinedLoadMetricSpecification["resource_label"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + } + if v, ok := mScalingInstruction["predictive_scaling_max_capacity_behavior"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if v, ok := mScalingInstruction["predictive_scaling_max_capacity_buffer"].(int); ok { + buf.WriteString(fmt.Sprintf("%d-", v)) + } + if v, ok := mScalingInstruction["predictive_scaling_mode"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if v, ok := mScalingInstruction["resource_id"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if v, ok := mScalingInstruction["scalable_dimension"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if v, ok := mScalingInstruction["scaling_policy_update_behavior"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if v, ok := mScalingInstruction["scheduled_action_buffer_time"].(int); ok { + buf.WriteString(fmt.Sprintf("%d-", v)) + } + if v, ok := mScalingInstruction["service_namespace"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if vTargetTrackingConfigurations, ok := mScalingInstruction["target_tracking_configuration"].(*schema.Set); ok { + // The order of the returned elements is deterministic. + for _, v := range vTargetTrackingConfigurations.List() { + buf.WriteString(fmt.Sprintf("%d-", autoScalingPlansTargetTrackingConfigurationHash(v))) + } + } + + return hashcode.String(buf.String()) +} + +func autoScalingPlansTargetTrackingConfigurationHash(vTargetTrackingConfiguration interface{}) int { + var buf bytes.Buffer + + mTargetTrackingConfiguration := vTargetTrackingConfiguration.(map[string]interface{}) + if vCustomizedScalingMetricSpecification, ok := mTargetTrackingConfiguration["customized_scaling_metric_specification"].([]interface{}); ok && len(vCustomizedScalingMetricSpecification) > 0 && vCustomizedScalingMetricSpecification[0] != nil { + mCustomizedScalingMetricSpecification := vCustomizedScalingMetricSpecification[0].(map[string]interface{}) + if v, ok := mCustomizedScalingMetricSpecification["dimensions"].(map[string]interface{}); ok { + buf.WriteString(fmt.Sprintf("%d-", stableMapHash(v))) + } + if v, ok := mCustomizedScalingMetricSpecification["metric_name"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if v, ok := mCustomizedScalingMetricSpecification["namespace"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if v, ok := mCustomizedScalingMetricSpecification["statistic"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if v, ok := mCustomizedScalingMetricSpecification["unit"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + } + if v, ok := mTargetTrackingConfiguration["disable_scale_in"].(bool); ok { + buf.WriteString(fmt.Sprintf("%t-", v)) + } + if v, ok := mTargetTrackingConfiguration["estimated_instance_warmup"].(int); ok { + buf.WriteString(fmt.Sprintf("%d-", v)) + } + if vPredefinedScalingMetricSpecification, ok := mTargetTrackingConfiguration["predefined_scaling_metric_specification"].([]interface{}); ok && len(vPredefinedScalingMetricSpecification) > 0 && vPredefinedScalingMetricSpecification[0] != nil { + mPredefinedScalingMetricSpecification := vPredefinedScalingMetricSpecification[0].(map[string]interface{}) + if v, ok := mPredefinedScalingMetricSpecification["predefined_scaling_metric_type"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + if v, ok := mPredefinedScalingMetricSpecification["resource_label"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + } + if v, ok := mTargetTrackingConfiguration["scale_in_cooldown"].(int); ok { + buf.WriteString(fmt.Sprintf("%d-", v)) + } + if v, ok := mTargetTrackingConfiguration["scale_out_cooldown"].(int); ok { + buf.WriteString(fmt.Sprintf("%d-", v)) + } + if v, ok := mTargetTrackingConfiguration["target_value"].(float64); ok { + buf.WriteString(fmt.Sprintf("%g-", v)) + } + + return hashcode.String(buf.String()) +} + +// stableMapHash returns a stable hash value for a map. +func stableMapHash(m map[string]interface{}) int { + // Go map iterator is random. + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + + hash := 0 + for _, k := range keys { + hash = hash ^ hashcode.String(fmt.Sprintf("%s-%s", k, m[k])) + } + + return hash +} diff --git a/aws/resource_aws_autoscalingplans_scaling_plan_test.go b/aws/resource_aws_autoscalingplans_scaling_plan_test.go new file mode 100644 index 000000000000..01e95199432b --- /dev/null +++ b/aws/resource_aws_autoscalingplans_scaling_plan_test.go @@ -0,0 +1,521 @@ +package aws + +import ( + "fmt" + "log" + "reflect" + "regexp" + "sort" + "strconv" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/autoscalingplans" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func init() { + resource.AddTestSweepers("aws_autoscalingplans_scaling_plan", &resource.Sweeper{ + Name: "aws_autoscalingplans_scaling_plan", + F: testSweepAutoScalingPlansScalingPlans, + }) +} + +func testSweepAutoScalingPlansScalingPlans(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.(*AWSClient).autoscalingplansconn + + input := &autoscalingplans.DescribeScalingPlansInput{} + for { + output, err := conn.DescribeScalingPlans(input) + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping Auto Scaling scaling plan sweep for %s: %s", region, err) + return nil + } + if err != nil { + return fmt.Errorf("error listing Auto Scaling scaling plans: %s", err) + } + + for _, scalingPlan := range output.ScalingPlans { + scalingPlanName := aws.StringValue(scalingPlan.ScalingPlanName) + scalingPlanVersion := int(aws.Int64Value(scalingPlan.ScalingPlanVersion)) + + _, err := conn.DeleteScalingPlan(&autoscalingplans.DeleteScalingPlanInput{ + ScalingPlanName: aws.String(scalingPlanName), + ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), + }) + if isAWSErr(err, autoscalingplans.ErrCodeObjectNotFoundException, "") { + continue + } + if err != nil { + return fmt.Errorf("error deleting Auto Scaling scaling plan (%s): %s", scalingPlanName, err) + } + + if err := waitForAutoScalingPlansScalingPlanDeletion(conn, scalingPlanName, scalingPlanVersion, 5*time.Minute); err != nil { + return fmt.Errorf("error waiting for Auto Scaling scaling plan (%s) to be deleted: %s", scalingPlanName, err) + } + } + + if aws.StringValue(output.NextToken) == "" { + break + } + input.NextToken = output.NextToken + } + + return nil +} + +func TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling(t *testing.T) { + var scalingPlan autoscalingplans.ScalingPlan + resourceIdMap := map[string]string{} + resourceName := "aws_autoscalingplans_scaling_plan.test" + asgName := fmt.Sprintf("tf-testacc-asg-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) + asgResourceId := fmt.Sprintf("autoScalingGroup/%s", asgName) + scalingPlanName := fmt.Sprintf("tf-testacc-scalingplan-%s", acctest.RandStringFromCharSet(9, acctest.CharSetAlphaNum)) + // Application source must be unique across scaling plans. + tagKey := fmt.Sprintf("tf-testacc-key-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) + tagValue := fmt.Sprintf("tf-testacc-value-%s", acctest.RandStringFromCharSet(15, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(asgName, scalingPlanName, tagKey, tagValue), + Check: resource.ComposeTestCheckFunc( + testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), + resource.TestCheckResourceAttr(resourceName, "name", scalingPlanName), + resource.TestCheckResourceAttr(resourceName, "scaling_plan_version", "1"), + resource.TestCheckResourceAttr(resourceName, "application_source.#", "1"), + resource.TestCheckResourceAttr(resourceName, "application_source.0.cloudformation_stack_arn", ""), + testAccCheckAutoScalingPlansApplicationSourceTags(&scalingPlan, map[string][]string{ + tagKey: {tagValue}, + }), + resource.TestCheckResourceAttr(resourceName, "scaling_instruction.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "customized_load_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "disable_dynamic_scaling", "false"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "max_capacity", "3"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "min_capacity", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_behavior", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_buffer", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_mode", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "resource_id", asgResourceId), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scalable_dimension", "autoscaling:autoScalingGroup:DesiredCapacity"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scaling_policy_update_behavior", "KeepExternalPolicies"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scheduled_action_buffer_time", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "service_namespace", "autoscaling"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.customized_scaling_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.disable_scale_in", "false"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.estimated_instance_warmup", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.resource_label", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_in_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_out_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.target_value", "75"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + return scalingPlanName, nil + }, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling(t *testing.T) { + var scalingPlan autoscalingplans.ScalingPlan + resourceIdMap := map[string]string{} + resourceName := "aws_autoscalingplans_scaling_plan.test" + asgName := fmt.Sprintf("tf-testacc-asg-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) + asgResourceId := fmt.Sprintf("autoScalingGroup/%s", asgName) + scalingPlanName := fmt.Sprintf("tf-testacc-scalingplan-%s", acctest.RandStringFromCharSet(9, acctest.CharSetAlphaNum)) + // Application source must be unique across scaling plans. + tagKey := fmt.Sprintf("tf-testacc-key-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) + tagValue := fmt.Sprintf("tf-testacc-value-%s", acctest.RandStringFromCharSet(15, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAutoScalingPlansScalingPlanConfig_basicPredictiveScaling(asgName, scalingPlanName, tagKey, tagValue), + Check: resource.ComposeTestCheckFunc( + testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), + resource.TestCheckResourceAttr(resourceName, "name", scalingPlanName), + resource.TestCheckResourceAttr(resourceName, "scaling_plan_version", "1"), + resource.TestCheckResourceAttr(resourceName, "application_source.#", "1"), + resource.TestCheckResourceAttr(resourceName, "application_source.0.cloudformation_stack_arn", ""), + testAccCheckAutoScalingPlansApplicationSourceTags(&scalingPlan, map[string][]string{ + tagKey: {tagValue}, + }), + resource.TestCheckResourceAttr(resourceName, "scaling_instruction.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "customized_load_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "disable_dynamic_scaling", "true"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "max_capacity", "3"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "min_capacity", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.0.predefined_load_metric_type", "ASGTotalCPUUtilization"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.0.resource_label", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_behavior", "SetForecastCapacityToMaxCapacity"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_buffer", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_mode", "ForecastOnly"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "resource_id", asgResourceId), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scalable_dimension", "autoscaling:autoScalingGroup:DesiredCapacity"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scaling_policy_update_behavior", "KeepExternalPolicies"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scheduled_action_buffer_time", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "service_namespace", "autoscaling"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.customized_scaling_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.disable_scale_in", "false"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.estimated_instance_warmup", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.resource_label", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_in_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_out_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.target_value", "75"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + return scalingPlanName, nil + }, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { + var scalingPlan autoscalingplans.ScalingPlan + resourceIdMap := map[string]string{} + resourceName := "aws_autoscalingplans_scaling_plan.test" + asgName := fmt.Sprintf("tf-testacc-asg-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) + asgResourceId := fmt.Sprintf("autoScalingGroup/%s", asgName) + scalingPlanName := fmt.Sprintf("tf-testacc-scalingplan-%s", acctest.RandStringFromCharSet(9, acctest.CharSetAlphaNum)) + // Application source must be unique across scaling plans. + tagKey1 := fmt.Sprintf("tf-testacc-key-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) + tagValue1 := fmt.Sprintf("tf-testacc-value-%s", acctest.RandStringFromCharSet(15, acctest.CharSetAlphaNum)) + tagKey2 := fmt.Sprintf("tf-testacc-key-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) + tagValue2 := fmt.Sprintf("tf-testacc-value-%s", acctest.RandStringFromCharSet(15, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(asgName, scalingPlanName, tagKey1, tagValue1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), + resource.TestCheckResourceAttr(resourceName, "name", scalingPlanName), + resource.TestCheckResourceAttr(resourceName, "scaling_plan_version", "1"), + resource.TestCheckResourceAttr(resourceName, "application_source.#", "1"), + resource.TestCheckResourceAttr(resourceName, "application_source.0.cloudformation_stack_arn", ""), + testAccCheckAutoScalingPlansApplicationSourceTags(&scalingPlan, map[string][]string{ + tagKey1: {tagValue1}, + }), + resource.TestCheckResourceAttr(resourceName, "scaling_instruction.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "customized_load_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "disable_dynamic_scaling", "false"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "max_capacity", "3"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "min_capacity", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_behavior", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_buffer", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_mode", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "resource_id", asgResourceId), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scalable_dimension", "autoscaling:autoScalingGroup:DesiredCapacity"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scaling_policy_update_behavior", "KeepExternalPolicies"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scheduled_action_buffer_time", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "service_namespace", "autoscaling"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.customized_scaling_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.disable_scale_in", "false"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.estimated_instance_warmup", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.resource_label", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_in_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_out_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.target_value", "75"), + ), + }, + { + Config: testAccAutoScalingPlansScalingPlanConfig_basicPredictiveScaling(asgName, scalingPlanName, tagKey2, tagValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), + resource.TestCheckResourceAttr(resourceName, "name", scalingPlanName), + resource.TestCheckResourceAttr(resourceName, "scaling_plan_version", "1"), + resource.TestCheckResourceAttr(resourceName, "application_source.#", "1"), + resource.TestCheckResourceAttr(resourceName, "application_source.0.cloudformation_stack_arn", ""), + testAccCheckAutoScalingPlansApplicationSourceTags(&scalingPlan, map[string][]string{ + tagKey2: {tagValue2}, + }), + resource.TestCheckResourceAttr(resourceName, "scaling_instruction.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "customized_load_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "disable_dynamic_scaling", "true"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "max_capacity", "3"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "min_capacity", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.0.predefined_load_metric_type", "ASGTotalCPUUtilization"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.0.resource_label", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_behavior", "SetForecastCapacityToMaxCapacity"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_buffer", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_mode", "ForecastOnly"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "resource_id", asgResourceId), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scalable_dimension", "autoscaling:autoScalingGroup:DesiredCapacity"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scaling_policy_update_behavior", "KeepExternalPolicies"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scheduled_action_buffer_time", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "service_namespace", "autoscaling"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.customized_scaling_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.disable_scale_in", "false"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.estimated_instance_warmup", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.resource_label", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_in_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_out_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.target_value", "75"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + return scalingPlanName, nil + }, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckAutoScalingPlansScalingPlanDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).autoscalingplansconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_autoscalingplans_scaling_plan" { + continue + } + + scalingPlanVersion, err := strconv.Atoi(rs.Primary.Attributes["scaling_plan_version"]) + if err != nil { + return err + } + + resp, err := conn.DescribeScalingPlans(&autoscalingplans.DescribeScalingPlansInput{ + ScalingPlanNames: aws.StringSlice([]string{rs.Primary.Attributes["name"]}), + ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), + }) + if err != nil { + return err + } + if len(resp.ScalingPlans) == 0 { + continue + } + return fmt.Errorf("still exist.") + } + + return nil +} + +func testAccCheckAutoScalingPlansScalingPlanExists(name string, scalingPlan *autoscalingplans.ScalingPlan, resourceIdMap *map[string]string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).autoscalingplansconn + + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + scalingPlanVersion, err := strconv.Atoi(rs.Primary.Attributes["scaling_plan_version"]) + if err != nil { + return err + } + + resp, err := conn.DescribeScalingPlans(&autoscalingplans.DescribeScalingPlansInput{ + ScalingPlanNames: aws.StringSlice([]string{rs.Primary.Attributes["name"]}), + ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), + }) + if err != nil { + return err + } + if len(resp.ScalingPlans) == 0 { + return fmt.Errorf("Not found: %s", name) + } + + *scalingPlan = *resp.ScalingPlans[0] + + // Build map of resource_id to scaling_plan hash value. + re := regexp.MustCompile(`^scaling_instruction\.(\d+)\.resource_id$`) + for k, v := range rs.Primary.Attributes { + matches := re.FindStringSubmatch(k) + if matches != nil { + (*resourceIdMap)[v] = matches[1] + } + } + + return nil + } +} + +func testAccCheckAutoScalingPlansApplicationSourceTags(scalingPlan *autoscalingplans.ScalingPlan, expectedTagFilters map[string][]string) resource.TestCheckFunc { + return func(s *terraform.State) error { + for _, tagFilter := range scalingPlan.ApplicationSource.TagFilters { + key := aws.StringValue(tagFilter.Key) + values := aws.StringValueSlice(tagFilter.Values) + + expectedValues, ok := expectedTagFilters[key] + if !ok { + return fmt.Errorf("Scaling plan application source tag filter key %q not expected", key) + } + + sort.Strings(values) + sort.Strings(expectedValues) + if !reflect.DeepEqual(values, expectedValues) { + return fmt.Errorf("Scaling plan application source tag filter values %q, expected %q", values, expectedValues) + } + } + + return nil + } +} + +func testAccCheckAutoScalingPlansScalingPlanAttr(name string, resourceIdMap *map[string]string, resourceId, key, value string) resource.TestCheckFunc { + return func(s *terraform.State) error { + return resource.TestCheckResourceAttr(name, fmt.Sprintf("scaling_instruction.%s.%s", (*resourceIdMap)[resourceId], key), value)(s) + } +} + +func testAccAutoScalingPlansScalingPlanConfig_asg(asgName, tagKey, tagValue string) string { + return fmt.Sprintf(` +data "aws_ami" "test" { + most_recent = true + owners = ["amazon"] + + filter { + name = "name" + values = ["amzn-ami-hvm-*-x86_64-gp2"] + } +} + +resource "aws_launch_configuration" "test" { + image_id = "${data.aws_ami.test.id}" + instance_type = "t2.micro" +} + +data "aws_availability_zones" "available" {} + +resource "aws_autoscaling_group" "test" { + name = %[1]q + + launch_configuration = "${aws_launch_configuration.test.name}" + availability_zones = ["${data.aws_availability_zones.available.names[0]}"] + + min_size = 0 + max_size = 3 + desired_capacity = 0 + + tags = [ + { + key = %[2]q + value = %[3]q + propagate_at_launch = true + }, + ] +} +`, asgName, tagKey, tagValue) +} + +func testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(asgName, scalingPlanName, tagKey, tagValue string) string { + return testAccAutoScalingPlansScalingPlanConfig_asg(asgName, tagKey, tagValue) + fmt.Sprintf(` +resource "aws_autoscalingplans_scaling_plan" "test" { + name = %[1]q + + application_source { + tag_filter { + key = %[2]q + values = [%[3]q] + } + } + + scaling_instruction { + max_capacity = "${aws_autoscaling_group.test.max_size}" + min_capacity = "${aws_autoscaling_group.test.min_size}" + resource_id = "${format("autoScalingGroup/%%s", aws_autoscaling_group.test.name)}" + scalable_dimension = "autoscaling:autoScalingGroup:DesiredCapacity" + service_namespace = "autoscaling" + + target_tracking_configuration { + predefined_scaling_metric_specification { + predefined_scaling_metric_type = "ASGAverageCPUUtilization" + } + + target_value = 75 + } + } +} +`, scalingPlanName, tagKey, tagValue) +} + +func testAccAutoScalingPlansScalingPlanConfig_basicPredictiveScaling(asgName, scalingPlanName, tagKey, tagValue string) string { + return testAccAutoScalingPlansScalingPlanConfig_asg(asgName, tagKey, tagValue) + fmt.Sprintf(` +resource "aws_autoscalingplans_scaling_plan" "test" { + name = %[1]q + + application_source { + tag_filter { + key = %[2]q + values = [%[3]q] + } + } + + scaling_instruction { + disable_dynamic_scaling = true + + max_capacity = "${aws_autoscaling_group.test.max_size}" + min_capacity = "${aws_autoscaling_group.test.min_size}" + resource_id = "${format("autoScalingGroup/%%s", aws_autoscaling_group.test.name)}" + scalable_dimension = "autoscaling:autoScalingGroup:DesiredCapacity" + service_namespace = "autoscaling" + + target_tracking_configuration { + predefined_scaling_metric_specification { + predefined_scaling_metric_type = "ASGAverageCPUUtilization" + } + + target_value = 75 + } + + predictive_scaling_max_capacity_behavior = "SetForecastCapacityToMaxCapacity" + predictive_scaling_mode = "ForecastOnly" + + predefined_load_metric_specification { + predefined_load_metric_type = "ASGTotalCPUUtilization" + } + } +} +`, scalingPlanName, tagKey, tagValue) +} diff --git a/aws/validators.go b/aws/validators.go index 12ae9401c9e1..5fb3b54619c5 100644 --- a/aws/validators.go +++ b/aws/validators.go @@ -32,6 +32,26 @@ var awsAccountIDRegexp = regexp.MustCompile(awsAccountIDRegexpPattern) var awsPartitionRegexp = regexp.MustCompile(awsPartitionRegexpPattern) var awsRegionRegexp = regexp.MustCompile(awsRegionRegexpPattern) +// validateStringDoesNotContainAny returns a SchemaValidateFunc which validates that the +// provided value does not contain any of the specified Unicode code points in chars. +// This function should be migrated to the Terraform Provider SDK. +func validateStringDoesNotContainAny(chars string) schema.SchemaValidateFunc { + return func(i interface{}, k string) (s []string, es []error) { + v, ok := i.(string) + if !ok { + es = append(es, fmt.Errorf("expected type of %s to be string", k)) + return + } + + if strings.ContainsAny(v, chars) { + es = append(es, fmt.Errorf("expected value of %s to not contain any of %q", k, chars)) + return + } + + return + } +} + // validateTypeStringNullableBoolean provides custom error messaging for TypeString booleans // Some arguments require three values: true, false, and "" (unspecified). // This ValidateFunc returns a custom message since the message with diff --git a/aws/validators_test.go b/aws/validators_test.go index 9439b384c914..4139fca932e5 100644 --- a/aws/validators_test.go +++ b/aws/validators_test.go @@ -10,6 +10,34 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" ) +func TestValidateStringDoesNotContainAny(t *testing.T) { + chars := "|:/" + + validStrings := []string{ + "HelloWorld", + "ABC_*&^%123", + } + for _, v := range validStrings { + _, errors := validateStringDoesNotContainAny(chars)(v, "name") + if len(errors) != 0 { + t.Fatalf("%q should not contain any of %q", v, chars) + } + } + + invalidStrings := []string{ + "Hello/World", + "ABC|123", + "This will fail:", + chars, + } + for _, v := range invalidStrings { + _, errors := validateStringDoesNotContainAny(chars)(v, "name") + if len(errors) == 0 { + t.Fatalf("%q should contain one of %q", v, chars) + } + } +} + func TestValidateTypeStringNullableBoolean(t *testing.T) { testCases := []struct { val interface{} diff --git a/website/docs/r/autoscalingplans_scaling_plan.html.markdown b/website/docs/r/autoscalingplans_scaling_plan.html.markdown new file mode 100644 index 000000000000..97e88e0f3394 --- /dev/null +++ b/website/docs/r/autoscalingplans_scaling_plan.html.markdown @@ -0,0 +1,229 @@ +--- +layout: "aws" +page_title: "AWS: aws_autoscalingplans_scaling_plan" +sidebar_current: "docs-aws-resource-autoscalingplans-scaling-plan" +description: |- + Manages an AWS Auto Scaling scaling plan. +--- + +# Resource: aws_autoscalingplans_scaling_plan + +Manages an AWS Auto Scaling scaling plan. +More information can be found in the [AWS Auto Scaling User Guide](https://docs.aws.amazon.com/autoscaling/plans/userguide/what-is-aws-auto-scaling.html). + +## Example Usage + +### Basic Dynamic Scaling + +```hcl +data "aws_availability_zones" "available" {} + +resource "aws_autoscaling_group" "example" { + name_prefix = "example" + + launch_configuration = "${aws_launch_configuration.example.name}" + availability_zones = ["${data.aws_availability_zones.available.names[0]}"] + + min_size = 0 + max_size = 3 + + tags = [ + { + key = "application" + value = "example" + propagate_at_launch = true + }, + ] +} + +resource "aws_autoscalingplans_scaling_plan" "example" { + name = "example-dynamic-cost-optimization" + + application_source { + tag_filter { + key = "application" + values = ["example"] + } + } + + scaling_instruction { + max_capacity = 3 + min_capacity = 0 + resource_id = "${format("autoScalingGroup/%s", aws_autoscaling_group.example.name)}" + scalable_dimension = "autoscaling:autoScalingGroup:DesiredCapacity" + service_namespace = "autoscaling" + + target_tracking_configuration { + predefined_scaling_metric_specification { + predefined_scaling_metric_type = "ASGAverageCPUUtilization" + } + + target_value = 70 + } + } +} +``` + +### Basic Predictive Scaling + +```hcl +data "aws_availability_zones" "available" {} + +resource "aws_autoscaling_group" "example" { + name_prefix = "example" + + launch_configuration = "${aws_launch_configuration.example.name}" + availability_zones = ["${data.aws_availability_zones.available.names[0]}"] + + min_size = 0 + max_size = 3 + + tags = [ + { + key = "application" + value = "example" + propagate_at_launch = true + }, + ] +} + +resource "aws_autoscalingplans_scaling_plan" "example" { + name = "example-predictive-cost-optimization" + + application_source { + tag_filter { + key = "application" + values = ["example"] + } + } + + scaling_instruction { + disable_dynamic_scaling = true + + max_capacity = 3 + min_capacity = 0 + resource_id = "${format("autoScalingGroup/%s", aws_autoscaling_group.example.name)}" + scalable_dimension = "autoscaling:autoScalingGroup:DesiredCapacity" + service_namespace = "autoscaling" + + target_tracking_configuration { + predefined_scaling_metric_specification { + predefined_scaling_metric_type = "ASGAverageCPUUtilization" + } + + target_value = 70 + } + + predictive_scaling_max_capacity_behavior = "SetForecastCapacityToMaxCapacity" + predictive_scaling_mode = "ForecastAndScale" + + predefined_load_metric_specification { + predefined_load_metric_type = "ASGTotalCPUUtilization" + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the scaling plan. Names cannot contain vertical bars, colons, or forward slashes. +* `application_source` - (Required) A CloudFormation stack or set of tags. You can create one scaling plan per application source. +* `scaling_instruction` - (Required) The scaling instructions. More details can be found in the [AWS Auto Scaling API Reference](https://docs.aws.amazon.com/autoscaling/plans/APIReference/API_ScalingInstruction.html). + +The `application_source` object supports the following: + +* `cloudformation_stack_arn` - (Optional) The Amazon Resource Name (ARN) of a AWS CloudFormation stack. +* `tag_filter` - (Optional) A set of tags. + +The `tag_filter` object supports the following: + +* `key` - (Required) The tag key. +* `values` - (Optional) The tag values. + +The `scaling_instruction` object supports the following: + +* `max_capacity` - (Required) The maximum capacity of the resource. The exception to this upper limit is if you specify a non-default setting for `predictive_scaling_max_capacity_behavior`. +* `min_capacity` - (Required) The minimum capacity of the resource. +* `resource_id` - (Required) The ID of the resource. This string consists of the resource type and unique identifier. +* `scalable_dimension` - (Required) The scalable dimension associated with the resource. Valid values: `autoscaling:autoScalingGroup:DesiredCapacity`, `dynamodb:index:ReadCapacityUnits`, `dynamodb:index:WriteCapacityUnits`, `dynamodb:table:ReadCapacityUnits`, `dynamodb:table:WriteCapacityUnits`, `ecs:service:DesiredCount`, `ec2:spot-fleet-request:TargetCapacity`, `rds:cluster:ReadReplicaCount`. +* `service_namespace` - (Required) The namespace of the AWS service. Valid values: `autoscaling`, `dynamodb`, `ecs`, `ec2`, `rds`. +* `target_tracking_configuration` - (Required) The structure that defines new target tracking configurations. Each of these structures includes a specific scaling metric and a target value for the metric, along with various parameters to use with dynamic scaling. +More details can be found in the [AWS Auto Scaling API Reference](https://docs.aws.amazon.com/autoscaling/plans/APIReference/API_TargetTrackingConfiguration.html). +* `customized_load_metric_specification` - (Optional) The customized load metric to use for predictive scaling. You must specify either `customized_load_metric_specification` or `predefined_load_metric_specification` when configuring predictive scaling. +More details can be found in the [AWS Auto Scaling API Reference](https://docs.aws.amazon.com/autoscaling/plans/APIReference/API_CustomizedLoadMetricSpecification.html). +* `disable_dynamic_scaling` - (Optional) Boolean controlling whether dynamic scaling by AWS Auto Scaling is disabled. Defaults to `false`. +* `predefined_load_metric_specification` - (Optional) The predefined load metric to use for predictive scaling. You must specify either `predefined_load_metric_specification` or `customized_load_metric_specification` when configuring predictive scaling. +More details can be found in the [AWS Auto Scaling API Reference](https://docs.aws.amazon.com/autoscaling/plans/APIReference/API_PredefinedLoadMetricSpecification.html). +* `predictive_scaling_max_capacity_behavior`- (Optional) Defines the behavior that should be applied if the forecast capacity approaches or exceeds the maximum capacity specified for the resource. +Valid values: `SetForecastCapacityToMaxCapacity`, `SetMaxCapacityAboveForecastCapacity`, `SetMaxCapacityToForecastCapacity`. +* `predictive_scaling_max_capacity_buffer` - (Optional) The size of the capacity buffer to use when the forecast capacity is close to or exceeds the maximum capacity. +* `predictive_scaling_mode` - (Optional) The predictive scaling mode. Valid values: `ForecastAndScale`, `ForecastOnly`. +* `scaling_policy_update_behavior` - (Optional) Controls whether a resource's externally created scaling policies are kept or replaced. Valid values: `KeepExternalPolicies`, `ReplaceExternalPolicies`. Defaults to `KeepExternalPolicies`. +* `scheduled_action_buffer_time` - (Optional) The amount of time, in seconds, to buffer the run time of scheduled scaling actions when scaling out. + +The `customized_load_metric_specification` object supports the following: + +* `metric_name` - (Required) The name of the metric. +* `namespace` - (Required) The namespace of the metric. +* `statistic` - (Required) The statistic of the metric. Currently, the value must always be `Sum`. +* `dimensions` - (Optional) The dimensions of the metric. +* `unit` - (Optional) The unit of the metric. + +The `predefined_load_metric_specification` object supports the following: + +* `predefined_load_metric_type` - (Required) The metric type. Valid values: `ALBTargetGroupRequestCount`, `ASGTotalCPUUtilization`, `ASGTotalNetworkIn`, `ASGTotalNetworkOut`. +* `resource_label` - (Optional) Identifies the resource associated with the metric type. + +The `target_tracking_configuration` object supports the following: + +* `target_value` - (Required) The target value for the metric. +* `customized_scaling_metric_specification` - (Optional) A customized metric. You can specify either `customized_scaling_metric_specification` or `predefined_scaling_metric_specification`. +More details can be found in the [AWS Auto Scaling API Reference](https://docs.aws.amazon.com/autoscaling/plans/APIReference/API_CustomizedScalingMetricSpecification.html). +* `disable_scale_in` - (Optional) Boolean indicating whether scale in by the target tracking scaling policy is disabled. Defaults to `false`. +* `predefined_scaling_metric_specification` - (Optional) A predefined metric. You can specify either `predefined_scaling_metric_specification` or `customized_scaling_metric_specification`. +More details can be found in the [AWS Auto Scaling API Reference](https://docs.aws.amazon.com/autoscaling/plans/APIReference/API_PredefinedScalingMetricSpecification.html). +* `estimated_instance_warmup` - (Optional) The estimated time, in seconds, until a newly launched instance can contribute to the CloudWatch metrics. +This value is used only if the resource is an Auto Scaling group. +* `scale_in_cooldown` - (Optional) The amount of time, in seconds, after a scale in activity completes before another scale in activity can start. +This value is not used if the scalable resource is an Auto Scaling group. +* `scale_out_cooldown` - (Optional) The amount of time, in seconds, after a scale-out activity completes before another scale-out activity can start. +This value is not used if the scalable resource is an Auto Scaling group. + +The `customized_scaling_metric_specification` object supports the following: + +* `metric_name` - (Required) The name of the metric. +* `namespace` - (Required) The namespace of the metric. +* `statistic` - (Required) The statistic of the metric. Valid values: `Average`, `Maximum`, `Minimum`, `SampleCount`, `Sum`. +* `dimensions` - (Optional) The dimensions of the metric. +* `unit` - (Optional) The unit of the metric. + +The `predefined_scaling_metric_specification` object supports the following: + +* `predefined_scaling_metric_type` - (Required) The metric type. Valid values: `ALBRequestCountPerTarget`, `ASGAverageCPUUtilization`, `ASGAverageNetworkIn`, `ASGAverageNetworkOut`, `DynamoDBReadCapacityUtilization`, `DynamoDBWriteCapacityUtilization`, `ECSServiceAverageCPUUtilization`, `ECSServiceAverageMemoryUtilization`, `EC2SpotFleetRequestAverageCPUUtilization`, `EC2SpotFleetRequestAverageNetworkIn`, `EC2SpotFleetRequestAverageNetworkOut`, `RDSReaderAverageCPUUtilization`, `RDSReaderAverageDatabaseConnections`. +* `resource_label` - (Optional) Identifies the resource associated with the metric type. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The scaling plan identifier. +* `scaling_plan_version` - The version number of the scaling plan. This value is always 1. + +## Timeouts + +`aws_autoscalingplans_scaling_plan` provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - (Default `5 minutes`) Used for creating Auto Scaling scaling plan +- `update` - (Default `5 minutes`) Used for updating Auto Scaling scaling plan +- `delete` - (Default `5 minutes`) Used for destroying Auto Scaling scaling plan + +## Import + +Auto Scaling scaling plans can be imported using the `name`, e.g. + +``` +$ terraform import aws_autoscalingplans_scaling_plan.example MyScale1 +``` From ce4c98e39e7f89150a9c633ed80c15fa48f8be1d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 5 Oct 2019 17:04:58 -0400 Subject: [PATCH 02/19] Terraform Plugin SDK migration. --- aws/resource_aws_autoscalingplans_scaling_plan.go | 8 ++++---- aws/resource_aws_autoscalingplans_scaling_plan_test.go | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_autoscalingplans_scaling_plan.go b/aws/resource_aws_autoscalingplans_scaling_plan.go index 9039288b8e3a..8a95322f8eef 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan.go @@ -10,10 +10,10 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/autoscalingplans" - "github.com/hashicorp/terraform/helper/hashcode" - "github.com/hashicorp/terraform/helper/resource" - "github.com/hashicorp/terraform/helper/schema" - "github.com/hashicorp/terraform/helper/validation" + "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) const ( diff --git a/aws/resource_aws_autoscalingplans_scaling_plan_test.go b/aws/resource_aws_autoscalingplans_scaling_plan_test.go index 01e95199432b..1d71d16ac3c6 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan_test.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan_test.go @@ -12,9 +12,9 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/autoscalingplans" - "github.com/hashicorp/terraform/helper/acctest" - "github.com/hashicorp/terraform/helper/resource" - "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" ) func init() { From df98e92bd761bf9da2cbbd12e0c28da73f684e55 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 22 Nov 2019 17:41:52 +0000 Subject: [PATCH 03/19] Add 'subcategory'. --- website/docs/r/autoscalingplans_scaling_plan.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/autoscalingplans_scaling_plan.html.markdown b/website/docs/r/autoscalingplans_scaling_plan.html.markdown index 97e88e0f3394..28828bd455d0 100644 --- a/website/docs/r/autoscalingplans_scaling_plan.html.markdown +++ b/website/docs/r/autoscalingplans_scaling_plan.html.markdown @@ -1,4 +1,5 @@ --- +subcategory: "Autoscaling Plans" layout: "aws" page_title: "AWS: aws_autoscalingplans_scaling_plan" sidebar_current: "docs-aws-resource-autoscalingplans-scaling-plan" From b254cec789385a3929b5c14c18825e4b5fab65ee Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 27 Nov 2019 10:15:25 -0500 Subject: [PATCH 04/19] Replace 'validateStringDoesNotContainAny' with 'validation.StringDoesNotContainAny'. --- ...ource_aws_autoscalingplans_scaling_plan.go | 2 +- aws/validators.go | 20 ------------- aws/validators_test.go | 28 ------------------- 3 files changed, 1 insertion(+), 49 deletions(-) diff --git a/aws/resource_aws_autoscalingplans_scaling_plan.go b/aws/resource_aws_autoscalingplans_scaling_plan.go index 8a95322f8eef..47ec40f2ad7b 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan.go @@ -44,7 +44,7 @@ func resourceAwsAutoScalingPlansScalingPlan() *schema.Resource { ValidateFunc: validation.All( validation.StringLenBetween(1, 128), validation.StringMatch(regexp.MustCompile(`^[[:print:]]+$`), "must be printable"), - validateStringDoesNotContainAny("|:/"), + validation.StringDoesNotContainAny("|:/"), ), }, diff --git a/aws/validators.go b/aws/validators.go index 5fb3b54619c5..12ae9401c9e1 100644 --- a/aws/validators.go +++ b/aws/validators.go @@ -32,26 +32,6 @@ var awsAccountIDRegexp = regexp.MustCompile(awsAccountIDRegexpPattern) var awsPartitionRegexp = regexp.MustCompile(awsPartitionRegexpPattern) var awsRegionRegexp = regexp.MustCompile(awsRegionRegexpPattern) -// validateStringDoesNotContainAny returns a SchemaValidateFunc which validates that the -// provided value does not contain any of the specified Unicode code points in chars. -// This function should be migrated to the Terraform Provider SDK. -func validateStringDoesNotContainAny(chars string) schema.SchemaValidateFunc { - return func(i interface{}, k string) (s []string, es []error) { - v, ok := i.(string) - if !ok { - es = append(es, fmt.Errorf("expected type of %s to be string", k)) - return - } - - if strings.ContainsAny(v, chars) { - es = append(es, fmt.Errorf("expected value of %s to not contain any of %q", k, chars)) - return - } - - return - } -} - // validateTypeStringNullableBoolean provides custom error messaging for TypeString booleans // Some arguments require three values: true, false, and "" (unspecified). // This ValidateFunc returns a custom message since the message with diff --git a/aws/validators_test.go b/aws/validators_test.go index 4139fca932e5..9439b384c914 100644 --- a/aws/validators_test.go +++ b/aws/validators_test.go @@ -10,34 +10,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" ) -func TestValidateStringDoesNotContainAny(t *testing.T) { - chars := "|:/" - - validStrings := []string{ - "HelloWorld", - "ABC_*&^%123", - } - for _, v := range validStrings { - _, errors := validateStringDoesNotContainAny(chars)(v, "name") - if len(errors) != 0 { - t.Fatalf("%q should not contain any of %q", v, chars) - } - } - - invalidStrings := []string{ - "Hello/World", - "ABC|123", - "This will fail:", - chars, - } - for _, v := range invalidStrings { - _, errors := validateStringDoesNotContainAny(chars)(v, "name") - if len(errors) == 0 { - t.Fatalf("%q should contain one of %q", v, chars) - } - } -} - func TestValidateTypeStringNullableBoolean(t *testing.T) { testCases := []struct { val interface{} From e88b0dc519ae1da1d834b2f224bce1fe52e20901 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 17 Mar 2020 17:26:57 -0400 Subject: [PATCH 05/19] Remove 'sidebar_current'. --- website/allowed-subcategories.txt | 1 + website/docs/r/autoscalingplans_scaling_plan.html.markdown | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/website/allowed-subcategories.txt b/website/allowed-subcategories.txt index 15d8db21d040..3acc31cc3043 100644 --- a/website/allowed-subcategories.txt +++ b/website/allowed-subcategories.txt @@ -9,6 +9,7 @@ AppSync Application Autoscaling Athena Autoscaling +Autoscaling Plans Backup Batch Budgets diff --git a/website/docs/r/autoscalingplans_scaling_plan.html.markdown b/website/docs/r/autoscalingplans_scaling_plan.html.markdown index 28828bd455d0..f3785542b6c0 100644 --- a/website/docs/r/autoscalingplans_scaling_plan.html.markdown +++ b/website/docs/r/autoscalingplans_scaling_plan.html.markdown @@ -2,7 +2,6 @@ subcategory: "Autoscaling Plans" layout: "aws" page_title: "AWS: aws_autoscalingplans_scaling_plan" -sidebar_current: "docs-aws-resource-autoscalingplans-scaling-plan" description: |- Manages an AWS Auto Scaling scaling plan. --- From 6fa9aa62e2b8c41f1063a565bc9aa1aae4ba6bda Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 11 May 2020 17:24:58 -0400 Subject: [PATCH 06/19] Use 'go-multierror' in test sweeper. --- ..._aws_autoscalingplans_scaling_plan_test.go | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_autoscalingplans_scaling_plan_test.go b/aws/resource_aws_autoscalingplans_scaling_plan_test.go index 1d71d16ac3c6..c8072e2d06e2 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan_test.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan_test.go @@ -12,6 +12,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/autoscalingplans" + "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" @@ -27,19 +28,21 @@ func init() { func testSweepAutoScalingPlansScalingPlans(region string) error { client, err := sharedClientForRegion(region) if err != nil { - return fmt.Errorf("error getting client: %s", err) + return fmt.Errorf("error getting client: %w", err) } conn := client.(*AWSClient).autoscalingplansconn - input := &autoscalingplans.DescribeScalingPlansInput{} + var sweeperErrs *multierror.Error + for { output, err := conn.DescribeScalingPlans(input) if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping Auto Scaling scaling plan sweep for %s: %s", region, err) - return nil + log.Printf("[WARN] Skipping Auto Scaling Scaling Plans sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors } if err != nil { - return fmt.Errorf("error listing Auto Scaling scaling plans: %s", err) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Auto Scaling Scaling Plans: %w", err)) + return sweeperErrs } for _, scalingPlan := range output.ScalingPlans { @@ -54,11 +57,16 @@ func testSweepAutoScalingPlansScalingPlans(region string) error { continue } if err != nil { - return fmt.Errorf("error deleting Auto Scaling scaling plan (%s): %s", scalingPlanName, err) + sweeperErr := fmt.Errorf("error deleting Auto Scaling Scaling Plan (%s): %w", scalingPlanName, err) + log.Printf("[ERROR] %s", sweeperErr) + sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) } if err := waitForAutoScalingPlansScalingPlanDeletion(conn, scalingPlanName, scalingPlanVersion, 5*time.Minute); err != nil { - return fmt.Errorf("error waiting for Auto Scaling scaling plan (%s) to be deleted: %s", scalingPlanName, err) + sweeperErr := fmt.Errorf("error waiting for Auto Scaling Scaling Plan (%s) to be deleted: %w", scalingPlanName, err) + log.Printf("[ERROR] %s", sweeperErr) + sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) + continue } } @@ -68,7 +76,7 @@ func testSweepAutoScalingPlansScalingPlans(region string) error { input.NextToken = output.NextToken } - return nil + return sweeperErrs.ErrorOrNil() } func TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling(t *testing.T) { From 1c979ffb6d7295c7119ac95e4901f6f90a208a40 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 11 May 2020 17:44:20 -0400 Subject: [PATCH 07/19] Add 'internal/service/autoscalingplans/waiter' package. --- .../service/autoscalingplans/waiter/status.go | 44 ++++++ .../service/autoscalingplans/waiter/waiter.go | 73 +++++++++ ...ource_aws_autoscalingplans_scaling_plan.go | 143 +++++------------- ..._aws_autoscalingplans_scaling_plan_test.go | 10 +- ...utoscalingplans_scaling_plan.html.markdown | 9 -- 5 files changed, 158 insertions(+), 121 deletions(-) create mode 100644 aws/internal/service/autoscalingplans/waiter/status.go create mode 100644 aws/internal/service/autoscalingplans/waiter/waiter.go diff --git a/aws/internal/service/autoscalingplans/waiter/status.go b/aws/internal/service/autoscalingplans/waiter/status.go new file mode 100644 index 000000000000..b2ccef45e94d --- /dev/null +++ b/aws/internal/service/autoscalingplans/waiter/status.go @@ -0,0 +1,44 @@ +package waiter + +import ( + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/autoscalingplans" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +const ( + // ScalingPlan NotFound + ScalingPlanStatusNotFound = "NotFound" + + // ScalingPlan Unknown + ScalingPlanStatusUnknown = "Unknown" +) + +// ScalingPlanStatus fetches the ScalingPlan and its Status +func ScalingPlanStatus(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &autoscalingplans.DescribeScalingPlansInput{ + ScalingPlanNames: aws.StringSlice([]string{scalingPlanName}), + ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), + } + + output, err := conn.DescribeScalingPlans(input) + + if err != nil { + return nil, ScalingPlanStatusUnknown, err + } + + if len(output.ScalingPlans) == 0 { + return "", ScalingPlanStatusNotFound, nil + } + + scalingPlan := output.ScalingPlans[0] + if statusMessage := aws.StringValue(scalingPlan.StatusMessage); statusMessage != "" { + log.Printf("[INFO] Auto Scaling Scaling Plan (%s/%d) status message: %s", scalingPlanName, scalingPlanVersion, statusMessage) + } + + return scalingPlan, aws.StringValue(scalingPlan.StatusCode), nil + } +} diff --git a/aws/internal/service/autoscalingplans/waiter/waiter.go b/aws/internal/service/autoscalingplans/waiter/waiter.go new file mode 100644 index 000000000000..affb17a3c764 --- /dev/null +++ b/aws/internal/service/autoscalingplans/waiter/waiter.go @@ -0,0 +1,73 @@ +package waiter + +import ( + "time" + + "github.com/aws/aws-sdk-go/service/autoscalingplans" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +const ( + // Maximum amount of time to wait for a ScalingPlan to return Created + ScalingPlanCreatedTimeout = 5 * time.Minute + + // Maximum amount of time to wait for a ScalingPlan to return Deleted + ScalingPlanDeletedTimeout = 5 * time.Minute + + // Maximum amount of time to wait for a ScalingPlan to return Updated + ScalingPlanUpdatedTimeout = 5 * time.Minute +) + +// ScalingPlanCreated waits for a ScalingPlan to return Created +func ScalingPlanCreated(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int) (*autoscalingplans.ScalingPlan, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{autoscalingplans.ScalingPlanStatusCodeCreationInProgress}, + Target: []string{autoscalingplans.ScalingPlanStatusCodeActive, autoscalingplans.ScalingPlanStatusCodeActiveWithProblems}, + Refresh: ScalingPlanStatus(conn, scalingPlanName, scalingPlanVersion), + Timeout: ScalingPlanCreatedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*autoscalingplans.ScalingPlan); ok { + return v, err + } + + return nil, err +} + +// ScalingPlanDeleted waits for a ScalingPlan to return Deleted +func ScalingPlanDeleted(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int) (*autoscalingplans.ScalingPlan, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{autoscalingplans.ScalingPlanStatusCodeDeletionInProgress}, + Target: []string{ScalingPlanStatusNotFound}, + Refresh: ScalingPlanStatus(conn, scalingPlanName, scalingPlanVersion), + Timeout: ScalingPlanDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*autoscalingplans.ScalingPlan); ok { + return v, err + } + + return nil, err +} + +// ScalingPlanUpdated waits for a ScalingPlan to return Updated +func ScalingPlanUpdated(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int) (*autoscalingplans.ScalingPlan, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{autoscalingplans.ScalingPlanStatusCodeUpdateInProgress}, + Target: []string{autoscalingplans.ScalingPlanStatusCodeActive, autoscalingplans.ScalingPlanStatusCodeActiveWithProblems}, + Refresh: ScalingPlanStatus(conn, scalingPlanName, scalingPlanVersion), + Timeout: ScalingPlanUpdatedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*autoscalingplans.ScalingPlan); ok { + return v, err + } + + return nil, err +} diff --git a/aws/resource_aws_autoscalingplans_scaling_plan.go b/aws/resource_aws_autoscalingplans_scaling_plan.go index 47ec40f2ad7b..9ecb6b214109 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan.go @@ -6,18 +6,13 @@ import ( "log" "regexp" "sort" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/autoscalingplans" "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" -) - -const ( - autoscalingplansScalingPlanStatusDeleted = "Deleted" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/autoscalingplans/waiter" ) func resourceAwsAutoScalingPlansScalingPlan() *schema.Resource { @@ -30,12 +25,6 @@ func resourceAwsAutoScalingPlansScalingPlan() *schema.Resource { State: resourceAwsAutoScalingPlansScalingPlanImport, }, - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(5 * time.Minute), - Update: schema.DefaultTimeout(5 * time.Minute), - Delete: schema.DefaultTimeout(5 * time.Minute), - }, - Schema: map[string]*schema.Schema{ "name": { Type: schema.TypeString, @@ -386,24 +375,26 @@ func resourceAwsAutoScalingPlansScalingPlanCreate(d *schema.ResourceData, meta i conn := meta.(*AWSClient).autoscalingplansconn scalingPlanName := d.Get("name").(string) - req := &autoscalingplans.CreateScalingPlanInput{ + + input := &autoscalingplans.CreateScalingPlanInput{ ApplicationSource: expandAutoScalingPlansApplicationSource(d.Get("application_source").([]interface{})), ScalingInstructions: expandAutoScalingPlansScalingInstructions(d.Get("scaling_instruction").(*schema.Set)), ScalingPlanName: aws.String(scalingPlanName), } - log.Printf("[DEBUG] Creating Auto Scaling scaling plan: %s", req) - resp, err := conn.CreateScalingPlan(req) + log.Printf("[DEBUG] Creating Auto Scaling Scaling Plan: %s", input) + output, err := conn.CreateScalingPlan(input) if err != nil { - return fmt.Errorf("error creating Auto Scaling scaling plan: %s", err) + return fmt.Errorf("error creating Auto Scaling Scaling Plan: %w", err) } - scalingPlanVersion := int(aws.Int64Value(resp.ScalingPlanVersion)) + scalingPlanVersion := int(aws.Int64Value(output.ScalingPlanVersion)) d.SetId(autoScalingPlansScalingPlanId(scalingPlanName, scalingPlanVersion)) d.Set("scaling_plan_version", scalingPlanVersion) - if err := waitForAutoScalingPlansScalingPlanAvailabilityOnCreate(conn, scalingPlanName, scalingPlanVersion, d.Timeout(schema.TimeoutCreate)); err != nil { - return fmt.Errorf("error waiting for Auto Scaling scaling plan (%s) to become available: %s", d.Id(), err) + _, err = waiter.ScalingPlanCreated(conn, scalingPlanName, scalingPlanVersion) + if err != nil { + return fmt.Errorf("error waiting for Auto Scaling Scaling Plan (%s) to be created: %w", d.Id(), err) } return resourceAwsAutoScalingPlansScalingPlanRead(d, meta) @@ -415,26 +406,25 @@ func resourceAwsAutoScalingPlansScalingPlanRead(d *schema.ResourceData, meta int scalingPlanName := d.Get("name").(string) scalingPlanVersion := d.Get("scaling_plan_version").(int) - scalingPlanRaw, state, err := autoScalingPlansScalingPlanRefresh(conn, scalingPlanName, scalingPlanVersion)() - if err != nil { - return fmt.Errorf("error reading Auto Scaling scaling plan (%s): %s", d.Id(), err) - } - - if state == autoscalingplansScalingPlanStatusDeleted { - log.Printf("[WARN] Auto Scaling scaling plan (%s) not found, removing from state", d.Id()) + v, state, err := waiter.ScalingPlanStatus(conn, scalingPlanName, scalingPlanVersion)() + if isAWSErr(err, autoscalingplans.ErrCodeObjectNotFoundException, "") || state == waiter.ScalingPlanStatusNotFound { + log.Printf("[WARN] Auto Scaling Scaling Plan (%s) not found, removing from state", d.Id()) d.SetId("") return nil } + if err != nil { + return fmt.Errorf("error reading Auto Scaling Scaling Plan (%s): %w", d.Id(), err) + } - scalingPlan := scalingPlanRaw.(*autoscalingplans.ScalingPlan) + scalingPlan := v.(*autoscalingplans.ScalingPlan) err = d.Set("application_source", flattenAutoScalingPlansApplicationSource(scalingPlan.ApplicationSource)) if err != nil { - return fmt.Errorf("error setting application_source: %s", err) + return fmt.Errorf("error setting application_source: %w", err) } d.Set("name", scalingPlan.ScalingPlanName) err = d.Set("scaling_instruction", flattenAutoScalingPlansScalingInstructions(scalingPlan.ScalingInstructions)) if err != nil { - return fmt.Errorf("error setting application_source: %s", err) + return fmt.Errorf("error setting application_source: %w", err) } d.Set("scaling_plan_version", int(aws.Int64Value(scalingPlan.ScalingPlanVersion))) @@ -447,21 +437,22 @@ func resourceAwsAutoScalingPlansScalingPlanUpdate(d *schema.ResourceData, meta i scalingPlanName := d.Get("name").(string) scalingPlanVersion := d.Get("scaling_plan_version").(int) - req := &autoscalingplans.UpdateScalingPlanInput{ + input := &autoscalingplans.UpdateScalingPlanInput{ ApplicationSource: expandAutoScalingPlansApplicationSource(d.Get("application_source").([]interface{})), ScalingInstructions: expandAutoScalingPlansScalingInstructions(d.Get("scaling_instruction").(*schema.Set)), ScalingPlanName: aws.String(scalingPlanName), ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), } - log.Printf("[DEBUG] Updating Auto Scaling scaling plan: %s", req) - _, err := conn.UpdateScalingPlan(req) + log.Printf("[DEBUG] Updating Auto Scaling Scaling Plan: %s", input) + _, err := conn.UpdateScalingPlan(input) if err != nil { - return fmt.Errorf("error updating Auto Scaling scaling plan (%s): %s", d.Id(), err) + return fmt.Errorf("error updating Auto Scaling Scaling Plan (%s): %w", d.Id(), err) } - if err := waitForAutoScalingPlansScalingPlanAvailabilityOnUpdate(conn, scalingPlanName, scalingPlanVersion, d.Timeout(schema.TimeoutUpdate)); err != nil { - return fmt.Errorf("error waiting for Auto Scaling scaling plan (%s) to become available: %s", d.Id(), err) + _, err = waiter.ScalingPlanUpdated(conn, scalingPlanName, scalingPlanVersion) + if err != nil { + return fmt.Errorf("error waiting for Auto Scaling Scaling Plan (%s) to be updated: %w", d.Id(), err) } return resourceAwsAutoScalingPlansScalingPlanRead(d, meta) @@ -473,7 +464,7 @@ func resourceAwsAutoScalingPlansScalingPlanDelete(d *schema.ResourceData, meta i scalingPlanName := d.Get("name").(string) scalingPlanVersion := d.Get("scaling_plan_version").(int) - log.Printf("[DEBUG] Deleting Auto Scaling scaling plan: %s", d.Id()) + log.Printf("[DEBUG] Deleting Auto Scaling Scaling Plan: %s", d.Id()) _, err := conn.DeleteScalingPlan(&autoscalingplans.DeleteScalingPlanInput{ ScalingPlanName: aws.String(scalingPlanName), ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), @@ -482,11 +473,15 @@ func resourceAwsAutoScalingPlansScalingPlanDelete(d *schema.ResourceData, meta i return nil } if err != nil { - return fmt.Errorf("error deleting Auto Scaling scaling plan (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting Auto Scaling Scaling Plan (%s): %w", d.Id(), err) } - if err := waitForAutoScalingPlansScalingPlanDeletion(conn, scalingPlanName, scalingPlanVersion, d.Timeout(schema.TimeoutDelete)); err != nil { - return fmt.Errorf("error waiting for Auto Scaling scaling plan (%s) to be deleted: %s", d.Id(), err) + _, err = waiter.ScalingPlanDeleted(conn, scalingPlanName, scalingPlanVersion) + if isAWSErr(err, autoscalingplans.ErrCodeObjectNotFoundException, "") { + return nil + } + if err != nil { + return fmt.Errorf("error waiting for Auto Scaling Scaling Plan (%s) to be deleted: %w", d.Id(), err) } return nil @@ -508,76 +503,6 @@ func autoScalingPlansScalingPlanId(scalingPlanName string, scalingPlanVersion in return fmt.Sprintf("%s/%d", scalingPlanName, scalingPlanVersion) } -func autoScalingPlansScalingPlanRefresh(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - resp, err := conn.DescribeScalingPlans(&autoscalingplans.DescribeScalingPlansInput{ - ScalingPlanNames: aws.StringSlice([]string{scalingPlanName}), - ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), - }) - if err != nil { - return nil, "", err - } - - if n := len(resp.ScalingPlans); n == 0 { - return "", autoscalingplansScalingPlanStatusDeleted, nil - } else if n > 1 { - return nil, "", fmt.Errorf("Found %d Auto Scaling scaling plans for %s, expected 1", n, scalingPlanName) - } - - scalingPlan := resp.ScalingPlans[0] - if statusMessage := aws.StringValue(scalingPlan.StatusMessage); statusMessage != "" { - log.Printf("[INFO] Auto Scaling scaling plan (%s) status message: %s", scalingPlanName, statusMessage) - } - - return scalingPlan, aws.StringValue(scalingPlan.StatusCode), nil - } -} - -func waitForAutoScalingPlansScalingPlanAvailabilityOnCreate(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int, timeout time.Duration) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{autoscalingplans.ScalingPlanStatusCodeCreationInProgress}, - Target: []string{autoscalingplans.ScalingPlanStatusCodeActive, autoscalingplans.ScalingPlanStatusCodeActiveWithProblems}, - Refresh: autoScalingPlansScalingPlanRefresh(conn, scalingPlanName, scalingPlanVersion), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 5 * time.Second, - } - - _, err := stateConf.WaitForState() - - return err -} - -func waitForAutoScalingPlansScalingPlanAvailabilityOnUpdate(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int, timeout time.Duration) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{autoscalingplans.ScalingPlanStatusCodeUpdateInProgress}, - Target: []string{autoscalingplans.ScalingPlanStatusCodeActive, autoscalingplans.ScalingPlanStatusCodeActiveWithProblems}, - Refresh: autoScalingPlansScalingPlanRefresh(conn, scalingPlanName, scalingPlanVersion), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 5 * time.Second, - } - - _, err := stateConf.WaitForState() - - return err -} - -func waitForAutoScalingPlansScalingPlanDeletion(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int, timeout time.Duration) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{autoscalingplans.ScalingPlanStatusCodeDeletionInProgress}, - Target: []string{autoscalingplansScalingPlanStatusDeleted}, - Refresh: autoScalingPlansScalingPlanRefresh(conn, scalingPlanName, scalingPlanVersion), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 5 * time.Second, - } - - _, err := stateConf.WaitForState() - - return err -} - // // ApplicationSource functions. // diff --git a/aws/resource_aws_autoscalingplans_scaling_plan_test.go b/aws/resource_aws_autoscalingplans_scaling_plan_test.go index c8072e2d06e2..e6cdebd20ad0 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan_test.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan_test.go @@ -8,7 +8,6 @@ import ( "sort" "strconv" "testing" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/autoscalingplans" @@ -16,6 +15,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/autoscalingplans/waiter" ) func init() { @@ -62,8 +62,12 @@ func testSweepAutoScalingPlansScalingPlans(region string) error { sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) } - if err := waitForAutoScalingPlansScalingPlanDeletion(conn, scalingPlanName, scalingPlanVersion, 5*time.Minute); err != nil { - sweeperErr := fmt.Errorf("error waiting for Auto Scaling Scaling Plan (%s) to be deleted: %w", scalingPlanName, err) + _, err = waiter.ScalingPlanDeleted(conn, scalingPlanName, scalingPlanVersion) + if isAWSErr(err, autoscalingplans.ErrCodeObjectNotFoundException, "") { + continue + } + if err != nil { + sweeperErr := fmt.Errorf("error waiting for Auto Scaling Scaling Plan (%s) deletion: %w", scalingPlanName, err) log.Printf("[ERROR] %s", sweeperErr) sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) continue diff --git a/website/docs/r/autoscalingplans_scaling_plan.html.markdown b/website/docs/r/autoscalingplans_scaling_plan.html.markdown index f3785542b6c0..4074ddf21b7f 100644 --- a/website/docs/r/autoscalingplans_scaling_plan.html.markdown +++ b/website/docs/r/autoscalingplans_scaling_plan.html.markdown @@ -211,15 +211,6 @@ In addition to all arguments above, the following attributes are exported: * `id` - The scaling plan identifier. * `scaling_plan_version` - The version number of the scaling plan. This value is always 1. -## Timeouts - -`aws_autoscalingplans_scaling_plan` provides the following -[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: - -- `create` - (Default `5 minutes`) Used for creating Auto Scaling scaling plan -- `update` - (Default `5 minutes`) Used for updating Auto Scaling scaling plan -- `delete` - (Default `5 minutes`) Used for destroying Auto Scaling scaling plan - ## Import Auto Scaling scaling plans can be imported using the `name`, e.g. From 2bddadce1fb00ae1f0ab8209aad19bdf208333d1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 12 May 2020 18:23:49 -0400 Subject: [PATCH 08/19] Simplify acceptance tests a bit. --- ..._aws_autoscalingplans_scaling_plan_test.go | 160 +++++++++--------- 1 file changed, 84 insertions(+), 76 deletions(-) diff --git a/aws/resource_aws_autoscalingplans_scaling_plan_test.go b/aws/resource_aws_autoscalingplans_scaling_plan_test.go index e6cdebd20ad0..7a01bef6188e 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan_test.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan_test.go @@ -87,28 +87,25 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling(t *testing.T) { var scalingPlan autoscalingplans.ScalingPlan resourceIdMap := map[string]string{} resourceName := "aws_autoscalingplans_scaling_plan.test" - asgName := fmt.Sprintf("tf-testacc-asg-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) - asgResourceId := fmt.Sprintf("autoScalingGroup/%s", asgName) - scalingPlanName := fmt.Sprintf("tf-testacc-scalingplan-%s", acctest.RandStringFromCharSet(9, acctest.CharSetAlphaNum)) - // Application source must be unique across scaling plans. - tagKey := fmt.Sprintf("tf-testacc-key-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) - tagValue := fmt.Sprintf("tf-testacc-value-%s", acctest.RandStringFromCharSet(15, acctest.CharSetAlphaNum)) + rName := acctest.RandomWithPrefix("tf-acc-test") + asgResourceId := fmt.Sprintf("autoScalingGroup/%s", rName) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, + DisableBinaryDriver: true, Steps: []resource.TestStep{ { - Config: testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(asgName, scalingPlanName, tagKey, tagValue), + Config: testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), - resource.TestCheckResourceAttr(resourceName, "name", scalingPlanName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "scaling_plan_version", "1"), resource.TestCheckResourceAttr(resourceName, "application_source.#", "1"), resource.TestCheckResourceAttr(resourceName, "application_source.0.cloudformation_stack_arn", ""), testAccCheckAutoScalingPlansApplicationSourceTags(&scalingPlan, map[string][]string{ - tagKey: {tagValue}, + rName: {rName}, }), resource.TestCheckResourceAttr(resourceName, "scaling_instruction.#", "1"), testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "customized_load_metric_specification.#", "0"), @@ -139,7 +136,7 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling(t *testing.T) { { ResourceName: resourceName, ImportStateIdFunc: func(s *terraform.State) (string, error) { - return scalingPlanName, nil + return rName, nil }, ImportState: true, ImportStateVerify: true, @@ -152,28 +149,25 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling(t *testing.T) var scalingPlan autoscalingplans.ScalingPlan resourceIdMap := map[string]string{} resourceName := "aws_autoscalingplans_scaling_plan.test" - asgName := fmt.Sprintf("tf-testacc-asg-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) - asgResourceId := fmt.Sprintf("autoScalingGroup/%s", asgName) - scalingPlanName := fmt.Sprintf("tf-testacc-scalingplan-%s", acctest.RandStringFromCharSet(9, acctest.CharSetAlphaNum)) - // Application source must be unique across scaling plans. - tagKey := fmt.Sprintf("tf-testacc-key-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) - tagValue := fmt.Sprintf("tf-testacc-value-%s", acctest.RandStringFromCharSet(15, acctest.CharSetAlphaNum)) + rName := acctest.RandomWithPrefix("tf-acc-test") + asgResourceId := fmt.Sprintf("autoScalingGroup/%s", rName) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, + DisableBinaryDriver: true, Steps: []resource.TestStep{ { - Config: testAccAutoScalingPlansScalingPlanConfig_basicPredictiveScaling(asgName, scalingPlanName, tagKey, tagValue), + Config: testAccAutoScalingPlansScalingPlanConfig_basicPredictiveScaling(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), - resource.TestCheckResourceAttr(resourceName, "name", scalingPlanName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "scaling_plan_version", "1"), resource.TestCheckResourceAttr(resourceName, "application_source.#", "1"), resource.TestCheckResourceAttr(resourceName, "application_source.0.cloudformation_stack_arn", ""), testAccCheckAutoScalingPlansApplicationSourceTags(&scalingPlan, map[string][]string{ - tagKey: {tagValue}, + rName: {rName}, }), resource.TestCheckResourceAttr(resourceName, "scaling_instruction.#", "1"), testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "customized_load_metric_specification.#", "0"), @@ -206,7 +200,7 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling(t *testing.T) { ResourceName: resourceName, ImportStateIdFunc: func(s *terraform.State) (string, error) { - return scalingPlanName, nil + return rName, nil }, ImportState: true, ImportStateVerify: true, @@ -219,30 +213,26 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { var scalingPlan autoscalingplans.ScalingPlan resourceIdMap := map[string]string{} resourceName := "aws_autoscalingplans_scaling_plan.test" - asgName := fmt.Sprintf("tf-testacc-asg-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) - asgResourceId := fmt.Sprintf("autoScalingGroup/%s", asgName) - scalingPlanName := fmt.Sprintf("tf-testacc-scalingplan-%s", acctest.RandStringFromCharSet(9, acctest.CharSetAlphaNum)) - // Application source must be unique across scaling plans. - tagKey1 := fmt.Sprintf("tf-testacc-key-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) - tagValue1 := fmt.Sprintf("tf-testacc-value-%s", acctest.RandStringFromCharSet(15, acctest.CharSetAlphaNum)) - tagKey2 := fmt.Sprintf("tf-testacc-key-%s", acctest.RandStringFromCharSet(17, acctest.CharSetAlphaNum)) - tagValue2 := fmt.Sprintf("tf-testacc-value-%s", acctest.RandStringFromCharSet(15, acctest.CharSetAlphaNum)) + rName := acctest.RandomWithPrefix("tf-acc-test") + asgResourceId := fmt.Sprintf("autoScalingGroup/%s", rName) + rNameUpdated := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, + DisableBinaryDriver: true, Steps: []resource.TestStep{ { - Config: testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(asgName, scalingPlanName, tagKey1, tagValue1), + Config: testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), - resource.TestCheckResourceAttr(resourceName, "name", scalingPlanName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "scaling_plan_version", "1"), resource.TestCheckResourceAttr(resourceName, "application_source.#", "1"), resource.TestCheckResourceAttr(resourceName, "application_source.0.cloudformation_stack_arn", ""), testAccCheckAutoScalingPlansApplicationSourceTags(&scalingPlan, map[string][]string{ - tagKey1: {tagValue1}, + rName: {rName}, }), resource.TestCheckResourceAttr(resourceName, "scaling_instruction.#", "1"), testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "customized_load_metric_specification.#", "0"), @@ -271,15 +261,15 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { ), }, { - Config: testAccAutoScalingPlansScalingPlanConfig_basicPredictiveScaling(asgName, scalingPlanName, tagKey2, tagValue2), + Config: testAccAutoScalingPlansScalingPlanConfig_basicPredictiveScaling(rName, rNameUpdated), Check: resource.ComposeTestCheckFunc( testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), - resource.TestCheckResourceAttr(resourceName, "name", scalingPlanName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "scaling_plan_version", "1"), resource.TestCheckResourceAttr(resourceName, "application_source.#", "1"), resource.TestCheckResourceAttr(resourceName, "application_source.0.cloudformation_stack_arn", ""), testAccCheckAutoScalingPlansApplicationSourceTags(&scalingPlan, map[string][]string{ - tagKey2: {tagValue2}, + rNameUpdated: {rNameUpdated}, }), resource.TestCheckResourceAttr(resourceName, "scaling_instruction.#", "1"), testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "customized_load_metric_specification.#", "0"), @@ -312,7 +302,7 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { { ResourceName: resourceName, ImportStateIdFunc: func(s *terraform.State) (string, error) { - return scalingPlanName, nil + return rName, nil }, ImportState: true, ImportStateVerify: true, @@ -321,6 +311,29 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { }) } +func TestAccAwsAutoScalingPlansScalingPlan_disappears(t *testing.T) { + var scalingPlan autoscalingplans.ScalingPlan + resourceIdMap := map[string]string{} + resourceName := "aws_autoscalingplans_scaling_plan.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(rName, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), + testAccCheckResourceDisappears(testAccProvider, resourceAwsAutoScalingPlansScalingPlan(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckAutoScalingPlansScalingPlanDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).autoscalingplansconn @@ -421,21 +434,14 @@ func testAccCheckAutoScalingPlansScalingPlanAttr(name string, resourceIdMap *map } } -func testAccAutoScalingPlansScalingPlanConfig_asg(asgName, tagKey, tagValue string) string { - return fmt.Sprintf(` -data "aws_ami" "test" { - most_recent = true - owners = ["amazon"] - - filter { - name = "name" - values = ["amzn-ami-hvm-*-x86_64-gp2"] - } -} - +func testAccAutoScalingPlansScalingPlanConfig_asg(rName, tagName string) string { + return composeConfig( + testAccLatestAmazonLinuxHvmEbsAmiConfig(), + testAccAvailableEc2InstanceTypeForAvailabilityZone("data.aws_availability_zones.available.names[0]", "t3.micro", "t2.micro"), + fmt.Sprintf(` resource "aws_launch_configuration" "test" { - image_id = "${data.aws_ami.test.id}" - instance_type = "t2.micro" + image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = data.aws_ec2_instance_type_offering.available.instance_type } data "aws_availability_zones" "available" {} @@ -443,8 +449,8 @@ data "aws_availability_zones" "available" {} resource "aws_autoscaling_group" "test" { name = %[1]q - launch_configuration = "${aws_launch_configuration.test.name}" - availability_zones = ["${data.aws_availability_zones.available.names[0]}"] + launch_configuration = aws_launch_configuration.test.name + availability_zones = [data.aws_availability_zones.available.names[0]] min_size = 0 max_size = 3 @@ -453,30 +459,31 @@ resource "aws_autoscaling_group" "test" { tags = [ { key = %[2]q - value = %[3]q + value = %[2]q propagate_at_launch = true }, ] } -`, asgName, tagKey, tagValue) +`, rName, tagName)) } -func testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(asgName, scalingPlanName, tagKey, tagValue string) string { - return testAccAutoScalingPlansScalingPlanConfig_asg(asgName, tagKey, tagValue) + fmt.Sprintf(` +func testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(rName, tagName string) string { + return composeConfig( + testAccAutoScalingPlansScalingPlanConfig_asg(rName, tagName) + fmt.Sprintf(` resource "aws_autoscalingplans_scaling_plan" "test" { name = %[1]q application_source { tag_filter { key = %[2]q - values = [%[3]q] + values = [%[2]q] } } scaling_instruction { - max_capacity = "${aws_autoscaling_group.test.max_size}" - min_capacity = "${aws_autoscaling_group.test.min_size}" - resource_id = "${format("autoScalingGroup/%%s", aws_autoscaling_group.test.name)}" + max_capacity = aws_autoscaling_group.test.max_size + min_capacity = aws_autoscaling_group.test.min_size + resource_id = format("autoScalingGroup/%%s", aws_autoscaling_group.test.name) scalable_dimension = "autoscaling:autoScalingGroup:DesiredCapacity" service_namespace = "autoscaling" @@ -489,27 +496,28 @@ resource "aws_autoscalingplans_scaling_plan" "test" { } } } -`, scalingPlanName, tagKey, tagValue) +`, rName, tagName)) } -func testAccAutoScalingPlansScalingPlanConfig_basicPredictiveScaling(asgName, scalingPlanName, tagKey, tagValue string) string { - return testAccAutoScalingPlansScalingPlanConfig_asg(asgName, tagKey, tagValue) + fmt.Sprintf(` +func testAccAutoScalingPlansScalingPlanConfig_basicPredictiveScaling(rName, tagName string) string { + return composeConfig( + testAccAutoScalingPlansScalingPlanConfig_asg(rName, tagName) + fmt.Sprintf(` resource "aws_autoscalingplans_scaling_plan" "test" { name = %[1]q application_source { tag_filter { key = %[2]q - values = [%[3]q] + values = [%[2]q] } } scaling_instruction { disable_dynamic_scaling = true - max_capacity = "${aws_autoscaling_group.test.max_size}" - min_capacity = "${aws_autoscaling_group.test.min_size}" - resource_id = "${format("autoScalingGroup/%%s", aws_autoscaling_group.test.name)}" + max_capacity = aws_autoscaling_group.test.max_size + min_capacity = aws_autoscaling_group.test.min_size + resource_id = format("autoScalingGroup/%%s", aws_autoscaling_group.test.name) scalable_dimension = "autoscaling:autoScalingGroup:DesiredCapacity" service_namespace = "autoscaling" @@ -529,5 +537,5 @@ resource "aws_autoscalingplans_scaling_plan" "test" { } } } -`, scalingPlanName, tagKey, tagValue) +`, rName, tagName)) } From dadedfeda774de5b8ebb80c73860f47bf23deb59 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 21 May 2020 16:50:47 -0400 Subject: [PATCH 09/19] r/aws_autoscalingplans_scaling_plan: Remove custom set hash functions. --- ...ource_aws_autoscalingplans_scaling_plan.go | 172 +----------------- ..._aws_autoscalingplans_scaling_plan_test.go | 72 ++++---- 2 files changed, 40 insertions(+), 204 deletions(-) diff --git a/aws/resource_aws_autoscalingplans_scaling_plan.go b/aws/resource_aws_autoscalingplans_scaling_plan.go index 9ecb6b214109..784439db1775 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan.go @@ -1,15 +1,12 @@ package aws import ( - "bytes" "fmt" "log" "regexp" - "sort" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/autoscalingplans" - "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/autoscalingplans/waiter" @@ -73,7 +70,6 @@ func resourceAwsAutoScalingPlansScalingPlan() *schema.Resource { }, }, }, - Set: autoScalingPlansTagFilterHash, ConflictsWith: []string{"application_source.0.cloudformation_stack_arn"}, }, }, @@ -356,11 +352,9 @@ func resourceAwsAutoScalingPlansScalingPlan() *schema.Resource { }, }, }, - Set: autoScalingPlansTargetTrackingConfigurationHash, }, }, }, - Set: autoScalingPlansScalingInstructionHash, }, "scaling_plan_version": { @@ -565,29 +559,12 @@ func flattenAutoScalingPlansApplicationSource(applicationSource *autoscalingplan vTagFilters = append(vTagFilters, mTagFilter) } - mApplicationSource["tag_filter"] = schema.NewSet(autoScalingPlansTagFilterHash, vTagFilters) + mApplicationSource["tag_filter"] = vTagFilters } return []interface{}{mApplicationSource} } -func autoScalingPlansTagFilterHash(vTagFilter interface{}) int { - var buf bytes.Buffer - - mTagFilter := vTagFilter.(map[string]interface{}) - if v, ok := mTagFilter["key"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if vValues, ok := mTagFilter["values"].(*schema.Set); ok { - // The order of the returned elements is deterministic. - for _, v := range vValues.List() { - buf.WriteString(fmt.Sprintf("%s-", v.(string))) - } - } - - return hashcode.String(buf.String()) -} - // // ScalingInstruction functions. // @@ -770,7 +747,7 @@ func expandAutoScalingPlansScalingInstructions(vScalingInstructions *schema.Set) return scalingInstructions } -func flattenAutoScalingPlansScalingInstructions(scalingInstructions []*autoscalingplans.ScalingInstruction) *schema.Set { +func flattenAutoScalingPlansScalingInstructions(scalingInstructions []*autoscalingplans.ScalingInstruction) []interface{} { vScalingInstructions := []interface{}{} for _, scalingInstruction := range scalingInstructions { @@ -855,152 +832,11 @@ func flattenAutoScalingPlansScalingInstructions(scalingInstructions []*autoscali vTargetTrackingConfigurations = append(vTargetTrackingConfigurations, mTargetTrackingConfiguration) } - mScalingInstruction["target_tracking_configuration"] = schema.NewSet(autoScalingPlansTargetTrackingConfigurationHash, vTargetTrackingConfigurations) + mScalingInstruction["target_tracking_configuration"] = vTargetTrackingConfigurations } vScalingInstructions = append(vScalingInstructions, mScalingInstruction) } - return schema.NewSet(autoScalingPlansScalingInstructionHash, vScalingInstructions) -} - -func autoScalingPlansScalingInstructionHash(vScalingInstruction interface{}) int { - var buf bytes.Buffer - - mScalingInstruction := vScalingInstruction.(map[string]interface{}) - if vCustomizedLoadMetricSpecification, ok := mScalingInstruction["customized_load_metric_specification"].([]interface{}); ok && len(vCustomizedLoadMetricSpecification) > 0 && vCustomizedLoadMetricSpecification[0] != nil { - mCustomizedLoadMetricSpecification := vCustomizedLoadMetricSpecification[0].(map[string]interface{}) - if v, ok := mCustomizedLoadMetricSpecification["dimensions"].(map[string]interface{}); ok { - buf.WriteString(fmt.Sprintf("%d-", stableMapHash(v))) - } - if v, ok := mCustomizedLoadMetricSpecification["metric_name"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := mCustomizedLoadMetricSpecification["namespace"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := mCustomizedLoadMetricSpecification["statistic"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := mCustomizedLoadMetricSpecification["unit"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - } - if v, ok := mScalingInstruction["disable_dynamic_scaling"].(bool); ok { - buf.WriteString(fmt.Sprintf("%t-", v)) - } - if v, ok := mScalingInstruction["max_capacity"].(int); ok { - buf.WriteString(fmt.Sprintf("%d-", v)) - } - if v, ok := mScalingInstruction["min_capacity"].(int); ok { - buf.WriteString(fmt.Sprintf("%d-", v)) - } - if vPredefinedLoadMetricSpecification, ok := mScalingInstruction["predefined_load_metric_specification"].([]interface{}); ok && len(vPredefinedLoadMetricSpecification) > 0 && vPredefinedLoadMetricSpecification[0] != nil { - mPredefinedLoadMetricSpecification := vPredefinedLoadMetricSpecification[0].(map[string]interface{}) - if v, ok := mPredefinedLoadMetricSpecification["predefined_load_metric_type"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := mPredefinedLoadMetricSpecification["resource_label"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - } - if v, ok := mScalingInstruction["predictive_scaling_max_capacity_behavior"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := mScalingInstruction["predictive_scaling_max_capacity_buffer"].(int); ok { - buf.WriteString(fmt.Sprintf("%d-", v)) - } - if v, ok := mScalingInstruction["predictive_scaling_mode"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := mScalingInstruction["resource_id"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := mScalingInstruction["scalable_dimension"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := mScalingInstruction["scaling_policy_update_behavior"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := mScalingInstruction["scheduled_action_buffer_time"].(int); ok { - buf.WriteString(fmt.Sprintf("%d-", v)) - } - if v, ok := mScalingInstruction["service_namespace"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if vTargetTrackingConfigurations, ok := mScalingInstruction["target_tracking_configuration"].(*schema.Set); ok { - // The order of the returned elements is deterministic. - for _, v := range vTargetTrackingConfigurations.List() { - buf.WriteString(fmt.Sprintf("%d-", autoScalingPlansTargetTrackingConfigurationHash(v))) - } - } - - return hashcode.String(buf.String()) -} - -func autoScalingPlansTargetTrackingConfigurationHash(vTargetTrackingConfiguration interface{}) int { - var buf bytes.Buffer - - mTargetTrackingConfiguration := vTargetTrackingConfiguration.(map[string]interface{}) - if vCustomizedScalingMetricSpecification, ok := mTargetTrackingConfiguration["customized_scaling_metric_specification"].([]interface{}); ok && len(vCustomizedScalingMetricSpecification) > 0 && vCustomizedScalingMetricSpecification[0] != nil { - mCustomizedScalingMetricSpecification := vCustomizedScalingMetricSpecification[0].(map[string]interface{}) - if v, ok := mCustomizedScalingMetricSpecification["dimensions"].(map[string]interface{}); ok { - buf.WriteString(fmt.Sprintf("%d-", stableMapHash(v))) - } - if v, ok := mCustomizedScalingMetricSpecification["metric_name"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := mCustomizedScalingMetricSpecification["namespace"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := mCustomizedScalingMetricSpecification["statistic"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := mCustomizedScalingMetricSpecification["unit"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - } - if v, ok := mTargetTrackingConfiguration["disable_scale_in"].(bool); ok { - buf.WriteString(fmt.Sprintf("%t-", v)) - } - if v, ok := mTargetTrackingConfiguration["estimated_instance_warmup"].(int); ok { - buf.WriteString(fmt.Sprintf("%d-", v)) - } - if vPredefinedScalingMetricSpecification, ok := mTargetTrackingConfiguration["predefined_scaling_metric_specification"].([]interface{}); ok && len(vPredefinedScalingMetricSpecification) > 0 && vPredefinedScalingMetricSpecification[0] != nil { - mPredefinedScalingMetricSpecification := vPredefinedScalingMetricSpecification[0].(map[string]interface{}) - if v, ok := mPredefinedScalingMetricSpecification["predefined_scaling_metric_type"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - if v, ok := mPredefinedScalingMetricSpecification["resource_label"].(string); ok { - buf.WriteString(fmt.Sprintf("%s-", v)) - } - } - if v, ok := mTargetTrackingConfiguration["scale_in_cooldown"].(int); ok { - buf.WriteString(fmt.Sprintf("%d-", v)) - } - if v, ok := mTargetTrackingConfiguration["scale_out_cooldown"].(int); ok { - buf.WriteString(fmt.Sprintf("%d-", v)) - } - if v, ok := mTargetTrackingConfiguration["target_value"].(float64); ok { - buf.WriteString(fmt.Sprintf("%g-", v)) - } - - return hashcode.String(buf.String()) -} - -// stableMapHash returns a stable hash value for a map. -func stableMapHash(m map[string]interface{}) int { - // Go map iterator is random. - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Strings(keys) - - hash := 0 - for _, k := range keys { - hash = hash ^ hashcode.String(fmt.Sprintf("%s-%s", k, m[k])) - } - - return hash + return vScalingInstructions } diff --git a/aws/resource_aws_autoscalingplans_scaling_plan_test.go b/aws/resource_aws_autoscalingplans_scaling_plan_test.go index 7a01bef6188e..99421cbd586a 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan_test.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan_test.go @@ -122,15 +122,15 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling(t *testing.T) { testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scheduled_action_buffer_time", "0"), testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "service_namespace", "autoscaling"), testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.customized_scaling_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.disable_scale_in", "false"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.estimated_instance_warmup", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.resource_label", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_in_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_out_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.target_value", "75"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.customized_scaling_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.disable_scale_in", "false"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.estimated_instance_warmup", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.resource_label", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_in_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_out_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.target_value", "75"), ), }, { @@ -186,15 +186,15 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling(t *testing.T) testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scheduled_action_buffer_time", "0"), testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "service_namespace", "autoscaling"), testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.customized_scaling_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.disable_scale_in", "false"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.estimated_instance_warmup", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.resource_label", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_in_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_out_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.target_value", "75"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.customized_scaling_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.disable_scale_in", "false"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.estimated_instance_warmup", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.resource_label", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_in_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_out_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.target_value", "75"), ), }, { @@ -249,15 +249,15 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scheduled_action_buffer_time", "0"), testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "service_namespace", "autoscaling"), testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.customized_scaling_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.disable_scale_in", "false"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.estimated_instance_warmup", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.resource_label", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_in_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_out_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.target_value", "75"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.customized_scaling_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.disable_scale_in", "false"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.estimated_instance_warmup", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.resource_label", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_in_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_out_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.target_value", "75"), ), }, { @@ -288,15 +288,15 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scheduled_action_buffer_time", "0"), testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "service_namespace", "autoscaling"), testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.customized_scaling_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.disable_scale_in", "false"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.estimated_instance_warmup", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.predefined_scaling_metric_specification.0.resource_label", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_in_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.scale_out_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.4253174532.target_value", "75"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.customized_scaling_metric_specification.#", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.disable_scale_in", "false"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.estimated_instance_warmup", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.#", "1"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.resource_label", ""), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_in_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_out_cooldown", "0"), + testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.target_value", "75"), ), }, { From 22726cfbdf576a76cd6ef92c2a50b6791f452739 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 6 Jul 2020 14:54:48 -0400 Subject: [PATCH 10/19] Use 'testAccAvailableEc2InstanceTypeForRegion', not 'testAccAvailableEc2InstanceTypeForAvailabilityZone'. --- ..._aws_autoscalingplans_scaling_plan_test.go | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/aws/resource_aws_autoscalingplans_scaling_plan_test.go b/aws/resource_aws_autoscalingplans_scaling_plan_test.go index 99421cbd586a..de4d7149e749 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan_test.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan_test.go @@ -97,7 +97,7 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling(t *testing.T) { DisableBinaryDriver: true, Steps: []resource.TestStep{ { - Config: testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(rName, rName), + Config: testAccAutoScalingPlansScalingPlanConfigBasicDynamicScaling(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -159,7 +159,7 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling(t *testing.T) DisableBinaryDriver: true, Steps: []resource.TestStep{ { - Config: testAccAutoScalingPlansScalingPlanConfig_basicPredictiveScaling(rName, rName), + Config: testAccAutoScalingPlansScalingPlanConfigBasicPredictiveScaling(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -224,7 +224,7 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { DisableBinaryDriver: true, Steps: []resource.TestStep{ { - Config: testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(rName, rName), + Config: testAccAutoScalingPlansScalingPlanConfigBasicDynamicScaling(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -261,7 +261,7 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { ), }, { - Config: testAccAutoScalingPlansScalingPlanConfig_basicPredictiveScaling(rName, rNameUpdated), + Config: testAccAutoScalingPlansScalingPlanConfigBasicPredictiveScaling(rName, rNameUpdated), Check: resource.ComposeTestCheckFunc( testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -323,7 +323,7 @@ func TestAccAwsAutoScalingPlansScalingPlan_disappears(t *testing.T) { CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, Steps: []resource.TestStep{ { - Config: testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(rName, rName), + Config: testAccAutoScalingPlansScalingPlanConfigBasicDynamicScaling(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), testAccCheckResourceDisappears(testAccProvider, resourceAwsAutoScalingPlansScalingPlan(), resourceName), @@ -434,18 +434,27 @@ func testAccCheckAutoScalingPlansScalingPlanAttr(name string, resourceIdMap *map } } -func testAccAutoScalingPlansScalingPlanConfig_asg(rName, tagName string) string { +func testAccAutoScalingPlansScalingPlanConfigAutoScalingGroupBase(rName, tagName string) string { return composeConfig( testAccLatestAmazonLinuxHvmEbsAmiConfig(), - testAccAvailableEc2InstanceTypeForAvailabilityZone("data.aws_availability_zones.available.names[0]", "t3.micro", "t2.micro"), + testAccAvailableEc2InstanceTypeForRegion("t3.micro", "t2.micro"), fmt.Sprintf(` +data "aws_availability_zones" "available" { + # Exclude usw2-az4 (us-west-2d) as it has limited instance types. + exclude_zone_ids = ["usw2-az4"] + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + resource "aws_launch_configuration" "test" { image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id instance_type = data.aws_ec2_instance_type_offering.available.instance_type } -data "aws_availability_zones" "available" {} - resource "aws_autoscaling_group" "test" { name = %[1]q @@ -467,9 +476,10 @@ resource "aws_autoscaling_group" "test" { `, rName, tagName)) } -func testAccAutoScalingPlansScalingPlanConfig_basicDynamicScaling(rName, tagName string) string { +func testAccAutoScalingPlansScalingPlanConfigBasicDynamicScaling(rName, tagName string) string { return composeConfig( - testAccAutoScalingPlansScalingPlanConfig_asg(rName, tagName) + fmt.Sprintf(` + testAccAutoScalingPlansScalingPlanConfigAutoScalingGroupBase(rName, tagName), + fmt.Sprintf(` resource "aws_autoscalingplans_scaling_plan" "test" { name = %[1]q @@ -499,9 +509,10 @@ resource "aws_autoscalingplans_scaling_plan" "test" { `, rName, tagName)) } -func testAccAutoScalingPlansScalingPlanConfig_basicPredictiveScaling(rName, tagName string) string { +func testAccAutoScalingPlansScalingPlanConfigBasicPredictiveScaling(rName, tagName string) string { return composeConfig( - testAccAutoScalingPlansScalingPlanConfig_asg(rName, tagName) + fmt.Sprintf(` + testAccAutoScalingPlansScalingPlanConfigAutoScalingGroupBase(rName, tagName), + fmt.Sprintf(` resource "aws_autoscalingplans_scaling_plan" "test" { name = %[1]q From c21359e76943a4e63165491eee4be9feea70d875 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 6 Jul 2020 15:52:19 -0400 Subject: [PATCH 11/19] Use 'tfawsresource' acceptance test checkers. --- ..._aws_autoscalingplans_scaling_plan_test.go | 214 +++++++----------- 1 file changed, 78 insertions(+), 136 deletions(-) diff --git a/aws/resource_aws_autoscalingplans_scaling_plan_test.go b/aws/resource_aws_autoscalingplans_scaling_plan_test.go index de4d7149e749..0e1bc365a54f 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan_test.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan_test.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "reflect" - "regexp" "sort" "strconv" "testing" @@ -16,6 +15,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/autoscalingplans/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfawsresource" ) func init() { @@ -85,21 +85,18 @@ func testSweepAutoScalingPlansScalingPlans(region string) error { func TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling(t *testing.T) { var scalingPlan autoscalingplans.ScalingPlan - resourceIdMap := map[string]string{} resourceName := "aws_autoscalingplans_scaling_plan.test" rName := acctest.RandomWithPrefix("tf-acc-test") - asgResourceId := fmt.Sprintf("autoScalingGroup/%s", rName) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, - DisableBinaryDriver: true, + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, Steps: []resource.TestStep{ { Config: testAccAutoScalingPlansScalingPlanConfigBasicDynamicScaling(rName, rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), + testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "scaling_plan_version", "1"), resource.TestCheckResourceAttr(resourceName, "application_source.#", "1"), @@ -108,29 +105,20 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling(t *testing.T) { rName: {rName}, }), resource.TestCheckResourceAttr(resourceName, "scaling_instruction.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "customized_load_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "disable_dynamic_scaling", "false"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "max_capacity", "3"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "min_capacity", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_behavior", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_buffer", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_mode", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "resource_id", asgResourceId), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scalable_dimension", "autoscaling:autoScalingGroup:DesiredCapacity"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scaling_policy_update_behavior", "KeepExternalPolicies"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scheduled_action_buffer_time", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "service_namespace", "autoscaling"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.customized_scaling_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.disable_scale_in", "false"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.estimated_instance_warmup", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.resource_label", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_in_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_out_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.target_value", "75"), + tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "scaling_instruction.*", map[string]string{ + "customized_load_metric_specification.#": "0", + "disable_dynamic_scaling": "false", + "max_capacity": "3", + "min_capacity": "0", + "predefined_load_metric_specification.#": "0", + "predictive_scaling_max_capacity_buffer": "0", + "resource_id": fmt.Sprintf("autoScalingGroup/%s", rName), + "scalable_dimension": "autoscaling:autoScalingGroup:DesiredCapacity", + "scaling_policy_update_behavior": "KeepExternalPolicies", + "scheduled_action_buffer_time": "0", + "service_namespace": "autoscaling", + "target_tracking_configuration.#": "1", + }), ), }, { @@ -147,21 +135,18 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling(t *testing.T) { func TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling(t *testing.T) { var scalingPlan autoscalingplans.ScalingPlan - resourceIdMap := map[string]string{} resourceName := "aws_autoscalingplans_scaling_plan.test" rName := acctest.RandomWithPrefix("tf-acc-test") - asgResourceId := fmt.Sprintf("autoScalingGroup/%s", rName) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, - DisableBinaryDriver: true, + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, Steps: []resource.TestStep{ { Config: testAccAutoScalingPlansScalingPlanConfigBasicPredictiveScaling(rName, rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), + testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "scaling_plan_version", "1"), resource.TestCheckResourceAttr(resourceName, "application_source.#", "1"), @@ -170,31 +155,23 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling(t *testing.T) rName: {rName}, }), resource.TestCheckResourceAttr(resourceName, "scaling_instruction.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "customized_load_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "disable_dynamic_scaling", "true"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "max_capacity", "3"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "min_capacity", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.0.predefined_load_metric_type", "ASGTotalCPUUtilization"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.0.resource_label", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_behavior", "SetForecastCapacityToMaxCapacity"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_buffer", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_mode", "ForecastOnly"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "resource_id", asgResourceId), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scalable_dimension", "autoscaling:autoScalingGroup:DesiredCapacity"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scaling_policy_update_behavior", "KeepExternalPolicies"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scheduled_action_buffer_time", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "service_namespace", "autoscaling"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.customized_scaling_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.disable_scale_in", "false"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.estimated_instance_warmup", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.resource_label", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_in_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_out_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.target_value", "75"), + tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "scaling_instruction.*", map[string]string{ + "customized_load_metric_specification.#": "0", + "disable_dynamic_scaling": "true", + "max_capacity": "3", + "min_capacity": "0", + "predefined_load_metric_specification.#": "1", + "predefined_load_metric_specification.0.predefined_load_metric_type": "ASGTotalCPUUtilization", + "predictive_scaling_max_capacity_behavior": "SetForecastCapacityToMaxCapacity", + "predictive_scaling_max_capacity_buffer": "0", + "predictive_scaling_mode": "ForecastOnly", + "resource_id": fmt.Sprintf("autoScalingGroup/%s", rName), + "scalable_dimension": "autoscaling:autoScalingGroup:DesiredCapacity", + "scaling_policy_update_behavior": "KeepExternalPolicies", + "scheduled_action_buffer_time": "0", + "service_namespace": "autoscaling", + "target_tracking_configuration.#": "1", + }), ), }, { @@ -211,10 +188,8 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling(t *testing.T) func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { var scalingPlan autoscalingplans.ScalingPlan - resourceIdMap := map[string]string{} resourceName := "aws_autoscalingplans_scaling_plan.test" rName := acctest.RandomWithPrefix("tf-acc-test") - asgResourceId := fmt.Sprintf("autoScalingGroup/%s", rName) rNameUpdated := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ @@ -226,7 +201,7 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { { Config: testAccAutoScalingPlansScalingPlanConfigBasicDynamicScaling(rName, rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), + testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "scaling_plan_version", "1"), resource.TestCheckResourceAttr(resourceName, "application_source.#", "1"), @@ -235,35 +210,26 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { rName: {rName}, }), resource.TestCheckResourceAttr(resourceName, "scaling_instruction.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "customized_load_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "disable_dynamic_scaling", "false"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "max_capacity", "3"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "min_capacity", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_behavior", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_buffer", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_mode", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "resource_id", asgResourceId), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scalable_dimension", "autoscaling:autoScalingGroup:DesiredCapacity"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scaling_policy_update_behavior", "KeepExternalPolicies"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scheduled_action_buffer_time", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "service_namespace", "autoscaling"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.customized_scaling_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.disable_scale_in", "false"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.estimated_instance_warmup", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.resource_label", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_in_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_out_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.target_value", "75"), + tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "scaling_instruction.*", map[string]string{ + "customized_load_metric_specification.#": "0", + "disable_dynamic_scaling": "false", + "max_capacity": "3", + "min_capacity": "0", + "predefined_load_metric_specification.#": "0", + "predictive_scaling_max_capacity_buffer": "0", + "resource_id": fmt.Sprintf("autoScalingGroup/%s", rName), + "scalable_dimension": "autoscaling:autoScalingGroup:DesiredCapacity", + "scaling_policy_update_behavior": "KeepExternalPolicies", + "scheduled_action_buffer_time": "0", + "service_namespace": "autoscaling", + "target_tracking_configuration.#": "1", + }), ), }, { Config: testAccAutoScalingPlansScalingPlanConfigBasicPredictiveScaling(rName, rNameUpdated), Check: resource.ComposeTestCheckFunc( - testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), + testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "scaling_plan_version", "1"), resource.TestCheckResourceAttr(resourceName, "application_source.#", "1"), @@ -272,31 +238,23 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { rNameUpdated: {rNameUpdated}, }), resource.TestCheckResourceAttr(resourceName, "scaling_instruction.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "customized_load_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "disable_dynamic_scaling", "true"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "max_capacity", "3"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "min_capacity", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.0.predefined_load_metric_type", "ASGTotalCPUUtilization"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predefined_load_metric_specification.0.resource_label", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_behavior", "SetForecastCapacityToMaxCapacity"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_max_capacity_buffer", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "predictive_scaling_mode", "ForecastOnly"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "resource_id", asgResourceId), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scalable_dimension", "autoscaling:autoScalingGroup:DesiredCapacity"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scaling_policy_update_behavior", "KeepExternalPolicies"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "scheduled_action_buffer_time", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "service_namespace", "autoscaling"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.customized_scaling_metric_specification.#", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.disable_scale_in", "false"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.estimated_instance_warmup", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.#", "1"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.predefined_scaling_metric_type", "ASGAverageCPUUtilization"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.predefined_scaling_metric_specification.0.resource_label", ""), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_in_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.scale_out_cooldown", "0"), - testAccCheckAutoScalingPlansScalingPlanAttr(resourceName, &resourceIdMap, asgResourceId, "target_tracking_configuration.1292942785.target_value", "75"), + tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "scaling_instruction.*", map[string]string{ + "customized_load_metric_specification.#": "0", + "disable_dynamic_scaling": "true", + "max_capacity": "3", + "min_capacity": "0", + "predefined_load_metric_specification.#": "1", + "predefined_load_metric_specification.0.predefined_load_metric_type": "ASGTotalCPUUtilization", + "predictive_scaling_max_capacity_behavior": "SetForecastCapacityToMaxCapacity", + "predictive_scaling_max_capacity_buffer": "0", + "predictive_scaling_mode": "ForecastOnly", + "resource_id": fmt.Sprintf("autoScalingGroup/%s", rName), + "scalable_dimension": "autoscaling:autoScalingGroup:DesiredCapacity", + "scaling_policy_update_behavior": "KeepExternalPolicies", + "scheduled_action_buffer_time": "0", + "service_namespace": "autoscaling", + "target_tracking_configuration.#": "1", + }), ), }, { @@ -313,7 +271,6 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { func TestAccAwsAutoScalingPlansScalingPlan_disappears(t *testing.T) { var scalingPlan autoscalingplans.ScalingPlan - resourceIdMap := map[string]string{} resourceName := "aws_autoscalingplans_scaling_plan.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -325,7 +282,7 @@ func TestAccAwsAutoScalingPlansScalingPlan_disappears(t *testing.T) { { Config: testAccAutoScalingPlansScalingPlanConfigBasicDynamicScaling(rName, rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan, &resourceIdMap), + testAccCheckAutoScalingPlansScalingPlanExists(resourceName, &scalingPlan), testAccCheckResourceDisappears(testAccProvider, resourceAwsAutoScalingPlansScalingPlan(), resourceName), ), ExpectNonEmptyPlan: true, @@ -363,7 +320,7 @@ func testAccCheckAutoScalingPlansScalingPlanDestroy(s *terraform.State) error { return nil } -func testAccCheckAutoScalingPlansScalingPlanExists(name string, scalingPlan *autoscalingplans.ScalingPlan, resourceIdMap *map[string]string) resource.TestCheckFunc { +func testAccCheckAutoScalingPlansScalingPlanExists(name string, scalingPlan *autoscalingplans.ScalingPlan) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).autoscalingplansconn @@ -393,15 +350,6 @@ func testAccCheckAutoScalingPlansScalingPlanExists(name string, scalingPlan *aut *scalingPlan = *resp.ScalingPlans[0] - // Build map of resource_id to scaling_plan hash value. - re := regexp.MustCompile(`^scaling_instruction\.(\d+)\.resource_id$`) - for k, v := range rs.Primary.Attributes { - matches := re.FindStringSubmatch(k) - if matches != nil { - (*resourceIdMap)[v] = matches[1] - } - } - return nil } } @@ -428,13 +376,7 @@ func testAccCheckAutoScalingPlansApplicationSourceTags(scalingPlan *autoscalingp } } -func testAccCheckAutoScalingPlansScalingPlanAttr(name string, resourceIdMap *map[string]string, resourceId, key, value string) resource.TestCheckFunc { - return func(s *terraform.State) error { - return resource.TestCheckResourceAttr(name, fmt.Sprintf("scaling_instruction.%s.%s", (*resourceIdMap)[resourceId], key), value)(s) - } -} - -func testAccAutoScalingPlansScalingPlanConfigAutoScalingGroupBase(rName, tagName string) string { +func testAccAutoScalingPlansScalingPlanConfigBase(rName, tagName string) string { return composeConfig( testAccLatestAmazonLinuxHvmEbsAmiConfig(), testAccAvailableEc2InstanceTypeForRegion("t3.micro", "t2.micro"), @@ -478,7 +420,7 @@ resource "aws_autoscaling_group" "test" { func testAccAutoScalingPlansScalingPlanConfigBasicDynamicScaling(rName, tagName string) string { return composeConfig( - testAccAutoScalingPlansScalingPlanConfigAutoScalingGroupBase(rName, tagName), + testAccAutoScalingPlansScalingPlanConfigBase(rName, tagName), fmt.Sprintf(` resource "aws_autoscalingplans_scaling_plan" "test" { name = %[1]q @@ -511,7 +453,7 @@ resource "aws_autoscalingplans_scaling_plan" "test" { func testAccAutoScalingPlansScalingPlanConfigBasicPredictiveScaling(rName, tagName string) string { return composeConfig( - testAccAutoScalingPlansScalingPlanConfigAutoScalingGroupBase(rName, tagName), + testAccAutoScalingPlansScalingPlanConfigBase(rName, tagName), fmt.Sprintf(` resource "aws_autoscalingplans_scaling_plan" "test" { name = %[1]q From 83043172da13871594c6ce3ec4df7799c438613c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 16 Aug 2020 17:13:38 -0400 Subject: [PATCH 12/19] Upgrade to Plugin SDK v2 and use Terraform 0.12 syntax in documentation. --- .../service/autoscalingplans/waiter/status.go | 2 +- .../service/autoscalingplans/waiter/waiter.go | 2 +- ...ource_aws_autoscalingplans_scaling_plan.go | 4 +-- ..._aws_autoscalingplans_scaling_plan_test.go | 33 ++++--------------- ...utoscalingplans_scaling_plan.html.markdown | 12 +++---- 5 files changed, 17 insertions(+), 36 deletions(-) diff --git a/aws/internal/service/autoscalingplans/waiter/status.go b/aws/internal/service/autoscalingplans/waiter/status.go index b2ccef45e94d..954188ccae02 100644 --- a/aws/internal/service/autoscalingplans/waiter/status.go +++ b/aws/internal/service/autoscalingplans/waiter/status.go @@ -5,7 +5,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/autoscalingplans" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) const ( diff --git a/aws/internal/service/autoscalingplans/waiter/waiter.go b/aws/internal/service/autoscalingplans/waiter/waiter.go index affb17a3c764..22324ffe2a15 100644 --- a/aws/internal/service/autoscalingplans/waiter/waiter.go +++ b/aws/internal/service/autoscalingplans/waiter/waiter.go @@ -4,7 +4,7 @@ import ( "time" "github.com/aws/aws-sdk-go/service/autoscalingplans" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) const ( diff --git a/aws/resource_aws_autoscalingplans_scaling_plan.go b/aws/resource_aws_autoscalingplans_scaling_plan.go index 784439db1775..d8bac8938eeb 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan.go @@ -7,8 +7,8 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/autoscalingplans" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/autoscalingplans/waiter" ) diff --git a/aws/resource_aws_autoscalingplans_scaling_plan_test.go b/aws/resource_aws_autoscalingplans_scaling_plan_test.go index 0e1bc365a54f..bb8f33681c51 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan_test.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan_test.go @@ -11,9 +11,9 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/autoscalingplans" "github.com/hashicorp/go-multierror" - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/autoscalingplans/waiter" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfawsresource" ) @@ -111,11 +111,9 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling(t *testing.T) { "max_capacity": "3", "min_capacity": "0", "predefined_load_metric_specification.#": "0", - "predictive_scaling_max_capacity_buffer": "0", "resource_id": fmt.Sprintf("autoScalingGroup/%s", rName), "scalable_dimension": "autoscaling:autoScalingGroup:DesiredCapacity", "scaling_policy_update_behavior": "KeepExternalPolicies", - "scheduled_action_buffer_time": "0", "service_namespace": "autoscaling", "target_tracking_configuration.#": "1", }), @@ -163,12 +161,10 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling(t *testing.T) "predefined_load_metric_specification.#": "1", "predefined_load_metric_specification.0.predefined_load_metric_type": "ASGTotalCPUUtilization", "predictive_scaling_max_capacity_behavior": "SetForecastCapacityToMaxCapacity", - "predictive_scaling_max_capacity_buffer": "0", "predictive_scaling_mode": "ForecastOnly", "resource_id": fmt.Sprintf("autoScalingGroup/%s", rName), "scalable_dimension": "autoscaling:autoScalingGroup:DesiredCapacity", "scaling_policy_update_behavior": "KeepExternalPolicies", - "scheduled_action_buffer_time": "0", "service_namespace": "autoscaling", "target_tracking_configuration.#": "1", }), @@ -193,10 +189,9 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { rNameUpdated := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, - DisableBinaryDriver: true, + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, Steps: []resource.TestStep{ { Config: testAccAutoScalingPlansScalingPlanConfigBasicDynamicScaling(rName, rName), @@ -216,11 +211,9 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { "max_capacity": "3", "min_capacity": "0", "predefined_load_metric_specification.#": "0", - "predictive_scaling_max_capacity_buffer": "0", "resource_id": fmt.Sprintf("autoScalingGroup/%s", rName), "scalable_dimension": "autoscaling:autoScalingGroup:DesiredCapacity", "scaling_policy_update_behavior": "KeepExternalPolicies", - "scheduled_action_buffer_time": "0", "service_namespace": "autoscaling", "target_tracking_configuration.#": "1", }), @@ -246,12 +239,10 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { "predefined_load_metric_specification.#": "1", "predefined_load_metric_specification.0.predefined_load_metric_type": "ASGTotalCPUUtilization", "predictive_scaling_max_capacity_behavior": "SetForecastCapacityToMaxCapacity", - "predictive_scaling_max_capacity_buffer": "0", "predictive_scaling_mode": "ForecastOnly", "resource_id": fmt.Sprintf("autoScalingGroup/%s", rName), "scalable_dimension": "autoscaling:autoScalingGroup:DesiredCapacity", "scaling_policy_update_behavior": "KeepExternalPolicies", - "scheduled_action_buffer_time": "0", "service_namespace": "autoscaling", "target_tracking_configuration.#": "1", }), @@ -379,19 +370,9 @@ func testAccCheckAutoScalingPlansApplicationSourceTags(scalingPlan *autoscalingp func testAccAutoScalingPlansScalingPlanConfigBase(rName, tagName string) string { return composeConfig( testAccLatestAmazonLinuxHvmEbsAmiConfig(), + testAccAvailableAZsNoOptInDefaultExcludeConfig(), testAccAvailableEc2InstanceTypeForRegion("t3.micro", "t2.micro"), fmt.Sprintf(` -data "aws_availability_zones" "available" { - # Exclude usw2-az4 (us-west-2d) as it has limited instance types. - exclude_zone_ids = ["usw2-az4"] - state = "available" - - filter { - name = "opt-in-status" - values = ["opt-in-not-required"] - } -} - resource "aws_launch_configuration" "test" { image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id instance_type = data.aws_ec2_instance_type_offering.available.instance_type diff --git a/website/docs/r/autoscalingplans_scaling_plan.html.markdown b/website/docs/r/autoscalingplans_scaling_plan.html.markdown index 4074ddf21b7f..46353fbec132 100644 --- a/website/docs/r/autoscalingplans_scaling_plan.html.markdown +++ b/website/docs/r/autoscalingplans_scaling_plan.html.markdown @@ -21,8 +21,8 @@ data "aws_availability_zones" "available" {} resource "aws_autoscaling_group" "example" { name_prefix = "example" - launch_configuration = "${aws_launch_configuration.example.name}" - availability_zones = ["${data.aws_availability_zones.available.names[0]}"] + launch_configuration = aws_launch_configuration.example.name + availability_zones = [data.aws_availability_zones.available.names[0]] min_size = 0 max_size = 3 @@ -49,7 +49,7 @@ resource "aws_autoscalingplans_scaling_plan" "example" { scaling_instruction { max_capacity = 3 min_capacity = 0 - resource_id = "${format("autoScalingGroup/%s", aws_autoscaling_group.example.name)}" + resource_id = format("autoScalingGroup/%s", aws_autoscaling_group.example.name) scalable_dimension = "autoscaling:autoScalingGroup:DesiredCapacity" service_namespace = "autoscaling" @@ -72,8 +72,8 @@ data "aws_availability_zones" "available" {} resource "aws_autoscaling_group" "example" { name_prefix = "example" - launch_configuration = "${aws_launch_configuration.example.name}" - availability_zones = ["${data.aws_availability_zones.available.names[0]}"] + launch_configuration = aws_launch_configuration.example.name + availability_zones = [data.aws_availability_zones.available.names[0]] min_size = 0 max_size = 3 @@ -102,7 +102,7 @@ resource "aws_autoscalingplans_scaling_plan" "example" { max_capacity = 3 min_capacity = 0 - resource_id = "${format("autoScalingGroup/%s", aws_autoscaling_group.example.name)}" + resource_id = format("autoScalingGroup/%s", aws_autoscaling_group.example.name) scalable_dimension = "autoscaling:autoScalingGroup:DesiredCapacity" service_namespace = "autoscaling" From 0662a1b14f9bc5e61b11540ac7001c756b5f05d4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 16 Oct 2020 13:54:10 -0400 Subject: [PATCH 13/19] r/aws_autoscalingplans_scaling_plan: Use '_Values()' (#14601). --- ...ource_aws_autoscalingplans_scaling_plan.go | 100 +++++------------- 1 file changed, 25 insertions(+), 75 deletions(-) diff --git a/aws/resource_aws_autoscalingplans_scaling_plan.go b/aws/resource_aws_autoscalingplans_scaling_plan.go index d8bac8938eeb..a02dbe1c10ee 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan.go @@ -145,14 +145,9 @@ func resourceAwsAutoScalingPlansScalingPlan() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "predefined_load_metric_type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - autoscalingplans.LoadMetricTypeAlbtargetGroupRequestCount, - autoscalingplans.LoadMetricTypeAsgtotalCpuutilization, - autoscalingplans.LoadMetricTypeAsgtotalNetworkIn, - autoscalingplans.LoadMetricTypeAsgtotalNetworkOut, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(autoscalingplans.LoadMetricType_Values(), false), }, "resource_label": { @@ -165,13 +160,9 @@ func resourceAwsAutoScalingPlansScalingPlan() *schema.Resource { }, "predictive_scaling_max_capacity_behavior": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - autoscalingplans.PredictiveScalingMaxCapacityBehaviorSetForecastCapacityToMaxCapacity, - autoscalingplans.PredictiveScalingMaxCapacityBehaviorSetMaxCapacityAboveForecastCapacity, - autoscalingplans.PredictiveScalingMaxCapacityBehaviorSetMaxCapacityToForecastCapacity, - }, false), + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(autoscalingplans.PredictiveScalingMaxCapacityBehavior_Values(), false), }, "predictive_scaling_max_capacity_buffer": { @@ -181,12 +172,9 @@ func resourceAwsAutoScalingPlansScalingPlan() *schema.Resource { }, "predictive_scaling_mode": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - autoscalingplans.PredictiveScalingModeForecastAndScale, - autoscalingplans.PredictiveScalingModeForecastOnly, - }, false), + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(autoscalingplans.PredictiveScalingMode_Values(), false), }, "resource_id": { @@ -196,28 +184,16 @@ func resourceAwsAutoScalingPlansScalingPlan() *schema.Resource { }, "scalable_dimension": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - autoscalingplans.ScalableDimensionAutoscalingAutoScalingGroupDesiredCapacity, - autoscalingplans.ScalableDimensionDynamodbIndexReadCapacityUnits, - autoscalingplans.ScalableDimensionDynamodbIndexWriteCapacityUnits, - autoscalingplans.ScalableDimensionDynamodbTableReadCapacityUnits, - autoscalingplans.ScalableDimensionDynamodbTableWriteCapacityUnits, - autoscalingplans.ScalableDimensionEcsServiceDesiredCount, - autoscalingplans.ScalableDimensionEc2SpotFleetRequestTargetCapacity, - autoscalingplans.ScalableDimensionRdsClusterReadReplicaCount, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(autoscalingplans.ScalableDimension_Values(), false), }, "scaling_policy_update_behavior": { - Type: schema.TypeString, - Optional: true, - Default: autoscalingplans.ScalingPolicyUpdateBehaviorKeepExternalPolicies, - ValidateFunc: validation.StringInSlice([]string{ - autoscalingplans.ScalingPolicyUpdateBehaviorKeepExternalPolicies, - autoscalingplans.ScalingPolicyUpdateBehaviorReplaceExternalPolicies, - }, false), + Type: schema.TypeString, + Optional: true, + Default: autoscalingplans.ScalingPolicyUpdateBehaviorKeepExternalPolicies, + ValidateFunc: validation.StringInSlice(autoscalingplans.ScalingPolicyUpdateBehavior_Values(), false), }, "scheduled_action_buffer_time": { @@ -227,15 +203,9 @@ func resourceAwsAutoScalingPlansScalingPlan() *schema.Resource { }, "service_namespace": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - autoscalingplans.ServiceNamespaceAutoscaling, - autoscalingplans.ServiceNamespaceDynamodb, - autoscalingplans.ServiceNamespaceEcs, - autoscalingplans.ServiceNamespaceEc2, - autoscalingplans.ServiceNamespaceRds, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(autoscalingplans.ServiceNamespace_Values(), false), }, "target_tracking_configuration": { @@ -269,15 +239,9 @@ func resourceAwsAutoScalingPlansScalingPlan() *schema.Resource { }, "statistic": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - autoscalingplans.MetricStatisticAverage, - autoscalingplans.MetricStatisticMaximum, - autoscalingplans.MetricStatisticMinimum, - autoscalingplans.MetricStatisticSampleCount, - autoscalingplans.MetricStatisticSum, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(autoscalingplans.MetricStatistic_Values(), false), }, "unit": { @@ -307,23 +271,9 @@ func resourceAwsAutoScalingPlansScalingPlan() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "predefined_scaling_metric_type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - autoscalingplans.ScalingMetricTypeAlbrequestCountPerTarget, - autoscalingplans.ScalingMetricTypeAsgaverageCpuutilization, - autoscalingplans.ScalingMetricTypeAsgaverageNetworkIn, - autoscalingplans.ScalingMetricTypeAsgaverageNetworkOut, - autoscalingplans.ScalingMetricTypeDynamoDbreadCapacityUtilization, - autoscalingplans.ScalingMetricTypeDynamoDbwriteCapacityUtilization, - autoscalingplans.ScalingMetricTypeEcsserviceAverageCpuutilization, - autoscalingplans.ScalingMetricTypeEcsserviceAverageMemoryUtilization, - autoscalingplans.ScalingMetricTypeEc2spotFleetRequestAverageCpuutilization, - autoscalingplans.ScalingMetricTypeEc2spotFleetRequestAverageNetworkIn, - autoscalingplans.ScalingMetricTypeEc2spotFleetRequestAverageNetworkOut, - autoscalingplans.ScalingMetricTypeRdsreaderAverageCpuutilization, - autoscalingplans.ScalingMetricTypeRdsreaderAverageDatabaseConnections, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(autoscalingplans.ScalingMetricType_Values(), false), }, "resource_label": { From 3883d3d9a3d0ac29c6af1d47d530e353dba404a6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 16 Oct 2020 14:37:52 -0400 Subject: [PATCH 14/19] r/aws_autoscalingplans_scaling_plan: Better handling of eventual consistency when waiting for creation and deletion. Acceptance test output: $ make testacc TEST=./aws/ TESTARGS='-run=TestAccAwsAutoScalingPlansScalingPlan_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAwsAutoScalingPlansScalingPlan_ -timeout 120m === RUN TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling === PAUSE TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling === RUN TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling === PAUSE TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling === RUN TestAccAwsAutoScalingPlansScalingPlan_basicUpdate === PAUSE TestAccAwsAutoScalingPlansScalingPlan_basicUpdate === RUN TestAccAwsAutoScalingPlansScalingPlan_disappears === PAUSE TestAccAwsAutoScalingPlansScalingPlan_disappears === CONT TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling === CONT TestAccAwsAutoScalingPlansScalingPlan_basicUpdate === CONT TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling === CONT TestAccAwsAutoScalingPlansScalingPlan_disappears 2020/10/16 14:29:48 [INFO] Auto Scaling Scaling Plan (tf-acc-test-2865312284272710950/1) status message: Scaling plan has been created and applied to all resources. resource_aws_autoscalingplans_scaling_plan_test.go:268: [INFO] Got non-empty plan, as expected --- PASS: TestAccAwsAutoScalingPlansScalingPlan_disappears (53.00s) --- PASS: TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling (57.22s) --- PASS: TestAccAwsAutoScalingPlansScalingPlan_basicDynamicScaling (67.94s) --- PASS: TestAccAwsAutoScalingPlansScalingPlan_basicUpdate (99.22s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 99.262s --- .../service/autoscalingplans/finder/finder.go | 26 +++++++++ .../service/autoscalingplans/waiter/status.go | 25 ++++----- .../service/autoscalingplans/waiter/waiter.go | 8 ++- ...ource_aws_autoscalingplans_scaling_plan.go | 18 ++---- ..._aws_autoscalingplans_scaling_plan_test.go | 55 +++++++------------ 5 files changed, 68 insertions(+), 64 deletions(-) create mode 100644 aws/internal/service/autoscalingplans/finder/finder.go diff --git a/aws/internal/service/autoscalingplans/finder/finder.go b/aws/internal/service/autoscalingplans/finder/finder.go new file mode 100644 index 000000000000..6e38289758dc --- /dev/null +++ b/aws/internal/service/autoscalingplans/finder/finder.go @@ -0,0 +1,26 @@ +package finder + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/autoscalingplans" +) + +// ScalingPlan returns the scaling plan corresponding to the specified name and version. +// Returns returns nil and potentially an API error if no scaling plan is found. +func ScalingPlan(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int) (*autoscalingplans.ScalingPlan, error) { + input := &autoscalingplans.DescribeScalingPlansInput{ + ScalingPlanNames: aws.StringSlice([]string{scalingPlanName}), + ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), + } + + output, err := conn.DescribeScalingPlans(input) + if err != nil { + return nil, err + } + + if output == nil || len(output.ScalingPlans) == 0 { + return nil, nil + } + + return output.ScalingPlans[0], nil +} diff --git a/aws/internal/service/autoscalingplans/waiter/status.go b/aws/internal/service/autoscalingplans/waiter/status.go index 954188ccae02..e1c7630c53f0 100644 --- a/aws/internal/service/autoscalingplans/waiter/status.go +++ b/aws/internal/service/autoscalingplans/waiter/status.go @@ -5,36 +5,33 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/autoscalingplans" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/autoscalingplans/finder" ) const ( - // ScalingPlan NotFound - ScalingPlanStatusNotFound = "NotFound" - - // ScalingPlan Unknown - ScalingPlanStatusUnknown = "Unknown" + scalingPlanStatusNotFound = "NotFound" + scalingPlanStatusUnknown = "Unknown" ) // ScalingPlanStatus fetches the ScalingPlan and its Status func ScalingPlanStatus(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int) resource.StateRefreshFunc { return func() (interface{}, string, error) { - input := &autoscalingplans.DescribeScalingPlansInput{ - ScalingPlanNames: aws.StringSlice([]string{scalingPlanName}), - ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), - } + scalingPlan, err := finder.ScalingPlan(conn, scalingPlanName, scalingPlanVersion) - output, err := conn.DescribeScalingPlans(input) + if tfawserr.ErrCodeEquals(err, autoscalingplans.ErrCodeObjectNotFoundException) { + return nil, scalingPlanStatusNotFound, nil + } if err != nil { - return nil, ScalingPlanStatusUnknown, err + return nil, scalingPlanStatusUnknown, err } - if len(output.ScalingPlans) == 0 { - return "", ScalingPlanStatusNotFound, nil + if scalingPlan == nil { + return nil, scalingPlanStatusNotFound, nil } - scalingPlan := output.ScalingPlans[0] if statusMessage := aws.StringValue(scalingPlan.StatusMessage); statusMessage != "" { log.Printf("[INFO] Auto Scaling Scaling Plan (%s/%d) status message: %s", scalingPlanName, scalingPlanVersion, statusMessage) } diff --git a/aws/internal/service/autoscalingplans/waiter/waiter.go b/aws/internal/service/autoscalingplans/waiter/waiter.go index 22324ffe2a15..fe3451026d38 100644 --- a/aws/internal/service/autoscalingplans/waiter/waiter.go +++ b/aws/internal/service/autoscalingplans/waiter/waiter.go @@ -39,8 +39,12 @@ func ScalingPlanCreated(conn *autoscalingplans.AutoScalingPlans, scalingPlanName // ScalingPlanDeleted waits for a ScalingPlan to return Deleted func ScalingPlanDeleted(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int) (*autoscalingplans.ScalingPlan, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{autoscalingplans.ScalingPlanStatusCodeDeletionInProgress}, - Target: []string{ScalingPlanStatusNotFound}, + Pending: []string{ + autoscalingplans.ScalingPlanStatusCodeActive, + autoscalingplans.ScalingPlanStatusCodeActiveWithProblems, + autoscalingplans.ScalingPlanStatusCodeDeletionInProgress, + }, + Target: []string{}, Refresh: ScalingPlanStatus(conn, scalingPlanName, scalingPlanVersion), Timeout: ScalingPlanDeletedTimeout, } diff --git a/aws/resource_aws_autoscalingplans_scaling_plan.go b/aws/resource_aws_autoscalingplans_scaling_plan.go index a02dbe1c10ee..df99d0517f26 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/service/autoscalingplans" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/autoscalingplans/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/autoscalingplans/waiter" ) @@ -347,20 +348,16 @@ func resourceAwsAutoScalingPlansScalingPlanCreate(d *schema.ResourceData, meta i func resourceAwsAutoScalingPlansScalingPlanRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).autoscalingplansconn - scalingPlanName := d.Get("name").(string) - scalingPlanVersion := d.Get("scaling_plan_version").(int) - - v, state, err := waiter.ScalingPlanStatus(conn, scalingPlanName, scalingPlanVersion)() - if isAWSErr(err, autoscalingplans.ErrCodeObjectNotFoundException, "") || state == waiter.ScalingPlanStatusNotFound { + scalingPlan, err := finder.ScalingPlan(conn, d.Get("name").(string), d.Get("scaling_plan_version").(int)) + if err != nil { + return fmt.Errorf("error reading Auto Scaling Scaling Plan (%s): %w", d.Id(), err) + } + if scalingPlan == nil { log.Printf("[WARN] Auto Scaling Scaling Plan (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - if err != nil { - return fmt.Errorf("error reading Auto Scaling Scaling Plan (%s): %w", d.Id(), err) - } - scalingPlan := v.(*autoscalingplans.ScalingPlan) err = d.Set("application_source", flattenAutoScalingPlansApplicationSource(scalingPlan.ApplicationSource)) if err != nil { return fmt.Errorf("error setting application_source: %w", err) @@ -421,9 +418,6 @@ func resourceAwsAutoScalingPlansScalingPlanDelete(d *schema.ResourceData, meta i } _, err = waiter.ScalingPlanDeleted(conn, scalingPlanName, scalingPlanVersion) - if isAWSErr(err, autoscalingplans.ErrCodeObjectNotFoundException, "") { - return nil - } if err != nil { return fmt.Errorf("error waiting for Auto Scaling Scaling Plan (%s) to be deleted: %w", d.Id(), err) } diff --git a/aws/resource_aws_autoscalingplans_scaling_plan_test.go b/aws/resource_aws_autoscalingplans_scaling_plan_test.go index bb8f33681c51..cc4b8de1b333 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan_test.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan_test.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/autoscalingplans/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/autoscalingplans/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfawsresource" ) @@ -42,34 +42,23 @@ func testSweepAutoScalingPlansScalingPlans(region string) error { } if err != nil { sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Auto Scaling Scaling Plans: %w", err)) - return sweeperErrs + return sweeperErrs.ErrorOrNil() } for _, scalingPlan := range output.ScalingPlans { scalingPlanName := aws.StringValue(scalingPlan.ScalingPlanName) scalingPlanVersion := int(aws.Int64Value(scalingPlan.ScalingPlanVersion)) - _, err := conn.DeleteScalingPlan(&autoscalingplans.DeleteScalingPlanInput{ - ScalingPlanName: aws.String(scalingPlanName), - ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), - }) - if isAWSErr(err, autoscalingplans.ErrCodeObjectNotFoundException, "") { - continue - } - if err != nil { - sweeperErr := fmt.Errorf("error deleting Auto Scaling Scaling Plan (%s): %w", scalingPlanName, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - } + r := resourceAwsAutoScalingPlansScalingPlan() + d := r.Data(nil) + d.SetId("????????????????") // ID not used in Delete. + d.Set("name", scalingPlanName) + d.Set("scaling_plan_version", scalingPlanVersion) + err = r.Delete(d, client) - _, err = waiter.ScalingPlanDeleted(conn, scalingPlanName, scalingPlanVersion) - if isAWSErr(err, autoscalingplans.ErrCodeObjectNotFoundException, "") { - continue - } if err != nil { - sweeperErr := fmt.Errorf("error waiting for Auto Scaling Scaling Plan (%s) deletion: %w", scalingPlanName, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) + log.Printf("[ERROR] %s", err) + sweeperErrs = multierror.Append(sweeperErrs, err) continue } } @@ -295,23 +284,20 @@ func testAccCheckAutoScalingPlansScalingPlanDestroy(s *terraform.State) error { return err } - resp, err := conn.DescribeScalingPlans(&autoscalingplans.DescribeScalingPlansInput{ - ScalingPlanNames: aws.StringSlice([]string{rs.Primary.Attributes["name"]}), - ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), - }) + scalingPlan, err := finder.ScalingPlan(conn, rs.Primary.Attributes["name"], scalingPlanVersion) if err != nil { return err } - if len(resp.ScalingPlans) == 0 { + if scalingPlan == nil { continue } - return fmt.Errorf("still exist.") + return fmt.Errorf("Auto Scaling Scaling Plan %s still exists", rs.Primary.ID) } return nil } -func testAccCheckAutoScalingPlansScalingPlanExists(name string, scalingPlan *autoscalingplans.ScalingPlan) resource.TestCheckFunc { +func testAccCheckAutoScalingPlansScalingPlanExists(name string, v *autoscalingplans.ScalingPlan) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).autoscalingplansconn @@ -320,7 +306,7 @@ func testAccCheckAutoScalingPlansScalingPlanExists(name string, scalingPlan *aut return fmt.Errorf("Not found: %s", name) } if rs.Primary.ID == "" { - return fmt.Errorf("No ID is set") + return fmt.Errorf("No Auto Scaling Scaling Plan ID is set") } scalingPlanVersion, err := strconv.Atoi(rs.Primary.Attributes["scaling_plan_version"]) @@ -328,18 +314,15 @@ func testAccCheckAutoScalingPlansScalingPlanExists(name string, scalingPlan *aut return err } - resp, err := conn.DescribeScalingPlans(&autoscalingplans.DescribeScalingPlansInput{ - ScalingPlanNames: aws.StringSlice([]string{rs.Primary.Attributes["name"]}), - ScalingPlanVersion: aws.Int64(int64(scalingPlanVersion)), - }) + scalingPlan, err := finder.ScalingPlan(conn, rs.Primary.Attributes["name"], scalingPlanVersion) if err != nil { return err } - if len(resp.ScalingPlans) == 0 { - return fmt.Errorf("Not found: %s", name) + if scalingPlan == nil { + return fmt.Errorf("Auto Scaling Scaling Plan %s not found", rs.Primary.ID) } - *scalingPlan = *resp.ScalingPlans[0] + *v = *scalingPlan return nil } From bb4302171f56a123a594499ffec961e2c3d6b74d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 19 Oct 2020 11:16:16 -0400 Subject: [PATCH 15/19] Add documentation note about service-linked role. --- website/docs/r/autoscalingplans_scaling_plan.html.markdown | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/website/docs/r/autoscalingplans_scaling_plan.html.markdown b/website/docs/r/autoscalingplans_scaling_plan.html.markdown index 46353fbec132..42053d97109b 100644 --- a/website/docs/r/autoscalingplans_scaling_plan.html.markdown +++ b/website/docs/r/autoscalingplans_scaling_plan.html.markdown @@ -11,6 +11,10 @@ description: |- Manages an AWS Auto Scaling scaling plan. More information can be found in the [AWS Auto Scaling User Guide](https://docs.aws.amazon.com/autoscaling/plans/userguide/what-is-aws-auto-scaling.html). +~> **NOTE:** The AWS Auto Scaling service uses an AWS IAM service-linked role to manage predictive scaling of Amazon EC2 Auto Scaling groups. The service attempts to automatically create this role the first time a scaling plan with predictive scaling enabled is created. +An [`aws_iam_service_linked_role`](/docs/providers/aws/r/iam_service_linked_role.html) resource can be used to manually managed this role. +See the [AWS documentation](https://docs.aws.amazon.com/autoscaling/plans/userguide/aws-auto-scaling-service-linked-roles.html#create-service-linked-role-manual) for more details. + ## Example Usage ### Basic Dynamic Scaling From a2ab9dc51902f6cb7e427a0daaab93a47c010653 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 19 Oct 2020 12:08:53 -0400 Subject: [PATCH 16/19] Update website/docs/r/autoscalingplans_scaling_plan.html.markdown Co-authored-by: angie pinilla --- website/docs/r/autoscalingplans_scaling_plan.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/autoscalingplans_scaling_plan.html.markdown b/website/docs/r/autoscalingplans_scaling_plan.html.markdown index 42053d97109b..73298f160d9e 100644 --- a/website/docs/r/autoscalingplans_scaling_plan.html.markdown +++ b/website/docs/r/autoscalingplans_scaling_plan.html.markdown @@ -12,7 +12,7 @@ Manages an AWS Auto Scaling scaling plan. More information can be found in the [AWS Auto Scaling User Guide](https://docs.aws.amazon.com/autoscaling/plans/userguide/what-is-aws-auto-scaling.html). ~> **NOTE:** The AWS Auto Scaling service uses an AWS IAM service-linked role to manage predictive scaling of Amazon EC2 Auto Scaling groups. The service attempts to automatically create this role the first time a scaling plan with predictive scaling enabled is created. -An [`aws_iam_service_linked_role`](/docs/providers/aws/r/iam_service_linked_role.html) resource can be used to manually managed this role. +An [`aws_iam_service_linked_role`](/docs/providers/aws/r/iam_service_linked_role.html) resource can be used to manually manage this role. See the [AWS documentation](https://docs.aws.amazon.com/autoscaling/plans/userguide/aws-auto-scaling-service-linked-roles.html#create-service-linked-role-manual) for more details. ## Example Usage From 1b8260eec662a6510de6b3787ea66a7dcfef10e0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 19 Oct 2020 12:54:48 -0400 Subject: [PATCH 17/19] Add 'testAccPreCheckIamServiceLinkedRole' and use for scaling plans with predictive scaling. --- aws/provider_test.go | 31 +++++++++++++++++++ ..._aws_autoscalingplans_scaling_plan_test.go | 10 ++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/aws/provider_test.go b/aws/provider_test.go index b2ccb4b6a695..426f0565fecd 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -14,6 +14,7 @@ import ( "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/organizations" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -571,6 +572,36 @@ func testAccOrganizationsEnabledPreCheck(t *testing.T) { } } +func testAccPreCheckIamServiceLinkedRole(t *testing.T, pathPrefix string) { + conn := testAccProvider.Meta().(*AWSClient).iamconn + + input := &iam.ListRolesInput{ + PathPrefix: aws.String(pathPrefix), + } + + var role *iam.Role + err := conn.ListRolesPages(input, func(page *iam.ListRolesOutput, lastPage bool) bool { + for _, r := range page.Roles { + role = r + break + } + + return !lastPage + }) + + if testAccPreCheckSkipError(err) { + t.Skipf("skipping tests: %s", err) + } + + if err != nil { + t.Fatalf("error listing IAM roles: %s", err) + } + + if role == nil { + t.Skipf("skipping tests; missing IAM service-linked role %s. Please create the role and retry", pathPrefix) + } +} + func testAccAlternateAccountProviderConfig() string { //lintignore:AT004 return fmt.Sprintf(` diff --git a/aws/resource_aws_autoscalingplans_scaling_plan_test.go b/aws/resource_aws_autoscalingplans_scaling_plan_test.go index cc4b8de1b333..b4f659d2ca32 100644 --- a/aws/resource_aws_autoscalingplans_scaling_plan_test.go +++ b/aws/resource_aws_autoscalingplans_scaling_plan_test.go @@ -126,7 +126,10 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicPredictiveScaling(t *testing.T) rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckIamServiceLinkedRole(t, "/aws-service-role/autoscaling-plans") + }, Providers: testAccProviders, CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, Steps: []resource.TestStep{ @@ -178,7 +181,10 @@ func TestAccAwsAutoScalingPlansScalingPlan_basicUpdate(t *testing.T) { rNameUpdated := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckIamServiceLinkedRole(t, "/aws-service-role/autoscaling-plans") + }, Providers: testAccProviders, CheckDestroy: testAccCheckAutoScalingPlansScalingPlanDestroy, Steps: []resource.TestStep{ From 4e83eb6d1de7326914520b3363924b2279a1c46b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 20 Oct 2020 17:38:35 -0400 Subject: [PATCH 18/19] Use 'StateChangeConf.Delay' to better handle API eventual consistency issues. --- aws/internal/service/autoscalingplans/waiter/waiter.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/aws/internal/service/autoscalingplans/waiter/waiter.go b/aws/internal/service/autoscalingplans/waiter/waiter.go index fe3451026d38..bc47bf5b5451 100644 --- a/aws/internal/service/autoscalingplans/waiter/waiter.go +++ b/aws/internal/service/autoscalingplans/waiter/waiter.go @@ -25,6 +25,7 @@ func ScalingPlanCreated(conn *autoscalingplans.AutoScalingPlans, scalingPlanName Target: []string{autoscalingplans.ScalingPlanStatusCodeActive, autoscalingplans.ScalingPlanStatusCodeActiveWithProblems}, Refresh: ScalingPlanStatus(conn, scalingPlanName, scalingPlanVersion), Timeout: ScalingPlanCreatedTimeout, + Delay: 10 * time.Second, } outputRaw, err := stateConf.WaitForState() @@ -39,14 +40,11 @@ func ScalingPlanCreated(conn *autoscalingplans.AutoScalingPlans, scalingPlanName // ScalingPlanDeleted waits for a ScalingPlan to return Deleted func ScalingPlanDeleted(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int) (*autoscalingplans.ScalingPlan, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{ - autoscalingplans.ScalingPlanStatusCodeActive, - autoscalingplans.ScalingPlanStatusCodeActiveWithProblems, - autoscalingplans.ScalingPlanStatusCodeDeletionInProgress, - }, + Pending: []string{autoscalingplans.ScalingPlanStatusCodeDeletionInProgress}, Target: []string{}, Refresh: ScalingPlanStatus(conn, scalingPlanName, scalingPlanVersion), Timeout: ScalingPlanDeletedTimeout, + Delay: 10 * time.Second, } outputRaw, err := stateConf.WaitForState() @@ -65,6 +63,7 @@ func ScalingPlanUpdated(conn *autoscalingplans.AutoScalingPlans, scalingPlanName Target: []string{autoscalingplans.ScalingPlanStatusCodeActive, autoscalingplans.ScalingPlanStatusCodeActiveWithProblems}, Refresh: ScalingPlanStatus(conn, scalingPlanName, scalingPlanVersion), Timeout: ScalingPlanUpdatedTimeout, + Delay: 10 * time.Second, } outputRaw, err := stateConf.WaitForState() From 543e5d37c86b41c4f57de5bf3108fd4c903b0cb1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 21 Oct 2020 06:12:04 -0400 Subject: [PATCH 19/19] Update aws/internal/service/autoscalingplans/finder/finder.go Co-authored-by: angie pinilla --- aws/internal/service/autoscalingplans/finder/finder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/internal/service/autoscalingplans/finder/finder.go b/aws/internal/service/autoscalingplans/finder/finder.go index 6e38289758dc..90892a83c4f1 100644 --- a/aws/internal/service/autoscalingplans/finder/finder.go +++ b/aws/internal/service/autoscalingplans/finder/finder.go @@ -6,7 +6,7 @@ import ( ) // ScalingPlan returns the scaling plan corresponding to the specified name and version. -// Returns returns nil and potentially an API error if no scaling plan is found. +// Returns nil and potentially an API error if no scaling plan is found. func ScalingPlan(conn *autoscalingplans.AutoScalingPlans, scalingPlanName string, scalingPlanVersion int) (*autoscalingplans.ScalingPlan, error) { input := &autoscalingplans.DescribeScalingPlansInput{ ScalingPlanNames: aws.StringSlice([]string{scalingPlanName}),