github.com/i0n/terraform@v0.4.3-0.20150506151324-010a39a58ec1/builtin/providers/aws/resource_aws_autoscaling_group.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/hashicorp/terraform/helper/resource"
    10  	"github.com/hashicorp/terraform/helper/schema"
    11  
    12  	"github.com/awslabs/aws-sdk-go/aws"
    13  	"github.com/awslabs/aws-sdk-go/service/autoscaling"
    14  )
    15  
    16  func resourceAwsAutoscalingGroup() *schema.Resource {
    17  	return &schema.Resource{
    18  		Create: resourceAwsAutoscalingGroupCreate,
    19  		Read:   resourceAwsAutoscalingGroupRead,
    20  		Update: resourceAwsAutoscalingGroupUpdate,
    21  		Delete: resourceAwsAutoscalingGroupDelete,
    22  
    23  		Schema: map[string]*schema.Schema{
    24  			"name": &schema.Schema{
    25  				Type:     schema.TypeString,
    26  				Required: true,
    27  				ForceNew: true,
    28  			},
    29  
    30  			"launch_configuration": &schema.Schema{
    31  				Type:     schema.TypeString,
    32  				Required: true,
    33  			},
    34  
    35  			"desired_capacity": &schema.Schema{
    36  				Type:     schema.TypeInt,
    37  				Optional: true,
    38  				Computed: true,
    39  			},
    40  
    41  			"min_size": &schema.Schema{
    42  				Type:     schema.TypeInt,
    43  				Required: true,
    44  			},
    45  
    46  			"max_size": &schema.Schema{
    47  				Type:     schema.TypeInt,
    48  				Required: true,
    49  			},
    50  
    51  			"default_cooldown": &schema.Schema{
    52  				Type:     schema.TypeInt,
    53  				Optional: true,
    54  				Computed: true,
    55  				ForceNew: true,
    56  			},
    57  
    58  			"force_delete": &schema.Schema{
    59  				Type:     schema.TypeBool,
    60  				Optional: true,
    61  				Computed: true,
    62  				ForceNew: true,
    63  			},
    64  
    65  			"health_check_grace_period": &schema.Schema{
    66  				Type:     schema.TypeInt,
    67  				Optional: true,
    68  				Computed: true,
    69  			},
    70  
    71  			"health_check_type": &schema.Schema{
    72  				Type:     schema.TypeString,
    73  				Optional: true,
    74  				Computed: true,
    75  				ForceNew: true,
    76  			},
    77  
    78  			"availability_zones": &schema.Schema{
    79  				Type:     schema.TypeSet,
    80  				Required: true,
    81  				ForceNew: true,
    82  				Elem:     &schema.Schema{Type: schema.TypeString},
    83  				Set:      schema.HashString,
    84  			},
    85  
    86  			"load_balancers": &schema.Schema{
    87  				Type:     schema.TypeSet,
    88  				Optional: true,
    89  				ForceNew: true,
    90  				Elem:     &schema.Schema{Type: schema.TypeString},
    91  				Set:      schema.HashString,
    92  			},
    93  
    94  			"vpc_zone_identifier": &schema.Schema{
    95  				Type:     schema.TypeSet,
    96  				Optional: true,
    97  				Computed: true,
    98  				ForceNew: true,
    99  				Elem:     &schema.Schema{Type: schema.TypeString},
   100  				Set:      schema.HashString,
   101  			},
   102  
   103  			"termination_policies": &schema.Schema{
   104  				Type:     schema.TypeSet,
   105  				Optional: true,
   106  				Computed: true,
   107  				ForceNew: true,
   108  				Elem:     &schema.Schema{Type: schema.TypeString},
   109  				Set:      schema.HashString,
   110  			},
   111  
   112  			"tag": autoscalingTagsSchema(),
   113  		},
   114  	}
   115  }
   116  
   117  func resourceAwsAutoscalingGroupCreate(d *schema.ResourceData, meta interface{}) error {
   118  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   119  
   120  	var autoScalingGroupOpts autoscaling.CreateAutoScalingGroupInput
   121  	autoScalingGroupOpts.AutoScalingGroupName = aws.String(d.Get("name").(string))
   122  	autoScalingGroupOpts.LaunchConfigurationName = aws.String(d.Get("launch_configuration").(string))
   123  	autoScalingGroupOpts.MinSize = aws.Long(int64(d.Get("min_size").(int)))
   124  	autoScalingGroupOpts.MaxSize = aws.Long(int64(d.Get("max_size").(int)))
   125  	autoScalingGroupOpts.AvailabilityZones = expandStringList(
   126  		d.Get("availability_zones").(*schema.Set).List())
   127  
   128  	if v, ok := d.GetOk("tag"); ok {
   129  		autoScalingGroupOpts.Tags = autoscalingTagsFromMap(
   130  			setToMapByKey(v.(*schema.Set), "key"), d.Get("name").(string))
   131  	}
   132  
   133  	if v, ok := d.GetOk("default_cooldown"); ok {
   134  		autoScalingGroupOpts.DefaultCooldown = aws.Long(int64(v.(int)))
   135  	}
   136  
   137  	if v, ok := d.GetOk("health_check_type"); ok && v.(string) != "" {
   138  		autoScalingGroupOpts.HealthCheckType = aws.String(v.(string))
   139  	}
   140  
   141  	if v, ok := d.GetOk("desired_capacity"); ok {
   142  		autoScalingGroupOpts.DesiredCapacity = aws.Long(int64(v.(int)))
   143  	}
   144  
   145  	if v, ok := d.GetOk("health_check_grace_period"); ok {
   146  		autoScalingGroupOpts.HealthCheckGracePeriod = aws.Long(int64(v.(int)))
   147  	}
   148  
   149  	if v, ok := d.GetOk("load_balancers"); ok && v.(*schema.Set).Len() > 0 {
   150  		autoScalingGroupOpts.LoadBalancerNames = expandStringList(
   151  			v.(*schema.Set).List())
   152  	}
   153  
   154  	if v, ok := d.GetOk("vpc_zone_identifier"); ok && v.(*schema.Set).Len() > 0 {
   155  		exp := expandStringList(v.(*schema.Set).List())
   156  		strs := make([]string, len(exp))
   157  		for _, s := range exp {
   158  			strs = append(strs, *s)
   159  		}
   160  		autoScalingGroupOpts.VPCZoneIdentifier = aws.String(strings.Join(strs, ","))
   161  	}
   162  
   163  	if v, ok := d.GetOk("termination_policies"); ok && v.(*schema.Set).Len() > 0 {
   164  		autoScalingGroupOpts.TerminationPolicies = expandStringList(
   165  			v.(*schema.Set).List())
   166  	}
   167  
   168  	log.Printf("[DEBUG] AutoScaling Group create configuration: %#v", autoScalingGroupOpts)
   169  	_, err := autoscalingconn.CreateAutoScalingGroup(&autoScalingGroupOpts)
   170  	if err != nil {
   171  		return fmt.Errorf("Error creating Autoscaling Group: %s", err)
   172  	}
   173  
   174  	d.SetId(d.Get("name").(string))
   175  	log.Printf("[INFO] AutoScaling Group ID: %s", d.Id())
   176  
   177  	return resourceAwsAutoscalingGroupRead(d, meta)
   178  }
   179  
   180  func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) error {
   181  	g, err := getAwsAutoscalingGroup(d, meta)
   182  	if err != nil {
   183  		return err
   184  	}
   185  	if g == nil {
   186  		return nil
   187  	}
   188  
   189  	d.Set("availability_zones", g.AvailabilityZones)
   190  	d.Set("default_cooldown", g.DefaultCooldown)
   191  	d.Set("desired_capacity", g.DesiredCapacity)
   192  	d.Set("health_check_grace_period", g.HealthCheckGracePeriod)
   193  	d.Set("health_check_type", g.HealthCheckType)
   194  	d.Set("launch_configuration", g.LaunchConfigurationName)
   195  	d.Set("load_balancers", g.LoadBalancerNames)
   196  	d.Set("min_size", g.MinSize)
   197  	d.Set("max_size", g.MaxSize)
   198  	d.Set("name", g.AutoScalingGroupName)
   199  	d.Set("tag", g.Tags)
   200  	d.Set("vpc_zone_identifier", strings.Split(*g.VPCZoneIdentifier, ","))
   201  	d.Set("termination_policies", g.TerminationPolicies)
   202  
   203  	return nil
   204  }
   205  
   206  func resourceAwsAutoscalingGroupUpdate(d *schema.ResourceData, meta interface{}) error {
   207  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   208  
   209  	opts := autoscaling.UpdateAutoScalingGroupInput{
   210  		AutoScalingGroupName: aws.String(d.Id()),
   211  	}
   212  
   213  	if d.HasChange("desired_capacity") {
   214  		opts.DesiredCapacity = aws.Long(int64(d.Get("desired_capacity").(int)))
   215  	}
   216  
   217  	if d.HasChange("launch_configuration") {
   218  		opts.LaunchConfigurationName = aws.String(d.Get("launch_configuration").(string))
   219  	}
   220  
   221  	if d.HasChange("min_size") {
   222  		opts.MinSize = aws.Long(int64(d.Get("min_size").(int)))
   223  	}
   224  
   225  	if d.HasChange("max_size") {
   226  		opts.MaxSize = aws.Long(int64(d.Get("max_size").(int)))
   227  	}
   228  	
   229  	if d.HasChange("health_check_grace_period") {
   230                  opts.HealthCheckGracePeriod = aws.Long(int64(d.Get("health_check_grace_period").(int)))
   231          }
   232  
   233  	if err := setAutoscalingTags(autoscalingconn, d); err != nil {
   234  		return err
   235  	} else {
   236  		d.SetPartial("tag")
   237  	}
   238  
   239  	log.Printf("[DEBUG] AutoScaling Group update configuration: %#v", opts)
   240  	_, err := autoscalingconn.UpdateAutoScalingGroup(&opts)
   241  	if err != nil {
   242  		d.Partial(true)
   243  		return fmt.Errorf("Error updating Autoscaling group: %s", err)
   244  	}
   245  
   246  	return resourceAwsAutoscalingGroupRead(d, meta)
   247  }
   248  
   249  func resourceAwsAutoscalingGroupDelete(d *schema.ResourceData, meta interface{}) error {
   250  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   251  
   252  	// Read the autoscaling group first. If it doesn't exist, we're done.
   253  	// We need the group in order to check if there are instances attached.
   254  	// If so, we need to remove those first.
   255  	g, err := getAwsAutoscalingGroup(d, meta)
   256  	if err != nil {
   257  		return err
   258  	}
   259  	if g == nil {
   260  		return nil
   261  	}
   262  	if len(g.Instances) > 0 || *g.DesiredCapacity > 0 {
   263  		if err := resourceAwsAutoscalingGroupDrain(d, meta); err != nil {
   264  			return err
   265  		}
   266  	}
   267  
   268  	log.Printf("[DEBUG] AutoScaling Group destroy: %v", d.Id())
   269  	deleteopts := autoscaling.DeleteAutoScalingGroupInput{AutoScalingGroupName: aws.String(d.Id())}
   270  
   271  	// You can force an autoscaling group to delete
   272  	// even if it's in the process of scaling a resource.
   273  	// Normally, you would set the min-size and max-size to 0,0
   274  	// and then delete the group. This bypasses that and leaves
   275  	// resources potentially dangling.
   276  	if d.Get("force_delete").(bool) {
   277  		deleteopts.ForceDelete = aws.Boolean(true)
   278  	}
   279  
   280  	if _, err := autoscalingconn.DeleteAutoScalingGroup(&deleteopts); err != nil {
   281  		autoscalingerr, ok := err.(aws.APIError)
   282  		if ok && autoscalingerr.Code == "InvalidGroup.NotFound" {
   283  			return nil
   284  		}
   285  		return err
   286  	}
   287  
   288  	return resource.Retry(5*time.Minute, func() error {
   289  		if g, _ = getAwsAutoscalingGroup(d, meta); g != nil {
   290  			return fmt.Errorf("Auto Scaling Group still exists")
   291  		}
   292  		return nil
   293  	})
   294  }
   295  
   296  func getAwsAutoscalingGroup(
   297  	d *schema.ResourceData,
   298  	meta interface{}) (*autoscaling.AutoScalingGroup, error) {
   299  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   300  
   301  	describeOpts := autoscaling.DescribeAutoScalingGroupsInput{
   302  		AutoScalingGroupNames: []*string{aws.String(d.Id())},
   303  	}
   304  
   305  	log.Printf("[DEBUG] AutoScaling Group describe configuration: %#v", describeOpts)
   306  	describeGroups, err := autoscalingconn.DescribeAutoScalingGroups(&describeOpts)
   307  	if err != nil {
   308  		autoscalingerr, ok := err.(aws.APIError)
   309  		if ok && autoscalingerr.Code == "InvalidGroup.NotFound" {
   310  			d.SetId("")
   311  			return nil, nil
   312  		}
   313  
   314  		return nil, fmt.Errorf("Error retrieving AutoScaling groups: %s", err)
   315  	}
   316  
   317  	// Search for the autoscaling group
   318  	for idx, asc := range describeGroups.AutoScalingGroups {
   319  		if *asc.AutoScalingGroupName == d.Id() {
   320  			return describeGroups.AutoScalingGroups[idx], nil
   321  		}
   322  	}
   323  
   324  	// ASG not found
   325  	d.SetId("")
   326  	return nil, nil
   327  }
   328  
   329  func resourceAwsAutoscalingGroupDrain(d *schema.ResourceData, meta interface{}) error {
   330  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   331  
   332  	// First, set the capacity to zero so the group will drain
   333  	log.Printf("[DEBUG] Reducing autoscaling group capacity to zero")
   334  	opts := autoscaling.UpdateAutoScalingGroupInput{
   335  		AutoScalingGroupName: aws.String(d.Id()),
   336  		DesiredCapacity:      aws.Long(0),
   337  		MinSize:              aws.Long(0),
   338  		MaxSize:              aws.Long(0),
   339  	}
   340  	if _, err := autoscalingconn.UpdateAutoScalingGroup(&opts); err != nil {
   341  		return fmt.Errorf("Error setting capacity to zero to drain: %s", err)
   342  	}
   343  
   344  	// Next, wait for the autoscale group to drain
   345  	log.Printf("[DEBUG] Waiting for group to have zero instances")
   346  	return resource.Retry(10*time.Minute, func() error {
   347  		g, err := getAwsAutoscalingGroup(d, meta)
   348  		if err != nil {
   349  			return resource.RetryError{Err: err}
   350  		}
   351  		if g == nil {
   352  			return nil
   353  		}
   354  
   355  		if len(g.Instances) == 0 {
   356  			return nil
   357  		}
   358  
   359  		return fmt.Errorf("group still has %d instances", len(g.Instances))
   360  	})
   361  }