From da0bffae4479eec97a6e3a40465e259e71b49a5b Mon Sep 17 00:00:00 2001 From: stack72 Date: Fri, 15 Jan 2016 10:29:15 +0000 Subject: [PATCH] Scaffold the AWS Autoscaling Group Metrics Collection --- builtin/providers/aws/provider.go | 1 + .../aws/resource_aws_autoscaling_group.go | 13 ++ ...urce_aws_autoscaling_metrics_collection.go | 140 +++++++++++++ ...aws_autoscaling_metrics_collection_test.go | 189 ++++++++++++++++++ builtin/providers/aws/structure.go | 11 + builtin/providers/aws/structure_test.go | 22 ++ ...toscaling_metrics_collection.html.markdown | 57 ++++++ website/source/layouts/aws.erb | 4 + 8 files changed, 437 insertions(+) create mode 100644 builtin/providers/aws/resource_aws_autoscaling_metrics_collection.go create mode 100644 builtin/providers/aws/resource_aws_autoscaling_metrics_collection_test.go create mode 100644 website/source/docs/providers/aws/r/autoscaling_metrics_collection.html.markdown diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index 9829972c8b5a..d5ebfa4ee5d0 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -109,6 +109,7 @@ func Provider() terraform.ResourceProvider { "aws_ami_from_instance": resourceAwsAmiFromInstance(), "aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(), "aws_autoscaling_group": resourceAwsAutoscalingGroup(), + "aws_autoscaling_metrics_collection": resourceAwsAutoscalingMetric(), "aws_autoscaling_notification": resourceAwsAutoscalingNotification(), "aws_autoscaling_policy": resourceAwsAutoscalingPolicy(), "aws_autoscaling_schedule": resourceAwsAutoscalingSchedule(), diff --git a/builtin/providers/aws/resource_aws_autoscaling_group.go b/builtin/providers/aws/resource_aws_autoscaling_group.go index 1e815d4656ab..bcd350843fe1 100644 --- a/builtin/providers/aws/resource_aws_autoscaling_group.go +++ b/builtin/providers/aws/resource_aws_autoscaling_group.go @@ -146,6 +146,13 @@ func resourceAwsAutoscalingGroup() *schema.Resource { Optional: true, }, + "enabled_metrics": &schema.Schema{ + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "tag": autoscalingTagsSchema(), }, } @@ -252,6 +259,12 @@ func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) e d.Set("vpc_zone_identifier", strings.Split(*g.VPCZoneIdentifier, ",")) d.Set("termination_policies", g.TerminationPolicies) + if g.EnabledMetrics != nil { + if err := d.Set("enabled_metrics", flattenAsgEnabledMetrics(g.EnabledMetrics)); err != nil { + log.Printf("[WARN] Error setting metrics for (%s): %s", d.Id(), err) + } + } + return nil } diff --git a/builtin/providers/aws/resource_aws_autoscaling_metrics_collection.go b/builtin/providers/aws/resource_aws_autoscaling_metrics_collection.go new file mode 100644 index 000000000000..9fa03ee41ac6 --- /dev/null +++ b/builtin/providers/aws/resource_aws_autoscaling_metrics_collection.go @@ -0,0 +1,140 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/autoscaling" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsAutoscalingMetric() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAutoscalingMetricCreate, + Read: resourceAwsAutoscalingMetricRead, + Update: resourceAwsAutoscalingMetricUpdate, + Delete: resourceAwsAutoscalingMetricDelete, + + Schema: map[string]*schema.Schema{ + "autoscaling_group_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "metrics": &schema.Schema{ + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "granularity": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +func resourceAwsAutoscalingMetricCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).autoscalingconn + + asgName := d.Get("autoscaling_group_name").(string) + props := &autoscaling.EnableMetricsCollectionInput{ + AutoScalingGroupName: aws.String(asgName), + Granularity: aws.String(d.Get("granularity").(string)), + Metrics: expandStringList(d.Get("metrics").(*schema.Set).List()), + } + + log.Printf("[INFO] Enabling metrics collection for the ASG: %s", asgName) + _, err := conn.EnableMetricsCollection(props) + if err != nil { + return err + } + + d.SetId(d.Get("autoscaling_group_name").(string)) + + return resourceAwsAutoscalingMetricRead(d, meta) +} + +func resourceAwsAutoscalingMetricRead(d *schema.ResourceData, meta interface{}) error { + g, err := getAwsAutoscalingGroup(d, meta) + if err != nil { + return err + } + if g == nil { + return nil + } + + if g.EnabledMetrics != nil && len(g.EnabledMetrics) > 0 { + if err := d.Set("metrics", flattenAsgEnabledMetrics(g.EnabledMetrics)); err != nil { + log.Printf("[WARN] Error setting metrics for (%s): %s", d.Id(), err) + } + d.Set("granularity", g.EnabledMetrics[0].Granularity) + } + + return nil +} + +func resourceAwsAutoscalingMetricUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).autoscalingconn + + if d.HasChange("metrics") { + o, n := d.GetChange("metrics") + if o == nil { + o = new(schema.Set) + } + if n == nil { + n = new(schema.Set) + } + + os := o.(*schema.Set) + ns := n.(*schema.Set) + + disableMetrics := os.Difference(ns) + if disableMetrics.Len() != 0 { + props := &autoscaling.DisableMetricsCollectionInput{ + AutoScalingGroupName: aws.String(d.Id()), + Metrics: expandStringList(disableMetrics.List()), + } + + _, err := conn.DisableMetricsCollection(props) + if err != nil { + return fmt.Errorf("Failure to Disable metrics collection types for ASG %s: %s", d.Id(), err) + } + } + + enabledMetrics := ns.Difference(os) + if enabledMetrics.Len() != 0 { + props := &autoscaling.EnableMetricsCollectionInput{ + AutoScalingGroupName: aws.String(d.Id()), + Metrics: expandStringList(enabledMetrics.List()), + } + + _, err := conn.EnableMetricsCollection(props) + if err != nil { + return fmt.Errorf("Failure to Enable metrics collection types for ASG %s: %s", d.Id(), err) + } + } + } + + return resourceAwsAutoscalingMetricRead(d, meta) +} + +func resourceAwsAutoscalingMetricDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).autoscalingconn + + props := &autoscaling.DisableMetricsCollectionInput{ + AutoScalingGroupName: aws.String(d.Id()), + } + + log.Printf("[INFO] Disabling ALL metrics collection for the ASG: %s", d.Id()) + _, err := conn.DisableMetricsCollection(props) + if err != nil { + return err + } + + return nil +} diff --git a/builtin/providers/aws/resource_aws_autoscaling_metrics_collection_test.go b/builtin/providers/aws/resource_aws_autoscaling_metrics_collection_test.go new file mode 100644 index 000000000000..a2cb6324d178 --- /dev/null +++ b/builtin/providers/aws/resource_aws_autoscaling_metrics_collection_test.go @@ -0,0 +1,189 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/autoscaling" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAWSAutoscalingMetricsCollection_basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAutoscalingMetricsCollectionDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSAutoscalingMetricsCollectionConfig_allMetricsCollected, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAutoscalingMetricsCollectionExists("aws_autoscaling_metrics_collection.test"), + resource.TestCheckResourceAttr( + "aws_autoscaling_metrics_collection.test", "metrics.#", "7"), + ), + }, + }, + }) +} + +func TestAccAWSAutoscalingMetricsCollection_update(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAutoscalingMetricsCollectionDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSAutoscalingMetricsCollectionConfig_allMetricsCollected, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAutoscalingMetricsCollectionExists("aws_autoscaling_metrics_collection.test"), + resource.TestCheckResourceAttr( + "aws_autoscaling_metrics_collection.test", "metrics.#", "7"), + ), + }, + + resource.TestStep{ + Config: testAccAWSAutoscalingMetricsCollectionConfig_updatingMetricsCollected, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAutoscalingMetricsCollectionExists("aws_autoscaling_metrics_collection.test"), + resource.TestCheckResourceAttr( + "aws_autoscaling_metrics_collection.test", "metrics.#", "5"), + ), + }, + }, + }) +} +func testAccCheckAWSAutoscalingMetricsCollectionExists(n string) 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 AutoScaling Group ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).autoscalingconn + + describeGroups, err := conn.DescribeAutoScalingGroups( + &autoscaling.DescribeAutoScalingGroupsInput{ + AutoScalingGroupNames: []*string{aws.String(rs.Primary.ID)}, + }) + + if err != nil { + return err + } + + if len(describeGroups.AutoScalingGroups) != 1 || + *describeGroups.AutoScalingGroups[0].AutoScalingGroupName != rs.Primary.ID { + return fmt.Errorf("AutoScaling Group not found") + } + + if describeGroups.AutoScalingGroups[0].EnabledMetrics == nil { + return fmt.Errorf("AutoScaling Groups Metrics Collection not found") + } + + return nil + } +} + +func testAccCheckAWSAutoscalingMetricsCollectionDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).autoscalingconn + + for _, rs := range s.RootModule().Resources { + // Try to find the Group + describeGroups, err := conn.DescribeAutoScalingGroups( + &autoscaling.DescribeAutoScalingGroupsInput{ + AutoScalingGroupNames: []*string{aws.String(rs.Primary.ID)}, + }) + + if err == nil { + if len(describeGroups.AutoScalingGroups) != 0 && + *describeGroups.AutoScalingGroups[0].AutoScalingGroupName == rs.Primary.ID { + return fmt.Errorf("AutoScalingGroup still exists") + } + } + + // Verify the error + ec2err, ok := err.(awserr.Error) + if !ok { + return err + } + if ec2err.Code() != "InvalidGroup.NotFound" { + return err + } + } + + return nil +} + +const testAccAWSAutoscalingMetricsCollectionConfig_allMetricsCollected = ` +resource "aws_launch_configuration" "foobar" { + image_id = "ami-21f78e11" + instance_type = "t1.micro" +} + +resource "aws_autoscaling_group" "bar" { + availability_zones = ["us-west-2a"] + name = "foobar3-terraform-test" + max_size = 1 + min_size = 0 + health_check_grace_period = 300 + health_check_type = "EC2" + desired_capacity = 0 + force_delete = true + termination_policies = ["OldestInstance","ClosestToNextInstanceHour"] + + launch_configuration = "${aws_launch_configuration.foobar.name}" +} + +resource "aws_autoscaling_metrics_collection" "test" { + autoscaling_group_name = "${aws_autoscaling_group.bar.name}" + granularity = "1Minute" + metrics = ["GroupTotalInstances", + "GroupPendingInstances", + "GroupTerminatingInstances", + "GroupDesiredCapacity", + "GroupInServiceInstances", + "GroupMinSize", + "GroupMaxSize" + ] +} +` + +const testAccAWSAutoscalingMetricsCollectionConfig_updatingMetricsCollected = ` +resource "aws_launch_configuration" "foobar" { + image_id = "ami-21f78e11" + instance_type = "t1.micro" +} + +resource "aws_autoscaling_group" "bar" { + availability_zones = ["us-west-2a"] + name = "foobar3-terraform-test" + max_size = 1 + min_size = 0 + health_check_grace_period = 300 + health_check_type = "EC2" + desired_capacity = 0 + force_delete = true + termination_policies = ["OldestInstance","ClosestToNextInstanceHour"] + + launch_configuration = "${aws_launch_configuration.foobar.name}" +} + +resource "aws_autoscaling_metrics_collection" "test" { + autoscaling_group_name = "${aws_autoscaling_group.bar.name}" + granularity = "1Minute" + metrics = ["GroupTotalInstances", + "GroupPendingInstances", + "GroupTerminatingInstances", + "GroupDesiredCapacity", + "GroupMaxSize" + ] +} +` diff --git a/builtin/providers/aws/structure.go b/builtin/providers/aws/structure.go index 5bc684433bf3..a7a8da5ccd44 100644 --- a/builtin/providers/aws/structure.go +++ b/builtin/providers/aws/structure.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/cloudformation" "github.com/aws/aws-sdk-go/service/directoryservice" "github.com/aws/aws-sdk-go/service/ec2" @@ -746,3 +747,13 @@ func flattenCloudFormationOutputs(cfOutputs []*cloudformation.Output) map[string } return outputs } + +func flattenAsgEnabledMetrics(list []*autoscaling.EnabledMetric) []string { + strs := make([]string, 0, len(list)) + for _, r := range list { + if r.Metric != nil { + strs = append(strs, *r.Metric) + } + } + return strs +} diff --git a/builtin/providers/aws/structure_test.go b/builtin/providers/aws/structure_test.go index 998a25747c29..898d93ce7083 100644 --- a/builtin/providers/aws/structure_test.go +++ b/builtin/providers/aws/structure_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/elasticache" "github.com/aws/aws-sdk-go/service/elb" @@ -700,3 +701,24 @@ func TestFlattenResourceRecords(t *testing.T) { t.Fatal("expected result to have value, but got nil") } } + +func TestFlattenAsgEnabledMetrics(t *testing.T) { + expanded := []*autoscaling.EnabledMetric{ + &autoscaling.EnabledMetric{Granularity: aws.String("1Minute"), Metric: aws.String("GroupTotalInstances")}, + &autoscaling.EnabledMetric{Granularity: aws.String("1Minute"), Metric: aws.String("GroupMaxSize")}, + } + + result := flattenAsgEnabledMetrics(expanded) + + if len(result) != 2 { + t.Fatalf("expected result had %d elements, but got %d", 2, len(result)) + } + + if result[0] != "GroupTotalInstances" { + t.Fatalf("expected id to be GroupTotalInstances, but was %s", result[0]) + } + + if result[1] != "GroupMaxSize" { + t.Fatalf("expected id to be GroupMaxSize, but was %s", result[1]) + } +} diff --git a/website/source/docs/providers/aws/r/autoscaling_metrics_collection.html.markdown b/website/source/docs/providers/aws/r/autoscaling_metrics_collection.html.markdown new file mode 100644 index 000000000000..607d87c8e5c1 --- /dev/null +++ b/website/source/docs/providers/aws/r/autoscaling_metrics_collection.html.markdown @@ -0,0 +1,57 @@ +--- +layout: "aws" +page_title: "AWS: aws_autoscaling_metrics_collection" +sidebar_current: "docs-aws-resource-autoscaling-metrics-collection" +description: |- + Enables / Disables Autoscaling Group Metrics Collection. +--- + +# aws\_autoscaling\_metrics\_collection + +Enables / Disables Autoscaling Group Metrics Collection. + +~> **NOTE:** You can only enable metrics collection for an Autoscaling Group if `enable_monitoring` +in it's underlying launch configuration for the group is set to `True`. + +## Example Usage + +``` +resource "aws_launch_configuration" "foobar" { + name = "web_config" + image_id = "ami-408c7f28" + instance_type = "t1.micro" + enable_monitoring = true +} + +resource "aws_autoscaling_group" "foobar" { + availability_zones = ["us-west-2a"] + name = "terraform-test-foobar5" + health_check_type = "EC2" + termination_policies = ["OldestInstance"] + launch_configuration = "${aws_launch_configuration.foobar.name}" + tag { + key = "Foo" + value = "foo-bar" + propagate_at_launch = true + } +} + +resource "aws_autoscaling_metrics_collection" "test" { + autoscaling_group_name = "${aws_autoscaling_group.bar.name}" + granularity = "1Minute" + metrics = ["GroupTotalInstances", + "GroupPendingInstances", + "GroupTerminatingInstances", + "GroupDesiredCapacity", + "GroupMaxSize" + ] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `autoscaling_group_name` - (Required) The name of the Auto Scaling group to which you want to enable / disable metrics collection +* `granularity` - (Required) The granularity to associate with the metrics to collect. The only valid value is `1Minute`. +* `metrics` - (Required) A list of metrics to collect. The allowed values are `GroupMinSize`, `GroupMaxSize`, `GroupDesiredCapacity`, `GroupInServiceInstances`, `GroupPendingInstances`, `GroupStandbyInstances`, `GroupTerminatingInstances`, `GroupTotalInstances`. \ No newline at end of file diff --git a/website/source/layouts/aws.erb b/website/source/layouts/aws.erb index 9958628e3708..3b5d4170d433 100644 --- a/website/source/layouts/aws.erb +++ b/website/source/layouts/aws.erb @@ -120,6 +120,10 @@ aws_autoscaling_lifecycle_hook + > + aws_autoscaling_metrics_collection + + > aws_autoscaling_notification