github.com/mohanarpit/terraform@v0.6.16-0.20160909104007-291f29853544/builtin/providers/aws/resource_aws_elb_test.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "math/rand" 6 "reflect" 7 "regexp" 8 "sort" 9 "testing" 10 "time" 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/elb" 15 "github.com/hashicorp/terraform/helper/acctest" 16 "github.com/hashicorp/terraform/helper/resource" 17 "github.com/hashicorp/terraform/terraform" 18 ) 19 20 func TestAccAWSELB_basic(t *testing.T) { 21 var conf elb.LoadBalancerDescription 22 23 resource.Test(t, resource.TestCase{ 24 PreCheck: func() { testAccPreCheck(t) }, 25 IDRefreshName: "aws_elb.bar", 26 Providers: testAccProviders, 27 CheckDestroy: testAccCheckAWSELBDestroy, 28 Steps: []resource.TestStep{ 29 resource.TestStep{ 30 Config: testAccAWSELBConfig, 31 Check: resource.ComposeTestCheckFunc( 32 testAccCheckAWSELBExists("aws_elb.bar", &conf), 33 testAccCheckAWSELBAttributes(&conf), 34 resource.TestCheckResourceAttr( 35 "aws_elb.bar", "availability_zones.#", "3"), 36 resource.TestCheckResourceAttr( 37 "aws_elb.bar", "availability_zones.2487133097", "us-west-2a"), 38 resource.TestCheckResourceAttr( 39 "aws_elb.bar", "availability_zones.221770259", "us-west-2b"), 40 resource.TestCheckResourceAttr( 41 "aws_elb.bar", "availability_zones.2050015877", "us-west-2c"), 42 resource.TestCheckResourceAttr( 43 "aws_elb.bar", "subnets.#", "3"), 44 // NOTE: Subnet IDs are different across AWS accounts and cannot be checked. 45 resource.TestCheckResourceAttr( 46 "aws_elb.bar", "listener.206423021.instance_port", "8000"), 47 resource.TestCheckResourceAttr( 48 "aws_elb.bar", "listener.206423021.instance_protocol", "http"), 49 resource.TestCheckResourceAttr( 50 "aws_elb.bar", "listener.206423021.lb_port", "80"), 51 resource.TestCheckResourceAttr( 52 "aws_elb.bar", "listener.206423021.lb_protocol", "http"), 53 resource.TestCheckResourceAttr( 54 "aws_elb.bar", "cross_zone_load_balancing", "true"), 55 ), 56 }, 57 }, 58 }) 59 } 60 61 func TestAccAWSELB_fullCharacterRange(t *testing.T) { 62 var conf elb.LoadBalancerDescription 63 64 lbName := fmt.Sprintf("Tf-%d", 65 rand.New(rand.NewSource(time.Now().UnixNano())).Int()) 66 67 resource.Test(t, resource.TestCase{ 68 PreCheck: func() { testAccPreCheck(t) }, 69 IDRefreshName: "aws_elb.foo", 70 Providers: testAccProviders, 71 CheckDestroy: testAccCheckAWSELBDestroy, 72 Steps: []resource.TestStep{ 73 resource.TestStep{ 74 Config: fmt.Sprintf(testAccAWSELBFullRangeOfCharacters, lbName), 75 Check: resource.ComposeTestCheckFunc( 76 testAccCheckAWSELBExists("aws_elb.foo", &conf), 77 resource.TestCheckResourceAttr( 78 "aws_elb.foo", "name", lbName), 79 ), 80 }, 81 }, 82 }) 83 } 84 85 func TestAccAWSELB_AccessLogs(t *testing.T) { 86 var conf elb.LoadBalancerDescription 87 88 resource.Test(t, resource.TestCase{ 89 PreCheck: func() { testAccPreCheck(t) }, 90 IDRefreshName: "aws_elb.foo", 91 Providers: testAccProviders, 92 CheckDestroy: testAccCheckAWSELBDestroy, 93 Steps: []resource.TestStep{ 94 resource.TestStep{ 95 Config: testAccAWSELBAccessLogs, 96 Check: resource.ComposeTestCheckFunc( 97 testAccCheckAWSELBExists("aws_elb.foo", &conf), 98 ), 99 }, 100 101 resource.TestStep{ 102 Config: testAccAWSELBAccessLogsOn, 103 Check: resource.ComposeTestCheckFunc( 104 testAccCheckAWSELBExists("aws_elb.foo", &conf), 105 resource.TestCheckResourceAttr( 106 "aws_elb.foo", "access_logs.#", "1"), 107 resource.TestCheckResourceAttr( 108 "aws_elb.foo", "access_logs.0.bucket", "terraform-access-logs-bucket"), 109 resource.TestCheckResourceAttr( 110 "aws_elb.foo", "access_logs.0.interval", "5"), 111 ), 112 }, 113 114 resource.TestStep{ 115 Config: testAccAWSELBAccessLogs, 116 Check: resource.ComposeTestCheckFunc( 117 testAccCheckAWSELBExists("aws_elb.foo", &conf), 118 resource.TestCheckResourceAttr( 119 "aws_elb.foo", "access_logs.#", "0"), 120 ), 121 }, 122 }, 123 }) 124 } 125 126 func TestAccAWSELB_generatedName(t *testing.T) { 127 var conf elb.LoadBalancerDescription 128 generatedNameRegexp := regexp.MustCompile("^tf-lb-") 129 130 resource.Test(t, resource.TestCase{ 131 PreCheck: func() { testAccPreCheck(t) }, 132 IDRefreshName: "aws_elb.foo", 133 Providers: testAccProviders, 134 CheckDestroy: testAccCheckAWSELBDestroy, 135 Steps: []resource.TestStep{ 136 resource.TestStep{ 137 Config: testAccAWSELBGeneratedName, 138 Check: resource.ComposeTestCheckFunc( 139 testAccCheckAWSELBExists("aws_elb.foo", &conf), 140 resource.TestMatchResourceAttr( 141 "aws_elb.foo", "name", generatedNameRegexp), 142 ), 143 }, 144 }, 145 }) 146 } 147 148 func TestAccAWSELB_availabilityZones(t *testing.T) { 149 var conf elb.LoadBalancerDescription 150 151 resource.Test(t, resource.TestCase{ 152 PreCheck: func() { testAccPreCheck(t) }, 153 IDRefreshName: "aws_elb.bar", 154 Providers: testAccProviders, 155 CheckDestroy: testAccCheckAWSELBDestroy, 156 Steps: []resource.TestStep{ 157 resource.TestStep{ 158 Config: testAccAWSELBConfig, 159 Check: resource.ComposeTestCheckFunc( 160 testAccCheckAWSELBExists("aws_elb.bar", &conf), 161 resource.TestCheckResourceAttr( 162 "aws_elb.bar", "availability_zones.#", "3"), 163 resource.TestCheckResourceAttr( 164 "aws_elb.bar", "availability_zones.2487133097", "us-west-2a"), 165 resource.TestCheckResourceAttr( 166 "aws_elb.bar", "availability_zones.221770259", "us-west-2b"), 167 resource.TestCheckResourceAttr( 168 "aws_elb.bar", "availability_zones.2050015877", "us-west-2c"), 169 ), 170 }, 171 172 resource.TestStep{ 173 Config: testAccAWSELBConfig_AvailabilityZonesUpdate, 174 Check: resource.ComposeTestCheckFunc( 175 testAccCheckAWSELBExists("aws_elb.bar", &conf), 176 resource.TestCheckResourceAttr( 177 "aws_elb.bar", "availability_zones.#", "2"), 178 resource.TestCheckResourceAttr( 179 "aws_elb.bar", "availability_zones.2487133097", "us-west-2a"), 180 resource.TestCheckResourceAttr( 181 "aws_elb.bar", "availability_zones.221770259", "us-west-2b"), 182 ), 183 }, 184 }, 185 }) 186 } 187 188 func TestAccAWSELB_tags(t *testing.T) { 189 var conf elb.LoadBalancerDescription 190 var td elb.TagDescription 191 192 resource.Test(t, resource.TestCase{ 193 PreCheck: func() { testAccPreCheck(t) }, 194 IDRefreshName: "aws_elb.bar", 195 Providers: testAccProviders, 196 CheckDestroy: testAccCheckAWSELBDestroy, 197 Steps: []resource.TestStep{ 198 resource.TestStep{ 199 Config: testAccAWSELBConfig, 200 Check: resource.ComposeTestCheckFunc( 201 testAccCheckAWSELBExists("aws_elb.bar", &conf), 202 testAccCheckAWSELBAttributes(&conf), 203 testAccLoadTags(&conf, &td), 204 testAccCheckELBTags(&td.Tags, "bar", "baz"), 205 ), 206 }, 207 208 resource.TestStep{ 209 Config: testAccAWSELBConfig_TagUpdate, 210 Check: resource.ComposeTestCheckFunc( 211 testAccCheckAWSELBExists("aws_elb.bar", &conf), 212 testAccCheckAWSELBAttributes(&conf), 213 testAccLoadTags(&conf, &td), 214 testAccCheckELBTags(&td.Tags, "foo", "bar"), 215 testAccCheckELBTags(&td.Tags, "new", "type"), 216 ), 217 }, 218 }, 219 }) 220 } 221 222 func TestAccAWSELB_iam_server_cert(t *testing.T) { 223 var conf elb.LoadBalancerDescription 224 // var td elb.TagDescription 225 testCheck := func(*terraform.State) error { 226 if len(conf.ListenerDescriptions) != 1 { 227 return fmt.Errorf( 228 "TestAccAWSELB_iam_server_cert expected 1 listener, got %d", 229 len(conf.ListenerDescriptions)) 230 } 231 return nil 232 } 233 resource.Test(t, resource.TestCase{ 234 PreCheck: func() { testAccPreCheck(t) }, 235 IDRefreshName: "aws_elb.bar", 236 Providers: testAccProviders, 237 CheckDestroy: testAccCheckAWSELBDestroy, 238 Steps: []resource.TestStep{ 239 resource.TestStep{ 240 Config: testAccELBIAMServerCertConfig( 241 fmt.Sprintf("tf-acctest-%s", acctest.RandString(10))), 242 Check: resource.ComposeTestCheckFunc( 243 testAccCheckAWSELBExists("aws_elb.bar", &conf), 244 testCheck, 245 ), 246 }, 247 }, 248 }) 249 } 250 251 func testAccLoadTags(conf *elb.LoadBalancerDescription, td *elb.TagDescription) resource.TestCheckFunc { 252 return func(s *terraform.State) error { 253 conn := testAccProvider.Meta().(*AWSClient).elbconn 254 255 describe, err := conn.DescribeTags(&elb.DescribeTagsInput{ 256 LoadBalancerNames: []*string{conf.LoadBalancerName}, 257 }) 258 259 if err != nil { 260 return err 261 } 262 if len(describe.TagDescriptions) > 0 { 263 *td = *describe.TagDescriptions[0] 264 } 265 return nil 266 } 267 } 268 269 func TestAccAWSELB_InstanceAttaching(t *testing.T) { 270 var conf elb.LoadBalancerDescription 271 272 testCheckInstanceAttached := func(count int) resource.TestCheckFunc { 273 return func(*terraform.State) error { 274 if len(conf.Instances) != count { 275 return fmt.Errorf("instance count does not match") 276 } 277 return nil 278 } 279 } 280 281 resource.Test(t, resource.TestCase{ 282 PreCheck: func() { testAccPreCheck(t) }, 283 IDRefreshName: "aws_elb.bar", 284 Providers: testAccProviders, 285 CheckDestroy: testAccCheckAWSELBDestroy, 286 Steps: []resource.TestStep{ 287 resource.TestStep{ 288 Config: testAccAWSELBConfig, 289 Check: resource.ComposeTestCheckFunc( 290 testAccCheckAWSELBExists("aws_elb.bar", &conf), 291 testAccCheckAWSELBAttributes(&conf), 292 ), 293 }, 294 295 resource.TestStep{ 296 Config: testAccAWSELBConfigNewInstance, 297 Check: resource.ComposeTestCheckFunc( 298 testAccCheckAWSELBExists("aws_elb.bar", &conf), 299 testCheckInstanceAttached(1), 300 ), 301 }, 302 }, 303 }) 304 } 305 306 func TestAccAWSELBUpdate_Listener(t *testing.T) { 307 var conf elb.LoadBalancerDescription 308 309 resource.Test(t, resource.TestCase{ 310 PreCheck: func() { testAccPreCheck(t) }, 311 IDRefreshName: "aws_elb.bar", 312 Providers: testAccProviders, 313 CheckDestroy: testAccCheckAWSELBDestroy, 314 Steps: []resource.TestStep{ 315 resource.TestStep{ 316 Config: testAccAWSELBConfig, 317 Check: resource.ComposeTestCheckFunc( 318 testAccCheckAWSELBExists("aws_elb.bar", &conf), 319 testAccCheckAWSELBAttributes(&conf), 320 resource.TestCheckResourceAttr( 321 "aws_elb.bar", "listener.206423021.instance_port", "8000"), 322 ), 323 }, 324 325 resource.TestStep{ 326 Config: testAccAWSELBConfigListener_update, 327 Check: resource.ComposeTestCheckFunc( 328 testAccCheckAWSELBExists("aws_elb.bar", &conf), 329 resource.TestCheckResourceAttr( 330 "aws_elb.bar", "listener.3931999347.instance_port", "8080"), 331 ), 332 }, 333 }, 334 }) 335 } 336 337 func TestAccAWSELB_HealthCheck(t *testing.T) { 338 var conf elb.LoadBalancerDescription 339 340 resource.Test(t, resource.TestCase{ 341 PreCheck: func() { testAccPreCheck(t) }, 342 IDRefreshName: "aws_elb.bar", 343 Providers: testAccProviders, 344 CheckDestroy: testAccCheckAWSELBDestroy, 345 Steps: []resource.TestStep{ 346 resource.TestStep{ 347 Config: testAccAWSELBConfigHealthCheck, 348 Check: resource.ComposeTestCheckFunc( 349 testAccCheckAWSELBExists("aws_elb.bar", &conf), 350 testAccCheckAWSELBAttributesHealthCheck(&conf), 351 resource.TestCheckResourceAttr( 352 "aws_elb.bar", "health_check.0.healthy_threshold", "5"), 353 resource.TestCheckResourceAttr( 354 "aws_elb.bar", "health_check.0.unhealthy_threshold", "5"), 355 resource.TestCheckResourceAttr( 356 "aws_elb.bar", "health_check.0.target", "HTTP:8000/"), 357 resource.TestCheckResourceAttr( 358 "aws_elb.bar", "health_check.0.timeout", "30"), 359 resource.TestCheckResourceAttr( 360 "aws_elb.bar", "health_check.0.interval", "60"), 361 ), 362 }, 363 }, 364 }) 365 } 366 367 func TestAccAWSELBUpdate_HealthCheck(t *testing.T) { 368 resource.Test(t, resource.TestCase{ 369 PreCheck: func() { testAccPreCheck(t) }, 370 IDRefreshName: "aws_elb.bar", 371 Providers: testAccProviders, 372 CheckDestroy: testAccCheckAWSELBDestroy, 373 Steps: []resource.TestStep{ 374 resource.TestStep{ 375 Config: testAccAWSELBConfigHealthCheck, 376 Check: resource.ComposeTestCheckFunc( 377 resource.TestCheckResourceAttr( 378 "aws_elb.bar", "health_check.0.healthy_threshold", "5"), 379 ), 380 }, 381 resource.TestStep{ 382 Config: testAccAWSELBConfigHealthCheck_update, 383 Check: resource.ComposeTestCheckFunc( 384 resource.TestCheckResourceAttr( 385 "aws_elb.bar", "health_check.0.healthy_threshold", "10"), 386 ), 387 }, 388 }, 389 }) 390 } 391 392 func TestAccAWSELB_Timeout(t *testing.T) { 393 var conf elb.LoadBalancerDescription 394 395 resource.Test(t, resource.TestCase{ 396 PreCheck: func() { testAccPreCheck(t) }, 397 IDRefreshName: "aws_elb.bar", 398 Providers: testAccProviders, 399 CheckDestroy: testAccCheckAWSELBDestroy, 400 Steps: []resource.TestStep{ 401 resource.TestStep{ 402 Config: testAccAWSELBConfigIdleTimeout, 403 Check: resource.ComposeTestCheckFunc( 404 testAccCheckAWSELBExists("aws_elb.bar", &conf), 405 resource.TestCheckResourceAttr( 406 "aws_elb.bar", "idle_timeout", "200", 407 ), 408 ), 409 }, 410 }, 411 }) 412 } 413 414 func TestAccAWSELBUpdate_Timeout(t *testing.T) { 415 resource.Test(t, resource.TestCase{ 416 PreCheck: func() { testAccPreCheck(t) }, 417 IDRefreshName: "aws_elb.bar", 418 Providers: testAccProviders, 419 CheckDestroy: testAccCheckAWSELBDestroy, 420 Steps: []resource.TestStep{ 421 resource.TestStep{ 422 Config: testAccAWSELBConfigIdleTimeout, 423 Check: resource.ComposeTestCheckFunc( 424 resource.TestCheckResourceAttr( 425 "aws_elb.bar", "idle_timeout", "200", 426 ), 427 ), 428 }, 429 resource.TestStep{ 430 Config: testAccAWSELBConfigIdleTimeout_update, 431 Check: resource.ComposeTestCheckFunc( 432 resource.TestCheckResourceAttr( 433 "aws_elb.bar", "idle_timeout", "400", 434 ), 435 ), 436 }, 437 }, 438 }) 439 } 440 441 func TestAccAWSELB_ConnectionDraining(t *testing.T) { 442 resource.Test(t, resource.TestCase{ 443 PreCheck: func() { testAccPreCheck(t) }, 444 IDRefreshName: "aws_elb.bar", 445 Providers: testAccProviders, 446 CheckDestroy: testAccCheckAWSELBDestroy, 447 Steps: []resource.TestStep{ 448 resource.TestStep{ 449 Config: testAccAWSELBConfigConnectionDraining, 450 Check: resource.ComposeTestCheckFunc( 451 resource.TestCheckResourceAttr( 452 "aws_elb.bar", "connection_draining", "true", 453 ), 454 resource.TestCheckResourceAttr( 455 "aws_elb.bar", "connection_draining_timeout", "400", 456 ), 457 ), 458 }, 459 }, 460 }) 461 } 462 463 func TestAccAWSELBUpdate_ConnectionDraining(t *testing.T) { 464 resource.Test(t, resource.TestCase{ 465 PreCheck: func() { testAccPreCheck(t) }, 466 IDRefreshName: "aws_elb.bar", 467 Providers: testAccProviders, 468 CheckDestroy: testAccCheckAWSELBDestroy, 469 Steps: []resource.TestStep{ 470 resource.TestStep{ 471 Config: testAccAWSELBConfigConnectionDraining, 472 Check: resource.ComposeTestCheckFunc( 473 resource.TestCheckResourceAttr( 474 "aws_elb.bar", "connection_draining", "true", 475 ), 476 resource.TestCheckResourceAttr( 477 "aws_elb.bar", "connection_draining_timeout", "400", 478 ), 479 ), 480 }, 481 resource.TestStep{ 482 Config: testAccAWSELBConfigConnectionDraining_update_timeout, 483 Check: resource.ComposeTestCheckFunc( 484 resource.TestCheckResourceAttr( 485 "aws_elb.bar", "connection_draining", "true", 486 ), 487 resource.TestCheckResourceAttr( 488 "aws_elb.bar", "connection_draining_timeout", "600", 489 ), 490 ), 491 }, 492 resource.TestStep{ 493 Config: testAccAWSELBConfigConnectionDraining_update_disable, 494 Check: resource.ComposeTestCheckFunc( 495 resource.TestCheckResourceAttr( 496 "aws_elb.bar", "connection_draining", "false", 497 ), 498 ), 499 }, 500 }, 501 }) 502 } 503 504 func TestAccAWSELB_SecurityGroups(t *testing.T) { 505 resource.Test(t, resource.TestCase{ 506 PreCheck: func() { testAccPreCheck(t) }, 507 IDRefreshName: "aws_elb.bar", 508 Providers: testAccProviders, 509 CheckDestroy: testAccCheckAWSELBDestroy, 510 Steps: []resource.TestStep{ 511 resource.TestStep{ 512 Config: testAccAWSELBConfig, 513 Check: resource.ComposeTestCheckFunc( 514 // ELBs get a default security group 515 resource.TestCheckResourceAttr( 516 "aws_elb.bar", "security_groups.#", "1", 517 ), 518 ), 519 }, 520 resource.TestStep{ 521 Config: testAccAWSELBConfigSecurityGroups, 522 Check: resource.ComposeTestCheckFunc( 523 // Count should still be one as we swap in a custom security group 524 resource.TestCheckResourceAttr( 525 "aws_elb.bar", "security_groups.#", "1", 526 ), 527 ), 528 }, 529 }, 530 }) 531 } 532 533 // Unit test for listeners hash 534 func TestResourceAwsElbListenerHash(t *testing.T) { 535 cases := map[string]struct { 536 Left map[string]interface{} 537 Right map[string]interface{} 538 Match bool 539 }{ 540 "protocols are case insensitive": { 541 map[string]interface{}{ 542 "instance_port": 80, 543 "instance_protocol": "TCP", 544 "lb_port": 80, 545 "lb_protocol": "TCP", 546 }, 547 map[string]interface{}{ 548 "instance_port": 80, 549 "instance_protocol": "Tcp", 550 "lb_port": 80, 551 "lb_protocol": "tcP", 552 }, 553 true, 554 }, 555 } 556 557 for tn, tc := range cases { 558 leftHash := resourceAwsElbListenerHash(tc.Left) 559 rightHash := resourceAwsElbListenerHash(tc.Right) 560 if leftHash == rightHash != tc.Match { 561 t.Fatalf("%s: expected match: %t, but did not get it", tn, tc.Match) 562 } 563 } 564 } 565 566 func TestResourceAWSELB_validateElbNameCannotBeginWithHyphen(t *testing.T) { 567 var elbName = "-Testing123" 568 _, errors := validateElbName(elbName, "SampleKey") 569 570 if len(errors) != 1 { 571 t.Fatalf("Expected the ELB Name to trigger a validation error") 572 } 573 } 574 575 func TestResourceAWSELB_validateElbNameCannotBeLongerThen32Characters(t *testing.T) { 576 var elbName = "Testing123dddddddddddddddddddvvvv" 577 _, errors := validateElbName(elbName, "SampleKey") 578 579 if len(errors) != 1 { 580 t.Fatalf("Expected the ELB Name to trigger a validation error") 581 } 582 } 583 584 func TestResourceAWSELB_validateElbNameCannotHaveSpecialCharacters(t *testing.T) { 585 var elbName = "Testing123%%" 586 _, errors := validateElbName(elbName, "SampleKey") 587 588 if len(errors) != 1 { 589 t.Fatalf("Expected the ELB Name to trigger a validation error") 590 } 591 } 592 593 func TestResourceAWSELB_validateElbNameCannotEndWithHyphen(t *testing.T) { 594 var elbName = "Testing123-" 595 _, errors := validateElbName(elbName, "SampleKey") 596 597 if len(errors) != 1 { 598 t.Fatalf("Expected the ELB Name to trigger a validation error") 599 } 600 } 601 602 func TestResourceAWSELB_validateAccessLogsInterval(t *testing.T) { 603 type testCases struct { 604 Value int 605 ErrCount int 606 } 607 608 invalidCases := []testCases{ 609 { 610 Value: 0, 611 ErrCount: 1, 612 }, 613 { 614 Value: 10, 615 ErrCount: 1, 616 }, 617 { 618 Value: -1, 619 ErrCount: 1, 620 }, 621 } 622 623 for _, tc := range invalidCases { 624 _, errors := validateAccessLogsInterval(tc.Value, "interval") 625 if len(errors) != tc.ErrCount { 626 t.Fatalf("Expected %q to trigger a validation error.", tc.Value) 627 } 628 } 629 630 } 631 632 func TestResourceAWSELB_validateListenerProtocol(t *testing.T) { 633 type testCases struct { 634 Value string 635 ErrCount int 636 } 637 638 invalidCases := []testCases{ 639 { 640 Value: "", 641 ErrCount: 1, 642 }, 643 { 644 Value: "incorrect", 645 ErrCount: 1, 646 }, 647 { 648 Value: "HTTP:", 649 ErrCount: 1, 650 }, 651 } 652 653 for _, tc := range invalidCases { 654 _, errors := validateListenerProtocol(tc.Value, "protocol") 655 if len(errors) != tc.ErrCount { 656 t.Fatalf("Expected %q to trigger a validation error.", tc.Value) 657 } 658 } 659 660 validCases := []testCases{ 661 { 662 Value: "TCP", 663 ErrCount: 0, 664 }, 665 { 666 Value: "ssl", 667 ErrCount: 0, 668 }, 669 { 670 Value: "HTTP", 671 ErrCount: 0, 672 }, 673 } 674 675 for _, tc := range validCases { 676 _, errors := validateListenerProtocol(tc.Value, "protocol") 677 if len(errors) != tc.ErrCount { 678 t.Fatalf("Expected %q not to trigger a validation error.", tc.Value) 679 } 680 } 681 } 682 683 func TestResourceAWSELB_validateHealthCheckTarget(t *testing.T) { 684 type testCase struct { 685 Value string 686 ErrCount int 687 } 688 689 randomRunes := func(n int) string { 690 rand.Seed(time.Now().UTC().UnixNano()) 691 692 // A complete set of modern Katakana characters. 693 runes := []rune("アイウエオ" + 694 "カキクケコガギグゲゴサシスセソザジズゼゾ" + 695 "タチツテトダヂヅデドナニヌネノハヒフヘホ" + 696 "バビブベボパピプペポマミムメモヤユヨラリ" + 697 "ルレロワヰヱヲン") 698 699 s := make([]rune, n) 700 for i := range s { 701 s[i] = runes[rand.Intn(len(runes))] 702 } 703 return string(s) 704 } 705 706 validCases := []testCase{ 707 { 708 Value: "TCP:1234", 709 ErrCount: 0, 710 }, 711 { 712 Value: "http:80/test", 713 ErrCount: 0, 714 }, 715 { 716 Value: fmt.Sprintf("HTTP:8080/%s", randomRunes(5)), 717 ErrCount: 0, 718 }, 719 { 720 Value: "SSL:8080", 721 ErrCount: 0, 722 }, 723 } 724 725 for _, tc := range validCases { 726 _, errors := validateHeathCheckTarget(tc.Value, "target") 727 if len(errors) != tc.ErrCount { 728 t.Fatalf("Expected %q not to trigger a validation error.", tc.Value) 729 } 730 } 731 732 invalidCases := []testCase{ 733 { 734 Value: "", 735 ErrCount: 1, 736 }, 737 { 738 Value: "TCP:", 739 ErrCount: 1, 740 }, 741 { 742 Value: "TCP:1234/", 743 ErrCount: 1, 744 }, 745 { 746 Value: "SSL:8080/", 747 ErrCount: 1, 748 }, 749 { 750 Value: "HTTP:8080", 751 ErrCount: 1, 752 }, 753 { 754 Value: "incorrect-value", 755 ErrCount: 1, 756 }, 757 { 758 Value: "TCP:123456", 759 ErrCount: 1, 760 }, 761 { 762 Value: "incorrect:80/", 763 ErrCount: 1, 764 }, 765 { 766 Value: fmt.Sprintf("HTTP:8080/%s%s", randomString(512), randomRunes(512)), 767 ErrCount: 1, 768 }, 769 } 770 771 for _, tc := range invalidCases { 772 _, errors := validateHeathCheckTarget(tc.Value, "target") 773 if len(errors) != tc.ErrCount { 774 t.Fatalf("Expected %q to trigger a validation error.", tc.Value) 775 } 776 } 777 } 778 779 func testAccCheckAWSELBDestroy(s *terraform.State) error { 780 conn := testAccProvider.Meta().(*AWSClient).elbconn 781 782 for _, rs := range s.RootModule().Resources { 783 if rs.Type != "aws_elb" { 784 continue 785 } 786 787 describe, err := conn.DescribeLoadBalancers(&elb.DescribeLoadBalancersInput{ 788 LoadBalancerNames: []*string{aws.String(rs.Primary.ID)}, 789 }) 790 791 if err == nil { 792 if len(describe.LoadBalancerDescriptions) != 0 && 793 *describe.LoadBalancerDescriptions[0].LoadBalancerName == rs.Primary.ID { 794 return fmt.Errorf("ELB still exists") 795 } 796 } 797 798 // Verify the error 799 providerErr, ok := err.(awserr.Error) 800 if !ok { 801 return err 802 } 803 804 if providerErr.Code() != "LoadBalancerNotFound" { 805 return fmt.Errorf("Unexpected error: %s", err) 806 } 807 } 808 809 return nil 810 } 811 812 func testAccCheckAWSELBAttributes(conf *elb.LoadBalancerDescription) resource.TestCheckFunc { 813 return func(s *terraform.State) error { 814 zones := []string{"us-west-2a", "us-west-2b", "us-west-2c"} 815 azs := make([]string, 0, len(conf.AvailabilityZones)) 816 for _, x := range conf.AvailabilityZones { 817 azs = append(azs, *x) 818 } 819 sort.StringSlice(azs).Sort() 820 if !reflect.DeepEqual(azs, zones) { 821 return fmt.Errorf("bad availability_zones") 822 } 823 824 l := elb.Listener{ 825 InstancePort: aws.Int64(int64(8000)), 826 InstanceProtocol: aws.String("HTTP"), 827 LoadBalancerPort: aws.Int64(int64(80)), 828 Protocol: aws.String("HTTP"), 829 } 830 831 if !reflect.DeepEqual(conf.ListenerDescriptions[0].Listener, &l) { 832 return fmt.Errorf( 833 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 834 conf.ListenerDescriptions[0].Listener, 835 l) 836 } 837 838 if *conf.DNSName == "" { 839 return fmt.Errorf("empty dns_name") 840 } 841 842 return nil 843 } 844 } 845 846 func testAccCheckAWSELBAttributesHealthCheck(conf *elb.LoadBalancerDescription) resource.TestCheckFunc { 847 return func(s *terraform.State) error { 848 zones := []string{"us-west-2a", "us-west-2b", "us-west-2c"} 849 azs := make([]string, 0, len(conf.AvailabilityZones)) 850 for _, x := range conf.AvailabilityZones { 851 azs = append(azs, *x) 852 } 853 sort.StringSlice(azs).Sort() 854 if !reflect.DeepEqual(azs, zones) { 855 return fmt.Errorf("bad availability_zones") 856 } 857 858 check := &elb.HealthCheck{ 859 Timeout: aws.Int64(int64(30)), 860 UnhealthyThreshold: aws.Int64(int64(5)), 861 HealthyThreshold: aws.Int64(int64(5)), 862 Interval: aws.Int64(int64(60)), 863 Target: aws.String("HTTP:8000/"), 864 } 865 866 if !reflect.DeepEqual(conf.HealthCheck, check) { 867 return fmt.Errorf( 868 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 869 conf.HealthCheck, 870 check) 871 } 872 873 if *conf.DNSName == "" { 874 return fmt.Errorf("empty dns_name") 875 } 876 877 return nil 878 } 879 } 880 881 func testAccCheckAWSELBExists(n string, res *elb.LoadBalancerDescription) resource.TestCheckFunc { 882 return func(s *terraform.State) error { 883 rs, ok := s.RootModule().Resources[n] 884 if !ok { 885 return fmt.Errorf("Not found: %s", n) 886 } 887 888 if rs.Primary.ID == "" { 889 return fmt.Errorf("No ELB ID is set") 890 } 891 892 conn := testAccProvider.Meta().(*AWSClient).elbconn 893 894 describe, err := conn.DescribeLoadBalancers(&elb.DescribeLoadBalancersInput{ 895 LoadBalancerNames: []*string{aws.String(rs.Primary.ID)}, 896 }) 897 898 if err != nil { 899 return err 900 } 901 902 if len(describe.LoadBalancerDescriptions) != 1 || 903 *describe.LoadBalancerDescriptions[0].LoadBalancerName != rs.Primary.ID { 904 return fmt.Errorf("ELB not found") 905 } 906 907 *res = *describe.LoadBalancerDescriptions[0] 908 909 // Confirm source_security_group_id for ELBs in a VPC 910 // See https://github.com/hashicorp/terraform/pull/3780 911 if res.VPCId != nil { 912 sgid := rs.Primary.Attributes["source_security_group_id"] 913 if sgid == "" { 914 return fmt.Errorf("Expected to find source_security_group_id for ELB, but was empty") 915 } 916 } 917 918 return nil 919 } 920 } 921 922 const testAccAWSELBConfig = ` 923 resource "aws_elb" "bar" { 924 availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"] 925 926 listener { 927 instance_port = 8000 928 instance_protocol = "http" 929 lb_port = 80 930 // Protocol should be case insensitive 931 lb_protocol = "HttP" 932 } 933 934 tags { 935 bar = "baz" 936 } 937 938 cross_zone_load_balancing = true 939 } 940 ` 941 942 const testAccAWSELBFullRangeOfCharacters = ` 943 resource "aws_elb" "foo" { 944 name = "%s" 945 availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"] 946 947 listener { 948 instance_port = 8000 949 instance_protocol = "http" 950 lb_port = 80 951 lb_protocol = "http" 952 } 953 } 954 ` 955 956 const testAccAWSELBAccessLogs = ` 957 resource "aws_elb" "foo" { 958 availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"] 959 960 listener { 961 instance_port = 8000 962 instance_protocol = "http" 963 lb_port = 80 964 lb_protocol = "http" 965 } 966 } 967 ` 968 const testAccAWSELBAccessLogsOn = ` 969 # an S3 bucket configured for Access logs 970 # The 797873946194 is the AWS ID for us-west-2, so this test 971 # must be ran in us-west-2 972 resource "aws_s3_bucket" "acceslogs_bucket" { 973 bucket = "terraform-access-logs-bucket" 974 acl = "private" 975 force_destroy = true 976 policy = <<EOF 977 { 978 "Id": "Policy1446577137248", 979 "Statement": [ 980 { 981 "Action": "s3:PutObject", 982 "Effect": "Allow", 983 "Principal": { 984 "AWS": "arn:aws:iam::797873946194:root" 985 }, 986 "Resource": "arn:aws:s3:::terraform-access-logs-bucket/*", 987 "Sid": "Stmt1446575236270" 988 } 989 ], 990 "Version": "2012-10-17" 991 } 992 EOF 993 } 994 995 resource "aws_elb" "foo" { 996 availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"] 997 998 listener { 999 instance_port = 8000 1000 instance_protocol = "http" 1001 lb_port = 80 1002 lb_protocol = "http" 1003 } 1004 1005 access_logs { 1006 interval = 5 1007 bucket = "${aws_s3_bucket.acceslogs_bucket.bucket}" 1008 } 1009 } 1010 ` 1011 1012 const testAccAWSELBGeneratedName = ` 1013 resource "aws_elb" "foo" { 1014 availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"] 1015 1016 listener { 1017 instance_port = 8000 1018 instance_protocol = "http" 1019 lb_port = 80 1020 lb_protocol = "http" 1021 } 1022 } 1023 ` 1024 1025 const testAccAWSELBConfig_AvailabilityZonesUpdate = ` 1026 resource "aws_elb" "bar" { 1027 availability_zones = ["us-west-2a", "us-west-2b"] 1028 1029 listener { 1030 instance_port = 8000 1031 instance_protocol = "http" 1032 lb_port = 80 1033 lb_protocol = "http" 1034 } 1035 } 1036 ` 1037 1038 const testAccAWSELBConfig_TagUpdate = ` 1039 resource "aws_elb" "bar" { 1040 availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"] 1041 1042 listener { 1043 instance_port = 8000 1044 instance_protocol = "http" 1045 lb_port = 80 1046 lb_protocol = "http" 1047 } 1048 1049 tags { 1050 foo = "bar" 1051 new = "type" 1052 } 1053 1054 cross_zone_load_balancing = true 1055 } 1056 ` 1057 1058 const testAccAWSELBConfigNewInstance = ` 1059 resource "aws_elb" "bar" { 1060 availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"] 1061 1062 listener { 1063 instance_port = 8000 1064 instance_protocol = "http" 1065 lb_port = 80 1066 lb_protocol = "http" 1067 } 1068 1069 instances = ["${aws_instance.foo.id}"] 1070 } 1071 1072 resource "aws_instance" "foo" { 1073 # us-west-2 1074 ami = "ami-043a5034" 1075 instance_type = "t1.micro" 1076 } 1077 ` 1078 1079 const testAccAWSELBConfigListenerSSLCertificateId = ` 1080 resource "aws_elb" "bar" { 1081 availability_zones = ["us-west-2a"] 1082 1083 listener { 1084 instance_port = 8000 1085 instance_protocol = "http" 1086 ssl_certificate_id = "%s" 1087 lb_port = 443 1088 lb_protocol = "https" 1089 } 1090 } 1091 ` 1092 1093 const testAccAWSELBConfigHealthCheck = ` 1094 resource "aws_elb" "bar" { 1095 availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"] 1096 1097 listener { 1098 instance_port = 8000 1099 instance_protocol = "http" 1100 lb_port = 80 1101 lb_protocol = "http" 1102 } 1103 1104 health_check { 1105 healthy_threshold = 5 1106 unhealthy_threshold = 5 1107 target = "HTTP:8000/" 1108 interval = 60 1109 timeout = 30 1110 } 1111 } 1112 ` 1113 1114 const testAccAWSELBConfigHealthCheck_update = ` 1115 resource "aws_elb" "bar" { 1116 availability_zones = ["us-west-2a"] 1117 1118 listener { 1119 instance_port = 8000 1120 instance_protocol = "http" 1121 lb_port = 80 1122 lb_protocol = "http" 1123 } 1124 1125 health_check { 1126 healthy_threshold = 10 1127 unhealthy_threshold = 5 1128 target = "HTTP:8000/" 1129 interval = 60 1130 timeout = 30 1131 } 1132 } 1133 ` 1134 1135 const testAccAWSELBConfigListener_update = ` 1136 resource "aws_elb" "bar" { 1137 availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"] 1138 1139 listener { 1140 instance_port = 8080 1141 instance_protocol = "http" 1142 lb_port = 80 1143 lb_protocol = "http" 1144 } 1145 } 1146 ` 1147 1148 const testAccAWSELBConfigIdleTimeout = ` 1149 resource "aws_elb" "bar" { 1150 availability_zones = ["us-west-2a"] 1151 1152 listener { 1153 instance_port = 8000 1154 instance_protocol = "http" 1155 lb_port = 80 1156 lb_protocol = "http" 1157 } 1158 1159 idle_timeout = 200 1160 } 1161 ` 1162 1163 const testAccAWSELBConfigIdleTimeout_update = ` 1164 resource "aws_elb" "bar" { 1165 availability_zones = ["us-west-2a"] 1166 1167 listener { 1168 instance_port = 8000 1169 instance_protocol = "http" 1170 lb_port = 80 1171 lb_protocol = "http" 1172 } 1173 1174 idle_timeout = 400 1175 } 1176 ` 1177 1178 const testAccAWSELBConfigConnectionDraining = ` 1179 resource "aws_elb" "bar" { 1180 availability_zones = ["us-west-2a"] 1181 1182 listener { 1183 instance_port = 8000 1184 instance_protocol = "http" 1185 lb_port = 80 1186 lb_protocol = "http" 1187 } 1188 1189 connection_draining = true 1190 connection_draining_timeout = 400 1191 } 1192 ` 1193 1194 const testAccAWSELBConfigConnectionDraining_update_timeout = ` 1195 resource "aws_elb" "bar" { 1196 availability_zones = ["us-west-2a"] 1197 1198 listener { 1199 instance_port = 8000 1200 instance_protocol = "http" 1201 lb_port = 80 1202 lb_protocol = "http" 1203 } 1204 1205 connection_draining = true 1206 connection_draining_timeout = 600 1207 } 1208 ` 1209 1210 const testAccAWSELBConfigConnectionDraining_update_disable = ` 1211 resource "aws_elb" "bar" { 1212 availability_zones = ["us-west-2a"] 1213 1214 listener { 1215 instance_port = 8000 1216 instance_protocol = "http" 1217 lb_port = 80 1218 lb_protocol = "http" 1219 } 1220 1221 connection_draining = false 1222 } 1223 ` 1224 1225 const testAccAWSELBConfigSecurityGroups = ` 1226 resource "aws_elb" "bar" { 1227 availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"] 1228 1229 listener { 1230 instance_port = 8000 1231 instance_protocol = "http" 1232 lb_port = 80 1233 lb_protocol = "http" 1234 } 1235 1236 security_groups = ["${aws_security_group.bar.id}"] 1237 } 1238 1239 resource "aws_security_group" "bar" { 1240 ingress { 1241 protocol = "tcp" 1242 from_port = 80 1243 to_port = 80 1244 cidr_blocks = ["0.0.0.0/0"] 1245 } 1246 1247 tags { 1248 Name = "tf_elb_sg_test" 1249 } 1250 } 1251 ` 1252 1253 // This IAM Server config is lifted from 1254 // builtin/providers/aws/resource_aws_iam_server_certificate_test.go 1255 func testAccELBIAMServerCertConfig(certName string) string { 1256 return fmt.Sprintf(` 1257 resource "aws_iam_server_certificate" "test_cert" { 1258 name = "%s" 1259 certificate_body = <<EOF 1260 -----BEGIN CERTIFICATE----- 1261 MIIDBjCCAe4CCQCGWwBmOiHQdTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB 1262 VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0 1263 cyBQdHkgTHRkMB4XDTE2MDYyMTE2MzM0MVoXDTE3MDYyMTE2MzM0MVowRTELMAkG 1264 A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0 1265 IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB 1266 AL+LFlsCJG5txZp4yuu+lQnuUrgBXRG+irQqcTXlV91Bp5hpmRIyhnGCtWxxDBUL 1267 xrh4WN3VV/0jDzKT976oLgOy3hj56Cdqf+JlZ1qgMN5bHB3mm3aVWnrnsLbBsfwZ 1268 SEbk3Kht/cE1nK2toNVW+rznS3m+eoV3Zn/DUNwGlZr42hGNs6ETn2jURY78ETqR 1269 mW47xvjf86eIo7vULHJaY6xyarPqkL8DZazOmvY06hUGvGwGBny7gugfXqDG+I8n 1270 cPBsGJGSAmHmVV8o0RCB9UjY+TvSMQRpEDoVlvyrGuglsD8to/4+7UcsuDGlRYN6 1271 jmIOC37mOi/jwRfWL1YUa4MCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAPDxTH0oQ 1272 JjKXoJgkmQxurB81RfnK/NrswJVzWbOv6ejcbhwh+/ZgJTMc15BrYcxU6vUW1V/i 1273 Z7APU0qJ0icECACML+a2fRI7YdLCTiPIOmY66HY8MZHAn3dGjU5TeiUflC0n0zkP 1274 mxKJe43kcYLNDItbfvUDo/GoxTXrC3EFVZyU0RhFzoVJdODlTHXMVFCzcbQEBrBJ 1275 xKdShCEc8nFMneZcGFeEU488ntZoWzzms8/QpYrKa5S0Sd7umEU2Kwu4HTkvUFg/ 1276 CqDUFjhydXxYRsxXBBrEiLOE5BdtJR1sH/QHxIJe23C9iHI2nS1NbLziNEApLwC4 1277 GnSud83VUo9G9w== 1278 -----END CERTIFICATE----- 1279 EOF 1280 1281 private_key = <<EOF 1282 -----BEGIN RSA PRIVATE KEY----- 1283 MIIEowIBAAKCAQEAv4sWWwIkbm3FmnjK676VCe5SuAFdEb6KtCpxNeVX3UGnmGmZ 1284 EjKGcYK1bHEMFQvGuHhY3dVX/SMPMpP3vqguA7LeGPnoJ2p/4mVnWqAw3lscHeab 1285 dpVaeuewtsGx/BlIRuTcqG39wTWcra2g1Vb6vOdLeb56hXdmf8NQ3AaVmvjaEY2z 1286 oROfaNRFjvwROpGZbjvG+N/zp4iju9QsclpjrHJqs+qQvwNlrM6a9jTqFQa8bAYG 1287 fLuC6B9eoMb4jydw8GwYkZICYeZVXyjREIH1SNj5O9IxBGkQOhWW/Ksa6CWwPy2j 1288 /j7tRyy4MaVFg3qOYg4LfuY6L+PBF9YvVhRrgwIDAQABAoIBAFqJ4h1Om+3e0WK8 1289 6h4YzdYN4ue7LUTv7hxPW4gASlH5cMDoWURywX3yLNN/dBiWom4b5NWmvJqY8dwU 1290 eSyTznxNFhJ0PjozaxOWnw4FXlQceOPhV2bsHgKudadNU1Y4lSN9lpe+tg2Xy+GE 1291 ituM66RTKCf502w3DioiJpx6OEkxuhrnsQAWNcGB0MnTukm2f+629V+04R5MT5V1 1292 nY+5Phx2BpHgYzWBKh6Px1puu7xFv5SMQda1ndlPIKb4cNp0yYn+1lHNjbOE7QL/ 1293 oEpWgrauS5Zk/APK33v/p3wVYHrKocIFHlPiCW0uIJJLsOZDY8pQXpTlc+/xGLLy 1294 WBu4boECgYEA6xO+1UNh6ndJ3xGuNippH+ucTi/uq1+0tG1bd63v+75tn5l4LyY2 1295 CWHRaWVlVn+WnDslkQTJzFD68X+9M7Cc4oP6WnhTyPamG7HlGv5JxfFHTC9GOKmz 1296 sSc624BDmqYJ7Xzyhe5kc3iHzqG/L72ZF1aijZdrodQMSY1634UX6aECgYEA0Jdr 1297 cBPSN+mgmEY6ogN5h7sO5uNV3TQQtW2IslfWZn6JhSRF4Rf7IReng48CMy9ZhFBy 1298 Q7H2I1pDGjEC9gQHhgVfm+FyMSVqXfCHEW/97pvvu9ougHA0MhPep1twzTGrqg+K 1299 f3PLW8hVkGyCrTfWgbDlPsHgsocA/wTaQOheaqMCgYBat5z+WemQfQZh8kXDm2xE 1300 KD2Cota9BcsLkeQpdFNXWC6f167cqydRSZFx1fJchhJOKjkeFLX3hgzBY6VVLEPu 1301 2jWj8imLNTv3Fhiu6RD5NVppWRkFRuAUbmo1SPNN2+Oa5YwGCXB0a0Alip/oQYex 1302 zPogIB4mLlmrjNCtL4SB4QKBgCEHKMrZSJrz0irqS9RlanPUaZqjenAJE3A2xMNA 1303 Z0FZXdsIEEyA6JGn1i1dkoKaR7lMp5sSbZ/RZfiatBZSMwLEjQv4mYUwoHP5Ztma 1304 +wEyDbaX6G8L1Sfsv3+OWgETkVPfHBXsNtH0mZ/BnrtgsQVeBh52wmZiPAUlNo26 1305 fWCzAoGBAJOjqovLelLWzyQGqPFx/MwuI56UFXd1CmFlCIvF2WxCFmk3tlExoCN1 1306 HqSpt92vsgYgV7+lAb4U7Uy/v012gwiU1LK+vyAE9geo3pTjG73BNzG4H547xtbY 1307 dg+Sd4Wjm89UQoUUoiIcstY7FPbqfBtYKfh4RYHAHV2BwDFqzZCM 1308 -----END RSA PRIVATE KEY----- 1309 EOF 1310 } 1311 1312 resource "aws_elb" "bar" { 1313 availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"] 1314 1315 listener { 1316 instance_port = 8000 1317 instance_protocol = "https" 1318 lb_port = 80 1319 // Protocol should be case insensitive 1320 lb_protocol = "HttPs" 1321 ssl_certificate_id = "${aws_iam_server_certificate.test_cert.arn}" 1322 } 1323 1324 tags { 1325 bar = "baz" 1326 } 1327 1328 cross_zone_load_balancing = true 1329 } 1330 `, certName) 1331 }