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 }