github.com/lamielle/terraform@v0.3.2-0.20141121070651-81f008ba53d5/builtin/providers/aws/resource_aws_autoscaling_group.go (about)

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