diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index 0d56bcc48..f577b9ac7 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -42,12 +42,13 @@ func Provider() *schema.Provider { }, ResourcesMap: map[string]*schema.Resource{ - "aws_eip": resourceAwsEip(), - "aws_elb": resourceAwsElb(), - "aws_instance": resourceAwsInstance(), - "aws_security_group": resourceAwsSecurityGroup(), - "aws_db_subnet_group": resourceAwsDbSubnetGroup(), - "aws_vpc": resourceAwsVpc(), + "aws_autoscaling_group": resourceAwsAutoscalingGroup(), + "aws_eip": resourceAwsEip(), + "aws_elb": resourceAwsElb(), + "aws_instance": resourceAwsInstance(), + "aws_security_group": resourceAwsSecurityGroup(), + "aws_db_subnet_group": resourceAwsDbSubnetGroup(), + "aws_vpc": resourceAwsVpc(), }, } } diff --git a/builtin/providers/aws/resource_aws_autoscaling_group.go b/builtin/providers/aws/resource_aws_autoscaling_group.go index 3b425e980..545160c97 100644 --- a/builtin/providers/aws/resource_aws_autoscaling_group.go +++ b/builtin/providers/aws/resource_aws_autoscaling_group.go @@ -3,297 +3,264 @@ package aws import ( "fmt" "log" - "strconv" - "github.com/hashicorp/terraform/flatmap" - "github.com/hashicorp/terraform/helper/config" - "github.com/hashicorp/terraform/helper/diff" - "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/schema" "github.com/mitchellh/goamz/autoscaling" ) -func resource_aws_autoscaling_group_create( - s *terraform.InstanceState, - d *terraform.InstanceDiff, - meta interface{}) (*terraform.InstanceState, error) { +func resourceAwsAutoscalingGroup() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAutoscalingGroupCreate, + Read: resourceAwsAutoscalingGroupRead, + Update: resourceAwsAutoscalingGroupUpdate, + Delete: resourceAwsAutoscalingGroupDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "launch_configuration": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "desired_capacity": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "min_size": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + + "max_size": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + + "default_cooldown": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "force_delete": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "health_check_grace_period": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "health_check_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + + "availability_zones": &schema.Schema{ + Type: schema.TypeSet, + Required: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: func(v interface{}) int { + return hashcode.String(v.(string)) + }, + }, + + "load_balancers": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: func(v interface{}) int { + return hashcode.String(v.(string)) + }, + }, + + "vpc_zone_identifier": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Computed: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: func(v interface{}) int { + return hashcode.String(v.(string)) + }, + }, + }, + } +} + +func resourceAwsAutoscalingGroupCreate(d *schema.ResourceData, meta interface{}) error { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn - // Merge the diff into the state so that we have all the attributes - // properly. - rs := s.MergeDiff(d) + var autoScalingGroupOpts autoscaling.CreateAutoScalingGroup + autoScalingGroupOpts.Name = d.Get("name").(string) + autoScalingGroupOpts.HealthCheckType = d.Get("health_check_type").(string) + autoScalingGroupOpts.LaunchConfigurationName = d.Get("launch_configuration").(string) + autoScalingGroupOpts.MinSize = d.Get("min_size").(int) + autoScalingGroupOpts.MaxSize = d.Get("max_size").(int) + autoScalingGroupOpts.SetMinSize = true + autoScalingGroupOpts.SetMaxSize = true + autoScalingGroupOpts.AvailZone = expandStringList( + d.Get("availability_zones").(*schema.Set).List()) - var err error - autoScalingGroupOpts := autoscaling.CreateAutoScalingGroup{} - - if rs.Attributes["min_size"] != "" { - autoScalingGroupOpts.MinSize, err = strconv.Atoi(rs.Attributes["min_size"]) - autoScalingGroupOpts.SetMinSize = true - } - - if rs.Attributes["max_size"] != "" { - autoScalingGroupOpts.MaxSize, err = strconv.Atoi(rs.Attributes["max_size"]) - autoScalingGroupOpts.SetMaxSize = true - } - - if rs.Attributes["default_cooldown"] != "" { - autoScalingGroupOpts.DefaultCooldown, err = strconv.Atoi(rs.Attributes["default_cooldown"]) + if v, ok := d.GetOk("default_cooldown"); ok { + autoScalingGroupOpts.DefaultCooldown = v.(int) autoScalingGroupOpts.SetDefaultCooldown = true } - if rs.Attributes["desired_capacity"] != "" { - autoScalingGroupOpts.DesiredCapacity, err = strconv.Atoi(rs.Attributes["desired_capacity"]) + if v, ok := d.GetOk("desired_capacity"); ok { + autoScalingGroupOpts.DesiredCapacity = v.(int) autoScalingGroupOpts.SetDesiredCapacity = true } - if rs.Attributes["health_check_grace_period"] != "" { - autoScalingGroupOpts.HealthCheckGracePeriod, err = strconv.Atoi(rs.Attributes["health_check_grace_period"]) + if v, ok := d.GetOk("health_check_grace_period"); ok { + autoScalingGroupOpts.HealthCheckGracePeriod = v.(int) autoScalingGroupOpts.SetHealthCheckGracePeriod = true } - if err != nil { - return nil, fmt.Errorf("Error parsing configuration: %s", err) + if v, ok := d.GetOk("load_balancers"); ok { + autoScalingGroupOpts.LoadBalancerNames = expandStringList( + v.(*schema.Set).List()) } - if _, ok := rs.Attributes["availability_zones.#"]; ok { - autoScalingGroupOpts.AvailZone = expandStringList(flatmap.Expand( - rs.Attributes, "availability_zones").([]interface{})) + if v, ok := d.GetOk("vpc_zone_identifier"); ok { + autoScalingGroupOpts.VPCZoneIdentifier = expandStringList( + v.(*schema.Set).List()) } - if _, ok := rs.Attributes["load_balancers.#"]; ok { - autoScalingGroupOpts.LoadBalancerNames = expandStringList(flatmap.Expand( - rs.Attributes, "load_balancers").([]interface{})) - } - - if _, ok := rs.Attributes["vpc_zone_identifier.#"]; ok { - autoScalingGroupOpts.VPCZoneIdentifier = expandStringList(flatmap.Expand( - rs.Attributes, "vpc_zone_identifier").([]interface{})) - } - - autoScalingGroupOpts.Name = rs.Attributes["name"] - autoScalingGroupOpts.HealthCheckType = rs.Attributes["health_check_type"] - autoScalingGroupOpts.LaunchConfigurationName = rs.Attributes["launch_configuration"] - log.Printf("[DEBUG] AutoScaling Group create configuration: %#v", autoScalingGroupOpts) - _, err = autoscalingconn.CreateAutoScalingGroup(&autoScalingGroupOpts) + _, err := autoscalingconn.CreateAutoScalingGroup(&autoScalingGroupOpts) if err != nil { - return nil, fmt.Errorf("Error creating AutoScaling Group: %s", err) + return fmt.Errorf("Error creating Autoscaling Group: %s", err) } - rs.ID = rs.Attributes["name"] + d.SetId(d.Get("name").(string)) + log.Printf("[INFO] AutoScaling Group ID: %s", d.Id()) - log.Printf("[INFO] AutoScaling Group ID: %s", rs.ID) - - g, err := resource_aws_autoscaling_group_retrieve(rs.ID, autoscalingconn) - if err != nil { - return rs, err - } - - return resource_aws_autoscaling_group_update_state(rs, g) + return resourceAwsAutoscalingGroupRead(d, meta) } -func resource_aws_autoscaling_group_update( - s *terraform.InstanceState, - d *terraform.InstanceDiff, - meta interface{}) (*terraform.InstanceState, error) { +func resourceAwsAutoscalingGroupUpdate(d *schema.ResourceData, meta interface{}) error { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn - rs := s.MergeDiff(d) opts := autoscaling.UpdateAutoScalingGroup{ - Name: rs.ID, + Name: d.Id(), } - var err error - - if _, ok := d.Attributes["min_size"]; ok { - opts.MinSize, err = strconv.Atoi(rs.Attributes["min_size"]) + if d.HasChange("min_size") { + opts.MinSize = d.Get("min_size").(int) opts.SetMinSize = true } - if _, ok := d.Attributes["max_size"]; ok { - opts.MaxSize, err = strconv.Atoi(rs.Attributes["max_size"]) + if d.HasChange("max_size") { + opts.MaxSize = d.Get("max_size").(int) opts.SetMaxSize = true } - if err != nil { - return s, fmt.Errorf("Error parsing configuration: %s", err) - } - log.Printf("[DEBUG] AutoScaling Group update configuration: %#v", opts) - - _, err = autoscalingconn.UpdateAutoScalingGroup(&opts) - + _, err := autoscalingconn.UpdateAutoScalingGroup(&opts) if err != nil { - return rs, fmt.Errorf("Error updating AutoScaling group: %s", err) + d.Partial(true) + return fmt.Errorf("Error updating Autoscaling group: %s", err) } - g, err := resource_aws_autoscaling_group_retrieve(rs.ID, autoscalingconn) - - if err != nil { - return rs, err - } - - return resource_aws_autoscaling_group_update_state(rs, g) + return resourceAwsAutoscalingGroupRead(d, meta) } -func resource_aws_autoscaling_group_destroy( - s *terraform.InstanceState, - meta interface{}) error { +func resourceAwsAutoscalingGroupDelete(d *schema.ResourceData, meta interface{}) error { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn - log.Printf("[DEBUG] AutoScaling Group destroy: %v", s.ID) - - deleteopts := autoscaling.DeleteAutoScalingGroup{Name: s.ID} + log.Printf("[DEBUG] AutoScaling Group destroy: %v", d.Id()) + deleteopts := autoscaling.DeleteAutoScalingGroup{Name: d.Id()} // You can force an autoscaling group to delete // even if it's in the process of scaling a resource. // Normally, you would set the min-size and max-size to 0,0 // and then delete the group. This bypasses that and leaves // resources potentially dangling. - if s.Attributes["force_delete"] != "" { + if d.Get("force_delete").(bool) { deleteopts.ForceDelete = true } _, err := autoscalingconn.DeleteAutoScalingGroup(&deleteopts) - if err != nil { autoscalingerr, ok := err.(*autoscaling.Error) if ok && autoscalingerr.Code == "InvalidGroup.NotFound" { return nil } + return err } return nil } -func resource_aws_autoscaling_group_refresh( - s *terraform.InstanceState, - meta interface{}) (*terraform.InstanceState, error) { +func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) error { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn - g, err := resource_aws_autoscaling_group_retrieve(s.ID, autoscalingconn) - - if err != nil { - return s, err - } - - return resource_aws_autoscaling_group_update_state(s, g) -} - -func resource_aws_autoscaling_group_diff( - s *terraform.InstanceState, - c *terraform.ResourceConfig, - meta interface{}) (*terraform.InstanceDiff, error) { - - b := &diff.ResourceBuilder{ - Attrs: map[string]diff.AttrType{ - "availability_zone": diff.AttrTypeCreate, - "default_cooldown": diff.AttrTypeCreate, - "desired_capacity": diff.AttrTypeCreate, - "force_delete": diff.AttrTypeCreate, - "health_check_grace_period": diff.AttrTypeCreate, - "health_check_type": diff.AttrTypeCreate, - "launch_configuration": diff.AttrTypeCreate, - "load_balancers": diff.AttrTypeCreate, - "name": diff.AttrTypeCreate, - "vpc_zone_identifier": diff.AttrTypeCreate, - - "max_size": diff.AttrTypeUpdate, - "min_size": diff.AttrTypeUpdate, - }, - - ComputedAttrs: []string{ - "health_check_grace_period", - "health_check_type", - "default_cooldown", - "vpc_zone_identifier", - "desired_capacity", - "force_delete", - }, - } - - return b.Diff(s, c) -} - -func resource_aws_autoscaling_group_update_state( - s *terraform.InstanceState, - g *autoscaling.AutoScalingGroup) (*terraform.InstanceState, error) { - - s.Attributes["min_size"] = strconv.Itoa(g.MinSize) - s.Attributes["max_size"] = strconv.Itoa(g.MaxSize) - s.Attributes["default_cooldown"] = strconv.Itoa(g.DefaultCooldown) - s.Attributes["name"] = g.Name - s.Attributes["desired_capacity"] = strconv.Itoa(g.DesiredCapacity) - s.Attributes["health_check_grace_period"] = strconv.Itoa(g.HealthCheckGracePeriod) - s.Attributes["health_check_type"] = g.HealthCheckType - s.Attributes["launch_configuration"] = g.LaunchConfigurationName - s.Attributes["vpc_zone_identifier"] = g.VPCZoneIdentifier - - // Flatten our group values - toFlatten := make(map[string]interface{}) - - // Special case the return of amazons load balancers names in the XML having - // a blank entry - if len(g.LoadBalancerNames) > 0 && g.LoadBalancerNames[0].LoadBalancerName != "" { - toFlatten["load_balancers"] = flattenLoadBalancers(g.LoadBalancerNames) - } - - toFlatten["availability_zones"] = flattenAvailabilityZones(g.AvailabilityZones) - - for k, v := range flatmap.Flatten(toFlatten) { - s.Attributes[k] = v - } - - return s, nil -} - -// Returns a single group by its ID -func resource_aws_autoscaling_group_retrieve(id string, autoscalingconn *autoscaling.AutoScaling) (*autoscaling.AutoScalingGroup, error) { describeOpts := autoscaling.DescribeAutoScalingGroups{ - Names: []string{id}, + Names: []string{d.Id()}, } log.Printf("[DEBUG] AutoScaling Group describe configuration: %#v", describeOpts) - describeGroups, err := autoscalingconn.DescribeAutoScalingGroups(&describeOpts) - if err != nil { - return nil, fmt.Errorf("Error retrieving AutoScaling groups: %s", err) + autoscalingerr, ok := err.(*autoscaling.Error) + if ok && autoscalingerr.Code == "InvalidGroup.NotFound" { + d.SetId("") + return nil + } + + return fmt.Errorf("Error retrieving AutoScaling groups: %s", err) } // Verify AWS returned our sg if len(describeGroups.AutoScalingGroups) != 1 || - describeGroups.AutoScalingGroups[0].Name != id { + describeGroups.AutoScalingGroups[0].Name != d.Id() { if err != nil { - return nil, fmt.Errorf("Unable to find AutoScaling group: %#v", describeGroups.AutoScalingGroups) + return fmt.Errorf("Unable to find AutoScaling group: %#v", describeGroups.AutoScalingGroups) } } g := describeGroups.AutoScalingGroups[0] - return &g, nil -} + d.Set("availability_zones", flattenAvailabilityZones(g.AvailabilityZones)) + d.Set("default_cooldown", g.DefaultCooldown) + d.Set("desired_capacity", g.DesiredCapacity) + d.Set("health_check_grace_period", g.HealthCheckGracePeriod) + d.Set("health_check_type", g.HealthCheckType) + d.Set("launch_configuration", g.LaunchConfigurationName) + d.Set("min_size", g.MinSize) + d.Set("max_size", g.MaxSize) + d.Set("name", g.Name) + d.Set("vpc_zone_identifier", g.VPCZoneIdentifier) -func resource_aws_autoscaling_group_validation() *config.Validator { - return &config.Validator{ - Required: []string{ - "name", - "max_size", - "min_size", - "availability_zones.*", - "launch_configuration", - }, - Optional: []string{ - "health_check_grace_period", - "health_check_type", - "desired_capacity", - "force_delete", - "load_balancers.*", - "vpc_zone_identifier.*", - }, + if len(g.LoadBalancerNames) > 0 && g.LoadBalancerNames[0].LoadBalancerName != "" { + d.Set("load_balancers", flattenLoadBalancers(g.LoadBalancerNames)) } + + return nil } diff --git a/builtin/providers/aws/resource_aws_autoscaling_group_test.go b/builtin/providers/aws/resource_aws_autoscaling_group_test.go index fd23ad470..3522c6add 100644 --- a/builtin/providers/aws/resource_aws_autoscaling_group_test.go +++ b/builtin/providers/aws/resource_aws_autoscaling_group_test.go @@ -9,7 +9,7 @@ import ( "github.com/mitchellh/goamz/autoscaling" ) -func TestAccAWSAutoScalingGroup(t *testing.T) { +func TestAccAWSAutoScalingGroup_basic(t *testing.T) { var group autoscaling.AutoScalingGroup resource.Test(t, resource.TestCase{ @@ -23,7 +23,7 @@ func TestAccAWSAutoScalingGroup(t *testing.T) { testAccCheckAWSAutoScalingGroupExists("aws_autoscaling_group.bar", &group), testAccCheckAWSAutoScalingGroupAttributes(&group), resource.TestCheckResourceAttr( - "aws_autoscaling_group.bar", "availability_zones.#.0", "us-west-2a"), + "aws_autoscaling_group.bar", "availability_zones.0", "us-west-2a"), resource.TestCheckResourceAttr( "aws_autoscaling_group.bar", "name", "foobar3-terraform-test"), resource.TestCheckResourceAttr( @@ -126,8 +126,8 @@ func testAccCheckAWSAutoScalingGroupAttributes(group *autoscaling.AutoScalingGro return fmt.Errorf("Bad desired_capacity: %d", group.DesiredCapacity) } - if group.LaunchConfigurationName != "" { - return fmt.Errorf("Bad desired_capacity: %d", group.DesiredCapacity) + if group.LaunchConfigurationName == "" { + return fmt.Errorf("Bad launch configuration name: %s", group.LaunchConfigurationName) } return nil diff --git a/builtin/providers/aws/resources.go b/builtin/providers/aws/resources.go index 57e93a6fa..11b809f30 100644 --- a/builtin/providers/aws/resources.go +++ b/builtin/providers/aws/resources.go @@ -12,15 +12,6 @@ var resourceMap *resource.Map func init() { resourceMap = &resource.Map{ Mapping: map[string]resource.Resource{ - "aws_autoscaling_group": resource.Resource{ - ConfigValidator: resource_aws_autoscaling_group_validation(), - Create: resource_aws_autoscaling_group_create, - Destroy: resource_aws_autoscaling_group_destroy, - Diff: resource_aws_autoscaling_group_diff, - Refresh: resource_aws_autoscaling_group_refresh, - Update: resource_aws_autoscaling_group_update, - }, - "aws_db_instance": resource.Resource{ ConfigValidator: resource_aws_db_instance_validation(), Create: resource_aws_db_instance_create,