github.com/erriapo/terraform@v0.6.12-0.20160203182612-0340ea72354f/builtin/providers/aws/resource_aws_elb.go (about) 1 package aws 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "strings" 8 "time" 9 10 "github.com/aws/aws-sdk-go/aws" 11 "github.com/aws/aws-sdk-go/aws/awserr" 12 "github.com/aws/aws-sdk-go/service/ec2" 13 "github.com/aws/aws-sdk-go/service/elb" 14 "github.com/hashicorp/terraform/helper/hashcode" 15 "github.com/hashicorp/terraform/helper/resource" 16 "github.com/hashicorp/terraform/helper/schema" 17 ) 18 19 func resourceAwsElb() *schema.Resource { 20 return &schema.Resource{ 21 Create: resourceAwsElbCreate, 22 Read: resourceAwsElbRead, 23 Update: resourceAwsElbUpdate, 24 Delete: resourceAwsElbDelete, 25 26 Schema: map[string]*schema.Schema{ 27 "name": &schema.Schema{ 28 Type: schema.TypeString, 29 Optional: true, 30 Computed: true, 31 ForceNew: true, 32 ValidateFunc: validateElbName, 33 }, 34 35 "internal": &schema.Schema{ 36 Type: schema.TypeBool, 37 Optional: true, 38 ForceNew: true, 39 Computed: true, 40 }, 41 42 "cross_zone_load_balancing": &schema.Schema{ 43 Type: schema.TypeBool, 44 Optional: true, 45 }, 46 47 "availability_zones": &schema.Schema{ 48 Type: schema.TypeSet, 49 Elem: &schema.Schema{Type: schema.TypeString}, 50 Optional: true, 51 Computed: true, 52 Set: schema.HashString, 53 }, 54 55 "instances": &schema.Schema{ 56 Type: schema.TypeSet, 57 Elem: &schema.Schema{Type: schema.TypeString}, 58 Optional: true, 59 Computed: true, 60 Set: schema.HashString, 61 }, 62 63 "security_groups": &schema.Schema{ 64 Type: schema.TypeSet, 65 Elem: &schema.Schema{Type: schema.TypeString}, 66 Optional: true, 67 Computed: true, 68 Set: schema.HashString, 69 }, 70 71 "source_security_group": &schema.Schema{ 72 Type: schema.TypeString, 73 Optional: true, 74 Computed: true, 75 }, 76 77 "source_security_group_id": &schema.Schema{ 78 Type: schema.TypeString, 79 Computed: true, 80 }, 81 82 "subnets": &schema.Schema{ 83 Type: schema.TypeSet, 84 Elem: &schema.Schema{Type: schema.TypeString}, 85 Optional: true, 86 Computed: true, 87 Set: schema.HashString, 88 }, 89 90 "idle_timeout": &schema.Schema{ 91 Type: schema.TypeInt, 92 Optional: true, 93 Default: 60, 94 }, 95 96 "connection_draining": &schema.Schema{ 97 Type: schema.TypeBool, 98 Optional: true, 99 Default: false, 100 }, 101 102 "connection_draining_timeout": &schema.Schema{ 103 Type: schema.TypeInt, 104 Optional: true, 105 Default: 300, 106 }, 107 108 "access_logs": &schema.Schema{ 109 Type: schema.TypeSet, 110 Optional: true, 111 Elem: &schema.Resource{ 112 Schema: map[string]*schema.Schema{ 113 "interval": &schema.Schema{ 114 Type: schema.TypeInt, 115 Optional: true, 116 Default: 60, 117 }, 118 "bucket": &schema.Schema{ 119 Type: schema.TypeString, 120 Required: true, 121 }, 122 "bucket_prefix": &schema.Schema{ 123 Type: schema.TypeString, 124 Optional: true, 125 }, 126 }, 127 }, 128 Set: resourceAwsElbAccessLogsHash, 129 }, 130 131 "listener": &schema.Schema{ 132 Type: schema.TypeSet, 133 Required: true, 134 Elem: &schema.Resource{ 135 Schema: map[string]*schema.Schema{ 136 "instance_port": &schema.Schema{ 137 Type: schema.TypeInt, 138 Required: true, 139 }, 140 141 "instance_protocol": &schema.Schema{ 142 Type: schema.TypeString, 143 Required: true, 144 }, 145 146 "lb_port": &schema.Schema{ 147 Type: schema.TypeInt, 148 Required: true, 149 }, 150 151 "lb_protocol": &schema.Schema{ 152 Type: schema.TypeString, 153 Required: true, 154 }, 155 156 "ssl_certificate_id": &schema.Schema{ 157 Type: schema.TypeString, 158 Optional: true, 159 }, 160 }, 161 }, 162 Set: resourceAwsElbListenerHash, 163 }, 164 165 "health_check": &schema.Schema{ 166 Type: schema.TypeSet, 167 Optional: true, 168 Computed: true, 169 Elem: &schema.Resource{ 170 Schema: map[string]*schema.Schema{ 171 "healthy_threshold": &schema.Schema{ 172 Type: schema.TypeInt, 173 Required: true, 174 }, 175 176 "unhealthy_threshold": &schema.Schema{ 177 Type: schema.TypeInt, 178 Required: true, 179 }, 180 181 "target": &schema.Schema{ 182 Type: schema.TypeString, 183 Required: true, 184 }, 185 186 "interval": &schema.Schema{ 187 Type: schema.TypeInt, 188 Required: true, 189 }, 190 191 "timeout": &schema.Schema{ 192 Type: schema.TypeInt, 193 Required: true, 194 }, 195 }, 196 }, 197 Set: resourceAwsElbHealthCheckHash, 198 }, 199 200 "dns_name": &schema.Schema{ 201 Type: schema.TypeString, 202 Computed: true, 203 }, 204 205 "zone_id": &schema.Schema{ 206 Type: schema.TypeString, 207 Computed: true, 208 }, 209 210 "tags": tagsSchema(), 211 }, 212 } 213 } 214 215 func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error { 216 elbconn := meta.(*AWSClient).elbconn 217 218 // Expand the "listener" set to aws-sdk-go compat []*elb.Listener 219 listeners, err := expandListeners(d.Get("listener").(*schema.Set).List()) 220 if err != nil { 221 return err 222 } 223 224 var elbName string 225 if v, ok := d.GetOk("name"); ok { 226 elbName = v.(string) 227 } else { 228 elbName = resource.PrefixedUniqueId("tf-lb-") 229 d.Set("name", elbName) 230 } 231 232 tags := tagsFromMapELB(d.Get("tags").(map[string]interface{})) 233 // Provision the elb 234 elbOpts := &elb.CreateLoadBalancerInput{ 235 LoadBalancerName: aws.String(elbName), 236 Listeners: listeners, 237 Tags: tags, 238 } 239 240 if scheme, ok := d.GetOk("internal"); ok && scheme.(bool) { 241 elbOpts.Scheme = aws.String("internal") 242 } 243 244 if v, ok := d.GetOk("availability_zones"); ok { 245 elbOpts.AvailabilityZones = expandStringList(v.(*schema.Set).List()) 246 } 247 248 if v, ok := d.GetOk("security_groups"); ok { 249 elbOpts.SecurityGroups = expandStringList(v.(*schema.Set).List()) 250 } 251 252 if v, ok := d.GetOk("subnets"); ok { 253 elbOpts.Subnets = expandStringList(v.(*schema.Set).List()) 254 } 255 256 log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts) 257 err = resource.Retry(1*time.Minute, func() error { 258 _, err := elbconn.CreateLoadBalancer(elbOpts) 259 260 if err != nil { 261 if awsErr, ok := err.(awserr.Error); ok { 262 // Check for IAM SSL Cert error, eventual consistancy issue 263 if awsErr.Code() == "CertificateNotFound" { 264 return fmt.Errorf("[WARN] Error creating ELB Listener with SSL Cert, retrying: %s", err) 265 } 266 } 267 return resource.RetryError{Err: err} 268 } 269 return nil 270 }) 271 272 if err != nil { 273 return err 274 } 275 276 // Assign the elb's unique identifier for use later 277 d.SetId(elbName) 278 log.Printf("[INFO] ELB ID: %s", d.Id()) 279 280 // Enable partial mode and record what we set 281 d.Partial(true) 282 d.SetPartial("name") 283 d.SetPartial("internal") 284 d.SetPartial("availability_zones") 285 d.SetPartial("listener") 286 d.SetPartial("security_groups") 287 d.SetPartial("subnets") 288 289 d.Set("tags", tagsToMapELB(tags)) 290 291 return resourceAwsElbUpdate(d, meta) 292 } 293 294 func resourceAwsElbRead(d *schema.ResourceData, meta interface{}) error { 295 elbconn := meta.(*AWSClient).elbconn 296 elbName := d.Id() 297 298 // Retrieve the ELB properties for updating the state 299 describeElbOpts := &elb.DescribeLoadBalancersInput{ 300 LoadBalancerNames: []*string{aws.String(elbName)}, 301 } 302 303 describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts) 304 if err != nil { 305 if isLoadBalancerNotFound(err) { 306 // The ELB is gone now, so just remove it from the state 307 d.SetId("") 308 return nil 309 } 310 311 return fmt.Errorf("Error retrieving ELB: %s", err) 312 } 313 if len(describeResp.LoadBalancerDescriptions) != 1 { 314 return fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancerDescriptions) 315 } 316 317 describeAttrsOpts := &elb.DescribeLoadBalancerAttributesInput{ 318 LoadBalancerName: aws.String(elbName), 319 } 320 describeAttrsResp, err := elbconn.DescribeLoadBalancerAttributes(describeAttrsOpts) 321 if err != nil { 322 if isLoadBalancerNotFound(err) { 323 // The ELB is gone now, so just remove it from the state 324 d.SetId("") 325 return nil 326 } 327 328 return fmt.Errorf("Error retrieving ELB: %s", err) 329 } 330 331 lbAttrs := describeAttrsResp.LoadBalancerAttributes 332 333 lb := describeResp.LoadBalancerDescriptions[0] 334 335 d.Set("name", *lb.LoadBalancerName) 336 d.Set("dns_name", *lb.DNSName) 337 d.Set("zone_id", *lb.CanonicalHostedZoneNameID) 338 d.Set("internal", *lb.Scheme == "internal") 339 d.Set("availability_zones", flattenStringList(lb.AvailabilityZones)) 340 d.Set("instances", flattenInstances(lb.Instances)) 341 d.Set("listener", flattenListeners(lb.ListenerDescriptions)) 342 d.Set("security_groups", flattenStringList(lb.SecurityGroups)) 343 if lb.SourceSecurityGroup != nil { 344 d.Set("source_security_group", lb.SourceSecurityGroup.GroupName) 345 346 // Manually look up the ELB Security Group ID, since it's not provided 347 var elbVpc string 348 if lb.VPCId != nil { 349 elbVpc = *lb.VPCId 350 sgId, err := sourceSGIdByName(meta, *lb.SourceSecurityGroup.GroupName, elbVpc) 351 if err != nil { 352 return fmt.Errorf("[WARN] Error looking up ELB Security Group ID: %s", err) 353 } else { 354 d.Set("source_security_group_id", sgId) 355 } 356 } 357 } 358 d.Set("subnets", flattenStringList(lb.Subnets)) 359 d.Set("idle_timeout", lbAttrs.ConnectionSettings.IdleTimeout) 360 d.Set("connection_draining", lbAttrs.ConnectionDraining.Enabled) 361 d.Set("connection_draining_timeout", lbAttrs.ConnectionDraining.Timeout) 362 if lbAttrs.AccessLog != nil { 363 if err := d.Set("access_logs", flattenAccessLog(lbAttrs.AccessLog)); err != nil { 364 return err 365 } 366 } 367 368 resp, err := elbconn.DescribeTags(&elb.DescribeTagsInput{ 369 LoadBalancerNames: []*string{lb.LoadBalancerName}, 370 }) 371 372 var et []*elb.Tag 373 if len(resp.TagDescriptions) > 0 { 374 et = resp.TagDescriptions[0].Tags 375 } 376 d.Set("tags", tagsToMapELB(et)) 377 // There's only one health check, so save that to state as we 378 // currently can 379 if *lb.HealthCheck.Target != "" { 380 d.Set("health_check", flattenHealthCheck(lb.HealthCheck)) 381 } 382 383 return nil 384 } 385 386 func resourceAwsElbUpdate(d *schema.ResourceData, meta interface{}) error { 387 elbconn := meta.(*AWSClient).elbconn 388 389 d.Partial(true) 390 391 if d.HasChange("listener") { 392 o, n := d.GetChange("listener") 393 os := o.(*schema.Set) 394 ns := n.(*schema.Set) 395 396 remove, _ := expandListeners(os.Difference(ns).List()) 397 add, _ := expandListeners(ns.Difference(os).List()) 398 399 if len(remove) > 0 { 400 ports := make([]*int64, 0, len(remove)) 401 for _, listener := range remove { 402 ports = append(ports, listener.LoadBalancerPort) 403 } 404 405 deleteListenersOpts := &elb.DeleteLoadBalancerListenersInput{ 406 LoadBalancerName: aws.String(d.Id()), 407 LoadBalancerPorts: ports, 408 } 409 410 log.Printf("[DEBUG] ELB Delete Listeners opts: %s", deleteListenersOpts) 411 _, err := elbconn.DeleteLoadBalancerListeners(deleteListenersOpts) 412 if err != nil { 413 return fmt.Errorf("Failure removing outdated ELB listeners: %s", err) 414 } 415 } 416 417 if len(add) > 0 { 418 createListenersOpts := &elb.CreateLoadBalancerListenersInput{ 419 LoadBalancerName: aws.String(d.Id()), 420 Listeners: add, 421 } 422 423 // Occasionally AWS will error with a 'duplicate listener', without any 424 // other listeners on the ELB. Retry here to eliminate that. 425 err := resource.Retry(1*time.Minute, func() error { 426 log.Printf("[DEBUG] ELB Create Listeners opts: %s", createListenersOpts) 427 if _, err := elbconn.CreateLoadBalancerListeners(createListenersOpts); err != nil { 428 if awserr, ok := err.(awserr.Error); ok && awserr.Code() == "DuplicateListener" { 429 log.Printf("[DEBUG] Duplicate listener found for ELB (%s), retrying", d.Id()) 430 return awserr 431 } 432 433 // Didn't recognize the error, so shouldn't retry. 434 return resource.RetryError{Err: err} 435 } 436 // Successful creation 437 return nil 438 }) 439 if err != nil { 440 return fmt.Errorf("Failure adding new or updated ELB listeners: %s", err) 441 } 442 } 443 444 d.SetPartial("listener") 445 } 446 447 // If we currently have instances, or did have instances, 448 // we want to figure out what to add and remove from the load 449 // balancer 450 if d.HasChange("instances") { 451 o, n := d.GetChange("instances") 452 os := o.(*schema.Set) 453 ns := n.(*schema.Set) 454 remove := expandInstanceString(os.Difference(ns).List()) 455 add := expandInstanceString(ns.Difference(os).List()) 456 457 if len(add) > 0 { 458 registerInstancesOpts := elb.RegisterInstancesWithLoadBalancerInput{ 459 LoadBalancerName: aws.String(d.Id()), 460 Instances: add, 461 } 462 463 _, err := elbconn.RegisterInstancesWithLoadBalancer(®isterInstancesOpts) 464 if err != nil { 465 return fmt.Errorf("Failure registering instances with ELB: %s", err) 466 } 467 } 468 if len(remove) > 0 { 469 deRegisterInstancesOpts := elb.DeregisterInstancesFromLoadBalancerInput{ 470 LoadBalancerName: aws.String(d.Id()), 471 Instances: remove, 472 } 473 474 _, err := elbconn.DeregisterInstancesFromLoadBalancer(&deRegisterInstancesOpts) 475 if err != nil { 476 return fmt.Errorf("Failure deregistering instances from ELB: %s", err) 477 } 478 } 479 480 d.SetPartial("instances") 481 } 482 483 if d.HasChange("cross_zone_load_balancing") || d.HasChange("idle_timeout") || d.HasChange("access_logs") { 484 attrs := elb.ModifyLoadBalancerAttributesInput{ 485 LoadBalancerName: aws.String(d.Get("name").(string)), 486 LoadBalancerAttributes: &elb.LoadBalancerAttributes{ 487 CrossZoneLoadBalancing: &elb.CrossZoneLoadBalancing{ 488 Enabled: aws.Bool(d.Get("cross_zone_load_balancing").(bool)), 489 }, 490 ConnectionSettings: &elb.ConnectionSettings{ 491 IdleTimeout: aws.Int64(int64(d.Get("idle_timeout").(int))), 492 }, 493 }, 494 } 495 496 logs := d.Get("access_logs").(*schema.Set).List() 497 if len(logs) > 1 { 498 return fmt.Errorf("Only one access logs config per ELB is supported") 499 } else if len(logs) == 1 { 500 log := logs[0].(map[string]interface{}) 501 accessLog := &elb.AccessLog{ 502 Enabled: aws.Bool(true), 503 EmitInterval: aws.Int64(int64(log["interval"].(int))), 504 S3BucketName: aws.String(log["bucket"].(string)), 505 } 506 507 if log["bucket_prefix"] != "" { 508 accessLog.S3BucketPrefix = aws.String(log["bucket_prefix"].(string)) 509 } 510 511 attrs.LoadBalancerAttributes.AccessLog = accessLog 512 } else if len(logs) == 0 { 513 // disable access logs 514 attrs.LoadBalancerAttributes.AccessLog = &elb.AccessLog{ 515 Enabled: aws.Bool(false), 516 } 517 } 518 519 log.Printf("[DEBUG] ELB Modify Load Balancer Attributes Request: %#v", attrs) 520 _, err := elbconn.ModifyLoadBalancerAttributes(&attrs) 521 if err != nil { 522 return fmt.Errorf("Failure configuring ELB attributes: %s", err) 523 } 524 525 d.SetPartial("cross_zone_load_balancing") 526 d.SetPartial("idle_timeout") 527 d.SetPartial("connection_draining_timeout") 528 } 529 530 // We have to do these changes separately from everything else since 531 // they have some weird undocumented rules. You can't set the timeout 532 // without having connection draining to true, so we set that to true, 533 // set the timeout, then reset it to false if requested. 534 if d.HasChange("connection_draining") || d.HasChange("connection_draining_timeout") { 535 // We do timeout changes first since they require us to set draining 536 // to true for a hot second. 537 if d.HasChange("connection_draining_timeout") { 538 attrs := elb.ModifyLoadBalancerAttributesInput{ 539 LoadBalancerName: aws.String(d.Get("name").(string)), 540 LoadBalancerAttributes: &elb.LoadBalancerAttributes{ 541 ConnectionDraining: &elb.ConnectionDraining{ 542 Enabled: aws.Bool(true), 543 Timeout: aws.Int64(int64(d.Get("connection_draining_timeout").(int))), 544 }, 545 }, 546 } 547 548 _, err := elbconn.ModifyLoadBalancerAttributes(&attrs) 549 if err != nil { 550 return fmt.Errorf("Failure configuring ELB attributes: %s", err) 551 } 552 553 d.SetPartial("connection_draining_timeout") 554 } 555 556 // Then we always set connection draining even if there is no change. 557 // This lets us reset to "false" if requested even with a timeout 558 // change. 559 attrs := elb.ModifyLoadBalancerAttributesInput{ 560 LoadBalancerName: aws.String(d.Get("name").(string)), 561 LoadBalancerAttributes: &elb.LoadBalancerAttributes{ 562 ConnectionDraining: &elb.ConnectionDraining{ 563 Enabled: aws.Bool(d.Get("connection_draining").(bool)), 564 }, 565 }, 566 } 567 568 _, err := elbconn.ModifyLoadBalancerAttributes(&attrs) 569 if err != nil { 570 return fmt.Errorf("Failure configuring ELB attributes: %s", err) 571 } 572 573 d.SetPartial("connection_draining") 574 } 575 576 if d.HasChange("health_check") { 577 vs := d.Get("health_check").(*schema.Set).List() 578 if len(vs) > 0 { 579 check := vs[0].(map[string]interface{}) 580 configureHealthCheckOpts := elb.ConfigureHealthCheckInput{ 581 LoadBalancerName: aws.String(d.Id()), 582 HealthCheck: &elb.HealthCheck{ 583 HealthyThreshold: aws.Int64(int64(check["healthy_threshold"].(int))), 584 UnhealthyThreshold: aws.Int64(int64(check["unhealthy_threshold"].(int))), 585 Interval: aws.Int64(int64(check["interval"].(int))), 586 Target: aws.String(check["target"].(string)), 587 Timeout: aws.Int64(int64(check["timeout"].(int))), 588 }, 589 } 590 _, err := elbconn.ConfigureHealthCheck(&configureHealthCheckOpts) 591 if err != nil { 592 return fmt.Errorf("Failure configuring health check for ELB: %s", err) 593 } 594 d.SetPartial("health_check") 595 } 596 } 597 598 if d.HasChange("security_groups") { 599 groups := d.Get("security_groups").(*schema.Set).List() 600 601 applySecurityGroupsOpts := elb.ApplySecurityGroupsToLoadBalancerInput{ 602 LoadBalancerName: aws.String(d.Id()), 603 SecurityGroups: expandStringList(groups), 604 } 605 606 _, err := elbconn.ApplySecurityGroupsToLoadBalancer(&applySecurityGroupsOpts) 607 if err != nil { 608 return fmt.Errorf("Failure applying security groups to ELB: %s", err) 609 } 610 611 d.SetPartial("security_groups") 612 } 613 614 if d.HasChange("availability_zones") { 615 o, n := d.GetChange("availability_zones") 616 os := o.(*schema.Set) 617 ns := n.(*schema.Set) 618 619 removed := expandStringList(os.Difference(ns).List()) 620 added := expandStringList(ns.Difference(os).List()) 621 622 if len(added) > 0 { 623 enableOpts := &elb.EnableAvailabilityZonesForLoadBalancerInput{ 624 LoadBalancerName: aws.String(d.Id()), 625 AvailabilityZones: added, 626 } 627 628 log.Printf("[DEBUG] ELB enable availability zones opts: %s", enableOpts) 629 _, err := elbconn.EnableAvailabilityZonesForLoadBalancer(enableOpts) 630 if err != nil { 631 return fmt.Errorf("Failure enabling ELB availability zones: %s", err) 632 } 633 } 634 635 if len(removed) > 0 { 636 disableOpts := &elb.DisableAvailabilityZonesForLoadBalancerInput{ 637 LoadBalancerName: aws.String(d.Id()), 638 AvailabilityZones: removed, 639 } 640 641 log.Printf("[DEBUG] ELB disable availability zones opts: %s", disableOpts) 642 _, err := elbconn.DisableAvailabilityZonesForLoadBalancer(disableOpts) 643 if err != nil { 644 return fmt.Errorf("Failure disabling ELB availability zones: %s", err) 645 } 646 } 647 648 d.SetPartial("availability_zones") 649 } 650 651 if d.HasChange("subnets") { 652 o, n := d.GetChange("subnets") 653 os := o.(*schema.Set) 654 ns := n.(*schema.Set) 655 656 removed := expandStringList(os.Difference(ns).List()) 657 added := expandStringList(ns.Difference(os).List()) 658 659 if len(added) > 0 { 660 attachOpts := &elb.AttachLoadBalancerToSubnetsInput{ 661 LoadBalancerName: aws.String(d.Id()), 662 Subnets: added, 663 } 664 665 log.Printf("[DEBUG] ELB attach subnets opts: %s", attachOpts) 666 _, err := elbconn.AttachLoadBalancerToSubnets(attachOpts) 667 if err != nil { 668 return fmt.Errorf("Failure adding ELB subnets: %s", err) 669 } 670 } 671 672 if len(removed) > 0 { 673 detachOpts := &elb.DetachLoadBalancerFromSubnetsInput{ 674 LoadBalancerName: aws.String(d.Id()), 675 Subnets: removed, 676 } 677 678 log.Printf("[DEBUG] ELB detach subnets opts: %s", detachOpts) 679 _, err := elbconn.DetachLoadBalancerFromSubnets(detachOpts) 680 if err != nil { 681 return fmt.Errorf("Failure removing ELB subnets: %s", err) 682 } 683 } 684 685 d.SetPartial("subnets") 686 } 687 688 if err := setTagsELB(elbconn, d); err != nil { 689 return err 690 } 691 692 d.SetPartial("tags") 693 d.Partial(false) 694 695 return resourceAwsElbRead(d, meta) 696 } 697 698 func resourceAwsElbDelete(d *schema.ResourceData, meta interface{}) error { 699 elbconn := meta.(*AWSClient).elbconn 700 701 log.Printf("[INFO] Deleting ELB: %s", d.Id()) 702 703 // Destroy the load balancer 704 deleteElbOpts := elb.DeleteLoadBalancerInput{ 705 LoadBalancerName: aws.String(d.Id()), 706 } 707 if _, err := elbconn.DeleteLoadBalancer(&deleteElbOpts); err != nil { 708 return fmt.Errorf("Error deleting ELB: %s", err) 709 } 710 711 return nil 712 } 713 714 func resourceAwsElbHealthCheckHash(v interface{}) int { 715 var buf bytes.Buffer 716 m := v.(map[string]interface{}) 717 buf.WriteString(fmt.Sprintf("%d-", m["healthy_threshold"].(int))) 718 buf.WriteString(fmt.Sprintf("%d-", m["unhealthy_threshold"].(int))) 719 buf.WriteString(fmt.Sprintf("%s-", m["target"].(string))) 720 buf.WriteString(fmt.Sprintf("%d-", m["interval"].(int))) 721 buf.WriteString(fmt.Sprintf("%d-", m["timeout"].(int))) 722 723 return hashcode.String(buf.String()) 724 } 725 726 func resourceAwsElbAccessLogsHash(v interface{}) int { 727 var buf bytes.Buffer 728 m := v.(map[string]interface{}) 729 buf.WriteString(fmt.Sprintf("%d-", m["interval"].(int))) 730 buf.WriteString(fmt.Sprintf("%s-", 731 strings.ToLower(m["bucket"].(string)))) 732 if v, ok := m["bucket_prefix"]; ok { 733 buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(v.(string)))) 734 } 735 736 return hashcode.String(buf.String()) 737 } 738 739 func resourceAwsElbListenerHash(v interface{}) int { 740 var buf bytes.Buffer 741 m := v.(map[string]interface{}) 742 buf.WriteString(fmt.Sprintf("%d-", m["instance_port"].(int))) 743 buf.WriteString(fmt.Sprintf("%s-", 744 strings.ToLower(m["instance_protocol"].(string)))) 745 buf.WriteString(fmt.Sprintf("%d-", m["lb_port"].(int))) 746 buf.WriteString(fmt.Sprintf("%s-", 747 strings.ToLower(m["lb_protocol"].(string)))) 748 749 if v, ok := m["ssl_certificate_id"]; ok { 750 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 751 } 752 753 return hashcode.String(buf.String()) 754 } 755 756 func isLoadBalancerNotFound(err error) bool { 757 elberr, ok := err.(awserr.Error) 758 return ok && elberr.Code() == "LoadBalancerNotFound" 759 } 760 761 func sourceSGIdByName(meta interface{}, sg, vpcId string) (string, error) { 762 conn := meta.(*AWSClient).ec2conn 763 var filters []*ec2.Filter 764 var sgFilterName, sgFilterVPCID *ec2.Filter 765 sgFilterName = &ec2.Filter{ 766 Name: aws.String("group-name"), 767 Values: []*string{aws.String(sg)}, 768 } 769 770 if vpcId != "" { 771 sgFilterVPCID = &ec2.Filter{ 772 Name: aws.String("vpc-id"), 773 Values: []*string{aws.String(vpcId)}, 774 } 775 } 776 777 filters = append(filters, sgFilterName) 778 779 if sgFilterVPCID != nil { 780 filters = append(filters, sgFilterVPCID) 781 } 782 783 req := &ec2.DescribeSecurityGroupsInput{ 784 Filters: filters, 785 } 786 resp, err := conn.DescribeSecurityGroups(req) 787 if err != nil { 788 if ec2err, ok := err.(awserr.Error); ok { 789 if ec2err.Code() == "InvalidSecurityGroupID.NotFound" || 790 ec2err.Code() == "InvalidGroup.NotFound" { 791 resp = nil 792 err = nil 793 } 794 } 795 796 if err != nil { 797 log.Printf("Error on ELB SG look up: %s", err) 798 return "", err 799 } 800 } 801 802 if resp == nil || len(resp.SecurityGroups) == 0 { 803 return "", fmt.Errorf("No security groups found for name %s and vpc id %s", sg, vpcId) 804 } 805 806 group := resp.SecurityGroups[0] 807 return *group.GroupId, nil 808 }