From 62a311a34160e7c3090f947dfe93e116be12ff06 Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Wed, 9 Jul 2014 19:00:11 -0400 Subject: [PATCH] providers/aws: add autoscalinggroup --- .../aws/resource_aws_autoscaling_group.go | 217 ++++++++++++++++++ builtin/providers/aws/resource_provider.go | 8 +- builtin/providers/aws/resources.go | 7 + builtin/providers/aws/structure.go | 19 ++ 4 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 builtin/providers/aws/resource_aws_autoscaling_group.go diff --git a/builtin/providers/aws/resource_aws_autoscaling_group.go b/builtin/providers/aws/resource_aws_autoscaling_group.go new file mode 100644 index 0000000000..52708df085 --- /dev/null +++ b/builtin/providers/aws/resource_aws_autoscaling_group.go @@ -0,0 +1,217 @@ +package aws + +import ( + "fmt" + "log" + "strconv" + + "github.com/hashicorp/terraform/flatmap" + "github.com/hashicorp/terraform/helper/diff" + "github.com/hashicorp/terraform/terraform" + "github.com/mitchellh/goamz/autoscaling" +) + +func resource_aws_autoscaling_group_create( + s *terraform.ResourceState, + d *terraform.ResourceDiff, + meta interface{}) (*terraform.ResourceState, 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) + log.Println(rs.Attributes["availability_zones"]) + + var err error + autoScalingGroupOpts := autoscaling.CreateAutoScalingGroup{} + + if rs.Attributes["min_size"] != "" { + autoScalingGroupOpts.MinSize, err = strconv.Atoi(rs.Attributes["min_size"]) + } + + if rs.Attributes["max_size"] != "" { + autoScalingGroupOpts.MaxSize, err = strconv.Atoi(rs.Attributes["max_size"]) + } + + if rs.Attributes["default_cooldown"] != "" { + autoScalingGroupOpts.DefaultCooldown, err = strconv.Atoi(rs.Attributes["default_cooldown"]) + } + + if rs.Attributes["desired_capicity"] != "" { + autoScalingGroupOpts.DesiredCapacity, err = strconv.Atoi(rs.Attributes["desired_capicity"]) + } + + if rs.Attributes["healthcheck_grace_period"] != "" { + autoScalingGroupOpts.HealthCheckGracePeriod, err = strconv.Atoi(rs.Attributes["healthcheck_grace_period"]) + } + + if err != nil { + return nil, fmt.Errorf("Error parsing configuration: %s", err) + } + + if rs.Attributes["availability_zones"] != "" { + autoScalingGroupOpts.AvailZone = expandStringList(flatmap.Expand( + rs.Attributes, "availability_zones").([]interface{})) + } + + if rs.Attributes["load_balancers"] != "" { + autoScalingGroupOpts.LoadBalancerNames = expandStringList(flatmap.Expand( + rs.Attributes, "load_balancers").([]interface{})) + } + + if rs.Attributes["vpc_identifier"] != "" { + autoScalingGroupOpts.VPCZoneIdentifier = expandStringList(flatmap.Expand( + rs.Attributes, "vpc_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) + if err != nil { + return nil, fmt.Errorf("Error creating autoscaling Group: %s", err) + } + + rs.ID = rs.Attributes["name"] + + 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) +} + +func resource_aws_autoscaling_group_update( + s *terraform.ResourceState, + d *terraform.ResourceDiff, + meta interface{}) (*terraform.ResourceState, error) { + + rs := s.MergeDiff(d) + log.Printf("ResourceDiff: %s", d) + log.Printf("ResourceState: %s", s) + log.Printf("Merged: %s", rs) + + return nil, fmt.Errorf("Did not update") +} + +func resource_aws_autoscaling_group_destroy( + s *terraform.ResourceState, + meta interface{}) error { + // p := meta.(*ResourceProvider) + // autoscalingconn := p.autoscalingconn + + log.Printf("[DEBUG] autoscaling Group destroy: %v", s.ID) + + // err := nil + + // _, err := autoscalingconn.DeleteAutoScalingGroup(autoscaling.autoscalingGroup{Id: s.ID}) + + // if err != nil { + // autoscalingerr, ok := err.(*autoscaling.Error) + // if ok && autoscalingerr.Code == "InvalidGroup.NotFound" { + // return nil + // } + // } + + return nil +} + +func resource_aws_autoscaling_group_refresh( + s *terraform.ResourceState, + meta interface{}) (*terraform.ResourceState, 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.ResourceState, + c *terraform.ResourceConfig, + meta interface{}) (*terraform.ResourceDiff, error) { + + b := &diff.ResourceBuilder{ + Attrs: map[string]diff.AttrType{ + "min_size": diff.AttrTypeCreate, + "max_size": diff.AttrTypeCreate, + "default_cooldown": diff.AttrTypeCreate, + "name": diff.AttrTypeCreate, + "desired_capicity": diff.AttrTypeCreate, + "health_check_grace_period": diff.AttrTypeCreate, + "health_check_type": diff.AttrTypeCreate, + "launch_configuration": diff.AttrTypeCreate, + "vpc_zone_identifier": diff.AttrTypeCreate, + "load_balancers": diff.AttrTypeCreate, + "availability_zones": diff.AttrTypeCreate, + }, + + ComputedAttrs: []string{}, + } + + return b.Diff(s, c) +} + +func resource_aws_autoscaling_group_update_state( + s *terraform.ResourceState, + g *autoscaling.AutoScalingGroup) (*terraform.ResourceState, 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 sg values + toFlatten := make(map[string]interface{}) + 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 it's ID +func resource_aws_autoscaling_group_retrieve(id string, autoscalingconn *autoscaling.AutoScaling) (*autoscaling.AutoScalingGroup, error) { + describeOpts := autoscaling.DescribeAutoScalingGroups{ + Names: []string{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) + } + + // Verify AWS returned our sg + if len(describeGroups.AutoScalingGroups) != 1 || + describeGroups.AutoScalingGroups[0].Name != id { + if err != nil { + return nil, fmt.Errorf("Unable to find autoscaling group: %#v", describeGroups.AutoScalingGroups) + } + } + + g := describeGroups.AutoScalingGroups[0] + + return &g, nil +} diff --git a/builtin/providers/aws/resource_provider.go b/builtin/providers/aws/resource_provider.go index e0243400b0..f5ada7080c 100644 --- a/builtin/providers/aws/resource_provider.go +++ b/builtin/providers/aws/resource_provider.go @@ -6,6 +6,7 @@ import ( "github.com/hashicorp/terraform/helper/config" "github.com/hashicorp/terraform/helper/multierror" "github.com/hashicorp/terraform/terraform" + "github.com/mitchellh/goamz/autoscaling" "github.com/mitchellh/goamz/ec2" "github.com/mitchellh/goamz/elb" ) @@ -13,8 +14,9 @@ import ( type ResourceProvider struct { Config Config - ec2conn *ec2.EC2 - elbconn *elb.ELB + ec2conn *ec2.EC2 + elbconn *elb.ELB + autoscalingconn *autoscaling.AutoScaling } func (p *ResourceProvider) Validate(c *terraform.ResourceConfig) ([]string, []error) { @@ -51,6 +53,8 @@ func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { p.ec2conn = ec2.New(auth, region) log.Println("Initializing ELB connection") p.elbconn = elb.New(auth, region) + log.Println("Initializing AutoScaling connection") + p.autoscalingconn = autoscaling.New(auth, region) } if len(errs) > 0 { diff --git a/builtin/providers/aws/resources.go b/builtin/providers/aws/resources.go index 50f726b901..d7ed1474cf 100644 --- a/builtin/providers/aws/resources.go +++ b/builtin/providers/aws/resources.go @@ -12,6 +12,13 @@ var resourceMap *resource.Map func init() { resourceMap = &resource.Map{ Mapping: map[string]resource.Resource{ + "aws_autoscaling_group": resource.Resource{ + Create: resource_aws_autoscaling_group_create, + Destroy: resource_aws_autoscaling_group_destroy, + Diff: resource_aws_autoscaling_group_diff, + Refresh: resource_aws_autoscaling_group_refresh, + }, + "aws_elb": resource.Resource{ Create: resource_aws_elb_create, Update: resource_aws_elb_update, diff --git a/builtin/providers/aws/structure.go b/builtin/providers/aws/structure.go index 1eede5d79b..a3130bdddb 100644 --- a/builtin/providers/aws/structure.go +++ b/builtin/providers/aws/structure.go @@ -1,6 +1,7 @@ package aws import ( + "github.com/mitchellh/goamz/autoscaling" "github.com/mitchellh/goamz/ec2" "github.com/mitchellh/goamz/elb" ) @@ -92,6 +93,24 @@ func flattenSecurityGroups(list []ec2.UserSecurityGroup) []string { return result } +// Flattens an array of AvailabilityZones into a []string +func flattenAvailabilityZones(list []autoscaling.AvailabilityZone) []string { + result := make([]string, 0, len(list)) + for _, g := range list { + result = append(result, g.AvailabilityZone) + } + return result +} + +// Flattens an array of LoadBalancerName into a []string +func flattenLoadBalancers(list []autoscaling.LoadBalancerName) []string { + result := make([]string, 0, len(list)) + for _, g := range list { + result = append(result, g.LoadBalancerName) + } + return result +} + // Takes the result of flatmap.Expand for an array of strings // and returns a []string func expandStringList(configured []interface{}) []string {