github.com/ndarilek/terraform@v0.3.8-0.20150320140257-d3135c1b2bac/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  
    13  	"github.com/hashicorp/aws-sdk-go/aws"
    14  	"github.com/hashicorp/aws-sdk-go/gen/autoscaling"
    15  )
    16  
    17  func resourceAwsAutoscalingGroup() *schema.Resource {
    18  	return &schema.Resource{
    19  		Create: resourceAwsAutoscalingGroupCreate,
    20  		Read:   resourceAwsAutoscalingGroupRead,
    21  		Update: resourceAwsAutoscalingGroupUpdate,
    22  		Delete: resourceAwsAutoscalingGroupDelete,
    23  
    24  		Schema: map[string]*schema.Schema{
    25  			"name": &schema.Schema{
    26  				Type:     schema.TypeString,
    27  				Required: true,
    28  				ForceNew: true,
    29  			},
    30  
    31  			"launch_configuration": &schema.Schema{
    32  				Type:     schema.TypeString,
    33  				Required: true,
    34  			},
    35  
    36  			"desired_capacity": &schema.Schema{
    37  				Type:     schema.TypeInt,
    38  				Optional: true,
    39  				Computed: true,
    40  			},
    41  
    42  			"min_size": &schema.Schema{
    43  				Type:     schema.TypeInt,
    44  				Required: true,
    45  			},
    46  
    47  			"max_size": &schema.Schema{
    48  				Type:     schema.TypeInt,
    49  				Required: true,
    50  			},
    51  
    52  			"default_cooldown": &schema.Schema{
    53  				Type:     schema.TypeInt,
    54  				Optional: true,
    55  				Computed: true,
    56  				ForceNew: true,
    57  			},
    58  
    59  			"force_delete": &schema.Schema{
    60  				Type:     schema.TypeBool,
    61  				Optional: true,
    62  				Computed: true,
    63  				ForceNew: true,
    64  			},
    65  
    66  			"health_check_grace_period": &schema.Schema{
    67  				Type:     schema.TypeInt,
    68  				Optional: true,
    69  				Computed: true,
    70  				ForceNew: true,
    71  			},
    72  
    73  			"health_check_type": &schema.Schema{
    74  				Type:     schema.TypeString,
    75  				Optional: true,
    76  				Computed: true,
    77  				ForceNew: true,
    78  			},
    79  
    80  			"availability_zones": &schema.Schema{
    81  				Type:     schema.TypeSet,
    82  				Required: true,
    83  				ForceNew: true,
    84  				Elem:     &schema.Schema{Type: schema.TypeString},
    85  				Set: func(v interface{}) int {
    86  					return hashcode.String(v.(string))
    87  				},
    88  			},
    89  
    90  			"load_balancers": &schema.Schema{
    91  				Type:     schema.TypeSet,
    92  				Optional: true,
    93  				ForceNew: true,
    94  				Elem:     &schema.Schema{Type: schema.TypeString},
    95  				Set: func(v interface{}) int {
    96  					return hashcode.String(v.(string))
    97  				},
    98  			},
    99  
   100  			"vpc_zone_identifier": &schema.Schema{
   101  				Type:     schema.TypeSet,
   102  				Optional: true,
   103  				Computed: true,
   104  				ForceNew: true,
   105  				Elem:     &schema.Schema{Type: schema.TypeString},
   106  				Set: func(v interface{}) int {
   107  					return hashcode.String(v.(string))
   108  				},
   109  			},
   110  
   111  			"termination_policies": &schema.Schema{
   112  				Type:     schema.TypeSet,
   113  				Optional: true,
   114  				Computed: true,
   115  				ForceNew: true,
   116  				Elem:     &schema.Schema{Type: schema.TypeString},
   117  				Set: func(v interface{}) int {
   118  					return hashcode.String(v.(string))
   119  				},
   120  			},
   121  		},
   122  	}
   123  }
   124  
   125  func resourceAwsAutoscalingGroupCreate(d *schema.ResourceData, meta interface{}) error {
   126  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   127  
   128  	var autoScalingGroupOpts autoscaling.CreateAutoScalingGroupType
   129  	autoScalingGroupOpts.AutoScalingGroupName = aws.String(d.Get("name").(string))
   130  	autoScalingGroupOpts.LaunchConfigurationName = aws.String(d.Get("launch_configuration").(string))
   131  	autoScalingGroupOpts.MinSize = aws.Integer(d.Get("min_size").(int))
   132  	autoScalingGroupOpts.MaxSize = aws.Integer(d.Get("max_size").(int))
   133  	autoScalingGroupOpts.AvailabilityZones = expandStringList(
   134  		d.Get("availability_zones").(*schema.Set).List())
   135  
   136  	if v, ok := d.GetOk("default_cooldown"); ok {
   137  		autoScalingGroupOpts.DefaultCooldown = aws.Integer(v.(int))
   138  	}
   139  
   140  	if v, ok := d.GetOk("health_check"); ok && v.(string) != "" {
   141  		autoScalingGroupOpts.HealthCheckType = aws.String(v.(string))
   142  	}
   143  
   144  	if v, ok := d.GetOk("desired_capacity"); ok {
   145  		autoScalingGroupOpts.DesiredCapacity = aws.Integer(v.(int))
   146  	}
   147  
   148  	if v, ok := d.GetOk("health_check_grace_period"); ok {
   149  		autoScalingGroupOpts.HealthCheckGracePeriod = aws.Integer(v.(int))
   150  	}
   151  
   152  	if v, ok := d.GetOk("load_balancers"); ok && v.(*schema.Set).Len() > 0 {
   153  		autoScalingGroupOpts.LoadBalancerNames = expandStringList(
   154  			v.(*schema.Set).List())
   155  	}
   156  
   157  	if v, ok := d.GetOk("vpc_zone_identifier"); ok && v.(*schema.Set).Len() > 0 {
   158  		exp := expandStringList(v.(*schema.Set).List())
   159  		autoScalingGroupOpts.VPCZoneIdentifier = aws.String(strings.Join(exp, ","))
   160  	}
   161  
   162  	if v, ok := d.GetOk("termination_policies"); ok && v.(*schema.Set).Len() > 0 {
   163  		autoScalingGroupOpts.TerminationPolicies = expandStringList(
   164  			v.(*schema.Set).List())
   165  	}
   166  
   167  	log.Printf("[DEBUG] AutoScaling Group create configuration: %#v", autoScalingGroupOpts)
   168  	err := autoscalingconn.CreateAutoScalingGroup(&autoScalingGroupOpts)
   169  	if err != nil {
   170  		return fmt.Errorf("Error creating Autoscaling Group: %s", err)
   171  	}
   172  
   173  	d.SetId(d.Get("name").(string))
   174  	log.Printf("[INFO] AutoScaling Group ID: %s", d.Id())
   175  
   176  	return resourceAwsAutoscalingGroupRead(d, meta)
   177  }
   178  
   179  func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) error {
   180  	g, err := getAwsAutoscalingGroup(d, meta)
   181  	if err != nil {
   182  		return err
   183  	}
   184  	if g == nil {
   185  		return nil
   186  	}
   187  
   188  	d.Set("availability_zones", g.AvailabilityZones)
   189  	d.Set("default_cooldown", *g.DefaultCooldown)
   190  	d.Set("desired_capacity", *g.DesiredCapacity)
   191  	d.Set("health_check_grace_period", *g.HealthCheckGracePeriod)
   192  	d.Set("health_check_type", *g.HealthCheckType)
   193  	d.Set("launch_configuration", *g.LaunchConfigurationName)
   194  	d.Set("load_balancers", g.LoadBalancerNames)
   195  	d.Set("min_size", *g.MinSize)
   196  	d.Set("max_size", *g.MaxSize)
   197  	d.Set("name", *g.AutoScalingGroupName)
   198  	d.Set("vpc_zone_identifier", strings.Split(*g.VPCZoneIdentifier, ","))
   199  	d.Set("termination_policies", g.TerminationPolicies)
   200  
   201  	return nil
   202  }
   203  
   204  func resourceAwsAutoscalingGroupUpdate(d *schema.ResourceData, meta interface{}) error {
   205  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   206  
   207  	opts := autoscaling.UpdateAutoScalingGroupType{
   208  		AutoScalingGroupName: aws.String(d.Id()),
   209  	}
   210  
   211  	if d.HasChange("desired_capacity") {
   212  		opts.DesiredCapacity = aws.Integer(d.Get("desired_capacity").(int))
   213  	}
   214  
   215  	if d.HasChange("launch_configuration") {
   216  		opts.LaunchConfigurationName = aws.String(d.Get("launch_configuration").(string))
   217  	}
   218  
   219  	if d.HasChange("min_size") {
   220  		opts.MinSize = aws.Integer(d.Get("min_size").(int))
   221  	}
   222  
   223  	if d.HasChange("max_size") {
   224  		opts.MaxSize = aws.Integer(d.Get("max_size").(int))
   225  	}
   226  
   227  	log.Printf("[DEBUG] AutoScaling Group update configuration: %#v", opts)
   228  	err := autoscalingconn.UpdateAutoScalingGroup(&opts)
   229  	if err != nil {
   230  		d.Partial(true)
   231  		return fmt.Errorf("Error updating Autoscaling group: %s", err)
   232  	}
   233  
   234  	return resourceAwsAutoscalingGroupRead(d, meta)
   235  }
   236  
   237  func resourceAwsAutoscalingGroupDelete(d *schema.ResourceData, meta interface{}) error {
   238  	autoscalingconn := meta.(*AWSClient).autoscalingconn
   239  
   240  	// Read the autoscaling group first. If it doesn't exist, we're done.
   241  	// We need the group in order to check if there are instances attached.
   242  	// If so, we need to remove those first.
   243  	g, err := getAwsAutoscalingGroup(d, meta)
   244  	if err != nil {
   245  		return err
   246  	}
   247  	if g == nil {
   248  		return nil
   249  	}
   250  	if len(g.Instances) > 0 || *g.DesiredCapacity > 0 {
   251  		if err := resourceAwsAutoscalingGroupDrain(d, meta); err != nil {
   252  			return err
   253  		}
   254  	}
   255  
   256  	log.Printf("[DEBUG] AutoScaling Group destroy: %v", d.Id())
   257  	deleteopts := autoscaling.DeleteAutoScalingGroupType{AutoScalingGroupName: aws.String(d.Id())}
   258  
   259  	// You can force an autoscaling group to delete
   260  	// even if it's in the process of scaling a resource.
   261  	// Normally, you would set the min-size and max-size to 0,0
   262  	// and then delete the group. This bypasses that and leaves
   263  	// resources potentially dangling.
   264  	if d.Get("force_delete").(bool) {
   265  		deleteopts.ForceDelete = aws.Boolean(true)
   266  	}
   267  
   268  	if err := autoscalingconn.DeleteAutoScalingGroup(&deleteopts); err != nil {
   269  		autoscalingerr, ok := err.(aws.APIError)
   270  		if ok && autoscalingerr.Code == "InvalidGroup.NotFound" {
   271  			return nil
   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.AutoScalingGroupNamesType{
   285  		AutoScalingGroupNames: []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.(aws.APIError)
   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.AutoScalingGroupName == 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.UpdateAutoScalingGroupType{
   318  		AutoScalingGroupName: aws.String(d.Id()),
   319  		DesiredCapacity:      aws.Integer(0),
   320  		MinSize:              aws.Integer(0),
   321  		MaxSize:              aws.Integer(0),
   322  	}
   323  	if err := autoscalingconn.UpdateAutoScalingGroup(&opts); err != nil {
   324  		return fmt.Errorf("Error setting capacity to zero to drain: %s", err)
   325  	}
   326  
   327  	// Next, wait for the autoscale group to drain
   328  	log.Printf("[DEBUG] Waiting for group to have zero instances")
   329  	return resource.Retry(10*time.Minute, func() error {
   330  		g, err := getAwsAutoscalingGroup(d, meta)
   331  		if err != nil {
   332  			return resource.RetryError{Err: err}
   333  		}
   334  		if g == nil {
   335  			return nil
   336  		}
   337  
   338  		if len(g.Instances) == 0 {
   339  			return nil
   340  		}
   341  
   342  		return fmt.Errorf("group still has %d instances", len(g.Instances))
   343  	})
   344  }