From b3fad6a68cc321d3ed56472f9f1145514c17d25b Mon Sep 17 00:00:00 2001 From: Paul Stack Date: Mon, 21 Nov 2016 17:02:20 +0200 Subject: [PATCH] provider/aws: Addition of suspended_processes to aws_autoscaling_group (#10096) Fixes #8954 Addition of the support of autoScaling group suspended_processes --- .../aws/resource_aws_autoscaling_group.go | 79 +++++++++++++ .../resource_aws_autoscaling_group_test.go | 107 ++++++++++++++++++ builtin/providers/aws/structure.go | 10 ++ .../aws/r/autoscaling_group.html.markdown | 2 + 4 files changed, 198 insertions(+) diff --git a/builtin/providers/aws/resource_aws_autoscaling_group.go b/builtin/providers/aws/resource_aws_autoscaling_group.go index 9aa2097ed..6a35164b0 100644 --- a/builtin/providers/aws/resource_aws_autoscaling_group.go +++ b/builtin/providers/aws/resource_aws_autoscaling_group.go @@ -160,6 +160,13 @@ func resourceAwsAutoscalingGroup() *schema.Resource { Set: schema.HashString, }, + "suspended_processes": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "metrics_granularity": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -382,6 +389,13 @@ func resourceAwsAutoscalingGroupCreate(d *schema.ResourceData, meta interface{}) return err } + if _, ok := d.GetOk("suspended_processes"); ok { + suspendedProcessesErr := enableASGSuspendedProcesses(d, conn) + if suspendedProcessesErr != nil { + return suspendedProcessesErr + } + } + if _, ok := d.GetOk("enabled_metrics"); ok { metricsErr := enableASGMetricsCollection(d, conn) if metricsErr != nil { @@ -413,6 +427,9 @@ func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) e d.Set("health_check_type", g.HealthCheckType) d.Set("launch_configuration", g.LaunchConfigurationName) d.Set("load_balancers", flattenStringList(g.LoadBalancerNames)) + if err := d.Set("suspended_processes", flattenAsgSuspendedProcesses(g.SuspendedProcesses)); err != nil { + log.Printf("[WARN] Error setting suspended_processes for %q: %s", d.Id(), err) + } if err := d.Set("target_group_arns", flattenStringList(g.TargetGroupARNs)); err != nil { log.Printf("[ERR] Error setting target groups: %s", err) } @@ -607,6 +624,12 @@ func resourceAwsAutoscalingGroupUpdate(d *schema.ResourceData, meta interface{}) } } + if d.HasChange("suspended_processes") { + if err := updateASGSuspendedProcesses(d, conn); err != nil { + return errwrap.Wrapf("Error updating AutoScaling Group Suspended Processes: {{err}}", err) + } + } + return resourceAwsAutoscalingGroupRead(d, meta) } @@ -742,6 +765,20 @@ func resourceAwsAutoscalingGroupDrain(d *schema.ResourceData, meta interface{}) }) } +func enableASGSuspendedProcesses(d *schema.ResourceData, conn *autoscaling.AutoScaling) error { + props := &autoscaling.ScalingProcessQuery{ + AutoScalingGroupName: aws.String(d.Id()), + ScalingProcesses: expandStringList(d.Get("suspended_processes").(*schema.Set).List()), + } + + _, err := conn.SuspendProcesses(props) + if err != nil { + return err + } + + return nil +} + func enableASGMetricsCollection(d *schema.ResourceData, conn *autoscaling.AutoScaling) error { props := &autoscaling.EnableMetricsCollectionInput{ AutoScalingGroupName: aws.String(d.Id()), @@ -758,6 +795,48 @@ func enableASGMetricsCollection(d *schema.ResourceData, conn *autoscaling.AutoSc return nil } +func updateASGSuspendedProcesses(d *schema.ResourceData, conn *autoscaling.AutoScaling) error { + o, n := d.GetChange("suspended_processes") + if o == nil { + o = new(schema.Set) + } + if n == nil { + n = new(schema.Set) + } + + os := o.(*schema.Set) + ns := n.(*schema.Set) + + resumeProcesses := os.Difference(ns) + if resumeProcesses.Len() != 0 { + props := &autoscaling.ScalingProcessQuery{ + AutoScalingGroupName: aws.String(d.Id()), + ScalingProcesses: expandStringList(resumeProcesses.List()), + } + + _, err := conn.ResumeProcesses(props) + if err != nil { + return fmt.Errorf("Error Resuming Processes for ASG %q: %s", d.Id(), err) + } + } + + suspendedProcesses := ns.Difference(os) + if suspendedProcesses.Len() != 0 { + props := &autoscaling.ScalingProcessQuery{ + AutoScalingGroupName: aws.String(d.Id()), + ScalingProcesses: expandStringList(suspendedProcesses.List()), + } + + _, err := conn.SuspendProcesses(props) + if err != nil { + return fmt.Errorf("Error Suspending Processes for ASG %q: %s", d.Id(), err) + } + } + + return nil + +} + func updateASGMetricsCollection(d *schema.ResourceData, conn *autoscaling.AutoScaling) error { o, n := d.GetChange("enabled_metrics") diff --git a/builtin/providers/aws/resource_aws_autoscaling_group_test.go b/builtin/providers/aws/resource_aws_autoscaling_group_test.go index 367c177b3..0bf1c414c 100644 --- a/builtin/providers/aws/resource_aws_autoscaling_group_test.go +++ b/builtin/providers/aws/resource_aws_autoscaling_group_test.go @@ -294,6 +294,43 @@ func TestAccAWSAutoScalingGroup_enablingMetrics(t *testing.T) { }) } +func TestAccAWSAutoScalingGroup_suspendingProcesses(t *testing.T) { + var group autoscaling.Group + randName := fmt.Sprintf("terraform-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAutoScalingGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAutoScalingGroupConfig(randName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAutoScalingGroupExists("aws_autoscaling_group.bar", &group), + resource.TestCheckResourceAttr( + "aws_autoscaling_group.bar", "suspended_processes.#", "0"), + ), + }, + { + Config: testAccAWSAutoScalingGroupConfigWithSuspendedProcesses(randName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAutoScalingGroupExists("aws_autoscaling_group.bar", &group), + resource.TestCheckResourceAttr( + "aws_autoscaling_group.bar", "suspended_processes.#", "2"), + ), + }, + { + Config: testAccAWSAutoScalingGroupConfigWithSuspendedProcessesUpdated(randName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAutoScalingGroupExists("aws_autoscaling_group.bar", &group), + resource.TestCheckResourceAttr( + "aws_autoscaling_group.bar", "suspended_processes.#", "2"), + ), + }, + }, + }) +} + func TestAccAWSAutoScalingGroup_withMetrics(t *testing.T) { var group autoscaling.Group @@ -1487,3 +1524,73 @@ resource "aws_autoscaling_group" "bar" { launch_configuration = "${aws_launch_configuration.foobar.name}" } ` + +func testAccAWSAutoScalingGroupConfigWithSuspendedProcesses(name string) string { + return fmt.Sprintf(` +resource "aws_launch_configuration" "foobar" { + image_id = "ami-21f78e11" + instance_type = "t1.micro" +} + +resource "aws_placement_group" "test" { + name = "asg_pg_%s" + strategy = "cluster" +} + +resource "aws_autoscaling_group" "bar" { + availability_zones = ["us-west-2a"] + name = "%s" + max_size = 5 + min_size = 2 + health_check_type = "ELB" + desired_capacity = 4 + force_delete = true + termination_policies = ["OldestInstance","ClosestToNextInstanceHour"] + + launch_configuration = "${aws_launch_configuration.foobar.name}" + + suspended_processes = ["AlarmNotification","ScheduledActions"] + + tag { + key = "Foo" + value = "foo-bar" + propagate_at_launch = true + } +} +`, name, name) +} + +func testAccAWSAutoScalingGroupConfigWithSuspendedProcessesUpdated(name string) string { + return fmt.Sprintf(` +resource "aws_launch_configuration" "foobar" { + image_id = "ami-21f78e11" + instance_type = "t1.micro" +} + +resource "aws_placement_group" "test" { + name = "asg_pg_%s" + strategy = "cluster" +} + +resource "aws_autoscaling_group" "bar" { + availability_zones = ["us-west-2a"] + name = "%s" + max_size = 5 + min_size = 2 + health_check_type = "ELB" + desired_capacity = 4 + force_delete = true + termination_policies = ["OldestInstance","ClosestToNextInstanceHour"] + + launch_configuration = "${aws_launch_configuration.foobar.name}" + + suspended_processes = ["AZRebalance","ScheduledActions"] + + tag { + key = "Foo" + value = "foo-bar" + propagate_at_launch = true + } +} +`, name, name) +} diff --git a/builtin/providers/aws/structure.go b/builtin/providers/aws/structure.go index 84f02d9d3..56bab499e 100644 --- a/builtin/providers/aws/structure.go +++ b/builtin/providers/aws/structure.go @@ -1050,6 +1050,16 @@ func flattenCloudFormationOutputs(cfOutputs []*cloudformation.Output) map[string return outputs } +func flattenAsgSuspendedProcesses(list []*autoscaling.SuspendedProcess) []string { + strs := make([]string, 0, len(list)) + for _, r := range list { + if r.ProcessName != nil { + strs = append(strs, *r.ProcessName) + } + } + return strs +} + func flattenAsgEnabledMetrics(list []*autoscaling.EnabledMetric) []string { strs := make([]string, 0, len(list)) for _, r := range list { diff --git a/website/source/docs/providers/aws/r/autoscaling_group.html.markdown b/website/source/docs/providers/aws/r/autoscaling_group.html.markdown index 9c2c7dac9..05deba089 100644 --- a/website/source/docs/providers/aws/r/autoscaling_group.html.markdown +++ b/website/source/docs/providers/aws/r/autoscaling_group.html.markdown @@ -93,6 +93,8 @@ The following arguments are supported: * `target_group_arns` (Optional) A list of `aws_alb_target_group` ARNs, for use with Application Load Balancing * `termination_policies` (Optional) A list of policies to decide how the instances in the auto scale group should be terminated. The allowed values are `OldestInstance`, `NewestInstance`, `OldestLaunchConfiguration`, `ClosestToNextInstanceHour`, `Default`. +* `suspended_processes` - (Optional) A list of processes to suspend for the AutoScaling Group. The allowed values are `Launch`, `Terminate`, `HealthCheck`, `ReplaceUnhealthy`, `AZRebalance`, `AlarmNotification`, `ScheduledActions`, `AddToLoadBalancer`. +Note that if you suspend either the `Launch` or `Terminate` process types, it can prevent your autoscaling group from functioning properly. * `tag` (Optional) A list of tag blocks. Tags documented below. * `placement_group` (Optional) The name of the placement group into which you'll launch your instances, if any. * `metrics_granularity` - (Optional) The granularity to associate with the metrics to collect. The only valid value is `1Minute`. Default is `1Minute`.