github.com/daveadams/terraform@v0.6.4-0.20160830094355-13ce74975936/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/resource" 10 "github.com/hashicorp/terraform/helper/schema" 11 12 "github.com/aws/aws-sdk-go/aws" 13 "github.com/aws/aws-sdk-go/aws/awserr" 14 "github.com/aws/aws-sdk-go/service/autoscaling" 15 "github.com/aws/aws-sdk-go/service/elb" 16 ) 17 18 func resourceAwsAutoscalingGroup() *schema.Resource { 19 return &schema.Resource{ 20 Create: resourceAwsAutoscalingGroupCreate, 21 Read: resourceAwsAutoscalingGroupRead, 22 Update: resourceAwsAutoscalingGroupUpdate, 23 Delete: resourceAwsAutoscalingGroupDelete, 24 Importer: &schema.ResourceImporter{ 25 State: schema.ImportStatePassthrough, 26 }, 27 28 Schema: map[string]*schema.Schema{ 29 "name": &schema.Schema{ 30 Type: schema.TypeString, 31 Optional: true, 32 Computed: true, 33 ForceNew: true, 34 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 35 // https://github.com/boto/botocore/blob/9f322b1/botocore/data/autoscaling/2011-01-01/service-2.json#L1862-L1873 36 value := v.(string) 37 if len(value) > 255 { 38 errors = append(errors, fmt.Errorf( 39 "%q cannot be longer than 255 characters", k)) 40 } 41 return 42 }, 43 }, 44 45 "launch_configuration": &schema.Schema{ 46 Type: schema.TypeString, 47 Required: true, 48 }, 49 50 "desired_capacity": &schema.Schema{ 51 Type: schema.TypeInt, 52 Optional: true, 53 Computed: true, 54 }, 55 56 "min_elb_capacity": &schema.Schema{ 57 Type: schema.TypeInt, 58 Optional: true, 59 }, 60 61 "min_size": &schema.Schema{ 62 Type: schema.TypeInt, 63 Required: true, 64 }, 65 66 "max_size": &schema.Schema{ 67 Type: schema.TypeInt, 68 Required: true, 69 }, 70 71 "default_cooldown": &schema.Schema{ 72 Type: schema.TypeInt, 73 Optional: true, 74 Computed: true, 75 }, 76 77 "force_delete": &schema.Schema{ 78 Type: schema.TypeBool, 79 Optional: true, 80 Default: false, 81 }, 82 83 "health_check_grace_period": &schema.Schema{ 84 Type: schema.TypeInt, 85 Optional: true, 86 Default: 300, 87 }, 88 89 "health_check_type": &schema.Schema{ 90 Type: schema.TypeString, 91 Optional: true, 92 Computed: true, 93 }, 94 95 "availability_zones": &schema.Schema{ 96 Type: schema.TypeSet, 97 Optional: true, 98 Computed: true, 99 Elem: &schema.Schema{Type: schema.TypeString}, 100 Set: schema.HashString, 101 }, 102 103 "placement_group": &schema.Schema{ 104 Type: schema.TypeString, 105 Optional: true, 106 }, 107 108 "load_balancers": &schema.Schema{ 109 Type: schema.TypeSet, 110 Optional: true, 111 Elem: &schema.Schema{Type: schema.TypeString}, 112 Set: schema.HashString, 113 }, 114 115 "vpc_zone_identifier": &schema.Schema{ 116 Type: schema.TypeSet, 117 Optional: true, 118 Computed: true, 119 Elem: &schema.Schema{Type: schema.TypeString}, 120 Set: schema.HashString, 121 }, 122 123 "termination_policies": &schema.Schema{ 124 Type: schema.TypeList, 125 Optional: true, 126 Elem: &schema.Schema{Type: schema.TypeString}, 127 }, 128 129 "wait_for_capacity_timeout": &schema.Schema{ 130 Type: schema.TypeString, 131 Optional: true, 132 Default: "10m", 133 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 134 value := v.(string) 135 duration, err := time.ParseDuration(value) 136 if err != nil { 137 errors = append(errors, fmt.Errorf( 138 "%q cannot be parsed as a duration: %s", k, err)) 139 } 140 if duration < 0 { 141 errors = append(errors, fmt.Errorf( 142 "%q must be greater than zero", k)) 143 } 144 return 145 }, 146 }, 147 148 "wait_for_elb_capacity": &schema.Schema{ 149 Type: schema.TypeInt, 150 Optional: true, 151 }, 152 153 "enabled_metrics": &schema.Schema{ 154 Type: schema.TypeSet, 155 Optional: true, 156 Elem: &schema.Schema{Type: schema.TypeString}, 157 Set: schema.HashString, 158 }, 159 160 "metrics_granularity": &schema.Schema{ 161 Type: schema.TypeString, 162 Optional: true, 163 Default: "1Minute", 164 }, 165 166 "protect_from_scale_in": &schema.Schema{ 167 Type: schema.TypeBool, 168 Optional: true, 169 Default: false, 170 }, 171 172 "target_group_arns": &schema.Schema{ 173 Type: schema.TypeSet, 174 Optional: true, 175 Elem: &schema.Schema{Type: schema.TypeString}, 176 Set: schema.HashString, 177 }, 178 179 "arn": &schema.Schema{ 180 Type: schema.TypeString, 181 Computed: true, 182 }, 183 184 "tag": autoscalingTagsSchema(), 185 }, 186 } 187 } 188 189 func resourceAwsAutoscalingGroupCreate(d *schema.ResourceData, meta interface{}) error { 190 conn := meta.(*AWSClient).autoscalingconn 191 192 var autoScalingGroupOpts autoscaling.CreateAutoScalingGroupInput 193 194 var asgName string 195 if v, ok := d.GetOk("name"); ok { 196 asgName = v.(string) 197 } else { 198 asgName = resource.PrefixedUniqueId("tf-asg-") 199 d.Set("name", asgName) 200 } 201 202 autoScalingGroupOpts.AutoScalingGroupName = aws.String(asgName) 203 autoScalingGroupOpts.LaunchConfigurationName = aws.String(d.Get("launch_configuration").(string)) 204 autoScalingGroupOpts.MinSize = aws.Int64(int64(d.Get("min_size").(int))) 205 autoScalingGroupOpts.MaxSize = aws.Int64(int64(d.Get("max_size").(int))) 206 autoScalingGroupOpts.NewInstancesProtectedFromScaleIn = aws.Bool(d.Get("protect_from_scale_in").(bool)) 207 208 // Availability Zones are optional if VPC Zone Identifer(s) are specified 209 if v, ok := d.GetOk("availability_zones"); ok && v.(*schema.Set).Len() > 0 { 210 autoScalingGroupOpts.AvailabilityZones = expandStringList(v.(*schema.Set).List()) 211 } 212 213 if v, ok := d.GetOk("tag"); ok { 214 autoScalingGroupOpts.Tags = autoscalingTagsFromMap( 215 setToMapByKey(v.(*schema.Set), "key"), d.Get("name").(string)) 216 } 217 218 if v, ok := d.GetOk("default_cooldown"); ok { 219 autoScalingGroupOpts.DefaultCooldown = aws.Int64(int64(v.(int))) 220 } 221 222 if v, ok := d.GetOk("health_check_type"); ok && v.(string) != "" { 223 autoScalingGroupOpts.HealthCheckType = aws.String(v.(string)) 224 } 225 226 if v, ok := d.GetOk("desired_capacity"); ok { 227 autoScalingGroupOpts.DesiredCapacity = aws.Int64(int64(v.(int))) 228 } 229 230 if v, ok := d.GetOk("health_check_grace_period"); ok { 231 autoScalingGroupOpts.HealthCheckGracePeriod = aws.Int64(int64(v.(int))) 232 } 233 234 if v, ok := d.GetOk("placement_group"); ok { 235 autoScalingGroupOpts.PlacementGroup = aws.String(v.(string)) 236 } 237 238 if v, ok := d.GetOk("load_balancers"); ok && v.(*schema.Set).Len() > 0 { 239 autoScalingGroupOpts.LoadBalancerNames = expandStringList( 240 v.(*schema.Set).List()) 241 } 242 243 if v, ok := d.GetOk("vpc_zone_identifier"); ok && v.(*schema.Set).Len() > 0 { 244 autoScalingGroupOpts.VPCZoneIdentifier = expandVpcZoneIdentifiers(v.(*schema.Set).List()) 245 } 246 247 if v, ok := d.GetOk("termination_policies"); ok && len(v.([]interface{})) > 0 { 248 autoScalingGroupOpts.TerminationPolicies = expandStringList(v.([]interface{})) 249 } 250 251 if v, ok := d.GetOk("target_group_arns"); ok && len(v.(*schema.Set).List()) > 0 { 252 autoScalingGroupOpts.TargetGroupARNs = expandStringList(v.(*schema.Set).List()) 253 } 254 255 log.Printf("[DEBUG] AutoScaling Group create configuration: %#v", autoScalingGroupOpts) 256 _, err := conn.CreateAutoScalingGroup(&autoScalingGroupOpts) 257 if err != nil { 258 return fmt.Errorf("Error creating Autoscaling Group: %s", err) 259 } 260 261 d.SetId(d.Get("name").(string)) 262 log.Printf("[INFO] AutoScaling Group ID: %s", d.Id()) 263 264 if err := waitForASGCapacity(d, meta, capacitySatifiedCreate); err != nil { 265 return err 266 } 267 268 if _, ok := d.GetOk("enabled_metrics"); ok { 269 metricsErr := enableASGMetricsCollection(d, conn) 270 if metricsErr != nil { 271 return metricsErr 272 } 273 } 274 275 return resourceAwsAutoscalingGroupRead(d, meta) 276 } 277 278 func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) error { 279 conn := meta.(*AWSClient).autoscalingconn 280 281 g, err := getAwsAutoscalingGroup(d.Id(), conn) 282 if err != nil { 283 return err 284 } 285 if g == nil { 286 log.Printf("[INFO] Autoscaling Group %q not found", d.Id()) 287 d.SetId("") 288 return nil 289 } 290 291 d.Set("availability_zones", flattenStringList(g.AvailabilityZones)) 292 d.Set("default_cooldown", g.DefaultCooldown) 293 d.Set("arn", g.AutoScalingGroupARN) 294 d.Set("desired_capacity", g.DesiredCapacity) 295 d.Set("health_check_grace_period", g.HealthCheckGracePeriod) 296 d.Set("health_check_type", g.HealthCheckType) 297 d.Set("launch_configuration", g.LaunchConfigurationName) 298 d.Set("load_balancers", flattenStringList(g.LoadBalancerNames)) 299 if err := d.Set("target_group_arns", flattenStringList(g.TargetGroupARNs)); err != nil { 300 log.Printf("[ERR] Error setting target groups: %s", err) 301 } 302 d.Set("min_size", g.MinSize) 303 d.Set("max_size", g.MaxSize) 304 d.Set("placement_group", g.PlacementGroup) 305 d.Set("name", g.AutoScalingGroupName) 306 d.Set("tag", autoscalingTagDescriptionsToSlice(g.Tags)) 307 d.Set("vpc_zone_identifier", strings.Split(*g.VPCZoneIdentifier, ",")) 308 d.Set("protect_from_scale_in", g.NewInstancesProtectedFromScaleIn) 309 310 // If no termination polices are explicitly configured and the upstream state 311 // is only using the "Default" policy, clear the state to make it consistent 312 // with the default AWS create API behavior. 313 _, ok := d.GetOk("termination_policies") 314 if !ok && len(g.TerminationPolicies) == 1 && *g.TerminationPolicies[0] == "Default" { 315 d.Set("termination_policies", []interface{}{}) 316 } else { 317 d.Set("termination_policies", flattenStringList(g.TerminationPolicies)) 318 } 319 320 if g.EnabledMetrics != nil { 321 if err := d.Set("enabled_metrics", flattenAsgEnabledMetrics(g.EnabledMetrics)); err != nil { 322 log.Printf("[WARN] Error setting metrics for (%s): %s", d.Id(), err) 323 } 324 d.Set("metrics_granularity", g.EnabledMetrics[0].Granularity) 325 } 326 327 return nil 328 } 329 330 func resourceAwsAutoscalingGroupUpdate(d *schema.ResourceData, meta interface{}) error { 331 conn := meta.(*AWSClient).autoscalingconn 332 shouldWaitForCapacity := false 333 334 opts := autoscaling.UpdateAutoScalingGroupInput{ 335 AutoScalingGroupName: aws.String(d.Id()), 336 } 337 338 opts.NewInstancesProtectedFromScaleIn = aws.Bool(d.Get("protect_from_scale_in").(bool)) 339 340 if d.HasChange("default_cooldown") { 341 opts.DefaultCooldown = aws.Int64(int64(d.Get("default_cooldown").(int))) 342 } 343 344 if d.HasChange("desired_capacity") { 345 opts.DesiredCapacity = aws.Int64(int64(d.Get("desired_capacity").(int))) 346 shouldWaitForCapacity = true 347 } 348 349 if d.HasChange("launch_configuration") { 350 opts.LaunchConfigurationName = aws.String(d.Get("launch_configuration").(string)) 351 } 352 353 if d.HasChange("min_size") { 354 opts.MinSize = aws.Int64(int64(d.Get("min_size").(int))) 355 shouldWaitForCapacity = true 356 } 357 358 if d.HasChange("max_size") { 359 opts.MaxSize = aws.Int64(int64(d.Get("max_size").(int))) 360 } 361 362 if d.HasChange("health_check_grace_period") { 363 opts.HealthCheckGracePeriod = aws.Int64(int64(d.Get("health_check_grace_period").(int))) 364 } 365 366 if d.HasChange("health_check_type") { 367 opts.HealthCheckGracePeriod = aws.Int64(int64(d.Get("health_check_grace_period").(int))) 368 opts.HealthCheckType = aws.String(d.Get("health_check_type").(string)) 369 } 370 371 if d.HasChange("vpc_zone_identifier") { 372 opts.VPCZoneIdentifier = expandVpcZoneIdentifiers(d.Get("vpc_zone_identifier").(*schema.Set).List()) 373 } 374 375 if d.HasChange("availability_zones") { 376 if v, ok := d.GetOk("availability_zones"); ok && v.(*schema.Set).Len() > 0 { 377 opts.AvailabilityZones = expandStringList(v.(*schema.Set).List()) 378 } 379 } 380 381 if d.HasChange("placement_group") { 382 opts.PlacementGroup = aws.String(d.Get("placement_group").(string)) 383 } 384 385 if d.HasChange("termination_policies") { 386 // If the termination policy is set to null, we need to explicitly set 387 // it back to "Default", or the API won't reset it for us. 388 if v, ok := d.GetOk("termination_policies"); ok && len(v.([]interface{})) > 0 { 389 opts.TerminationPolicies = expandStringList(v.([]interface{})) 390 } else { 391 log.Printf("[DEBUG] Explictly setting null termination policy to 'Default'") 392 opts.TerminationPolicies = aws.StringSlice([]string{"Default"}) 393 } 394 } 395 396 if err := setAutoscalingTags(conn, d); err != nil { 397 return err 398 } else { 399 d.SetPartial("tag") 400 } 401 402 log.Printf("[DEBUG] AutoScaling Group update configuration: %#v", opts) 403 _, err := conn.UpdateAutoScalingGroup(&opts) 404 if err != nil { 405 d.Partial(true) 406 return fmt.Errorf("Error updating Autoscaling group: %s", err) 407 } 408 409 if d.HasChange("load_balancers") { 410 411 o, n := d.GetChange("load_balancers") 412 if o == nil { 413 o = new(schema.Set) 414 } 415 if n == nil { 416 n = new(schema.Set) 417 } 418 419 os := o.(*schema.Set) 420 ns := n.(*schema.Set) 421 remove := expandStringList(os.Difference(ns).List()) 422 add := expandStringList(ns.Difference(os).List()) 423 424 if len(remove) > 0 { 425 _, err := conn.DetachLoadBalancers(&autoscaling.DetachLoadBalancersInput{ 426 AutoScalingGroupName: aws.String(d.Id()), 427 LoadBalancerNames: remove, 428 }) 429 if err != nil { 430 return fmt.Errorf("[WARN] Error updating Load Balancers for AutoScaling Group (%s), error: %s", d.Id(), err) 431 } 432 } 433 434 if len(add) > 0 { 435 _, err := conn.AttachLoadBalancers(&autoscaling.AttachLoadBalancersInput{ 436 AutoScalingGroupName: aws.String(d.Id()), 437 LoadBalancerNames: add, 438 }) 439 if err != nil { 440 return fmt.Errorf("[WARN] Error updating Load Balancers for AutoScaling Group (%s), error: %s", d.Id(), err) 441 } 442 } 443 } 444 445 if d.HasChange("target_group_arns") { 446 447 o, n := d.GetChange("target_group_arns") 448 if o == nil { 449 o = new(schema.Set) 450 } 451 if n == nil { 452 n = new(schema.Set) 453 } 454 455 os := o.(*schema.Set) 456 ns := n.(*schema.Set) 457 remove := expandStringList(os.Difference(ns).List()) 458 add := expandStringList(ns.Difference(os).List()) 459 460 if len(remove) > 0 { 461 _, err := conn.DetachLoadBalancerTargetGroups(&autoscaling.DetachLoadBalancerTargetGroupsInput{ 462 AutoScalingGroupName: aws.String(d.Id()), 463 TargetGroupARNs: remove, 464 }) 465 if err != nil { 466 return fmt.Errorf("[WARN] Error updating Load Balancers Target Groups for AutoScaling Group (%s), error: %s", d.Id(), err) 467 } 468 } 469 470 if len(add) > 0 { 471 _, err := conn.AttachLoadBalancerTargetGroups(&autoscaling.AttachLoadBalancerTargetGroupsInput{ 472 AutoScalingGroupName: aws.String(d.Id()), 473 TargetGroupARNs: add, 474 }) 475 if err != nil { 476 return fmt.Errorf("[WARN] Error updating Load Balancers Target Groups for AutoScaling Group (%s), error: %s", d.Id(), err) 477 } 478 } 479 } 480 481 if shouldWaitForCapacity { 482 waitForASGCapacity(d, meta, capacitySatifiedUpdate) 483 } 484 485 if d.HasChange("enabled_metrics") { 486 updateASGMetricsCollection(d, conn) 487 } 488 489 return resourceAwsAutoscalingGroupRead(d, meta) 490 } 491 492 func resourceAwsAutoscalingGroupDelete(d *schema.ResourceData, meta interface{}) error { 493 conn := meta.(*AWSClient).autoscalingconn 494 495 // Read the autoscaling group first. If it doesn't exist, we're done. 496 // We need the group in order to check if there are instances attached. 497 // If so, we need to remove those first. 498 g, err := getAwsAutoscalingGroup(d.Id(), conn) 499 if err != nil { 500 return err 501 } 502 if g == nil { 503 log.Printf("[INFO] Autoscaling Group %q not found", d.Id()) 504 d.SetId("") 505 return nil 506 } 507 if len(g.Instances) > 0 || *g.DesiredCapacity > 0 { 508 if err := resourceAwsAutoscalingGroupDrain(d, meta); err != nil { 509 return err 510 } 511 } 512 513 log.Printf("[DEBUG] AutoScaling Group destroy: %v", d.Id()) 514 deleteopts := autoscaling.DeleteAutoScalingGroupInput{ 515 AutoScalingGroupName: aws.String(d.Id()), 516 ForceDelete: aws.Bool(d.Get("force_delete").(bool)), 517 } 518 519 // We retry the delete operation to handle InUse/InProgress errors coming 520 // from scaling operations. We should be able to sneak in a delete in between 521 // scaling operations within 5m. 522 err = resource.Retry(5*time.Minute, func() *resource.RetryError { 523 if _, err := conn.DeleteAutoScalingGroup(&deleteopts); err != nil { 524 if awserr, ok := err.(awserr.Error); ok { 525 switch awserr.Code() { 526 case "InvalidGroup.NotFound": 527 // Already gone? Sure! 528 return nil 529 case "ResourceInUse", "ScalingActivityInProgress": 530 // These are retryable 531 return resource.RetryableError(awserr) 532 } 533 } 534 // Didn't recognize the error, so shouldn't retry. 535 return resource.NonRetryableError(err) 536 } 537 // Successful delete 538 return nil 539 }) 540 if err != nil { 541 return err 542 } 543 544 return resource.Retry(5*time.Minute, func() *resource.RetryError { 545 if g, _ = getAwsAutoscalingGroup(d.Id(), conn); g != nil { 546 return resource.RetryableError( 547 fmt.Errorf("Auto Scaling Group still exists")) 548 } 549 return nil 550 }) 551 } 552 553 func getAwsAutoscalingGroup( 554 asgName string, 555 conn *autoscaling.AutoScaling) (*autoscaling.Group, error) { 556 557 describeOpts := autoscaling.DescribeAutoScalingGroupsInput{ 558 AutoScalingGroupNames: []*string{aws.String(asgName)}, 559 } 560 561 log.Printf("[DEBUG] AutoScaling Group describe configuration: %#v", describeOpts) 562 describeGroups, err := conn.DescribeAutoScalingGroups(&describeOpts) 563 if err != nil { 564 autoscalingerr, ok := err.(awserr.Error) 565 if ok && autoscalingerr.Code() == "InvalidGroup.NotFound" { 566 return nil, nil 567 } 568 569 return nil, fmt.Errorf("Error retrieving AutoScaling groups: %s", err) 570 } 571 572 // Search for the autoscaling group 573 for idx, asc := range describeGroups.AutoScalingGroups { 574 if *asc.AutoScalingGroupName == asgName { 575 return describeGroups.AutoScalingGroups[idx], nil 576 } 577 } 578 579 return nil, nil 580 } 581 582 func resourceAwsAutoscalingGroupDrain(d *schema.ResourceData, meta interface{}) error { 583 conn := meta.(*AWSClient).autoscalingconn 584 585 if d.Get("force_delete").(bool) { 586 log.Printf("[DEBUG] Skipping ASG drain, force_delete was set.") 587 return nil 588 } 589 590 // First, set the capacity to zero so the group will drain 591 log.Printf("[DEBUG] Reducing autoscaling group capacity to zero") 592 opts := autoscaling.UpdateAutoScalingGroupInput{ 593 AutoScalingGroupName: aws.String(d.Id()), 594 DesiredCapacity: aws.Int64(0), 595 MinSize: aws.Int64(0), 596 MaxSize: aws.Int64(0), 597 } 598 if _, err := conn.UpdateAutoScalingGroup(&opts); err != nil { 599 return fmt.Errorf("Error setting capacity to zero to drain: %s", err) 600 } 601 602 // Next, wait for the autoscale group to drain 603 log.Printf("[DEBUG] Waiting for group to have zero instances") 604 return resource.Retry(10*time.Minute, func() *resource.RetryError { 605 g, err := getAwsAutoscalingGroup(d.Id(), conn) 606 if err != nil { 607 return resource.NonRetryableError(err) 608 } 609 if g == nil { 610 log.Printf("[INFO] Autoscaling Group %q not found", d.Id()) 611 d.SetId("") 612 return nil 613 } 614 615 if len(g.Instances) == 0 { 616 return nil 617 } 618 619 return resource.RetryableError( 620 fmt.Errorf("group still has %d instances", len(g.Instances))) 621 }) 622 } 623 624 func enableASGMetricsCollection(d *schema.ResourceData, conn *autoscaling.AutoScaling) error { 625 props := &autoscaling.EnableMetricsCollectionInput{ 626 AutoScalingGroupName: aws.String(d.Id()), 627 Granularity: aws.String(d.Get("metrics_granularity").(string)), 628 Metrics: expandStringList(d.Get("enabled_metrics").(*schema.Set).List()), 629 } 630 631 log.Printf("[INFO] Enabling metrics collection for the ASG: %s", d.Id()) 632 _, metricsErr := conn.EnableMetricsCollection(props) 633 if metricsErr != nil { 634 return metricsErr 635 } 636 637 return nil 638 } 639 640 func updateASGMetricsCollection(d *schema.ResourceData, conn *autoscaling.AutoScaling) error { 641 642 o, n := d.GetChange("enabled_metrics") 643 if o == nil { 644 o = new(schema.Set) 645 } 646 if n == nil { 647 n = new(schema.Set) 648 } 649 650 os := o.(*schema.Set) 651 ns := n.(*schema.Set) 652 653 disableMetrics := os.Difference(ns) 654 if disableMetrics.Len() != 0 { 655 props := &autoscaling.DisableMetricsCollectionInput{ 656 AutoScalingGroupName: aws.String(d.Id()), 657 Metrics: expandStringList(disableMetrics.List()), 658 } 659 660 _, err := conn.DisableMetricsCollection(props) 661 if err != nil { 662 return fmt.Errorf("Failure to Disable metrics collection types for ASG %s: %s", d.Id(), err) 663 } 664 } 665 666 enabledMetrics := ns.Difference(os) 667 if enabledMetrics.Len() != 0 { 668 props := &autoscaling.EnableMetricsCollectionInput{ 669 AutoScalingGroupName: aws.String(d.Id()), 670 Metrics: expandStringList(enabledMetrics.List()), 671 Granularity: aws.String(d.Get("metrics_granularity").(string)), 672 } 673 674 _, err := conn.EnableMetricsCollection(props) 675 if err != nil { 676 return fmt.Errorf("Failure to Enable metrics collection types for ASG %s: %s", d.Id(), err) 677 } 678 } 679 680 return nil 681 } 682 683 // Returns a mapping of the instance states of all the ELBs attached to the 684 // provided ASG. 685 // 686 // Nested like: lbName -> instanceId -> instanceState 687 func getLBInstanceStates(g *autoscaling.Group, meta interface{}) (map[string]map[string]string, error) { 688 lbInstanceStates := make(map[string]map[string]string) 689 elbconn := meta.(*AWSClient).elbconn 690 691 for _, lbName := range g.LoadBalancerNames { 692 lbInstanceStates[*lbName] = make(map[string]string) 693 opts := &elb.DescribeInstanceHealthInput{LoadBalancerName: lbName} 694 r, err := elbconn.DescribeInstanceHealth(opts) 695 if err != nil { 696 return nil, err 697 } 698 for _, is := range r.InstanceStates { 699 if is.InstanceId == nil || is.State == nil { 700 continue 701 } 702 lbInstanceStates[*lbName][*is.InstanceId] = *is.State 703 } 704 } 705 706 return lbInstanceStates, nil 707 } 708 709 func expandVpcZoneIdentifiers(list []interface{}) *string { 710 strs := make([]string, len(list)) 711 for _, s := range list { 712 strs = append(strs, s.(string)) 713 } 714 return aws.String(strings.Join(strs, ",")) 715 }