From 70493d479dd4d9bf679f9b4b0c970c75d3806a18 Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Thu, 9 Nov 2017 21:54:09 +0900 Subject: [PATCH 1/6] Make files --- aws/provider.go | 1 + ...rce_aws_appautoscaling_scheduled_action.go | 29 ++++++++++++ ...ws_appautoscaling_scheduled_action_test.go | 44 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 aws/resource_aws_appautoscaling_scheduled_action.go create mode 100644 aws/resource_aws_appautoscaling_scheduled_action_test.go diff --git a/aws/provider.go b/aws/provider.go index 219efe2fe33..6ef07b28141 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -261,6 +261,7 @@ func Provider() terraform.ResourceProvider { "aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(), "aws_appautoscaling_target": resourceAwsAppautoscalingTarget(), "aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(), + "aws_appautoscaling_scheduled_action": resourceAwsAppautoscalingScheduledAction(), "aws_athena_database": resourceAwsAthenaDatabase(), "aws_athena_named_query": resourceAwsAthenaNamedQuery(), "aws_autoscaling_attachment": resourceAwsAutoscalingAttachment(), diff --git a/aws/resource_aws_appautoscaling_scheduled_action.go b/aws/resource_aws_appautoscaling_scheduled_action.go new file mode 100644 index 00000000000..115bca28f37 --- /dev/null +++ b/aws/resource_aws_appautoscaling_scheduled_action.go @@ -0,0 +1,29 @@ +package aws + +import ( + "errors" + + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsAppautoscalingScheduledAction() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAppautoscalingScheduledActionCreate, + Read: resourceAwsAppautoscalingScheduledActionRead, + Delete: resourceAwsAppautoscalingScheduledActionDelete, + + Schema: map[string]*schema.Schema{}, + } +} + +func resourceAwsAppautoscalingScheduledActionCreate(d *schema.ResourceData, meta interface{}) error { + return errors.New("error") +} + +func resourceAwsAppautoscalingScheduledActionRead(d *schema.ResourceData, meta interface{}) error { + return errors.New("error") +} + +func resourceAwsAppautoscalingScheduledActionDelete(d *schema.ResourceData, meta interface{}) error { + return errors.New("error") +} diff --git a/aws/resource_aws_appautoscaling_scheduled_action_test.go b/aws/resource_aws_appautoscaling_scheduled_action_test.go new file mode 100644 index 00000000000..a5fcf305c7d --- /dev/null +++ b/aws/resource_aws_appautoscaling_scheduled_action_test.go @@ -0,0 +1,44 @@ +package aws + +import ( + "errors" + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAwsAppautoscalingScheduledAction_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsAppautoscalingScheduledActionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppautoscalingScheduledActionConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAppautoscalingScheduledActionExists(""), + ), + }, + }, + }) +} + +func testAccCheckAwsAppautoscalingScheduledActionDestroy(s *terraform.State) error { + return errors.New("error") +} + +func testAccCheckAwsAppautoscalingScheduledActionExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + return nil + } +} + +func testAccAppautoscalingScheduledActionConfig() string { + return fmt.Sprintf(``) +} From 490b46794b3fe2ed62502c3c2d9390579dd14fdc Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Fri, 10 Nov 2017 08:22:18 +0900 Subject: [PATCH 2/6] WIP --- ...rce_aws_appautoscaling_scheduled_action.go | 106 +++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_appautoscaling_scheduled_action.go b/aws/resource_aws_appautoscaling_scheduled_action.go index 115bca28f37..3fed0813e73 100644 --- a/aws/resource_aws_appautoscaling_scheduled_action.go +++ b/aws/resource_aws_appautoscaling_scheduled_action.go @@ -3,6 +3,7 @@ package aws import ( "errors" + "github.com/aws/aws-sdk-go/service/applicationautoscaling" "github.com/hashicorp/terraform/helper/schema" ) @@ -12,18 +13,121 @@ func resourceAwsAppautoscalingScheduledAction() *schema.Resource { Read: resourceAwsAppautoscalingScheduledActionRead, Delete: resourceAwsAppautoscalingScheduledActionDelete, - Schema: map[string]*schema.Schema{}, + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "service_namespace": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + validServiceNamespaces := []string{"ecs", "elasticmapreduce", "ec2", "appstream", "dynamodb"} + for _, str := range validServiceNamespaces { + if value == str { + return + } + } + errors = append(errors, fmt.Errorf("expected %s to be one of %v, got %s", k, validServiceNamespaces, value)) + return + }, + }, + "resource_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "scalable_dimension": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + validDimensions := []string{"ecs:service:DesiredCount", "ec2:spot-fleet-request:TargetCapacity", + "elasticmapreduce:instancegroup:InstanceCount", "appstream:fleet:DesiredCapacity", + "dynamodb:table:ReadCapacityUnits", "dynamodb:table:WriteCapacityUnits", + "dynamodb:index:ReadCapacityUnits", "dynamodb:index:WriteCapacityUnits"} + for _, str := range validDimensions { + if value == str { + return + } + } + errors = append(errors, fmt.Errorf("expected %s to be one of %v, got %s", k, validDimensions, value)) + return + }, + }, + "scalable_target_action": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max_capacity": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + }, + "min_capacity": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + }, + }, + }, + }, + "schedule": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "start_time": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "end_time": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, } } func resourceAwsAppautoscalingScheduledActionCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appautoscalingconn + + input := applicationautoscaling.PutScheduledActionInput{ + ScheduledActionName: aws.String(d.Get("name").(string)), + } + _, err := conn.PutScheduledAction(input) + if err != nil { + return err + } return errors.New("error") } func resourceAwsAppautoscalingScheduledActionRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appautoscalingconn + + input := applicationautoscaling.DescribeScheduledActionsInput{} + _, err := conn.DescribeScheduledActions(input) + if err != nil { + return err + } return errors.New("error") } func resourceAwsAppautoscalingScheduledActionDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appautoscalingconn + + input := applicationautoscaling.DeleteScheduledActionInput{} + _, err := conn.DeleteScheduledAction(input) + if err != nil { + return err + } return errors.New("error") } From 9f1456e1c8caecce165e6a7f9d5fcec99c7b6f0b Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Sat, 11 Nov 2017 01:14:15 +0900 Subject: [PATCH 3/6] WIP --- ...rce_aws_appautoscaling_scheduled_action.go | 83 +++++++++++++++++-- 1 file changed, 76 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_appautoscaling_scheduled_action.go b/aws/resource_aws_appautoscaling_scheduled_action.go index 3fed0813e73..97bfe8e4f25 100644 --- a/aws/resource_aws_appautoscaling_scheduled_action.go +++ b/aws/resource_aws_appautoscaling_scheduled_action.go @@ -2,11 +2,17 @@ package aws import ( "errors" + "fmt" + "time" + "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/schema" ) +const awsAppautoscalingScheduleTimeLayout = "2006-01-02T15:04:05Z" + func resourceAwsAppautoscalingScheduledAction() *schema.Resource { return &schema.Resource{ Create: resourceAwsAppautoscalingScheduledActionCreate, @@ -60,9 +66,10 @@ func resourceAwsAppautoscalingScheduledAction() *schema.Resource { }, }, "scalable_target_action": &schema.Schema{ - Type: schema.TypeSet, + Type: schema.TypeList, Optional: true, ForceNew: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "max_capacity": &schema.Schema{ @@ -93,6 +100,10 @@ func resourceAwsAppautoscalingScheduledAction() *schema.Resource { Optional: true, ForceNew: true, }, + "arn": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -100,34 +111,92 @@ func resourceAwsAppautoscalingScheduledAction() *schema.Resource { func resourceAwsAppautoscalingScheduledActionCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appautoscalingconn - input := applicationautoscaling.PutScheduledActionInput{ + input := &applicationautoscaling.PutScheduledActionInput{ ScheduledActionName: aws.String(d.Get("name").(string)), + ServiceNamespace: aws.String(d.Get("service_namespace").(string)), + ResourceId: aws.String(d.Get("resource_id").(string)), + } + if v, ok := d.GetOk("scalable_dimension"); ok { + input.ScalableDimension = aws.String(v.(string)) + } + if v, ok := d.GetOk("schedule"); ok { + input.Schedule = aws.String(v.(string)) + } + if v, ok := d.GetOk("scalable_target_action"); ok { + raw := v.([]interface{})[0].(map[string]interface{}) + if max, ok := raw["max_capacity"]; ok { + input.ScalableTargetAction.MaxCapacity = aws.Int64(int64(max.(int))) + } + if min, ok := raw["min_capacity"]; ok { + input.ScalableTargetAction.MaxCapacity = aws.Int64(int64(min.(int))) + } + } + if v, ok := d.GetOk("start_time"); ok { + t, err := time.Parse(awsAppautoscalingScheduleTimeLayout, v.(string)) + if err != nil { + return fmt.Errorf("Error Parsing Appautoscaling Scheduled Action Start Time: %s", err.Error()) + } + input.StartTime = aws.Time(t) + } + if v, ok := d.GetOk("end_time"); ok { + t, err := time.Parse(awsAppautoscalingScheduleTimeLayout, v.(string)) + if err != nil { + return fmt.Errorf("Error Parsing Appautoscaling Scheduled Action End Time: %s", err.Error()) + } + input.EndTime = aws.Time(t) } _, err := conn.PutScheduledAction(input) if err != nil { return err } - return errors.New("error") + d.SetId(d.Get("name").(string)) + return resourceAwsAppautoscalingScheduledActionRead(d, meta) } func resourceAwsAppautoscalingScheduledActionRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appautoscalingconn - input := applicationautoscaling.DescribeScheduledActionsInput{} - _, err := conn.DescribeScheduledActions(input) + saName := d.Id() + input := &applicationautoscaling.DescribeScheduledActionsInput{ + ScheduledActionNames: []*string{aws.String(saName)}, + } + resp, err := conn.DescribeScheduledActions(input) if err != nil { return err } + if len(resp.ScheduledActions) < 1 { + d.SetId("") + return nil + } + if len(resp.ScheduledActions) != 1 { + return fmt.Errorf("Number of Scheduled Action (%s) isn't one, got %d", saName, len(resp.ScheduledActions)) + } + if *resp.ScheduledActions[0].ScheduledActionName != saName { + return fmt.Errorf("Scheduled Action (%s) not found", saName) + } + d.Set("arn", resp.ScheduledActions[0].ScheduledActionARN) return errors.New("error") } func resourceAwsAppautoscalingScheduledActionDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appautoscalingconn - input := applicationautoscaling.DeleteScheduledActionInput{} + input := &applicationautoscaling.DeleteScheduledActionInput{ + ScheduledActionName: aws.String(d.Get("name").(string)), + ServiceNamespace: aws.String(d.Get("service_namespace").(string)), + ResourceId: aws.String(d.Get("resource_id").(string)), + } + if v, ok := d.GetOk("scalable_dimension"); ok { + input.ScalableDimension = aws.String(v.(string)) + } _, err := conn.DeleteScheduledAction(input) if err != nil { + if aerr, ok := err.(awserr.Error); ok && aerr.Code() == applicationautoscaling.ErrCodeObjectNotFoundException { + d.SetId("") + return nil + } return err } - return errors.New("error") + d.SetId("") + return nil } From 99a586a4fec46898c5f57d7e7ee4656f9a1b8479 Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Sat, 11 Nov 2017 15:59:55 +0900 Subject: [PATCH 4/6] New Resource: aws_appautoscaling_scheduled_action --- ...rce_aws_appautoscaling_scheduled_action.go | 30 +- ...ws_appautoscaling_scheduled_action_test.go | 649 +++++++++++++++++- website/aws.erb | 4 +- ...autoscaling_scheduled_action.html.markdown | 89 +++ 4 files changed, 759 insertions(+), 13 deletions(-) create mode 100644 website/docs/r/appautoscaling_scheduled_action.html.markdown diff --git a/aws/resource_aws_appautoscaling_scheduled_action.go b/aws/resource_aws_appautoscaling_scheduled_action.go index 97bfe8e4f25..410cc504e9a 100644 --- a/aws/resource_aws_appautoscaling_scheduled_action.go +++ b/aws/resource_aws_appautoscaling_scheduled_action.go @@ -1,13 +1,13 @@ package aws import ( - "errors" "fmt" "time" "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/resource" "github.com/hashicorp/terraform/helper/schema" ) @@ -123,13 +123,15 @@ func resourceAwsAppautoscalingScheduledActionCreate(d *schema.ResourceData, meta input.Schedule = aws.String(v.(string)) } if v, ok := d.GetOk("scalable_target_action"); ok { + sta := &applicationautoscaling.ScalableTargetAction{} raw := v.([]interface{})[0].(map[string]interface{}) if max, ok := raw["max_capacity"]; ok { - input.ScalableTargetAction.MaxCapacity = aws.Int64(int64(max.(int))) + sta.MaxCapacity = aws.Int64(int64(max.(int))) } if min, ok := raw["min_capacity"]; ok { - input.ScalableTargetAction.MaxCapacity = aws.Int64(int64(min.(int))) + sta.MaxCapacity = aws.Int64(int64(min.(int))) } + input.ScalableTargetAction = sta } if v, ok := d.GetOk("start_time"); ok { t, err := time.Parse(awsAppautoscalingScheduleTimeLayout, v.(string)) @@ -145,10 +147,27 @@ func resourceAwsAppautoscalingScheduledActionCreate(d *schema.ResourceData, meta } input.EndTime = aws.Time(t) } - _, err := conn.PutScheduledAction(input) + + err := resource.Retry(5*time.Minute, func() *resource.RetryError { + _, err := conn.PutScheduledAction(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case applicationautoscaling.ErrCodeObjectNotFoundException: + return resource.RetryableError(err) + default: + return resource.NonRetryableError(err) + } + } + return resource.NonRetryableError(err) + } + return nil + }) + if err != nil { return err } + d.SetId(d.Get("name").(string)) return resourceAwsAppautoscalingScheduledActionRead(d, meta) } @@ -159,6 +178,7 @@ func resourceAwsAppautoscalingScheduledActionRead(d *schema.ResourceData, meta i saName := d.Id() input := &applicationautoscaling.DescribeScheduledActionsInput{ ScheduledActionNames: []*string{aws.String(saName)}, + ServiceNamespace: aws.String(d.Get("service_namespace").(string)), } resp, err := conn.DescribeScheduledActions(input) if err != nil { @@ -175,7 +195,7 @@ func resourceAwsAppautoscalingScheduledActionRead(d *schema.ResourceData, meta i return fmt.Errorf("Scheduled Action (%s) not found", saName) } d.Set("arn", resp.ScheduledActions[0].ScheduledActionARN) - return errors.New("error") + return nil } func resourceAwsAppautoscalingScheduledActionDelete(d *schema.ResourceData, meta interface{}) error { diff --git a/aws/resource_aws_appautoscaling_scheduled_action_test.go b/aws/resource_aws_appautoscaling_scheduled_action_test.go index a5fcf305c7d..9a7647b37c4 100644 --- a/aws/resource_aws_appautoscaling_scheduled_action_test.go +++ b/aws/resource_aws_appautoscaling_scheduled_action_test.go @@ -1,24 +1,79 @@ package aws import ( - "errors" "fmt" "testing" + "time" + "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 TestAccAwsAppautoscalingScheduledAction_basic(t *testing.T) { +func TestAccAwsAppautoscalingScheduledAction_dynamo(t *testing.T) { + ts := time.Now().AddDate(0, 0, 1).Format("2006-01-02T15:04:05") resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAwsAppautoscalingScheduledActionDestroy, Steps: []resource.TestStep{ { - Config: testAccAppautoscalingScheduledActionConfig(), + Config: testAccAppautoscalingScheduledActionConfig_DynamoDB(acctest.RandString(5), ts), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsAppautoscalingScheduledActionExists(""), + testAccCheckAwsAppautoscalingScheduledActionExists("aws_appautoscaling_scheduled_action.hoge"), + ), + }, + }, + }) +} + +func TestAccAwsAppautoscalingScheduledAction_ECS(t *testing.T) { + ts := time.Now().AddDate(0, 0, 1).Format("2006-01-02T15:04:05") + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsAppautoscalingScheduledActionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppautoscalingScheduledActionConfig_ECS(acctest.RandString(5), ts), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAppautoscalingScheduledActionExists("aws_appautoscaling_scheduled_action.hoge"), + ), + }, + }, + }) +} + +func TestAccAwsAppautoscalingScheduledAction_EMR(t *testing.T) { + ts := time.Now().AddDate(0, 0, 1).Format("2006-01-02T15:04:05") + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsAppautoscalingScheduledActionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppautoscalingScheduledActionConfig_EMR(acctest.RandString(5), ts), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAppautoscalingScheduledActionExists("aws_appautoscaling_scheduled_action.hoge"), + ), + }, + }, + }) +} + +func TestAccAwsAppautoscalingScheduledAction_SpotFleet(t *testing.T) { + ts := time.Now().AddDate(0, 0, 1).Format("2006-01-02T15:04:05") + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsAppautoscalingScheduledActionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppautoscalingScheduledActionConfig_SpotFleet(acctest.RandString(5), ts), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAppautoscalingScheduledActionExists("aws_appautoscaling_scheduled_action.hoge"), ), }, }, @@ -26,7 +81,26 @@ func TestAccAwsAppautoscalingScheduledAction_basic(t *testing.T) { } func testAccCheckAwsAppautoscalingScheduledActionDestroy(s *terraform.State) error { - return errors.New("error") + conn := testAccProvider.Meta().(*AWSClient).appautoscalingconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_appautoscaling_scheduled_action" { + continue + } + + input := &applicationautoscaling.DescribeScheduledActionsInput{ + ScheduledActionNames: []*string{aws.String(rs.Primary.ID)}, + ServiceNamespace: aws.String(rs.Primary.Attributes["service_namespace"]), + } + resp, err := conn.DescribeScheduledActions(input) + if err != nil { + return err + } + if len(resp.ScheduledActions) > 0 { + return fmt.Errorf("Appautoscaling Scheduled Action (%s) not deleted", rs.Primary.ID) + } + } + return nil } func testAccCheckAwsAppautoscalingScheduledActionExists(name string) resource.TestCheckFunc { @@ -39,6 +113,567 @@ func testAccCheckAwsAppautoscalingScheduledActionExists(name string) resource.Te } } -func testAccAppautoscalingScheduledActionConfig() string { - return fmt.Sprintf(``) +func testAccAppautoscalingScheduledActionConfig_DynamoDB(rName, ts string) string { + return fmt.Sprintf(` +resource "aws_dynamodb_table" "hoge" { + name = "tf-ddb-%s" + read_capacity = 5 + write_capacity = 5 + hash_key = "UserID" + + attribute { + name = "UserID" + type = "S" + } +} + +resource "aws_iam_role" "hoge" { + assume_role_policy = <> aws_appautoscaling_policy - + > + aws_appautoscaling_scheduled_action + > aws_appautoscaling_target diff --git a/website/docs/r/appautoscaling_scheduled_action.html.markdown b/website/docs/r/appautoscaling_scheduled_action.html.markdown new file mode 100644 index 00000000000..cf32fae2ba5 --- /dev/null +++ b/website/docs/r/appautoscaling_scheduled_action.html.markdown @@ -0,0 +1,89 @@ +--- +layout: "aws" +page_title: "AWS: aws_appautoscaling_scheduled_action" +sidebar_current: "docs-aws-resource-appautoscaling-scheduled-action" +description: |- + Provides an Application AutoScaling ScheduledAction resource. +--- + +# aws_appautoscaling_scheduled_action + +Provides an Application AutoScaling ScheduledAction resource. + +## Example Usage + +### DynamoDB Table Autoscaling + +```hcl +resource "aws_appautoscaling_target" "dynamodb" { + max_capacity = 100 + min_capacity = 5 + resource_id = "table/tableName" + role_arn = "${data.aws_iam_role.DynamoDBAutoscaleRole.arn}" + scalable_dimension = "dynamodb:table:ReadCapacityUnits" + service_namespace = "dynamodb" +} + +resource "aws_appautoscaling_scheduled_action" "dynamodb" { + name = "dynamodb" + service_namespace = "${aws_appautoscaling_target.dynamodb.service_namespace}" + resource_id = "${aws_appautoscaling_target.dynamodb.resource_id}" + scalable_dimension = "${aws_appautoscaling_target.dynamodb.scalable_dimension}" + schedule = "at(2006-01-02T15:04:05)" + + scalable_target_action { + min_capacity = 1 + max_capacity = 200 + } +} +``` + +### ECS Service Autoscaling + +```hcl +resource "aws_appautoscaling_target" "ecs" { + max_capacity = 4 + min_capacity = 1 + resource_id = "service/clusterName/serviceName" + role_arn = "${var.ecs_iam_role}" + scalable_dimension = "ecs:service:DesiredCount" + service_namespace = "ecs" +} + +resource "aws_appautoscaling_scheduled_action" "ecs" { + name = "ecs" + service_namespace = "${aws_appautoscaling_target.ecs.service_namespace}" + resource_id = "${aws_appautoscaling_target.ecs.resource_id}" + scalable_dimension = "${aws_appautoscaling_target.ecs.scalable_dimension}" + schedule = "at(2006-01-02T15:04:05)" + + scalable_target_action { + min_capacity = 1 + max_capacity = 10 + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the scheduled action. +* `service_namespace` - (Required) The namespace of the AWS service. Documentation can be found in the parameter at: [AWS Application Auto Scaling API Reference](https://docs.aws.amazon.com/ApplicationAutoScaling/latest/APIReference/API_PutScheduledAction.html#ApplicationAutoScaling-PutScheduledAction-request-ServiceNamespace) Valid Values: ecs | elasticmapreduce | ec2 | appstream | dynamodb +* `resource_id` - (Required) The identifier of the resource associated with the scheduled action. Documentation can be found in the parameter at: [AWS Application Auto Scaling API Reference](https://docs.aws.amazon.com/ApplicationAutoScaling/latest/APIReference/API_PutScheduledAction.html#ApplicationAutoScaling-PutScheduledAction-request-ResourceId) +* `scalable_dimension` - (Optional) The scalable dimension. Documentation can be found in the parameter at: [AWS Application Auto Scaling API Reference](https://docs.aws.amazon.com/ApplicationAutoScaling/latest/APIReference/API_PutScheduledAction.html#ApplicationAutoScaling-PutScheduledAction-request-ScalableDimension) Valid Values: ecs:service:DesiredCount | ec2:spot-fleet-request:TargetCapacity | elasticmapreduce:instancegroup:InstanceCount | appstream:fleet:DesiredCapacity | dynamodb:table:ReadCapacityUnits | dynamodb:table:WriteCapacityUnits | dynamodb:index:ReadCapacityUnits | dynamodb:index:WriteCapacityUnits +* `scalable_target_action` - (Optional) The new minimum and maximum capacity. You can set both values or just one. See [below](#scalable-target-action-arguments) +* `schedule` - (Optional) The schedule for this action. The following formats are supported: At expressions - at(yyyy-mm-ddThh:mm:ss), Rate expressions - rate(valueunit), Cron expressions - cron(fields). In UTC. Documentation can be found in the parameter at: [AWS Application Auto Scaling API Reference](https://docs.aws.amazon.com/ApplicationAutoScaling/latest/APIReference/API_PutScheduledAction.html#ApplicationAutoScaling-PutScheduledAction-request-Schedule) +* `start_time` - (Optional) The date and time for the scheduled action to start. Specify the following format: 2006-01-02T15:04:05Z +* `end_time` - (Optional) The date and time for the scheduled action to end. Specify the following format: 2006-01-02T15:04:05Z + +### Scalable Target Action Arguments + +* `max_capacity` - (Optional) The maximum capacity. +* `min_capacity` - (Optional) The minimum capacity. + +## Attributes Reference + +The following attributes are exported: + +* `arn` - The Amazon Resource Name (ARN) of the scheduled action. From 6a24fcf86b3f94139685a94780169e3a603d46eb Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Sat, 2 Dec 2017 21:43:33 +0900 Subject: [PATCH 5/6] Reflect reviews --- ...rce_aws_appautoscaling_scheduled_action.go | 40 +++---------------- ...ws_appautoscaling_scheduled_action_test.go | 20 +++++----- ...autoscaling_scheduled_action.html.markdown | 4 +- 3 files changed, 17 insertions(+), 47 deletions(-) diff --git a/aws/resource_aws_appautoscaling_scheduled_action.go b/aws/resource_aws_appautoscaling_scheduled_action.go index 410cc504e9a..943da2a8763 100644 --- a/aws/resource_aws_appautoscaling_scheduled_action.go +++ b/aws/resource_aws_appautoscaling_scheduled_action.go @@ -15,7 +15,7 @@ const awsAppautoscalingScheduleTimeLayout = "2006-01-02T15:04:05Z" func resourceAwsAppautoscalingScheduledAction() *schema.Resource { return &schema.Resource{ - Create: resourceAwsAppautoscalingScheduledActionCreate, + Create: resourceAwsAppautoscalingScheduledActionPut, Read: resourceAwsAppautoscalingScheduledActionRead, Delete: resourceAwsAppautoscalingScheduledActionDelete, @@ -29,17 +29,6 @@ func resourceAwsAppautoscalingScheduledAction() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - validServiceNamespaces := []string{"ecs", "elasticmapreduce", "ec2", "appstream", "dynamodb"} - for _, str := range validServiceNamespaces { - if value == str { - return - } - } - errors = append(errors, fmt.Errorf("expected %s to be one of %v, got %s", k, validServiceNamespaces, value)) - return - }, }, "resource_id": &schema.Schema{ Type: schema.TypeString, @@ -50,20 +39,6 @@ func resourceAwsAppautoscalingScheduledAction() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - validDimensions := []string{"ecs:service:DesiredCount", "ec2:spot-fleet-request:TargetCapacity", - "elasticmapreduce:instancegroup:InstanceCount", "appstream:fleet:DesiredCapacity", - "dynamodb:table:ReadCapacityUnits", "dynamodb:table:WriteCapacityUnits", - "dynamodb:index:ReadCapacityUnits", "dynamodb:index:WriteCapacityUnits"} - for _, str := range validDimensions { - if value == str { - return - } - } - errors = append(errors, fmt.Errorf("expected %s to be one of %v, got %s", k, validDimensions, value)) - return - }, }, "scalable_target_action": &schema.Schema{ Type: schema.TypeList, @@ -108,7 +83,7 @@ func resourceAwsAppautoscalingScheduledAction() *schema.Resource { } } -func resourceAwsAppautoscalingScheduledActionCreate(d *schema.ResourceData, meta interface{}) error { +func resourceAwsAppautoscalingScheduledActionPut(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appautoscalingconn input := &applicationautoscaling.PutScheduledActionInput{ @@ -151,13 +126,8 @@ func resourceAwsAppautoscalingScheduledActionCreate(d *schema.ResourceData, meta err := resource.Retry(5*time.Minute, func() *resource.RetryError { _, err := conn.PutScheduledAction(input) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case applicationautoscaling.ErrCodeObjectNotFoundException: - return resource.RetryableError(err) - default: - return resource.NonRetryableError(err) - } + if isAWSErr(err, applicationautoscaling.ErrCodeObjectNotFoundException, "") { + return resource.RetryableError(err) } return resource.NonRetryableError(err) } @@ -189,7 +159,7 @@ func resourceAwsAppautoscalingScheduledActionRead(d *schema.ResourceData, meta i return nil } if len(resp.ScheduledActions) != 1 { - return fmt.Errorf("Number of Scheduled Action (%s) isn't one, got %d", saName, len(resp.ScheduledActions)) + return fmt.Errorf("Expected 1 scheduled action under %s, found %d", saName, len(resp.ScheduledActions)) } if *resp.ScheduledActions[0].ScheduledActionName != saName { return fmt.Errorf("Scheduled Action (%s) not found", saName) diff --git a/aws/resource_aws_appautoscaling_scheduled_action_test.go b/aws/resource_aws_appautoscaling_scheduled_action_test.go index 9a7647b37c4..58d0cbf6750 100644 --- a/aws/resource_aws_appautoscaling_scheduled_action_test.go +++ b/aws/resource_aws_appautoscaling_scheduled_action_test.go @@ -221,7 +221,7 @@ resource "aws_iam_role_policy" "hoge" { "Action": [ "ecs:DescribeServices", "ecs:UpdateService", - "cloudwatch:DescribeAlarms" + "cloudwatch:DescribeAlarms" ], "Resource": [ "*" @@ -233,11 +233,11 @@ EOF } resource "aws_ecs_cluster" "hoge" { - name = "tf-ecs-cluster-%s" + name = "tf-ecs-cluster-%s" } resource "aws_ecs_task_definition" "hoge" { - family = "foobar" + family = "foobar%s" container_definitions = < Date: Mon, 4 Dec 2017 20:23:18 +0900 Subject: [PATCH 6/6] Used 3fields for id --- aws/resource_aws_appautoscaling_scheduled_action.go | 7 +++---- aws/resource_aws_appautoscaling_scheduled_action_test.go | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_appautoscaling_scheduled_action.go b/aws/resource_aws_appautoscaling_scheduled_action.go index 943da2a8763..0cccbeb4eba 100644 --- a/aws/resource_aws_appautoscaling_scheduled_action.go +++ b/aws/resource_aws_appautoscaling_scheduled_action.go @@ -5,7 +5,6 @@ import ( "time" "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/resource" "github.com/hashicorp/terraform/helper/schema" @@ -138,14 +137,14 @@ func resourceAwsAppautoscalingScheduledActionPut(d *schema.ResourceData, meta in return err } - d.SetId(d.Get("name").(string)) + d.SetId(d.Get("name").(string) + "-" + d.Get("service_namespace").(string) + "-" + d.Get("resource_id").(string)) return resourceAwsAppautoscalingScheduledActionRead(d, meta) } func resourceAwsAppautoscalingScheduledActionRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appautoscalingconn - saName := d.Id() + saName := d.Get("name").(string) input := &applicationautoscaling.DescribeScheduledActionsInput{ ScheduledActionNames: []*string{aws.String(saName)}, ServiceNamespace: aws.String(d.Get("service_namespace").(string)), @@ -181,7 +180,7 @@ func resourceAwsAppautoscalingScheduledActionDelete(d *schema.ResourceData, meta } _, err := conn.DeleteScheduledAction(input) if err != nil { - if aerr, ok := err.(awserr.Error); ok && aerr.Code() == applicationautoscaling.ErrCodeObjectNotFoundException { + if isAWSErr(err, applicationautoscaling.ErrCodeObjectNotFoundException, "") { d.SetId("") return nil } diff --git a/aws/resource_aws_appautoscaling_scheduled_action_test.go b/aws/resource_aws_appautoscaling_scheduled_action_test.go index 58d0cbf6750..bff9dfea906 100644 --- a/aws/resource_aws_appautoscaling_scheduled_action_test.go +++ b/aws/resource_aws_appautoscaling_scheduled_action_test.go @@ -89,7 +89,7 @@ func testAccCheckAwsAppautoscalingScheduledActionDestroy(s *terraform.State) err } input := &applicationautoscaling.DescribeScheduledActionsInput{ - ScheduledActionNames: []*string{aws.String(rs.Primary.ID)}, + ScheduledActionNames: []*string{aws.String(rs.Primary.Attributes["name"])}, ServiceNamespace: aws.String(rs.Primary.Attributes["service_namespace"]), } resp, err := conn.DescribeScheduledActions(input) @@ -97,7 +97,7 @@ func testAccCheckAwsAppautoscalingScheduledActionDestroy(s *terraform.State) err return err } if len(resp.ScheduledActions) > 0 { - return fmt.Errorf("Appautoscaling Scheduled Action (%s) not deleted", rs.Primary.ID) + return fmt.Errorf("Appautoscaling Scheduled Action (%s) not deleted", rs.Primary.Attributes["name"]) } } return nil