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 }