From cc912c39e56cd70e9a3d12eed6f84328ce7c11e8 Mon Sep 17 00:00:00 2001 From: Andreas Skarmutsos Lindh Date: Fri, 15 Jul 2016 13:54:36 +0200 Subject: [PATCH 1/3] AWS Application AutoScaling Initial work on two new resource types: * `aws_appautoscaling_target` * `aws_appautoscaling_policy` Fix acc tests --- builtin/providers/aws/config.go | 3 + builtin/providers/aws/provider.go | 2 + .../aws/resource_aws_appautoscaling_policy.go | 331 ++++++++++++++++++ ...resource_aws_appautoscaling_policy_test.go | 148 ++++++++ .../aws/resource_aws_appautoscaling_target.go | 202 +++++++++++ ...resource_aws_appautoscaling_target_test.go | 209 +++++++++++ .../aws/r/appautoscaling_policy.html.markdown | 74 ++++ .../aws/r/appautoscaling_target.html.markdown | 40 +++ 8 files changed, 1009 insertions(+) create mode 100644 builtin/providers/aws/resource_aws_appautoscaling_policy.go create mode 100644 builtin/providers/aws/resource_aws_appautoscaling_policy_test.go create mode 100644 builtin/providers/aws/resource_aws_appautoscaling_target.go create mode 100644 builtin/providers/aws/resource_aws_appautoscaling_target_test.go create mode 100644 website/source/docs/providers/aws/r/appautoscaling_policy.html.markdown create mode 100644 website/source/docs/providers/aws/r/appautoscaling_target.html.markdown diff --git a/builtin/providers/aws/config.go b/builtin/providers/aws/config.go index 88bf4d0e7..434bdffdd 100644 --- a/builtin/providers/aws/config.go +++ b/builtin/providers/aws/config.go @@ -18,6 +18,7 @@ import ( "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/apigateway" + "github.com/aws/aws-sdk-go/service/applicationautoscaling" "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/cloudformation" "github.com/aws/aws-sdk-go/service/cloudfront" @@ -94,6 +95,7 @@ type AWSClient struct { emrconn *emr.EMR esconn *elasticsearch.ElasticsearchService apigateway *apigateway.APIGateway + appautoscalingconn *applicationautoscaling.ApplicationAutoScaling autoscalingconn *autoscaling.AutoScaling s3conn *s3.S3 sesConn *ses.SES @@ -213,6 +215,7 @@ func (c *Config) Client() (interface{}, error) { } client.apigateway = apigateway.New(sess) + client.appautoscalingconn = applicationautoscaling.New(sess) client.autoscalingconn = autoscaling.New(sess) client.cfconn = cloudformation.New(sess) client.cloudfrontconn = cloudfront.New(sess) diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index 689335889..69e264dd9 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -135,6 +135,8 @@ func Provider() terraform.ResourceProvider { "aws_api_gateway_resource": resourceAwsApiGatewayResource(), "aws_api_gateway_rest_api": resourceAwsApiGatewayRestApi(), "aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(), + "aws_appautoscaling_target": resourceAwsAppautoscalingTarget(), + "aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(), "aws_autoscaling_group": resourceAwsAutoscalingGroup(), "aws_autoscaling_notification": resourceAwsAutoscalingNotification(), "aws_autoscaling_policy": resourceAwsAutoscalingPolicy(), diff --git a/builtin/providers/aws/resource_aws_appautoscaling_policy.go b/builtin/providers/aws/resource_aws_appautoscaling_policy.go new file mode 100644 index 000000000..44461e3a7 --- /dev/null +++ b/builtin/providers/aws/resource_aws_appautoscaling_policy.go @@ -0,0 +1,331 @@ +package aws + +import ( + "bytes" + "fmt" + "log" + "strconv" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/applicationautoscaling" + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsAppautoscalingPolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAppautoscalingPolicyCreate, + Read: resourceAwsAppautoscalingPolicyRead, + Update: resourceAwsAppautoscalingPolicyUpdate, + Delete: resourceAwsAppautoscalingPolicyDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { + // https://github.com/boto/botocore/blob/9f322b1/botocore/data/autoscaling/2011-01-01/service-2.json#L1862-L1873 + value := v.(string) + if len(value) > 255 { + errors = append(errors, fmt.Errorf("q cannot be longer than 255 characters", k)) + } + return + }, + }, + "arn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "policy_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "StepScaling", + }, + "resource_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "scalable_dimension": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "ecs:service:DesiredCount", + ForceNew: true, + }, + "service_namespace": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "ecs", + ForceNew: true, + }, + "adjustment_type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "cooldown": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "metric_aggregation_type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "min_adjustment_magnitude": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + }, + "alarms": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "step_adjustment": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metric_interval_lower_bound": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "metric_interval_upper_bound": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "scaling_adjustment": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + }, + }, + Set: resourceAwsAppautoscalingAdjustmentHash, + }, + }, + } +} + +func resourceAwsAppautoscalingPolicyCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appautoscalingconn + + params, err := getAwsAppautoscalingPutScalingPolicyInput(d) + if err != nil { + return err + } + + log.Printf("[DEBUG] ApplicationAutoScaling PutScalingPolicy: %#v", params) + resp, err := conn.PutScalingPolicy(¶ms) + if err != nil { + return fmt.Errorf("Error putting scaling policy: %s", err) + } + + d.Set("arn", resp.PolicyARN) + d.SetId(d.Get("name").(string)) + log.Printf("[INFO] ApplicationAutoScaling scaling PolicyARN: %s", d.Get("arn").(string)) + + return resourceAwsAppautoscalingPolicyRead(d, meta) +} + +func resourceAwsAppautoscalingPolicyRead(d *schema.ResourceData, meta interface{}) error { + p, err := getAwsAppautoscalingPolicy(d, meta) + if err != nil { + return err + } + if p == nil { + d.SetId("") + return nil + } + + log.Printf("[DEBUG] Read ApplicationAutoScaling policy: %s, SP: %s, Obj: %s", d.Get("name"), d.Get("name"), p) + + d.Set("arn", p.PolicyARN) + d.Set("name", p.PolicyName) + d.Set("policy_type", p.PolicyType) + d.Set("resource_id", p.ResourceId) + d.Set("scalable_dimension", p.ScalableDimension) + d.Set("service_namespace", p.ServiceNamespace) + d.Set("alarms", p.Alarms) + d.Set("step_scaling_policy_configuration", p.StepScalingPolicyConfiguration) + + return nil +} + +func resourceAwsAppautoscalingPolicyUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appautoscalingconn + + params, inputErr := getAwsAppautoscalingPutScalingPolicyInput(d) + if inputErr != nil { + return inputErr + } + + log.Printf("[DEBUG] Application Autoscaling Update Scaling Policy: %#v", params) + _, err := conn.PutScalingPolicy(¶ms) + if err != nil { + return err + } + + return resourceAwsAppautoscalingPolicyRead(d, meta) +} + +func resourceAwsAppautoscalingPolicyDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appautoscalingconn + p, err := getAwsAppautoscalingPolicy(d, meta) + if err != nil { + return fmt.Errorf("Error getting policy: %s", err) + } + if p == nil { + return nil + } + + params := applicationautoscaling.DeleteScalingPolicyInput{ + PolicyName: aws.String(d.Get("name").(string)), + ResourceId: aws.String(d.Get("resource_id").(string)), + ScalableDimension: aws.String(d.Get("scalable_dimension").(string)), + ServiceNamespace: aws.String(d.Get("service_namespace").(string)), + } + log.Printf("[DEBUG] Deleting Application AutoScaling Policy opts: %#v", params) + if _, err := conn.DeleteScalingPolicy(¶ms); err != nil { + return fmt.Errorf("Application AutoScaling Policy: %s", err) + } + + d.SetId("") + return nil +} + +// Takes the result of flatmap.Expand for an array of step adjustments and +// returns a []*applicationautoscaling.StepAdjustment. +func expandAppautoscalingStepAdjustments(configured []interface{}) ([]*applicationautoscaling.StepAdjustment, error) { + var adjustments []*applicationautoscaling.StepAdjustment + + // Loop over our configured step adjustments and create an array + // of aws-sdk-go compatible objects. We're forced to convert strings + // to floats here because there's no way to detect whether or not + // an uninitialized, optional schema element is "0.0" deliberately. + // With strings, we can test for "", which is definitely an empty + // struct value. + for _, raw := range configured { + data := raw.(map[string]interface{}) + a := &applicationautoscaling.StepAdjustment{ + ScalingAdjustment: aws.Int64(int64(data["scaling_adjustment"].(int))), + } + if data["metric_interval_lower_bound"] != "" { + bound := data["metric_interval_lower_bound"] + switch bound := bound.(type) { + case string: + f, err := strconv.ParseFloat(bound, 64) + if err != nil { + return nil, fmt.Errorf( + "metric_interval_lower_bound must be a float value represented as a string") + } + a.MetricIntervalLowerBound = aws.Float64(f) + default: + return nil, fmt.Errorf( + "metric_interval_lower_bound isn't a string. This is a bug. Please file an issue.") + } + } + if data["metric_interval_upper_bound"] != "" { + bound := data["metric_interval_upper_bound"] + switch bound := bound.(type) { + case string: + f, err := strconv.ParseFloat(bound, 64) + if err != nil { + return nil, fmt.Errorf( + "metric_interval_upper_bound must be a float value represented as a string") + } + a.MetricIntervalUpperBound = aws.Float64(f) + default: + return nil, fmt.Errorf( + "metric_interval_upper_bound isn't a string. This is a bug. Please file an issue.") + } + } + adjustments = append(adjustments, a) + } + + return adjustments, nil +} + +func getAwsAppautoscalingPutScalingPolicyInput(d *schema.ResourceData) (applicationautoscaling.PutScalingPolicyInput, error) { + var params = applicationautoscaling.PutScalingPolicyInput{ + PolicyName: aws.String(d.Get("name").(string)), + ResourceId: aws.String(d.Get("resource_id").(string)), + } + + if v, ok := d.GetOk("policy_type"); ok { + params.PolicyType = aws.String(v.(string)) + } + + if v, ok := d.GetOk("service_namespace"); ok { + params.ServiceNamespace = aws.String(v.(string)) + } + + if v, ok := d.GetOk("policy_type"); ok { + params.PolicyType = aws.String(v.(string)) + } + + if v, ok := d.GetOk("scalable_dimension"); ok { + params.ScalableDimension = aws.String(v.(string)) + } + + var adjustmentSteps []*applicationautoscaling.StepAdjustment + if v, ok := d.GetOk("step_adjustment"); ok { + steps, err := expandAppautoscalingStepAdjustments(v.(*schema.Set).List()) + if err != nil { + return params, fmt.Errorf("metric_interval_lower_bound and metric_interval_upper_bound must be strings!") + } + adjustmentSteps = steps + } + + // build StepScalingPolicyConfiguration + params.StepScalingPolicyConfiguration = &applicationautoscaling.StepScalingPolicyConfiguration{ + AdjustmentType: aws.String(d.Get("adjustment_type").(string)), + Cooldown: aws.Int64(int64(d.Get("cooldown").(int))), + MetricAggregationType: aws.String(d.Get("metric_aggregation_type").(string)), + StepAdjustments: adjustmentSteps, + } + + if v, ok := d.GetOk("min_adjustment_magnitude"); ok { + params.StepScalingPolicyConfiguration.MinAdjustmentMagnitude = aws.Int64(int64(v.(int))) + } + + return params, nil +} + +func getAwsAppautoscalingPolicy(d *schema.ResourceData, meta interface{}) (*applicationautoscaling.ScalingPolicy, error) { + conn := meta.(*AWSClient).appautoscalingconn + + params := applicationautoscaling.DescribeScalingPoliciesInput{ + PolicyNames: []*string{aws.String(d.Get("name").(string))}, + ServiceNamespace: aws.String(d.Get("service_namespace").(string)), + } + + log.Printf("[DEBUG] Application AutoScaling Policy Describe Params: %#v", params) + resp, err := conn.DescribeScalingPolicies(¶ms) + if err != nil { + return nil, fmt.Errorf("Error retrieving scaling policies: %s", err) + } + + // find scaling policy + name := d.Get("name") + for idx, sp := range resp.ScalingPolicies { + if *sp.PolicyName == name { + return resp.ScalingPolicies[idx], nil + } + } + + // policy not found + return nil, nil +} + +func resourceAwsAppautoscalingAdjustmentHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + if v, ok := m["metric_interval_lower_bound"]; ok { + buf.WriteString(fmt.Sprintf("%f-", v)) + } + if v, ok := m["metric_interval_upper_bound"]; ok { + buf.WriteString(fmt.Sprintf("%f-", v)) + } + buf.WriteString(fmt.Sprintf("%d-", m["scaling_adjustment"].(int))) + + return hashcode.String(buf.String()) +} diff --git a/builtin/providers/aws/resource_aws_appautoscaling_policy_test.go b/builtin/providers/aws/resource_aws_appautoscaling_policy_test.go new file mode 100644 index 000000000..cef3d7d74 --- /dev/null +++ b/builtin/providers/aws/resource_aws_appautoscaling_policy_test.go @@ -0,0 +1,148 @@ +package aws + +import ( + "fmt" + "os" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/applicationautoscaling" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAWSAppautoscalingPolicy_basic(t *testing.T) { + var policy applicationautoscaling.ScalingPolicy + var awsAccountId = os.Getenv("AWS_ACCOUNT_ID") + + randClusterName := fmt.Sprintf("cluster-%s", acctest.RandString(10)) + // randResourceId := fmt.Sprintf("service/%s/%s", randClusterName, acctest.RandString(10)) + randPolicyName := fmt.Sprintf("terraform-test-foobar-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAppautoscalingPolicyDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSAppautoscalingPolicyConfig(randClusterName, randPolicyName, awsAccountId), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppautoscalingPolicyExists("aws_appautoscaling_policy.foobar_simple", &policy), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "adjustment_type", "ChangeInCapacity"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "policy_type", "StepScaling"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "cooldown", "60"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "name", randPolicyName), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "resource_id", fmt.Sprintf("service/%s/foobar", randClusterName)), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "service_namespace", "ecs"), + resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "scalable_dimension", "ecs:service:DesiredCount"), + ), + }, + }, + }) +} + +func testAccCheckAWSAppautoscalingPolicyExists(n string, policy *applicationautoscaling.ScalingPolicy) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := testAccProvider.Meta().(*AWSClient).appautoscalingconn + params := &applicationautoscaling.DescribeScalingPoliciesInput{ + ServiceNamespace: aws.String(rs.Primary.Attributes["service_namespace"]), + PolicyNames: []*string{aws.String(rs.Primary.ID)}, + } + resp, err := conn.DescribeScalingPolicies(params) + if err != nil { + return err + } + if len(resp.ScalingPolicies) == 0 { + return fmt.Errorf("ScalingPolicy %s not found", rs.Primary.ID) + } + + return nil + } +} + +func testAccCheckAWSAppautoscalingPolicyDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).appautoscalingconn + + for _, rs := range s.RootModule().Resources { + params := applicationautoscaling.DescribeScalingPoliciesInput{ + ServiceNamespace: aws.String(rs.Primary.Attributes["service_namespace"]), + PolicyNames: []*string{aws.String(rs.Primary.ID)}, + } + + resp, err := conn.DescribeScalingPolicies(¶ms) + + if err == nil { + if len(resp.ScalingPolicies) != 0 && + *resp.ScalingPolicies[0].PolicyName == rs.Primary.ID { + return fmt.Errorf("Application autoscaling policy still exists: %s", rs.Primary.ID) + } + } + } + + return nil +} + +func testAccAWSAppautoscalingPolicyConfig( + randClusterName string, + randPolicyName string, + awsAccountId string) string { + return fmt.Sprintf(` +resource "aws_ecs_cluster" "foo" { + name = "%s" +} + +resource "aws_ecs_task_definition" "task" { + family = "foobar" + container_definitions = < 255 { + errors = append(errors, fmt.Errorf( + "%q cannot be longer than 255 characters", k)) + } + return + }, + }, + "arn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "max_capacity": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + "min_capacity": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + "resource_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "role_arn": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "scalable_dimension": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "ecs:service:DesiredCount", + ForceNew: true, + }, + "service_namespace": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "ecs", + ForceNew: true, + }, + }, + } +} + +func resourceAwsAppautoscalingTargetCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appautoscalingconn + + var targetOpts applicationautoscaling.RegisterScalableTargetInput + + targetOpts.MaxCapacity = aws.Int64(int64(d.Get("max_capacity").(int))) + targetOpts.MinCapacity = aws.Int64(int64(d.Get("min_capacity").(int))) + targetOpts.ResourceId = aws.String(d.Get("resource_id").(string)) + targetOpts.RoleARN = aws.String(d.Get("role_arn").(string)) + targetOpts.ScalableDimension = aws.String(d.Get("scalable_dimension").(string)) + targetOpts.ServiceNamespace = aws.String(d.Get("service_namespace").(string)) + + log.Printf("[DEBUG] Application autoscaling target create configuration %#v", targetOpts) + _, err := conn.RegisterScalableTarget(&targetOpts) + if err != nil { + return fmt.Errorf("Error creating application autoscaling target: %s", err) + } + + d.SetId(d.Get("resource_id").(string)) + log.Printf("[INFO] Application AutoScaling Target ID: %s", d.Id()) + + return resourceAwsAppautoscalingTargetRead(d, meta) +} + +func resourceAwsAppautoscalingTargetRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appautoscalingconn + + t, err := getAwsAppautoscalingTarget(d, conn) + if err != nil { + return err + } + if t == nil { + log.Printf("[INFO] Application AutoScaling Target %q not found", d.Id()) + d.SetId("") + return nil + } + + d.Set("max_capacity", t.MaxCapacity) + d.Set("min_capacity", t.MinCapacity) + d.Set("resource_id", t.ResourceId) + d.Set("role_arn", t.RoleARN) + d.Set("scalable_dimension", t.ScalableDimension) + d.Set("service_namespace", t.ServiceNamespace) + + return nil +} + +// Updating Target is not supported +// func getAwsAppautoscalingTargetUpdate(d *schema.ResourceData, meta interface{}) error { +// conn := meta.(*AWSClient).appautoscalingconn + +// } + +func resourceAwsAppautoscalingTargetDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appautoscalingconn + + t, err := getAwsAppautoscalingTarget(d, conn) + if err != nil { + return err + } + if t == nil { + log.Printf("[INFO] Application AutoScaling Target %q not found", d.Id()) + d.SetId("") + return nil + } + + log.Printf("[DEBUG] Application AutoScaling Target destroy: %#v", d.Id()) + deleteOpts := applicationautoscaling.DeregisterScalableTargetInput{ + ResourceId: aws.String(d.Get("resource_id").(string)), + ServiceNamespace: aws.String(d.Get("service_namespace").(string)), + ScalableDimension: aws.String(d.Get("scalable_dimension").(string)), + } + + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + if _, err := conn.DeregisterScalableTarget(&deleteOpts); err != nil { + if awserr, ok := err.(awserr.Error); ok { + // @TODO: We should do stuff here depending on the actual error returned + return resource.RetryableError(awserr) + } + // Non recognized error, no retry. + return resource.NonRetryableError(err) + } + // Successful delete + return nil + }) + if err != nil { + return err + } + + return resource.Retry(5*time.Minute, func() *resource.RetryError { + if t, _ = getAwsAppautoscalingTarget(d, conn); t != nil { + return resource.RetryableError( + fmt.Errorf("Application AutoScaling Target still exists")) + } + return nil + }) +} + +func getAwsAppautoscalingTarget( + d *schema.ResourceData, + conn *applicationautoscaling.ApplicationAutoScaling) (*applicationautoscaling.ScalableTarget, error) { + + tgtName := d.Id() + describeOpts := applicationautoscaling.DescribeScalableTargetsInput{ + ResourceIds: []*string{aws.String(tgtName)}, + ServiceNamespace: aws.String(d.Get("service_namespace").(string)), + } + + log.Printf("[DEBUG] Application AutoScaling Target describe configuration: %#v", describeOpts) + describeTargets, err := conn.DescribeScalableTargets(&describeOpts) + if err != nil { + // @TODO: We should probably send something else back if we're trying to access an unknown Resource ID + // targetserr, ok := err.(awserr.Error) + // if ok && targetserr.Code() == "" + return nil, fmt.Errorf("Error retrieving Application AutoScaling Target: %s", err) + } + + for idx, tgt := range describeTargets.ScalableTargets { + if *tgt.ResourceId == tgtName { + return describeTargets.ScalableTargets[idx], nil + } + } + + return nil, nil +} diff --git a/builtin/providers/aws/resource_aws_appautoscaling_target_test.go b/builtin/providers/aws/resource_aws_appautoscaling_target_test.go new file mode 100644 index 000000000..c53262336 --- /dev/null +++ b/builtin/providers/aws/resource_aws_appautoscaling_target_test.go @@ -0,0 +1,209 @@ +package aws + +import ( + "fmt" + "os" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/applicationautoscaling" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAWSAppautoScalingTarget_basic(t *testing.T) { + var target applicationautoscaling.ScalableTarget + var awsAccountId = os.Getenv("AWS_ACCOUNT_ID") + + randClusterName := fmt.Sprintf("cluster-%s", acctest.RandString(10)) + randResourceId := fmt.Sprintf("service/%s/%s", randClusterName, acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_appautoscaling_target.bar", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAppautoscalingTargetDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSAppautoscalingTargetConfig(randClusterName, randResourceId, awsAccountId), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppautoscalingTargetExists("aws_appautoscaling_target.bar", &target), + testAccCheckAWSAppautoscalingTargetAttributes(&target, randResourceId), + resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "service_namespace", "ecs"), + resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "resource_id", fmt.Sprintf("service/%s/foobar", randClusterName)), + resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "scalable_dimension", "ecs:service:DesiredCount"), + resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "min_capacity", "1"), + resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "max_capacity", "3"), + ), + }, + + resource.TestStep{ + Config: testAccAWSAppautoscalingTargetConfigUpdate(randClusterName, randResourceId, awsAccountId), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppautoscalingTargetExists("aws_appautoscaling_target.bar", &target), + resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "min_capacity", "3"), + resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "max_capacity", "6"), + ), + }, + }, + }) +} + +func testAccCheckAWSAppautoscalingTargetDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).appautoscalingconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_appautoscaling_target" { + continue + } + + // Try to find the target + describeTargets, err := conn.DescribeScalableTargets( + &applicationautoscaling.DescribeScalableTargetsInput{ + ResourceIds: []*string{aws.String(rs.Primary.ID)}, + }, + ) + + if err == nil { + if len(describeTargets.ScalableTargets) != 0 && + *describeTargets.ScalableTargets[0].ResourceId == rs.Primary.ID { + return fmt.Errorf("Application AutoScaling Target still exists") + } + } + + // Verify error + e, ok := err.(awserr.Error) + if !ok { + return err + } + if e.Code() != "" { + return e + } + } + + return nil +} + +func testAccCheckAWSAppautoscalingTargetExists(n string, target *applicationautoscaling.ScalableTarget) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Application AutoScaling Target ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).appautoscalingconn + + describeTargets, err := conn.DescribeScalableTargets( + &applicationautoscaling.DescribeScalableTargetsInput{ + ResourceIds: []*string{aws.String(rs.Primary.ID)}, + }, + ) + + if err != nil { + return err + } + + if len(describeTargets.ScalableTargets) != 1 || + *describeTargets.ScalableTargets[0].ResourceId != rs.Primary.ID { + return fmt.Errorf("Application AutoScaling ResourceId not found") + } + + *target = *describeTargets.ScalableTargets[0] + + return nil + } +} + +func testAccCheckAWSAppautoscalingTargetAttributes(target *applicationautoscaling.ScalableTarget, resourceId string) resource.TestCheckFunc { + return nil +} + +func testAccAWSAppautoscalingTargetConfig( + randClusterName string, + randResourceId string, + awsAccountId string) string { + return fmt.Sprintf(` +resource "aws_ecs_cluster" "foo" { + name = "%s" +} +resource "aws_ecs_task_definition" "task" { + family = "foobar" + container_definitions = < Date: Sat, 16 Jul 2016 15:21:45 +0200 Subject: [PATCH 2/3] added applicationautoscaling from aws-sdk-go using: `govendor add github.com/aws/aws-sdk-go/service/applicationautoscaling@v1.2.5` introduce a retry for scalable target creation Due to possible inconsistencies in IAM, let's retry creation of the scalable target before we fail. Added IAM role as part of acceptance test --- ...resource_aws_appautoscaling_policy_test.go | 42 +- .../aws/resource_aws_appautoscaling_target.go | 16 +- ...resource_aws_appautoscaling_target_test.go | 124 +- .../service/applicationautoscaling/api.go | 1450 +++++++++++++++++ .../service/applicationautoscaling/service.go | 112 ++ vendor/vendor.json | 6 + 6 files changed, 1729 insertions(+), 21 deletions(-) create mode 100644 vendor/github.com/aws/aws-sdk-go/service/applicationautoscaling/api.go create mode 100644 vendor/github.com/aws/aws-sdk-go/service/applicationautoscaling/service.go diff --git a/builtin/providers/aws/resource_aws_appautoscaling_policy_test.go b/builtin/providers/aws/resource_aws_appautoscaling_policy_test.go index cef3d7d74..62d6d777d 100644 --- a/builtin/providers/aws/resource_aws_appautoscaling_policy_test.go +++ b/builtin/providers/aws/resource_aws_appautoscaling_policy_test.go @@ -2,7 +2,6 @@ package aws import ( "fmt" - "os" "testing" "github.com/aws/aws-sdk-go/aws" @@ -14,9 +13,8 @@ import ( func TestAccAWSAppautoscalingPolicy_basic(t *testing.T) { var policy applicationautoscaling.ScalingPolicy - var awsAccountId = os.Getenv("AWS_ACCOUNT_ID") - randClusterName := fmt.Sprintf("cluster-%s", acctest.RandString(10)) + randClusterName := fmt.Sprintf("cluster%s", acctest.RandString(10)) // randResourceId := fmt.Sprintf("service/%s/%s", randClusterName, acctest.RandString(10)) randPolicyName := fmt.Sprintf("terraform-test-foobar-%s", acctest.RandString(5)) @@ -26,7 +24,7 @@ func TestAccAWSAppautoscalingPolicy_basic(t *testing.T) { CheckDestroy: testAccCheckAWSAppautoscalingPolicyDestroy, Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccAWSAppautoscalingPolicyConfig(randClusterName, randPolicyName, awsAccountId), + Config: testAccAWSAppautoscalingPolicyConfig(randClusterName, randPolicyName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAppautoscalingPolicyExists("aws_appautoscaling_policy.foobar_simple", &policy), resource.TestCheckResourceAttr("aws_appautoscaling_policy.foobar_simple", "adjustment_type", "ChangeInCapacity"), @@ -90,9 +88,37 @@ func testAccCheckAWSAppautoscalingPolicyDestroy(s *terraform.State) error { func testAccAWSAppautoscalingPolicyConfig( randClusterName string, - randPolicyName string, - awsAccountId string) string { + randPolicyName string) string { return fmt.Sprintf(` +resource "aws_iam_role" "autoscale_role" { + name = "%s" + path = "/" + + assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":[\"sts:AssumeRole\"]}]}" +} + +resource "aws_iam_role_policy" "autoscale_role_policy" { + name = "%s" + role = "${aws_iam_role.autoscale_role.id}" + + policy = < 0 { + return invalidParams + } + return nil +} + +type DeleteScalingPolicyOutput struct { + _ struct{} `type:"structure"` +} + +// String returns the string representation +func (s DeleteScalingPolicyOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeleteScalingPolicyOutput) GoString() string { + return s.String() +} + +type DeregisterScalableTargetInput struct { + _ struct{} `type:"structure"` + + // The unique identifier string for the resource associated with the scalable + // target. For Amazon ECS services, this value is the resource type, followed + // by the cluster name and service name, such as service/default/sample-webapp. + ResourceId *string `min:"1" type:"string" required:"true"` + + // The scalable dimension associated with the scalable target. The scalable + // dimension contains the service namespace, resource type, and scaling property, + // such as ecs:service:DesiredCount for the desired task count of an Amazon + // ECS service. + ScalableDimension *string `type:"string" required:"true" enum:"ScalableDimension"` + + // The namespace for the AWS service that the scalable target is associated + // with. For more information, see AWS Service Namespaces (http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces) + // in the Amazon Web Services General Reference. + ServiceNamespace *string `type:"string" required:"true" enum:"ServiceNamespace"` +} + +// String returns the string representation +func (s DeregisterScalableTargetInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeregisterScalableTargetInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *DeregisterScalableTargetInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DeregisterScalableTargetInput"} + if s.ResourceId == nil { + invalidParams.Add(request.NewErrParamRequired("ResourceId")) + } + if s.ResourceId != nil && len(*s.ResourceId) < 1 { + invalidParams.Add(request.NewErrParamMinLen("ResourceId", 1)) + } + if s.ScalableDimension == nil { + invalidParams.Add(request.NewErrParamRequired("ScalableDimension")) + } + if s.ServiceNamespace == nil { + invalidParams.Add(request.NewErrParamRequired("ServiceNamespace")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +type DeregisterScalableTargetOutput struct { + _ struct{} `type:"structure"` +} + +// String returns the string representation +func (s DeregisterScalableTargetOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DeregisterScalableTargetOutput) GoString() string { + return s.String() +} + +type DescribeScalableTargetsInput struct { + _ struct{} `type:"structure"` + + // The maximum number of scalable target results returned by DescribeScalableTargets + // in paginated output. When this parameter is used, DescribeScalableTargets + // returns up to MaxResults results in a single page along with a NextToken + // response element. The remaining results of the initial request can be seen + // by sending another DescribeScalableTargets request with the returned NextToken + // value. This value can be between 1 and 50. If this parameter is not used, + // then DescribeScalableTargets returns up to 50 results and a NextToken value, + // if applicable. + MaxResults *int64 `type:"integer"` + + // The NextToken value returned from a previous paginated DescribeScalableTargets + // request. Pagination continues from the end of the previous results that returned + // the NextToken value. This value is null when there are no more results to + // return. + NextToken *string `type:"string"` + + // The unique identifier string for the resource associated with the scalable + // target. For Amazon ECS services, this value is the resource type, followed + // by the cluster name and service name, such as service/default/sample-webapp. + // If you specify a scalable dimension, you must also specify a resource ID. + ResourceIds []*string `type:"list"` + + // The scalable dimension associated with the scalable target. The scalable + // dimension contains the service namespace, resource type, and scaling property, + // such as ecs:service:DesiredCount for the desired task count of an Amazon + // ECS service. If you specify a scalable dimension, you must also specify a + // resource ID. + ScalableDimension *string `type:"string" enum:"ScalableDimension"` + + // The namespace for the AWS service that the scalable target is associated + // with. For more information, see AWS Service Namespaces (http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces) + // in the Amazon Web Services General Reference. + ServiceNamespace *string `type:"string" required:"true" enum:"ServiceNamespace"` +} + +// String returns the string representation +func (s DescribeScalableTargetsInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeScalableTargetsInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *DescribeScalableTargetsInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DescribeScalableTargetsInput"} + if s.ServiceNamespace == nil { + invalidParams.Add(request.NewErrParamRequired("ServiceNamespace")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +type DescribeScalableTargetsOutput struct { + _ struct{} `type:"structure"` + + // The NextToken value to include in a future DescribeScalableTargets request. + // When the results of a DescribeScalableTargets request exceed MaxResults, + // this value can be used to retrieve the next page of results. This value is + // null when there are no more results to return. + NextToken *string `type:"string"` + + // The list of scalable targets that matches the request parameters. + ScalableTargets []*ScalableTarget `type:"list"` +} + +// String returns the string representation +func (s DescribeScalableTargetsOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeScalableTargetsOutput) GoString() string { + return s.String() +} + +type DescribeScalingActivitiesInput struct { + _ struct{} `type:"structure"` + + // The maximum number of scaling activity results returned by DescribeScalingActivities + // in paginated output. When this parameter is used, DescribeScalingActivities + // returns up to MaxResults results in a single page along with a NextToken + // response element. The remaining results of the initial request can be seen + // by sending another DescribeScalingActivities request with the returned NextToken + // value. This value can be between 1 and 50. If this parameter is not used, + // then DescribeScalingActivities returns up to 50 results and a NextToken value, + // if applicable. + MaxResults *int64 `type:"integer"` + + // The NextToken value returned from a previous paginated DescribeScalingActivities + // request. Pagination continues from the end of the previous results that returned + // the NextToken value. This value is null when there are no more results to + // return. + NextToken *string `type:"string"` + + // The unique identifier string for the resource associated with the scaling + // activity. For Amazon ECS services, this value is the resource type, followed + // by the cluster name and service name, such as service/default/sample-webapp. + // If you specify a scalable dimension, you must also specify a resource ID. + ResourceId *string `min:"1" type:"string"` + + // The scalable dimension associated with the scaling activity. The scalable + // dimension contains the service namespace, resource type, and scaling property, + // such as ecs:service:DesiredCount for the desired task count of an Amazon + // ECS service. If you specify a scalable dimension, you must also specify a + // resource ID. + ScalableDimension *string `type:"string" enum:"ScalableDimension"` + + // The namespace for the AWS service that the scaling activity is associated + // with. For more information, see AWS Service Namespaces (http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces) + // in the Amazon Web Services General Reference. + ServiceNamespace *string `type:"string" required:"true" enum:"ServiceNamespace"` +} + +// String returns the string representation +func (s DescribeScalingActivitiesInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeScalingActivitiesInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *DescribeScalingActivitiesInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DescribeScalingActivitiesInput"} + if s.ResourceId != nil && len(*s.ResourceId) < 1 { + invalidParams.Add(request.NewErrParamMinLen("ResourceId", 1)) + } + if s.ServiceNamespace == nil { + invalidParams.Add(request.NewErrParamRequired("ServiceNamespace")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +type DescribeScalingActivitiesOutput struct { + _ struct{} `type:"structure"` + + // The NextToken value to include in a future DescribeScalingActivities request. + // When the results of a DescribeScalingActivities request exceed MaxResults, + // this value can be used to retrieve the next page of results. This value is + // null when there are no more results to return. + NextToken *string `type:"string"` + + // A list of scaling activity objects. + ScalingActivities []*ScalingActivity `type:"list"` +} + +// String returns the string representation +func (s DescribeScalingActivitiesOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeScalingActivitiesOutput) GoString() string { + return s.String() +} + +type DescribeScalingPoliciesInput struct { + _ struct{} `type:"structure"` + + // The maximum number of scaling policy results returned by DescribeScalingPolicies + // in paginated output. When this parameter is used, DescribeScalingPolicies + // returns up to MaxResults results in a single page along with a NextToken + // response element. The remaining results of the initial request can be seen + // by sending another DescribeScalingPolicies request with the returned NextToken + // value. This value can be between 1 and 50. If this parameter is not used, + // then DescribeScalingPolicies returns up to 50 results and a NextToken value, + // if applicable. + MaxResults *int64 `type:"integer"` + + // The NextToken value returned from a previous paginated DescribeScalingPolicies + // request. Pagination continues from the end of the previous results that returned + // the NextToken value. This value is null when there are no more results to + // return. + NextToken *string `type:"string"` + + // The names of the scaling policies to describe. + PolicyNames []*string `type:"list"` + + // The unique resource identifier string of the scalable target that the scaling + // policy is associated with. For Amazon ECS services, this value is the resource + // type, followed by the cluster name and service name, such as service/default/sample-webapp. + // If you specify a scalable dimension, you must also specify a resource ID. + ResourceId *string `min:"1" type:"string"` + + // The scalable dimension of the scalable target that the scaling policy is + // associated with. The scalable dimension contains the service namespace, resource + // type, and scaling property, such as ecs:service:DesiredCount for the desired + // task count of an Amazon ECS service. If you specify a scalable dimension, + // you must also specify a resource ID. + ScalableDimension *string `type:"string" enum:"ScalableDimension"` + + // The AWS service namespace of the scalable target that the scaling policy + // is associated with. For more information, see AWS Service Namespaces (http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces) + // in the Amazon Web Services General Reference. + ServiceNamespace *string `type:"string" required:"true" enum:"ServiceNamespace"` +} + +// String returns the string representation +func (s DescribeScalingPoliciesInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeScalingPoliciesInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *DescribeScalingPoliciesInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "DescribeScalingPoliciesInput"} + if s.ResourceId != nil && len(*s.ResourceId) < 1 { + invalidParams.Add(request.NewErrParamMinLen("ResourceId", 1)) + } + if s.ServiceNamespace == nil { + invalidParams.Add(request.NewErrParamRequired("ServiceNamespace")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +type DescribeScalingPoliciesOutput struct { + _ struct{} `type:"structure"` + + // The NextToken value to include in a future DescribeScalingPolicies request. + // When the results of a DescribeScalingPolicies request exceed MaxResults, + // this value can be used to retrieve the next page of results. This value is + // null when there are no more results to return. + NextToken *string `type:"string"` + + // A list of scaling policy objects. + ScalingPolicies []*ScalingPolicy `type:"list"` +} + +// String returns the string representation +func (s DescribeScalingPoliciesOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s DescribeScalingPoliciesOutput) GoString() string { + return s.String() +} + +type PutScalingPolicyInput struct { + _ struct{} `type:"structure"` + + // The name of the scaling policy. + PolicyName *string `min:"1" type:"string" required:"true"` + + // The policy type. This parameter is required if you are creating a new policy. + PolicyType *string `type:"string" enum:"PolicyType"` + + // The unique resource identifier string for the scalable target that this scaling + // policy applies to. For Amazon ECS services, this value is the resource type, + // followed by the cluster name and service name, such as service/default/sample-webapp. + ResourceId *string `min:"1" type:"string" required:"true"` + + // The scalable dimension of the scalable target that this scaling policy applies + // to. The scalable dimension contains the service namespace, resource type, + // and scaling property, such as ecs:service:DesiredCount for the desired task + // count of an Amazon ECS service. + ScalableDimension *string `type:"string" required:"true" enum:"ScalableDimension"` + + // The AWS service namespace of the scalable target that this scaling policy + // applies to. For more information, see AWS Service Namespaces (http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces) + // in the Amazon Web Services General Reference. + ServiceNamespace *string `type:"string" required:"true" enum:"ServiceNamespace"` + + // The configuration for the step scaling policy. This parameter is required + // if you are creating a new policy. For more information, see StepScalingPolicyConfiguration + // and StepAdjustment. + StepScalingPolicyConfiguration *StepScalingPolicyConfiguration `type:"structure"` +} + +// String returns the string representation +func (s PutScalingPolicyInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s PutScalingPolicyInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *PutScalingPolicyInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "PutScalingPolicyInput"} + if s.PolicyName == nil { + invalidParams.Add(request.NewErrParamRequired("PolicyName")) + } + if s.PolicyName != nil && len(*s.PolicyName) < 1 { + invalidParams.Add(request.NewErrParamMinLen("PolicyName", 1)) + } + if s.ResourceId == nil { + invalidParams.Add(request.NewErrParamRequired("ResourceId")) + } + if s.ResourceId != nil && len(*s.ResourceId) < 1 { + invalidParams.Add(request.NewErrParamMinLen("ResourceId", 1)) + } + if s.ScalableDimension == nil { + invalidParams.Add(request.NewErrParamRequired("ScalableDimension")) + } + if s.ServiceNamespace == nil { + invalidParams.Add(request.NewErrParamRequired("ServiceNamespace")) + } + if s.StepScalingPolicyConfiguration != nil { + if err := s.StepScalingPolicyConfiguration.Validate(); err != nil { + invalidParams.AddNested("StepScalingPolicyConfiguration", err.(request.ErrInvalidParams)) + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +type PutScalingPolicyOutput struct { + _ struct{} `type:"structure"` + + // The Amazon Resource Name (ARN) of the resulting scaling policy. + PolicyARN *string `min:"1" type:"string" required:"true"` +} + +// String returns the string representation +func (s PutScalingPolicyOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s PutScalingPolicyOutput) GoString() string { + return s.String() +} + +type RegisterScalableTargetInput struct { + _ struct{} `type:"structure"` + + // The maximum value for this scalable target to scale out to in response to + // scaling activities. This parameter is required if you are registering a new + // scalable target, and it is optional if you are updating an existing one. + MaxCapacity *int64 `type:"integer"` + + // The minimum value for this scalable target to scale in to in response to + // scaling activities. This parameter is required if you are registering a new + // scalable target, and it is optional if you are updating an existing one. + MinCapacity *int64 `type:"integer"` + + // The unique identifier string for the resource to associate with the scalable + // target. For Amazon ECS services, this value is the resource type, followed + // by the cluster name and service name, such as service/default/sample-webapp. + ResourceId *string `min:"1" type:"string" required:"true"` + + // The ARN of the IAM role that allows Application Auto Scaling to modify your + // scalable target on your behalf. This parameter is required if you are registering + // a new scalable target, and it is optional if you are updating an existing + // one. + RoleARN *string `min:"1" type:"string"` + + // The scalable dimension associated with the scalable target. The scalable + // dimension contains the service namespace, resource type, and scaling property, + // such as ecs:service:DesiredCount for the desired task count of an Amazon + // ECS service. + ScalableDimension *string `type:"string" required:"true" enum:"ScalableDimension"` + + // The namespace for the AWS service that the scalable target is associated + // with. For Amazon ECS services, the namespace value is ecs. For more information, + // see AWS Service Namespaces (http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces) + // in the Amazon Web Services General Reference. + ServiceNamespace *string `type:"string" required:"true" enum:"ServiceNamespace"` +} + +// String returns the string representation +func (s RegisterScalableTargetInput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s RegisterScalableTargetInput) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *RegisterScalableTargetInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "RegisterScalableTargetInput"} + if s.ResourceId == nil { + invalidParams.Add(request.NewErrParamRequired("ResourceId")) + } + if s.ResourceId != nil && len(*s.ResourceId) < 1 { + invalidParams.Add(request.NewErrParamMinLen("ResourceId", 1)) + } + if s.RoleARN != nil && len(*s.RoleARN) < 1 { + invalidParams.Add(request.NewErrParamMinLen("RoleARN", 1)) + } + if s.ScalableDimension == nil { + invalidParams.Add(request.NewErrParamRequired("ScalableDimension")) + } + if s.ServiceNamespace == nil { + invalidParams.Add(request.NewErrParamRequired("ServiceNamespace")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +type RegisterScalableTargetOutput struct { + _ struct{} `type:"structure"` +} + +// String returns the string representation +func (s RegisterScalableTargetOutput) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s RegisterScalableTargetOutput) GoString() string { + return s.String() +} + +// An object representing a scalable target. +type ScalableTarget struct { + _ struct{} `type:"structure"` + + // The Unix timestamp for when the scalable target was created. + CreationTime *time.Time `type:"timestamp" timestampFormat:"unix" required:"true"` + + // The maximum value for this scalable target to scale out to in response to + // scaling activities. + MaxCapacity *int64 `type:"integer" required:"true"` + + // The minimum value for this scalable target to scale in to in response to + // scaling activities. + MinCapacity *int64 `type:"integer" required:"true"` + + // The unique identifier string for the resource associated with the scalable + // target. For Amazon ECS services, this value is the resource type, followed + // by the cluster name and service name, such as service/default/sample-webapp. + ResourceId *string `min:"1" type:"string" required:"true"` + + // The ARN of the IAM role that allows Application Auto Scaling to modify your + // scalable target on your behalf. + RoleARN *string `min:"1" type:"string" required:"true"` + + // The scalable dimension associated with the scalable target. The scalable + // dimension contains the service namespace, resource type, and scaling property, + // such as ecs:service:DesiredCount for the desired task count of an Amazon + // ECS service. + ScalableDimension *string `type:"string" required:"true" enum:"ScalableDimension"` + + // The namespace for the AWS service that the scalable target is associated + // with. For more information, see AWS Service Namespaces (http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces) + // in the Amazon Web Services General Reference. + ServiceNamespace *string `type:"string" required:"true" enum:"ServiceNamespace"` +} + +// String returns the string representation +func (s ScalableTarget) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ScalableTarget) GoString() string { + return s.String() +} + +// An object representing a scaling activity. +type ScalingActivity struct { + _ struct{} `type:"structure"` + + // The unique identifier string for the scaling activity. + ActivityId *string `type:"string" required:"true"` + + // A simple description of what caused the scaling activity to happen. + Cause *string `type:"string" required:"true"` + + // A simple description of what action the scaling activity intends to accomplish. + Description *string `type:"string" required:"true"` + + // The details about the scaling activity. + Details *string `type:"string"` + + // The Unix timestamp for when the scaling activity ended. + EndTime *time.Time `type:"timestamp" timestampFormat:"unix"` + + // The unique identifier string for the resource associated with the scaling + // activity. For Amazon ECS services, this value is the resource type, followed + // by the cluster name and service name, such as service/default/sample-webapp. + ResourceId *string `min:"1" type:"string" required:"true"` + + // The scalable dimension associated with the scaling activity. The scalable + // dimension contains the service namespace, resource type, and scaling property, + // such as ecs:service:DesiredCount for the desired task count of an Amazon + // ECS service. + ScalableDimension *string `type:"string" required:"true" enum:"ScalableDimension"` + + // The namespace for the AWS service that the scaling activity is associated + // with. For more information, see AWS Service Namespaces (http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces) + // in the Amazon Web Services General Reference. + ServiceNamespace *string `type:"string" required:"true" enum:"ServiceNamespace"` + + // The Unix timestamp for when the scaling activity began. + StartTime *time.Time `type:"timestamp" timestampFormat:"unix" required:"true"` + + // Indicates the status of the scaling activity. + StatusCode *string `type:"string" required:"true" enum:"ScalingActivityStatusCode"` + + // A simple message about the current status of the scaling activity. + StatusMessage *string `type:"string"` +} + +// String returns the string representation +func (s ScalingActivity) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ScalingActivity) GoString() string { + return s.String() +} + +// An object representing a scaling policy. +type ScalingPolicy struct { + _ struct{} `type:"structure"` + + // The CloudWatch alarms that are associated with the scaling policy. + Alarms []*Alarm `type:"list"` + + // The Unix timestamp for when the scaling policy was created. + CreationTime *time.Time `type:"timestamp" timestampFormat:"unix" required:"true"` + + // The Amazon Resource Name (ARN) of the scaling policy. + PolicyARN *string `min:"1" type:"string" required:"true"` + + // The name of the scaling policy. + PolicyName *string `min:"1" type:"string" required:"true"` + + // The scaling policy type. + PolicyType *string `type:"string" required:"true" enum:"PolicyType"` + + // The unique identifier string for the resource associated with the scaling + // policy. For Amazon ECS services, this value is the resource type, followed + // by the cluster name and service name, such as service/default/sample-webapp. + ResourceId *string `min:"1" type:"string" required:"true"` + + // The scalable dimension associated with the scaling policy. The scalable dimension + // contains the service namespace, resource type, and scaling property, such + // as ecs:service:DesiredCount for the desired task count of an Amazon ECS service. + ScalableDimension *string `type:"string" required:"true" enum:"ScalableDimension"` + + // The namespace for the AWS service that the scaling policy is associated with. + // For more information, see AWS Service Namespaces (http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces) + // in the Amazon Web Services General Reference. + ServiceNamespace *string `type:"string" required:"true" enum:"ServiceNamespace"` + + // The configuration for the step scaling policy. + StepScalingPolicyConfiguration *StepScalingPolicyConfiguration `type:"structure"` +} + +// String returns the string representation +func (s ScalingPolicy) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s ScalingPolicy) GoString() string { + return s.String() +} + +// An object representing a step adjustment for a StepScalingPolicyConfiguration. +// Describes an adjustment based on the difference between the value of the +// aggregated CloudWatch metric and the breach threshold that you've defined +// for the alarm. +// +// For the following examples, suppose that you have an alarm with a breach +// threshold of 50: +// +// If you want the adjustment to be triggered when the metric is greater +// than or equal to 50 and less than 60, specify a lower bound of 0 and an upper +// bound of 10. +// +// If you want the adjustment to be triggered when the metric is greater +// than 40 and less than or equal to 50, specify a lower bound of -10 and an +// upper bound of 0. +// +// There are a few rules for the step adjustments for your step policy: +// +// The ranges of your step adjustments can't overlap or have a gap. +// +// At most one step adjustment can have a null lower bound. If one step adjustment +// has a negative lower bound, then there must be a step adjustment with a null +// lower bound. +// +// At most one step adjustment can have a null upper bound. If one step adjustment +// has a positive upper bound, then there must be a step adjustment with a null +// upper bound. +// +// The upper and lower bound can't be null in the same step adjustment. +type StepAdjustment struct { + _ struct{} `type:"structure"` + + // The lower bound for the difference between the alarm threshold and the CloudWatch + // metric. If the metric value is above the breach threshold, the lower bound + // is inclusive (the metric must be greater than or equal to the threshold plus + // the lower bound). Otherwise, it is exclusive (the metric must be greater + // than the threshold plus the lower bound). A null value indicates negative + // infinity. + MetricIntervalLowerBound *float64 `type:"double"` + + // The upper bound for the difference between the alarm threshold and the CloudWatch + // metric. If the metric value is above the breach threshold, the upper bound + // is exclusive (the metric must be less than the threshold plus the upper bound). + // Otherwise, it is inclusive (the metric must be less than or equal to the + // threshold plus the upper bound). A null value indicates positive infinity. + // + // The upper bound must be greater than the lower bound. + MetricIntervalUpperBound *float64 `type:"double"` + + // The amount by which to scale, based on the specified adjustment type. A positive + // value adds to the current scalable dimension while a negative number removes + // from the current scalable dimension. + ScalingAdjustment *int64 `type:"integer" required:"true"` +} + +// String returns the string representation +func (s StepAdjustment) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s StepAdjustment) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *StepAdjustment) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "StepAdjustment"} + if s.ScalingAdjustment == nil { + invalidParams.Add(request.NewErrParamRequired("ScalingAdjustment")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +// An object representing a step scaling policy configuration. +type StepScalingPolicyConfiguration struct { + _ struct{} `type:"structure"` + + // The adjustment type, which specifies how the ScalingAdjustment parameter + // in a StepAdjustment is interpreted. + AdjustmentType *string `type:"string" enum:"AdjustmentType"` + + // The amount of time, in seconds, after a scaling activity completes where + // previous trigger-related scaling activities can influence future scaling + // events. + // + // For scale out policies, while Cooldown is in effect, the capacity that has + // been added by the previous scale out event that initiated the Cooldown is + // calculated as part of the desired capacity for the next scale out. The intention + // is to continuously (but not excessively) scale out. For example, an alarm + // triggers a step scaling policy to scale out an Amazon ECS service by 2 tasks, + // the scaling activity completes successfully, and a Cooldown period of 5 minutes + // starts. During the Cooldown period, if the alarm triggers the same policy + // again but at a more aggressive step adjustment to scale out the service by + // 3 tasks, the 2 tasks that were added in the previous scale out event are + // considered part of that capacity and only 1 additional task is added to the + // desired count. + // + // For scale in policies, the Cooldown period is used to block subsequent scale + // in requests until it has expired. The intention is to scale in conservatively + // to protect your application's availability. However, if another alarm triggers + // a scale out policy during the Cooldown period after a scale-in, Application + // Auto Scaling scales out your scalable target immediately. + Cooldown *int64 `type:"integer"` + + // The aggregation type for the CloudWatch metrics. Valid values are Minimum, + // Maximum, and Average. + MetricAggregationType *string `type:"string" enum:"MetricAggregationType"` + + // The minimum number to adjust your scalable dimension as a result of a scaling + // activity. If the adjustment type is PercentChangeInCapacity, the scaling + // policy changes the scalable dimension of the scalable target by this amount. + MinAdjustmentMagnitude *int64 `type:"integer"` + + // A set of adjustments that enable you to scale based on the size of the alarm + // breach. + StepAdjustments []*StepAdjustment `type:"list"` +} + +// String returns the string representation +func (s StepScalingPolicyConfiguration) String() string { + return awsutil.Prettify(s) +} + +// GoString returns the string representation +func (s StepScalingPolicyConfiguration) GoString() string { + return s.String() +} + +// Validate inspects the fields of the type to determine if they are valid. +func (s *StepScalingPolicyConfiguration) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "StepScalingPolicyConfiguration"} + if s.StepAdjustments != nil { + for i, v := range s.StepAdjustments { + if v == nil { + continue + } + if err := v.Validate(); err != nil { + invalidParams.AddNested(fmt.Sprintf("%s[%v]", "StepAdjustments", i), err.(request.ErrInvalidParams)) + } + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +const ( + // @enum AdjustmentType + AdjustmentTypeChangeInCapacity = "ChangeInCapacity" + // @enum AdjustmentType + AdjustmentTypePercentChangeInCapacity = "PercentChangeInCapacity" + // @enum AdjustmentType + AdjustmentTypeExactCapacity = "ExactCapacity" +) + +const ( + // @enum MetricAggregationType + MetricAggregationTypeAverage = "Average" + // @enum MetricAggregationType + MetricAggregationTypeMinimum = "Minimum" + // @enum MetricAggregationType + MetricAggregationTypeMaximum = "Maximum" +) + +const ( + // @enum PolicyType + PolicyTypeStepScaling = "StepScaling" +) + +const ( + // @enum ScalableDimension + ScalableDimensionEcsServiceDesiredCount = "ecs:service:DesiredCount" +) + +const ( + // @enum ScalingActivityStatusCode + ScalingActivityStatusCodePending = "Pending" + // @enum ScalingActivityStatusCode + ScalingActivityStatusCodeInProgress = "InProgress" + // @enum ScalingActivityStatusCode + ScalingActivityStatusCodeSuccessful = "Successful" + // @enum ScalingActivityStatusCode + ScalingActivityStatusCodeOverridden = "Overridden" + // @enum ScalingActivityStatusCode + ScalingActivityStatusCodeUnfulfilled = "Unfulfilled" + // @enum ScalingActivityStatusCode + ScalingActivityStatusCodeFailed = "Failed" +) + +const ( + // @enum ServiceNamespace + ServiceNamespaceEcs = "ecs" +) diff --git a/vendor/github.com/aws/aws-sdk-go/service/applicationautoscaling/service.go b/vendor/github.com/aws/aws-sdk-go/service/applicationautoscaling/service.go new file mode 100644 index 000000000..d6e797ff2 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/service/applicationautoscaling/service.go @@ -0,0 +1,112 @@ +// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. + +package applicationautoscaling + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/aws/signer/v4" + "github.com/aws/aws-sdk-go/private/protocol/jsonrpc" +) + +// Application Auto Scaling is a general purpose Auto Scaling service for supported +// elastic AWS resources. With Application Auto Scaling, you can automatically +// scale your AWS resources, with an experience similar to that of Auto Scaling. +// +// At this time, Application Auto Scaling only supports scaling Amazon ECS +// services. +// +// For example, you can use Application Auto Scaling to accomplish the following +// tasks: +// +// Define scaling policies for automatically adjusting your application’s +// resources +// +// Scale your resources in response to CloudWatch alarms +// +// View history of your scaling events +// +// Application Auto Scaling is available in the following regions: +// +// us-east-1 +// +// us-west-2 +// +// eu-west-1 +//The service client's operations are safe to be used concurrently. +// It is not safe to mutate any of the client's properties though. +type ApplicationAutoScaling struct { + *client.Client +} + +// Used for custom client initialization logic +var initClient func(*client.Client) + +// Used for custom request initialization logic +var initRequest func(*request.Request) + +// A ServiceName is the name of the service the client will make API calls to. +const ServiceName = "autoscaling" + +// New creates a new instance of the ApplicationAutoScaling client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a ApplicationAutoScaling client from just a session. +// svc := applicationautoscaling.New(mySession) +// +// // Create a ApplicationAutoScaling client with additional configuration +// svc := applicationautoscaling.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func New(p client.ConfigProvider, cfgs ...*aws.Config) *ApplicationAutoScaling { + c := p.ClientConfig(ServiceName, cfgs...) + return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion) +} + +// newClient creates, initializes and returns a new service client instance. +func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *ApplicationAutoScaling { + svc := &ApplicationAutoScaling{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: ServiceName, + SigningName: "application-autoscaling", + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2016-02-06", + JSONVersion: "1.1", + TargetPrefix: "AnyScaleFrontendService", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(jsonrpc.UnmarshalErrorHandler) + + // Run custom client initialization if present + if initClient != nil { + initClient(svc.Client) + } + + return svc +} + +// newRequest creates a new request for a ApplicationAutoScaling operation and runs any +// custom request initialization. +func (c *ApplicationAutoScaling) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + // Run custom request initialization if present + if initRequest != nil { + initRequest(req) + } + + return req +} diff --git a/vendor/vendor.json b/vendor/vendor.json index d50287eaa..db04e37e7 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -532,6 +532,12 @@ "version": "v1.2.7", "versionExact": "v1.2.7" }, + { + "checksumSHA1": "Td30Frd+lrCLlkMAirUTbjBXq5Q=", + "path": "github.com/aws/aws-sdk-go/service/applicationautoscaling", + "revision": "90dec2183a5f5458ee79cbaf4b8e9ab910bc81a6", + "revisionTime": "2016-07-08T00:08:20Z" + }, { "checksumSHA1": "AUA6op9dlm0X4vv1YPFnIFs6404=", "comment": "v1.1.23", From 76aea014cc55956722b0f9ffc54f129d62ebdb64 Mon Sep 17 00:00:00 2001 From: stack72 Date: Tue, 26 Jul 2016 10:42:21 +0100 Subject: [PATCH 3/3] provider/aws: Making some slight changes to the tests in resources --- ...resource_aws_appautoscaling_policy_test.go | 3 +- ...resource_aws_appautoscaling_target_test.go | 34 +++++++------------ 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/builtin/providers/aws/resource_aws_appautoscaling_policy_test.go b/builtin/providers/aws/resource_aws_appautoscaling_policy_test.go index 62d6d777d..0b5b0888d 100644 --- a/builtin/providers/aws/resource_aws_appautoscaling_policy_test.go +++ b/builtin/providers/aws/resource_aws_appautoscaling_policy_test.go @@ -11,11 +11,10 @@ import ( "github.com/hashicorp/terraform/terraform" ) -func TestAccAWSAppautoscalingPolicy_basic(t *testing.T) { +func TestAccAWSAppautoScalingPolicy_basic(t *testing.T) { var policy applicationautoscaling.ScalingPolicy randClusterName := fmt.Sprintf("cluster%s", acctest.RandString(10)) - // randResourceId := fmt.Sprintf("service/%s/%s", randClusterName, acctest.RandString(10)) randPolicyName := fmt.Sprintf("terraform-test-foobar-%s", acctest.RandString(5)) resource.Test(t, resource.TestCase{ diff --git a/builtin/providers/aws/resource_aws_appautoscaling_target_test.go b/builtin/providers/aws/resource_aws_appautoscaling_target_test.go index 185751c63..e3796e34e 100644 --- a/builtin/providers/aws/resource_aws_appautoscaling_target_test.go +++ b/builtin/providers/aws/resource_aws_appautoscaling_target_test.go @@ -16,7 +16,6 @@ func TestAccAWSAppautoScalingTarget_basic(t *testing.T) { var target applicationautoscaling.ScalableTarget randClusterName := fmt.Sprintf("cluster-%s", acctest.RandString(10)) - randResourceId := fmt.Sprintf("service/%s/%s", randClusterName, acctest.RandString(10)) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -25,12 +24,10 @@ func TestAccAWSAppautoScalingTarget_basic(t *testing.T) { CheckDestroy: testAccCheckAWSAppautoscalingTargetDestroy, Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccAWSAppautoscalingTargetConfig(randClusterName, randResourceId), + Config: testAccAWSAppautoscalingTargetConfig(randClusterName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAppautoscalingTargetExists("aws_appautoscaling_target.bar", &target), - testAccCheckAWSAppautoscalingTargetAttributes(&target, randResourceId), resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "service_namespace", "ecs"), - resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "resource_id", fmt.Sprintf("service/%s/foobar", randClusterName)), resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "scalable_dimension", "ecs:service:DesiredCount"), resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "min_capacity", "1"), resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "max_capacity", "3"), @@ -38,11 +35,11 @@ func TestAccAWSAppautoScalingTarget_basic(t *testing.T) { }, resource.TestStep{ - Config: testAccAWSAppautoscalingTargetConfigUpdate(randClusterName, randResourceId), + Config: testAccAWSAppautoscalingTargetConfigUpdate(randClusterName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAppautoscalingTargetExists("aws_appautoscaling_target.bar", &target), - resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "min_capacity", "3"), - resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "max_capacity", "6"), + resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "min_capacity", "2"), + resource.TestCheckResourceAttr("aws_appautoscaling_target.bar", "max_capacity", "8"), ), }, }, @@ -60,7 +57,8 @@ func testAccCheckAWSAppautoscalingTargetDestroy(s *terraform.State) error { // Try to find the target describeTargets, err := conn.DescribeScalableTargets( &applicationautoscaling.DescribeScalableTargetsInput{ - ResourceIds: []*string{aws.String(rs.Primary.ID)}, + ResourceIds: []*string{aws.String(rs.Primary.ID)}, + ServiceNamespace: aws.String(rs.Primary.Attributes["service_namespace"]), }, ) @@ -99,7 +97,8 @@ func testAccCheckAWSAppautoscalingTargetExists(n string, target *applicationauto describeTargets, err := conn.DescribeScalableTargets( &applicationautoscaling.DescribeScalableTargetsInput{ - ResourceIds: []*string{aws.String(rs.Primary.ID)}, + ResourceIds: []*string{aws.String(rs.Primary.ID)}, + ServiceNamespace: aws.String(rs.Primary.Attributes["service_namespace"]), }, ) @@ -107,24 +106,18 @@ func testAccCheckAWSAppautoscalingTargetExists(n string, target *applicationauto return err } - if len(describeTargets.ScalableTargets) != 1 || - *describeTargets.ScalableTargets[0].ResourceId != rs.Primary.ID { + if len(describeTargets.ScalableTargets) != 1 || *describeTargets.ScalableTargets[0].ResourceId != rs.Primary.ID { return fmt.Errorf("Application AutoScaling ResourceId not found") } - *target = *describeTargets.ScalableTargets[0] + target = describeTargets.ScalableTargets[0] return nil } } -func testAccCheckAWSAppautoscalingTargetAttributes(target *applicationautoscaling.ScalableTarget, resourceId string) resource.TestCheckFunc { - return nil -} - func testAccAWSAppautoscalingTargetConfig( - randClusterName string, - randResourceId string) string { + randClusterName string) string { return fmt.Sprintf(` resource "aws_iam_role" "autoscale_role" { name = "autoscalerole%s" @@ -210,14 +203,13 @@ resource "aws_appautoscaling_target" "bar" { scalable_dimension = "ecs:service:DesiredCount" role_arn = "${aws_iam_role.autoscale_role.arn}" min_capacity = 1 - max_capacity = 4 + max_capacity = 3 } `, randClusterName, randClusterName, randClusterName) } func testAccAWSAppautoscalingTargetConfigUpdate( - randClusterName, - randResourceId string) string { + randClusterName string) string { return fmt.Sprintf(` resource "aws_iam_role" "autoscale_role" { name = "autoscalerole%s"