providers/aws: drain autoscale groups before deleting [GH-435]

This commit is contained in:
Mitchell Hashimoto 2014-10-17 20:10:52 -07:00
parent 7c89fb06cc
commit f5c2aba215
2 changed files with 97 additions and 27 deletions

View File

@ -16,6 +16,7 @@ BUG FIXES:
* providers/aws: Retry deleting security groups for some amount of time * providers/aws: Retry deleting security groups for some amount of time
if there is a dependency violation since it is probably just eventual if there is a dependency violation since it is probably just eventual
consistency. [GH-436] consistency. [GH-436]
* providers/aws: Drain autoscale groups before deleting. [GH-435]
## 0.3.0 (October 14, 2014) ## 0.3.0 (October 14, 2014)

View File

@ -3,8 +3,10 @@ package aws
import ( import (
"fmt" "fmt"
"log" "log"
"time"
"github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"github.com/mitchellh/goamz/autoscaling" "github.com/mitchellh/goamz/autoscaling"
) )
@ -196,6 +198,22 @@ func resourceAwsAutoscalingGroupDelete(d *schema.ResourceData, meta interface{})
p := meta.(*ResourceProvider) p := meta.(*ResourceProvider)
autoscalingconn := p.autoscalingconn autoscalingconn := p.autoscalingconn
// Read the autoscaling group first. If it doesn't exist, we're done.
// We need the group in order to check if there are instances attached.
// If so, we need to remove those first.
g, err := getAwsAutoscalingGroup(d, meta)
if err != nil {
return err
}
if g == nil {
return nil
}
if len(g.Instances) > 0 || g.DesiredCapacity > 0 {
if err := resourceAwsAutoscalingGroupDrain(d, meta); err != nil {
return err
}
}
log.Printf("[DEBUG] AutoScaling Group destroy: %v", d.Id()) log.Printf("[DEBUG] AutoScaling Group destroy: %v", d.Id())
deleteopts := autoscaling.DeleteAutoScalingGroup{Name: d.Id()} deleteopts := autoscaling.DeleteAutoScalingGroup{Name: d.Id()}
@ -208,8 +226,7 @@ func resourceAwsAutoscalingGroupDelete(d *schema.ResourceData, meta interface{})
deleteopts.ForceDelete = true deleteopts.ForceDelete = true
} }
_, err := autoscalingconn.DeleteAutoScalingGroup(&deleteopts) if _, err := autoscalingconn.DeleteAutoScalingGroup(&deleteopts); err != nil {
if err != nil {
autoscalingerr, ok := err.(*autoscaling.Error) autoscalingerr, ok := err.(*autoscaling.Error)
if ok && autoscalingerr.Code == "InvalidGroup.NotFound" { if ok && autoscalingerr.Code == "InvalidGroup.NotFound" {
return nil return nil
@ -222,35 +239,14 @@ func resourceAwsAutoscalingGroupDelete(d *schema.ResourceData, meta interface{})
} }
func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) error {
p := meta.(*ResourceProvider) g, err := getAwsAutoscalingGroup(d, meta)
autoscalingconn := p.autoscalingconn
describeOpts := autoscaling.DescribeAutoScalingGroups{
Names: []string{d.Id()},
}
log.Printf("[DEBUG] AutoScaling Group describe configuration: %#v", describeOpts)
describeGroups, err := autoscalingconn.DescribeAutoScalingGroups(&describeOpts)
if err != nil { if err != nil {
autoscalingerr, ok := err.(*autoscaling.Error) return err
if ok && autoscalingerr.Code == "InvalidGroup.NotFound" { }
d.SetId("") if g == nil {
return nil return nil
} }
return fmt.Errorf("Error retrieving AutoScaling groups: %s", err)
}
// Verify AWS returned our sg
if len(describeGroups.AutoScalingGroups) != 1 ||
describeGroups.AutoScalingGroups[0].Name != d.Id() {
if err != nil {
return fmt.Errorf("Unable to find AutoScaling group: %#v", describeGroups.AutoScalingGroups)
}
}
g := describeGroups.AutoScalingGroups[0]
d.Set("availability_zones", g.AvailabilityZones) d.Set("availability_zones", g.AvailabilityZones)
d.Set("default_cooldown", g.DefaultCooldown) d.Set("default_cooldown", g.DefaultCooldown)
d.Set("desired_capacity", g.DesiredCapacity) d.Set("desired_capacity", g.DesiredCapacity)
@ -265,3 +261,76 @@ func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) e
return nil return nil
} }
func getAwsAutoscalingGroup(
d *schema.ResourceData,
meta interface{}) (*autoscaling.AutoScalingGroup, error) {
p := meta.(*ResourceProvider)
autoscalingconn := p.autoscalingconn
describeOpts := autoscaling.DescribeAutoScalingGroups{
Names: []string{d.Id()},
}
log.Printf("[DEBUG] AutoScaling Group describe configuration: %#v", describeOpts)
describeGroups, err := autoscalingconn.DescribeAutoScalingGroups(&describeOpts)
if err != nil {
autoscalingerr, ok := err.(*autoscaling.Error)
if ok && autoscalingerr.Code == "InvalidGroup.NotFound" {
d.SetId("")
return nil, 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 != d.Id() {
if err != nil {
return nil, fmt.Errorf(
"Unable to find AutoScaling group: %#v",
describeGroups.AutoScalingGroups)
}
}
return &describeGroups.AutoScalingGroups[0], nil
}
func resourceAwsAutoscalingGroupDrain(d *schema.ResourceData, meta interface{}) error {
p := meta.(*ResourceProvider)
autoscalingconn := p.autoscalingconn
// First, set the capacity to zero so the group will drain
log.Printf("[DEBUG] Reducing autoscaling group capacity to zero")
opts := autoscaling.UpdateAutoScalingGroup{
Name: d.Id(),
DesiredCapacity: 0,
MinSize: 0,
MaxSize: 0,
SetDesiredCapacity: true,
SetMinSize: true,
SetMaxSize: true,
}
if _, err := autoscalingconn.UpdateAutoScalingGroup(&opts); err != nil {
return fmt.Errorf("Error setting capacity to zero to drain: %s", err)
}
// Next, wait for the autoscale group to drain
log.Printf("[DEBUG] Waiting for group to have zero instances")
return resource.Retry(10*time.Minute, func() error {
g, err := getAwsAutoscalingGroup(d, meta)
if err != nil {
return resource.RetryError{err}
}
if g == nil {
return nil
}
if len(g.Instances) == 0 {
return nil
}
return fmt.Errorf("group still has %d instances", len(g.Instances))
})
}