github.com/chalford/terraform@v0.3.7-0.20150113080010-a78c69a8c81f/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/hashcode"
    10  	"github.com/hashicorp/terraform/helper/resource"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  	"github.com/mitchellh/goamz/autoscaling"
    13  )
    14  
    15  func resourceAwsAutoscalingGroup() *schema.Resource {
    16  	return &schema.Resource{
    17  		Create: resourceAwsAutoscalingGroupCreate,
    18  		Read:   resourceAwsAutoscalingGroupRead,
    19  		Update: resourceAwsAutoscalingGroupUpdate,
    20  		Delete: resourceAwsAutoscalingGroupDelete,
    21  
    22  		Schema: map[string]*schema.Schema{
    23  			"name": &schema.Schema{
    24  				Type:     schema.TypeString,
    25  				Required: true,
    26  				ForceNew: true,
    27  			},
    28  
    29  			"launch_configuration": &schema.Schema{
    30  				Type:     schema.TypeString,
    31  				Required: true,
    32  				ForceNew: 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  				ForceNew: true,
    70  			},
    71  
    72  			"health_check_type": &schema.Schema{
    73  				Type:     schema.TypeString,
    74  				Optional: true,
    75  				Computed: true,
    76  				ForceNew: true,
    77  			},
    78  
    79  			"availability_zones": &schema.Schema{
    80  				Type:     schema.TypeSet,
    81  				Required: true,
    82  				ForceNew: true,
    83  				Elem:     &schema.Schema{Type: schema.TypeString},
    84  				Set: func(v interface{}) int {
    85  					return hashcode.String(v.(string))
    86  				},
    87  			},
    88  
    89  			"load_balancers": &schema.Schema{
    90  				Type:     schema.TypeSet,
    91  				Optional: true,
    92  				ForceNew: true,
    93  				Elem:     &schema.Schema{Type: schema.TypeString},
    94  				Set: func(v interface{}) int {
    95  					return hashcode.String(v.(string))
    96  				},
    97  			},
    98  
    99  			"vpc_zone_identifier": &schema.Schema{
   100  				Type:     schema.TypeSet,
   101  				Optional: true,
   102  				Computed: true,
   103  				ForceNew: true,
   104  				Elem:     &schema.Schema{Type: schema.TypeString},
   105  				Set: func(v interface{}) int {
   106  					return hashcode.String(v.(string))
   107  				},
   108  			},
   109  
   110  			"termination_policies": &schema.Schema{
   111  				Type:     schema.TypeSet,
   112  				Optional: true,
   113  				Computed: true,
   114  				ForceNew: true,
   115  				Elem:     &schema.Schema{Type: schema.TypeString},
   116  				Set: func(v interface{}) int {
   117  					return hashcode.String(v.(string))
   118  				},
   119  			},
   120  		},
   121  	}
   122  }
   123  
   124  func resourceAwsAutoscalingGroupCreate(d *schema.ResourceData, meta interface{}) error {
   125  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   126  
   127  	var autoScalingGroupOpts autoscaling.CreateAutoScalingGroup
   128  	autoScalingGroupOpts.Name = d.Get("name").(string)
   129  	autoScalingGroupOpts.HealthCheckType = d.Get("health_check_type").(string)
   130  	autoScalingGroupOpts.LaunchConfigurationName = d.Get("launch_configuration").(string)
   131  	autoScalingGroupOpts.MinSize = d.Get("min_size").(int)
   132  	autoScalingGroupOpts.MaxSize = d.Get("max_size").(int)
   133  	autoScalingGroupOpts.SetMinSize = true
   134  	autoScalingGroupOpts.SetMaxSize = true
   135  	autoScalingGroupOpts.AvailZone = expandStringList(
   136  		d.Get("availability_zones").(*schema.Set).List())
   137  
   138  	if v, ok := d.GetOk("default_cooldown"); ok {
   139  		autoScalingGroupOpts.DefaultCooldown = v.(int)
   140  		autoScalingGroupOpts.SetDefaultCooldown = true
   141  	}
   142  
   143  	if v, ok := d.GetOk("desired_capacity"); ok {
   144  		autoScalingGroupOpts.DesiredCapacity = v.(int)
   145  		autoScalingGroupOpts.SetDesiredCapacity = true
   146  	}
   147  
   148  	if v, ok := d.GetOk("health_check_grace_period"); ok {
   149  		autoScalingGroupOpts.HealthCheckGracePeriod = v.(int)
   150  		autoScalingGroupOpts.SetHealthCheckGracePeriod = true
   151  	}
   152  
   153  	if v, ok := d.GetOk("load_balancers"); ok {
   154  		autoScalingGroupOpts.LoadBalancerNames = expandStringList(
   155  			v.(*schema.Set).List())
   156  	}
   157  
   158  	if v, ok := d.GetOk("vpc_zone_identifier"); ok {
   159  		autoScalingGroupOpts.VPCZoneIdentifier = expandStringList(
   160  			v.(*schema.Set).List())
   161  	}
   162  
   163  	if v, ok := d.GetOk("termination_policies"); ok {
   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.Name)
   199  	d.Set("vpc_zone_identifier", strings.Split(g.VPCZoneIdentifier, ","))
   200  
   201  	return nil
   202  }
   203  
   204  func resourceAwsAutoscalingGroupUpdate(d *schema.ResourceData, meta interface{}) error {
   205  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   206  
   207  	opts := autoscaling.UpdateAutoScalingGroup{
   208  		Name: d.Id(),
   209  	}
   210  
   211  	if d.HasChange("desired_capacity") {
   212  		opts.DesiredCapacity = d.Get("desired_capacity").(int)
   213  		opts.SetDesiredCapacity = true
   214  	}
   215  
   216  	if d.HasChange("min_size") {
   217  		opts.MinSize = d.Get("min_size").(int)
   218  		opts.SetMinSize = true
   219  	}
   220  
   221  	if d.HasChange("max_size") {
   222  		opts.MaxSize = d.Get("max_size").(int)
   223  		opts.SetMaxSize = true
   224  	}
   225  
   226  	log.Printf("[DEBUG] AutoScaling Group update configuration: %#v", opts)
   227  	_, err := autoscalingconn.UpdateAutoScalingGroup(&opts)
   228  	if err != nil {
   229  		d.Partial(true)
   230  		return fmt.Errorf("Error updating Autoscaling group: %s", err)
   231  	}
   232  
   233  	return resourceAwsAutoscalingGroupRead(d, meta)
   234  }
   235  
   236  func resourceAwsAutoscalingGroupDelete(d *schema.ResourceData, meta interface{}) error {
   237  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   238  
   239  	// Read the autoscaling group first. If it doesn't exist, we're done.
   240  	// We need the group in order to check if there are instances attached.
   241  	// If so, we need to remove those first.
   242  	g, err := getAwsAutoscalingGroup(d, meta)
   243  	if err != nil {
   244  		return err
   245  	}
   246  	if g == nil {
   247  		return nil
   248  	}
   249  	if len(g.Instances) > 0 || g.DesiredCapacity > 0 {
   250  		if err := resourceAwsAutoscalingGroupDrain(d, meta); err != nil {
   251  			return err
   252  		}
   253  	}
   254  
   255  	log.Printf("[DEBUG] AutoScaling Group destroy: %v", d.Id())
   256  	deleteopts := autoscaling.DeleteAutoScalingGroup{Name: d.Id()}
   257  
   258  	// You can force an autoscaling group to delete
   259  	// even if it's in the process of scaling a resource.
   260  	// Normally, you would set the min-size and max-size to 0,0
   261  	// and then delete the group. This bypasses that and leaves
   262  	// resources potentially dangling.
   263  	if d.Get("force_delete").(bool) {
   264  		deleteopts.ForceDelete = true
   265  	}
   266  
   267  	if _, err := autoscalingconn.DeleteAutoScalingGroup(&deleteopts); err != nil {
   268  		autoscalingerr, ok := err.(*autoscaling.Error)
   269  		if ok && autoscalingerr.Code == "InvalidGroup.NotFound" {
   270  			return nil
   271  		}
   272  
   273  		return err
   274  	}
   275  
   276  	return nil
   277  }
   278  
   279  func getAwsAutoscalingGroup(
   280  	d *schema.ResourceData,
   281  	meta interface{}) (*autoscaling.AutoScalingGroup, error) {
   282  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   283  
   284  	describeOpts := autoscaling.DescribeAutoScalingGroups{
   285  		Names: []string{d.Id()},
   286  	}
   287  
   288  	log.Printf("[DEBUG] AutoScaling Group describe configuration: %#v", describeOpts)
   289  	describeGroups, err := autoscalingconn.DescribeAutoScalingGroups(&describeOpts)
   290  	if err != nil {
   291  		autoscalingerr, ok := err.(*autoscaling.Error)
   292  		if ok && autoscalingerr.Code == "InvalidGroup.NotFound" {
   293  			d.SetId("")
   294  			return nil, nil
   295  		}
   296  
   297  		return nil, fmt.Errorf("Error retrieving AutoScaling groups: %s", err)
   298  	}
   299  
   300  	// Search for the autoscaling group
   301  	for idx, asc := range describeGroups.AutoScalingGroups {
   302  		if asc.Name == d.Id() {
   303  			return &describeGroups.AutoScalingGroups[idx], nil
   304  		}
   305  	}
   306  
   307  	// ASG not found
   308  	d.SetId("")
   309  	return nil, nil
   310  }
   311  
   312  func resourceAwsAutoscalingGroupDrain(d *schema.ResourceData, meta interface{}) error {
   313  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   314  
   315  	// First, set the capacity to zero so the group will drain
   316  	log.Printf("[DEBUG] Reducing autoscaling group capacity to zero")
   317  	opts := autoscaling.UpdateAutoScalingGroup{
   318  		Name:               d.Id(),
   319  		DesiredCapacity:    0,
   320  		MinSize:            0,
   321  		MaxSize:            0,
   322  		SetDesiredCapacity: true,
   323  		SetMinSize:         true,
   324  		SetMaxSize:         true,
   325  	}
   326  	if _, err := autoscalingconn.UpdateAutoScalingGroup(&opts); err != nil {
   327  		return fmt.Errorf("Error setting capacity to zero to drain: %s", err)
   328  	}
   329  
   330  	// Next, wait for the autoscale group to drain
   331  	log.Printf("[DEBUG] Waiting for group to have zero instances")
   332  	return resource.Retry(10*time.Minute, func() error {
   333  		g, err := getAwsAutoscalingGroup(d, meta)
   334  		if err != nil {
   335  			return resource.RetryError{err}
   336  		}
   337  		if g == nil {
   338  			return nil
   339  		}
   340  
   341  		if len(g.Instances) == 0 {
   342  			return nil
   343  		}
   344  
   345  		return fmt.Errorf("group still has %d instances", len(g.Instances))
   346  	})
   347  }