github.com/profects/terraform@v0.9.0-beta1.0.20170227135739-92d4809db30d/builtin/providers/aws/resource_aws_instance_test.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "reflect" 6 "testing" 7 8 "github.com/aws/aws-sdk-go/aws" 9 "github.com/aws/aws-sdk-go/aws/awserr" 10 "github.com/aws/aws-sdk-go/service/ec2" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/helper/schema" 13 "github.com/hashicorp/terraform/terraform" 14 ) 15 16 func TestAccAWSInstance_basic(t *testing.T) { 17 var v ec2.Instance 18 var vol *ec2.Volume 19 20 testCheck := func(*terraform.State) error { 21 if *v.Placement.AvailabilityZone != "us-west-2a" { 22 return fmt.Errorf("bad availability zone: %#v", *v.Placement.AvailabilityZone) 23 } 24 25 if len(v.SecurityGroups) == 0 { 26 return fmt.Errorf("no security groups: %#v", v.SecurityGroups) 27 } 28 if *v.SecurityGroups[0].GroupName != "tf_test_foo" { 29 return fmt.Errorf("no security groups: %#v", v.SecurityGroups) 30 } 31 32 return nil 33 } 34 35 resource.Test(t, resource.TestCase{ 36 PreCheck: func() { testAccPreCheck(t) }, 37 38 // We ignore security groups because even with EC2 classic 39 // we'll import as VPC security groups, which is fine. We verify 40 // VPC security group import in other tests 41 IDRefreshName: "aws_instance.foo", 42 IDRefreshIgnore: []string{"security_groups", "vpc_security_group_ids"}, 43 44 Providers: testAccProviders, 45 CheckDestroy: testAccCheckInstanceDestroy, 46 Steps: []resource.TestStep{ 47 // Create a volume to cover #1249 48 { 49 // Need a resource in this config so the provisioner will be available 50 Config: testAccInstanceConfig_pre, 51 Check: func(*terraform.State) error { 52 conn := testAccProvider.Meta().(*AWSClient).ec2conn 53 var err error 54 vol, err = conn.CreateVolume(&ec2.CreateVolumeInput{ 55 AvailabilityZone: aws.String("us-west-2a"), 56 Size: aws.Int64(int64(5)), 57 }) 58 return err 59 }, 60 }, 61 62 { 63 Config: testAccInstanceConfig, 64 Check: resource.ComposeTestCheckFunc( 65 testAccCheckInstanceExists( 66 "aws_instance.foo", &v), 67 testCheck, 68 resource.TestCheckResourceAttr( 69 "aws_instance.foo", 70 "user_data", 71 "3dc39dda39be1205215e776bad998da361a5955d"), 72 resource.TestCheckResourceAttr( 73 "aws_instance.foo", "ebs_block_device.#", "0"), 74 ), 75 }, 76 77 // We repeat the exact same test so that we can be sure 78 // that the user data hash stuff is working without generating 79 // an incorrect diff. 80 { 81 Config: testAccInstanceConfig, 82 Check: resource.ComposeTestCheckFunc( 83 testAccCheckInstanceExists( 84 "aws_instance.foo", &v), 85 testCheck, 86 resource.TestCheckResourceAttr( 87 "aws_instance.foo", 88 "user_data", 89 "3dc39dda39be1205215e776bad998da361a5955d"), 90 resource.TestCheckResourceAttr( 91 "aws_instance.foo", "ebs_block_device.#", "0"), 92 ), 93 }, 94 95 // Clean up volume created above 96 { 97 Config: testAccInstanceConfig, 98 Check: func(*terraform.State) error { 99 conn := testAccProvider.Meta().(*AWSClient).ec2conn 100 _, err := conn.DeleteVolume(&ec2.DeleteVolumeInput{VolumeId: vol.VolumeId}) 101 return err 102 }, 103 }, 104 }, 105 }) 106 } 107 108 func TestAccAWSInstance_GP2IopsDevice(t *testing.T) { 109 var v ec2.Instance 110 111 testCheck := func() resource.TestCheckFunc { 112 return func(*terraform.State) error { 113 114 // Map out the block devices by name, which should be unique. 115 blockDevices := make(map[string]*ec2.InstanceBlockDeviceMapping) 116 for _, blockDevice := range v.BlockDeviceMappings { 117 blockDevices[*blockDevice.DeviceName] = blockDevice 118 } 119 120 // Check if the root block device exists. 121 if _, ok := blockDevices["/dev/sda1"]; !ok { 122 return fmt.Errorf("block device doesn't exist: /dev/sda1") 123 } 124 125 return nil 126 } 127 } 128 129 resource.Test(t, resource.TestCase{ 130 PreCheck: func() { testAccPreCheck(t) }, 131 IDRefreshName: "aws_instance.foo", 132 IDRefreshIgnore: []string{ 133 "ephemeral_block_device", "user_data", "security_groups", "vpc_security_groups"}, 134 Providers: testAccProviders, 135 CheckDestroy: testAccCheckInstanceDestroy, 136 Steps: []resource.TestStep{ 137 { 138 Config: testAccInstanceGP2IopsDevice, 139 //Config: testAccInstanceConfigBlockDevices, 140 Check: resource.ComposeTestCheckFunc( 141 testAccCheckInstanceExists( 142 "aws_instance.foo", &v), 143 resource.TestCheckResourceAttr( 144 "aws_instance.foo", "root_block_device.#", "1"), 145 resource.TestCheckResourceAttr( 146 "aws_instance.foo", "root_block_device.0.volume_size", "11"), 147 resource.TestCheckResourceAttr( 148 "aws_instance.foo", "root_block_device.0.volume_type", "gp2"), 149 resource.TestCheckResourceAttr( 150 "aws_instance.foo", "root_block_device.0.iops", "100"), 151 testCheck(), 152 ), 153 }, 154 }, 155 }) 156 } 157 158 func TestAccAWSInstance_blockDevices(t *testing.T) { 159 var v ec2.Instance 160 161 testCheck := func() resource.TestCheckFunc { 162 return func(*terraform.State) error { 163 164 // Map out the block devices by name, which should be unique. 165 blockDevices := make(map[string]*ec2.InstanceBlockDeviceMapping) 166 for _, blockDevice := range v.BlockDeviceMappings { 167 blockDevices[*blockDevice.DeviceName] = blockDevice 168 } 169 170 // Check if the root block device exists. 171 if _, ok := blockDevices["/dev/sda1"]; !ok { 172 return fmt.Errorf("block device doesn't exist: /dev/sda1") 173 } 174 175 // Check if the secondary block device exists. 176 if _, ok := blockDevices["/dev/sdb"]; !ok { 177 return fmt.Errorf("block device doesn't exist: /dev/sdb") 178 } 179 180 // Check if the third block device exists. 181 if _, ok := blockDevices["/dev/sdc"]; !ok { 182 return fmt.Errorf("block device doesn't exist: /dev/sdc") 183 } 184 185 // Check if the encrypted block device exists 186 if _, ok := blockDevices["/dev/sdd"]; !ok { 187 return fmt.Errorf("block device doesn't exist: /dev/sdd") 188 } 189 190 return nil 191 } 192 } 193 194 resource.Test(t, resource.TestCase{ 195 PreCheck: func() { testAccPreCheck(t) }, 196 IDRefreshName: "aws_instance.foo", 197 IDRefreshIgnore: []string{ 198 "ephemeral_block_device", "security_groups", "vpc_security_groups"}, 199 Providers: testAccProviders, 200 CheckDestroy: testAccCheckInstanceDestroy, 201 Steps: []resource.TestStep{ 202 { 203 Config: testAccInstanceConfigBlockDevices, 204 Check: resource.ComposeTestCheckFunc( 205 testAccCheckInstanceExists( 206 "aws_instance.foo", &v), 207 resource.TestCheckResourceAttr( 208 "aws_instance.foo", "root_block_device.#", "1"), 209 resource.TestCheckResourceAttr( 210 "aws_instance.foo", "root_block_device.0.volume_size", "11"), 211 resource.TestCheckResourceAttr( 212 "aws_instance.foo", "root_block_device.0.volume_type", "gp2"), 213 resource.TestCheckResourceAttr( 214 "aws_instance.foo", "ebs_block_device.#", "3"), 215 resource.TestCheckResourceAttr( 216 "aws_instance.foo", "ebs_block_device.2576023345.device_name", "/dev/sdb"), 217 resource.TestCheckResourceAttr( 218 "aws_instance.foo", "ebs_block_device.2576023345.volume_size", "9"), 219 resource.TestCheckResourceAttr( 220 "aws_instance.foo", "ebs_block_device.2576023345.volume_type", "standard"), 221 resource.TestCheckResourceAttr( 222 "aws_instance.foo", "ebs_block_device.2554893574.device_name", "/dev/sdc"), 223 resource.TestCheckResourceAttr( 224 "aws_instance.foo", "ebs_block_device.2554893574.volume_size", "10"), 225 resource.TestCheckResourceAttr( 226 "aws_instance.foo", "ebs_block_device.2554893574.volume_type", "io1"), 227 resource.TestCheckResourceAttr( 228 "aws_instance.foo", "ebs_block_device.2554893574.iops", "100"), 229 resource.TestCheckResourceAttr( 230 "aws_instance.foo", "ebs_block_device.2634515331.device_name", "/dev/sdd"), 231 resource.TestCheckResourceAttr( 232 "aws_instance.foo", "ebs_block_device.2634515331.encrypted", "true"), 233 resource.TestCheckResourceAttr( 234 "aws_instance.foo", "ebs_block_device.2634515331.volume_size", "12"), 235 resource.TestCheckResourceAttr( 236 "aws_instance.foo", "ephemeral_block_device.#", "1"), 237 resource.TestCheckResourceAttr( 238 "aws_instance.foo", "ephemeral_block_device.1692014856.device_name", "/dev/sde"), 239 resource.TestCheckResourceAttr( 240 "aws_instance.foo", "ephemeral_block_device.1692014856.virtual_name", "ephemeral0"), 241 testCheck(), 242 ), 243 }, 244 }, 245 }) 246 } 247 248 func TestAccAWSInstance_rootInstanceStore(t *testing.T) { 249 var v ec2.Instance 250 251 resource.Test(t, resource.TestCase{ 252 PreCheck: func() { testAccPreCheck(t) }, 253 IDRefreshName: "aws_instance.foo", 254 Providers: testAccProviders, 255 CheckDestroy: testAccCheckInstanceDestroy, 256 Steps: []resource.TestStep{ 257 { 258 Config: ` 259 resource "aws_instance" "foo" { 260 # us-west-2 261 # Amazon Linux HVM Instance Store 64-bit (2016.09.0) 262 # https://aws.amazon.com/amazon-linux-ami 263 ami = "ami-44c36524" 264 265 # Only certain instance types support ephemeral root instance stores. 266 # http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/InstanceStorage.html 267 instance_type = "m3.medium" 268 }`, 269 Check: resource.ComposeTestCheckFunc( 270 testAccCheckInstanceExists( 271 "aws_instance.foo", &v), 272 resource.TestCheckResourceAttr( 273 "aws_instance.foo", "ami", "ami-44c36524"), 274 resource.TestCheckResourceAttr( 275 "aws_instance.foo", "ebs_block_device.#", "0"), 276 resource.TestCheckResourceAttr( 277 "aws_instance.foo", "ebs_optimized", "false"), 278 resource.TestCheckResourceAttr( 279 "aws_instance.foo", "instance_type", "m3.medium"), 280 resource.TestCheckResourceAttr( 281 "aws_instance.foo", "root_block_device.#", "0"), 282 ), 283 }, 284 }, 285 }) 286 } 287 288 func TestAcctABSInstance_noAMIEphemeralDevices(t *testing.T) { 289 var v ec2.Instance 290 291 testCheck := func() resource.TestCheckFunc { 292 return func(*terraform.State) error { 293 294 // Map out the block devices by name, which should be unique. 295 blockDevices := make(map[string]*ec2.InstanceBlockDeviceMapping) 296 for _, blockDevice := range v.BlockDeviceMappings { 297 blockDevices[*blockDevice.DeviceName] = blockDevice 298 } 299 300 // Check if the root block device exists. 301 if _, ok := blockDevices["/dev/sda1"]; !ok { 302 return fmt.Errorf("block device doesn't exist: /dev/sda1") 303 } 304 305 // Check if the secondary block not exists. 306 if _, ok := blockDevices["/dev/sdb"]; ok { 307 return fmt.Errorf("block device exist: /dev/sdb") 308 } 309 310 // Check if the third block device not exists. 311 if _, ok := blockDevices["/dev/sdc"]; ok { 312 return fmt.Errorf("block device exist: /dev/sdc") 313 } 314 return nil 315 } 316 } 317 318 resource.Test(t, resource.TestCase{ 319 PreCheck: func() { testAccPreCheck(t) }, 320 IDRefreshName: "aws_instance.foo", 321 IDRefreshIgnore: []string{ 322 "ephemeral_block_device", "security_groups", "vpc_security_groups"}, 323 Providers: testAccProviders, 324 CheckDestroy: testAccCheckInstanceDestroy, 325 Steps: []resource.TestStep{ 326 { 327 Config: ` 328 resource "aws_instance" "foo" { 329 # us-west-2 330 ami = "ami-01f05461" // This AMI (Ubuntu) contains two ephemerals 331 332 instance_type = "c3.large" 333 334 root_block_device { 335 volume_type = "gp2" 336 volume_size = 11 337 } 338 ephemeral_block_device { 339 device_name = "/dev/sdb" 340 no_device = true 341 } 342 ephemeral_block_device { 343 device_name = "/dev/sdc" 344 no_device = true 345 } 346 }`, 347 Check: resource.ComposeTestCheckFunc( 348 testAccCheckInstanceExists( 349 "aws_instance.foo", &v), 350 resource.TestCheckResourceAttr( 351 "aws_instance.foo", "ami", "ami-01f05461"), 352 resource.TestCheckResourceAttr( 353 "aws_instance.foo", "ebs_optimized", "false"), 354 resource.TestCheckResourceAttr( 355 "aws_instance.foo", "instance_type", "c3.large"), 356 resource.TestCheckResourceAttr( 357 "aws_instance.foo", "root_block_device.#", "1"), 358 resource.TestCheckResourceAttr( 359 "aws_instance.foo", "root_block_device.0.volume_size", "11"), 360 resource.TestCheckResourceAttr( 361 "aws_instance.foo", "root_block_device.0.volume_type", "gp2"), 362 resource.TestCheckResourceAttr( 363 "aws_instance.foo", "ebs_block_device.#", "0"), 364 resource.TestCheckResourceAttr( 365 "aws_instance.foo", "ephemeral_block_device.#", "2"), 366 resource.TestCheckResourceAttr( 367 "aws_instance.foo", "ephemeral_block_device.172787947.device_name", "/dev/sdb"), 368 resource.TestCheckResourceAttr( 369 "aws_instance.foo", "ephemeral_block_device.172787947.no_device", "true"), 370 resource.TestCheckResourceAttr( 371 "aws_instance.foo", "ephemeral_block_device.3336996981.device_name", "/dev/sdc"), 372 resource.TestCheckResourceAttr( 373 "aws_instance.foo", "ephemeral_block_device.3336996981.no_device", "true"), 374 testCheck(), 375 ), 376 }, 377 }, 378 }) 379 } 380 381 func TestAccAWSInstance_sourceDestCheck(t *testing.T) { 382 var v ec2.Instance 383 384 testCheck := func(enabled bool) resource.TestCheckFunc { 385 return func(*terraform.State) error { 386 if v.SourceDestCheck == nil { 387 return fmt.Errorf("bad source_dest_check: got nil") 388 } 389 if *v.SourceDestCheck != enabled { 390 return fmt.Errorf("bad source_dest_check: %#v", *v.SourceDestCheck) 391 } 392 393 return nil 394 } 395 } 396 397 resource.Test(t, resource.TestCase{ 398 PreCheck: func() { testAccPreCheck(t) }, 399 IDRefreshName: "aws_instance.foo", 400 Providers: testAccProviders, 401 CheckDestroy: testAccCheckInstanceDestroy, 402 Steps: []resource.TestStep{ 403 { 404 Config: testAccInstanceConfigSourceDestDisable, 405 Check: resource.ComposeTestCheckFunc( 406 testAccCheckInstanceExists("aws_instance.foo", &v), 407 testCheck(false), 408 ), 409 }, 410 411 { 412 Config: testAccInstanceConfigSourceDestEnable, 413 Check: resource.ComposeTestCheckFunc( 414 testAccCheckInstanceExists("aws_instance.foo", &v), 415 testCheck(true), 416 ), 417 }, 418 419 { 420 Config: testAccInstanceConfigSourceDestDisable, 421 Check: resource.ComposeTestCheckFunc( 422 testAccCheckInstanceExists("aws_instance.foo", &v), 423 testCheck(false), 424 ), 425 }, 426 }, 427 }) 428 } 429 430 func TestAccAWSInstance_disableApiTermination(t *testing.T) { 431 var v ec2.Instance 432 433 checkDisableApiTermination := func(expected bool) resource.TestCheckFunc { 434 return func(*terraform.State) error { 435 conn := testAccProvider.Meta().(*AWSClient).ec2conn 436 r, err := conn.DescribeInstanceAttribute(&ec2.DescribeInstanceAttributeInput{ 437 InstanceId: v.InstanceId, 438 Attribute: aws.String("disableApiTermination"), 439 }) 440 if err != nil { 441 return err 442 } 443 got := *r.DisableApiTermination.Value 444 if got != expected { 445 return fmt.Errorf("expected: %t, got: %t", expected, got) 446 } 447 return nil 448 } 449 } 450 451 resource.Test(t, resource.TestCase{ 452 PreCheck: func() { testAccPreCheck(t) }, 453 IDRefreshName: "aws_instance.foo", 454 Providers: testAccProviders, 455 CheckDestroy: testAccCheckInstanceDestroy, 456 Steps: []resource.TestStep{ 457 { 458 Config: testAccInstanceConfigDisableAPITermination(true), 459 Check: resource.ComposeTestCheckFunc( 460 testAccCheckInstanceExists("aws_instance.foo", &v), 461 checkDisableApiTermination(true), 462 ), 463 }, 464 465 { 466 Config: testAccInstanceConfigDisableAPITermination(false), 467 Check: resource.ComposeTestCheckFunc( 468 testAccCheckInstanceExists("aws_instance.foo", &v), 469 checkDisableApiTermination(false), 470 ), 471 }, 472 }, 473 }) 474 } 475 476 func TestAccAWSInstance_vpc(t *testing.T) { 477 var v ec2.Instance 478 479 resource.Test(t, resource.TestCase{ 480 PreCheck: func() { testAccPreCheck(t) }, 481 IDRefreshName: "aws_instance.foo", 482 IDRefreshIgnore: []string{"associate_public_ip_address"}, 483 Providers: testAccProviders, 484 CheckDestroy: testAccCheckInstanceDestroy, 485 Steps: []resource.TestStep{ 486 { 487 Config: testAccInstanceConfigVPC, 488 Check: resource.ComposeTestCheckFunc( 489 testAccCheckInstanceExists( 490 "aws_instance.foo", &v), 491 resource.TestCheckResourceAttr( 492 "aws_instance.foo", 493 "user_data", 494 "562a3e32810edf6ff09994f050f12e799452379d"), 495 ), 496 }, 497 }, 498 }) 499 } 500 501 func TestAccAWSInstance_multipleRegions(t *testing.T) { 502 var v ec2.Instance 503 504 // record the initialized providers so that we can use them to 505 // check for the instances in each region 506 var providers []*schema.Provider 507 providerFactories := map[string]terraform.ResourceProviderFactory{ 508 "aws": func() (terraform.ResourceProvider, error) { 509 p := Provider() 510 providers = append(providers, p.(*schema.Provider)) 511 return p, nil 512 }, 513 } 514 515 resource.Test(t, resource.TestCase{ 516 PreCheck: func() { testAccPreCheck(t) }, 517 ProviderFactories: providerFactories, 518 CheckDestroy: testAccCheckInstanceDestroyWithProviders(&providers), 519 Steps: []resource.TestStep{ 520 { 521 Config: testAccInstanceConfigMultipleRegions, 522 Check: resource.ComposeTestCheckFunc( 523 testAccCheckInstanceExistsWithProviders( 524 "aws_instance.foo", &v, &providers), 525 testAccCheckInstanceExistsWithProviders( 526 "aws_instance.bar", &v, &providers), 527 ), 528 }, 529 }, 530 }) 531 } 532 533 func TestAccAWSInstance_NetworkInstanceSecurityGroups(t *testing.T) { 534 var v ec2.Instance 535 536 resource.Test(t, resource.TestCase{ 537 PreCheck: func() { testAccPreCheck(t) }, 538 IDRefreshName: "aws_instance.foo_instance", 539 IDRefreshIgnore: []string{"associate_public_ip_address"}, 540 Providers: testAccProviders, 541 CheckDestroy: testAccCheckInstanceDestroy, 542 Steps: []resource.TestStep{ 543 { 544 Config: testAccInstanceNetworkInstanceSecurityGroups, 545 Check: resource.ComposeTestCheckFunc( 546 testAccCheckInstanceExists( 547 "aws_instance.foo_instance", &v), 548 ), 549 }, 550 }, 551 }) 552 } 553 554 func TestAccAWSInstance_NetworkInstanceVPCSecurityGroupIDs(t *testing.T) { 555 var v ec2.Instance 556 557 resource.Test(t, resource.TestCase{ 558 PreCheck: func() { testAccPreCheck(t) }, 559 IDRefreshName: "aws_instance.foo_instance", 560 Providers: testAccProviders, 561 CheckDestroy: testAccCheckInstanceDestroy, 562 Steps: []resource.TestStep{ 563 { 564 Config: testAccInstanceNetworkInstanceVPCSecurityGroupIDs, 565 Check: resource.ComposeTestCheckFunc( 566 testAccCheckInstanceExists( 567 "aws_instance.foo_instance", &v), 568 resource.TestCheckResourceAttr( 569 "aws_instance.foo_instance", "security_groups.#", "0"), 570 resource.TestCheckResourceAttr( 571 "aws_instance.foo_instance", "vpc_security_group_ids.#", "1"), 572 ), 573 }, 574 }, 575 }) 576 } 577 578 func TestAccAWSInstance_tags(t *testing.T) { 579 var v ec2.Instance 580 581 resource.Test(t, resource.TestCase{ 582 PreCheck: func() { testAccPreCheck(t) }, 583 Providers: testAccProviders, 584 CheckDestroy: testAccCheckInstanceDestroy, 585 Steps: []resource.TestStep{ 586 { 587 Config: testAccCheckInstanceConfigTags, 588 Check: resource.ComposeTestCheckFunc( 589 testAccCheckInstanceExists("aws_instance.foo", &v), 590 testAccCheckTags(&v.Tags, "foo", "bar"), 591 // Guard against regression of https://github.com/hashicorp/terraform/issues/914 592 testAccCheckTags(&v.Tags, "#", ""), 593 ), 594 }, 595 596 { 597 Config: testAccCheckInstanceConfigTagsUpdate, 598 Check: resource.ComposeTestCheckFunc( 599 testAccCheckInstanceExists("aws_instance.foo", &v), 600 testAccCheckTags(&v.Tags, "foo", ""), 601 testAccCheckTags(&v.Tags, "bar", "baz"), 602 ), 603 }, 604 }, 605 }) 606 } 607 608 func TestAccAWSInstance_privateIP(t *testing.T) { 609 var v ec2.Instance 610 611 testCheckPrivateIP := func() resource.TestCheckFunc { 612 return func(*terraform.State) error { 613 if *v.PrivateIpAddress != "10.1.1.42" { 614 return fmt.Errorf("bad private IP: %s", *v.PrivateIpAddress) 615 } 616 617 return nil 618 } 619 } 620 621 resource.Test(t, resource.TestCase{ 622 PreCheck: func() { testAccPreCheck(t) }, 623 IDRefreshName: "aws_instance.foo", 624 Providers: testAccProviders, 625 CheckDestroy: testAccCheckInstanceDestroy, 626 Steps: []resource.TestStep{ 627 { 628 Config: testAccInstanceConfigPrivateIP, 629 Check: resource.ComposeTestCheckFunc( 630 testAccCheckInstanceExists("aws_instance.foo", &v), 631 testCheckPrivateIP(), 632 ), 633 }, 634 }, 635 }) 636 } 637 638 func TestAccAWSInstance_associatePublicIPAndPrivateIP(t *testing.T) { 639 var v ec2.Instance 640 641 testCheckPrivateIP := func() resource.TestCheckFunc { 642 return func(*terraform.State) error { 643 if *v.PrivateIpAddress != "10.1.1.42" { 644 return fmt.Errorf("bad private IP: %s", *v.PrivateIpAddress) 645 } 646 647 return nil 648 } 649 } 650 651 resource.Test(t, resource.TestCase{ 652 PreCheck: func() { testAccPreCheck(t) }, 653 IDRefreshName: "aws_instance.foo", 654 IDRefreshIgnore: []string{"associate_public_ip_address"}, 655 Providers: testAccProviders, 656 CheckDestroy: testAccCheckInstanceDestroy, 657 Steps: []resource.TestStep{ 658 { 659 Config: testAccInstanceConfigAssociatePublicIPAndPrivateIP, 660 Check: resource.ComposeTestCheckFunc( 661 testAccCheckInstanceExists("aws_instance.foo", &v), 662 testCheckPrivateIP(), 663 ), 664 }, 665 }, 666 }) 667 } 668 669 // Guard against regression with KeyPairs 670 // https://github.com/hashicorp/terraform/issues/2302 671 func TestAccAWSInstance_keyPairCheck(t *testing.T) { 672 var v ec2.Instance 673 674 testCheckKeyPair := func(keyName string) resource.TestCheckFunc { 675 return func(*terraform.State) error { 676 if v.KeyName == nil { 677 return fmt.Errorf("No Key Pair found, expected(%s)", keyName) 678 } 679 if v.KeyName != nil && *v.KeyName != keyName { 680 return fmt.Errorf("Bad key name, expected (%s), got (%s)", keyName, *v.KeyName) 681 } 682 683 return nil 684 } 685 } 686 687 resource.Test(t, resource.TestCase{ 688 PreCheck: func() { testAccPreCheck(t) }, 689 IDRefreshName: "aws_instance.foo", 690 IDRefreshIgnore: []string{"source_dest_check"}, 691 Providers: testAccProviders, 692 CheckDestroy: testAccCheckInstanceDestroy, 693 Steps: []resource.TestStep{ 694 { 695 Config: testAccInstanceConfigKeyPair, 696 Check: resource.ComposeTestCheckFunc( 697 testAccCheckInstanceExists("aws_instance.foo", &v), 698 testCheckKeyPair("tmp-key"), 699 ), 700 }, 701 }, 702 }) 703 } 704 705 func TestAccAWSInstance_rootBlockDeviceMismatch(t *testing.T) { 706 var v ec2.Instance 707 708 resource.Test(t, resource.TestCase{ 709 PreCheck: func() { testAccPreCheck(t) }, 710 Providers: testAccProviders, 711 CheckDestroy: testAccCheckInstanceDestroy, 712 Steps: []resource.TestStep{ 713 { 714 Config: testAccInstanceConfigRootBlockDeviceMismatch, 715 Check: resource.ComposeTestCheckFunc( 716 testAccCheckInstanceExists("aws_instance.foo", &v), 717 resource.TestCheckResourceAttr( 718 "aws_instance.foo", "root_block_device.0.volume_size", "13"), 719 ), 720 }, 721 }, 722 }) 723 } 724 725 // This test reproduces the bug here: 726 // https://github.com/hashicorp/terraform/issues/1752 727 // 728 // I wish there were a way to exercise resources built with helper.Schema in a 729 // unit context, in which case this test could be moved there, but for now this 730 // will cover the bugfix. 731 // 732 // The following triggers "diffs didn't match during apply" without the fix in to 733 // set NewRemoved on the .# field when it changes to 0. 734 func TestAccAWSInstance_forceNewAndTagsDrift(t *testing.T) { 735 var v ec2.Instance 736 737 resource.Test(t, resource.TestCase{ 738 PreCheck: func() { testAccPreCheck(t) }, 739 IDRefreshName: "aws_instance.foo", 740 Providers: testAccProviders, 741 CheckDestroy: testAccCheckInstanceDestroy, 742 Steps: []resource.TestStep{ 743 { 744 Config: testAccInstanceConfigForceNewAndTagsDrift, 745 Check: resource.ComposeTestCheckFunc( 746 testAccCheckInstanceExists("aws_instance.foo", &v), 747 driftTags(&v), 748 ), 749 ExpectNonEmptyPlan: true, 750 }, 751 { 752 Config: testAccInstanceConfigForceNewAndTagsDrift_Update, 753 Check: resource.ComposeTestCheckFunc( 754 testAccCheckInstanceExists("aws_instance.foo", &v), 755 ), 756 }, 757 }, 758 }) 759 } 760 761 func TestAccAWSInstance_changeInstanceType(t *testing.T) { 762 var before ec2.Instance 763 var after ec2.Instance 764 765 resource.Test(t, resource.TestCase{ 766 PreCheck: func() { testAccPreCheck(t) }, 767 Providers: testAccProviders, 768 CheckDestroy: testAccCheckInstanceDestroy, 769 Steps: []resource.TestStep{ 770 { 771 Config: testAccInstanceConfigWithSmallInstanceType, 772 Check: resource.ComposeTestCheckFunc( 773 testAccCheckInstanceExists("aws_instance.foo", &before), 774 ), 775 }, 776 { 777 Config: testAccInstanceConfigUpdateInstanceType, 778 Check: resource.ComposeTestCheckFunc( 779 testAccCheckInstanceExists("aws_instance.foo", &after), 780 testAccCheckInstanceNotRecreated( 781 t, &before, &after), 782 ), 783 }, 784 }, 785 }) 786 } 787 788 func testAccCheckInstanceNotRecreated(t *testing.T, 789 before, after *ec2.Instance) resource.TestCheckFunc { 790 return func(s *terraform.State) error { 791 if *before.InstanceId != *after.InstanceId { 792 t.Fatalf("AWS Instance IDs have changed. Before %s. After %s", *before.InstanceId, *after.InstanceId) 793 } 794 return nil 795 } 796 } 797 798 func testAccCheckInstanceDestroy(s *terraform.State) error { 799 return testAccCheckInstanceDestroyWithProvider(s, testAccProvider) 800 } 801 802 func testAccCheckInstanceDestroyWithProviders(providers *[]*schema.Provider) resource.TestCheckFunc { 803 return func(s *terraform.State) error { 804 for _, provider := range *providers { 805 if provider.Meta() == nil { 806 continue 807 } 808 if err := testAccCheckInstanceDestroyWithProvider(s, provider); err != nil { 809 return err 810 } 811 } 812 return nil 813 } 814 } 815 816 func testAccCheckInstanceDestroyWithProvider(s *terraform.State, provider *schema.Provider) error { 817 conn := provider.Meta().(*AWSClient).ec2conn 818 819 for _, rs := range s.RootModule().Resources { 820 if rs.Type != "aws_instance" { 821 continue 822 } 823 824 // Try to find the resource 825 resp, err := conn.DescribeInstances(&ec2.DescribeInstancesInput{ 826 InstanceIds: []*string{aws.String(rs.Primary.ID)}, 827 }) 828 if err == nil { 829 for _, r := range resp.Reservations { 830 for _, i := range r.Instances { 831 if i.State != nil && *i.State.Name != "terminated" { 832 return fmt.Errorf("Found unterminated instance: %s", i) 833 } 834 } 835 } 836 } 837 838 // Verify the error is what we want 839 if ae, ok := err.(awserr.Error); ok && ae.Code() == "InvalidInstanceID.NotFound" { 840 continue 841 } 842 843 return err 844 } 845 846 return nil 847 } 848 849 func testAccCheckInstanceExists(n string, i *ec2.Instance) resource.TestCheckFunc { 850 providers := []*schema.Provider{testAccProvider} 851 return testAccCheckInstanceExistsWithProviders(n, i, &providers) 852 } 853 854 func testAccCheckInstanceExistsWithProviders(n string, i *ec2.Instance, providers *[]*schema.Provider) resource.TestCheckFunc { 855 return func(s *terraform.State) error { 856 rs, ok := s.RootModule().Resources[n] 857 if !ok { 858 return fmt.Errorf("Not found: %s", n) 859 } 860 861 if rs.Primary.ID == "" { 862 return fmt.Errorf("No ID is set") 863 } 864 for _, provider := range *providers { 865 // Ignore if Meta is empty, this can happen for validation providers 866 if provider.Meta() == nil { 867 continue 868 } 869 870 conn := provider.Meta().(*AWSClient).ec2conn 871 resp, err := conn.DescribeInstances(&ec2.DescribeInstancesInput{ 872 InstanceIds: []*string{aws.String(rs.Primary.ID)}, 873 }) 874 if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidInstanceID.NotFound" { 875 continue 876 } 877 if err != nil { 878 return err 879 } 880 881 if len(resp.Reservations) > 0 { 882 *i = *resp.Reservations[0].Instances[0] 883 return nil 884 } 885 } 886 887 return fmt.Errorf("Instance not found") 888 } 889 } 890 891 func TestInstanceTenancySchema(t *testing.T) { 892 actualSchema := resourceAwsInstance().Schema["tenancy"] 893 expectedSchema := &schema.Schema{ 894 Type: schema.TypeString, 895 Optional: true, 896 Computed: true, 897 ForceNew: true, 898 } 899 if !reflect.DeepEqual(actualSchema, expectedSchema) { 900 t.Fatalf( 901 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 902 actualSchema, 903 expectedSchema) 904 } 905 } 906 907 func driftTags(instance *ec2.Instance) resource.TestCheckFunc { 908 return func(s *terraform.State) error { 909 conn := testAccProvider.Meta().(*AWSClient).ec2conn 910 _, err := conn.CreateTags(&ec2.CreateTagsInput{ 911 Resources: []*string{instance.InstanceId}, 912 Tags: []*ec2.Tag{ 913 { 914 Key: aws.String("Drift"), 915 Value: aws.String("Happens"), 916 }, 917 }, 918 }) 919 return err 920 } 921 } 922 923 const testAccInstanceConfig_pre = ` 924 resource "aws_security_group" "tf_test_foo" { 925 name = "tf_test_foo" 926 description = "foo" 927 928 ingress { 929 protocol = "icmp" 930 from_port = -1 931 to_port = -1 932 cidr_blocks = ["0.0.0.0/0"] 933 } 934 } 935 ` 936 937 const testAccInstanceConfig = ` 938 resource "aws_security_group" "tf_test_foo" { 939 name = "tf_test_foo" 940 description = "foo" 941 942 ingress { 943 protocol = "icmp" 944 from_port = -1 945 to_port = -1 946 cidr_blocks = ["0.0.0.0/0"] 947 } 948 } 949 950 resource "aws_instance" "foo" { 951 # us-west-2 952 ami = "ami-4fccb37f" 953 availability_zone = "us-west-2a" 954 955 instance_type = "m1.small" 956 security_groups = ["${aws_security_group.tf_test_foo.name}"] 957 user_data = "foo:-with-character's" 958 } 959 ` 960 961 const testAccInstanceConfigWithSmallInstanceType = ` 962 resource "aws_instance" "foo" { 963 # us-west-2 964 ami = "ami-55a7ea65" 965 availability_zone = "us-west-2a" 966 967 instance_type = "m3.medium" 968 969 tags { 970 Name = "tf-acctest" 971 } 972 } 973 ` 974 975 const testAccInstanceConfigUpdateInstanceType = ` 976 resource "aws_instance" "foo" { 977 # us-west-2 978 ami = "ami-55a7ea65" 979 availability_zone = "us-west-2a" 980 981 instance_type = "m3.large" 982 983 tags { 984 Name = "tf-acctest" 985 } 986 } 987 ` 988 989 const testAccInstanceGP2IopsDevice = ` 990 resource "aws_instance" "foo" { 991 # us-west-2 992 ami = "ami-55a7ea65" 993 994 # In order to attach an encrypted volume to an instance you need to have an 995 # m3.medium or larger. See "Supported Instance Types" in: 996 # http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html 997 instance_type = "m3.medium" 998 999 root_block_device { 1000 volume_type = "gp2" 1001 volume_size = 11 1002 iops = 330 1003 } 1004 } 1005 ` 1006 1007 const testAccInstanceConfigBlockDevices = ` 1008 resource "aws_instance" "foo" { 1009 # us-west-2 1010 ami = "ami-55a7ea65" 1011 1012 # In order to attach an encrypted volume to an instance you need to have an 1013 # m3.medium or larger. See "Supported Instance Types" in: 1014 # http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html 1015 instance_type = "m3.medium" 1016 1017 root_block_device { 1018 volume_type = "gp2" 1019 volume_size = 11 1020 } 1021 ebs_block_device { 1022 device_name = "/dev/sdb" 1023 volume_size = 9 1024 } 1025 ebs_block_device { 1026 device_name = "/dev/sdc" 1027 volume_size = 10 1028 volume_type = "io1" 1029 iops = 100 1030 } 1031 1032 # Encrypted ebs block device 1033 ebs_block_device { 1034 device_name = "/dev/sdd" 1035 volume_size = 12 1036 encrypted = true 1037 } 1038 1039 ephemeral_block_device { 1040 device_name = "/dev/sde" 1041 virtual_name = "ephemeral0" 1042 } 1043 } 1044 ` 1045 1046 const testAccInstanceConfigSourceDestEnable = ` 1047 resource "aws_vpc" "foo" { 1048 cidr_block = "10.1.0.0/16" 1049 } 1050 1051 resource "aws_subnet" "foo" { 1052 cidr_block = "10.1.1.0/24" 1053 vpc_id = "${aws_vpc.foo.id}" 1054 } 1055 1056 resource "aws_instance" "foo" { 1057 # us-west-2 1058 ami = "ami-4fccb37f" 1059 instance_type = "m1.small" 1060 subnet_id = "${aws_subnet.foo.id}" 1061 } 1062 ` 1063 1064 const testAccInstanceConfigSourceDestDisable = ` 1065 resource "aws_vpc" "foo" { 1066 cidr_block = "10.1.0.0/16" 1067 } 1068 1069 resource "aws_subnet" "foo" { 1070 cidr_block = "10.1.1.0/24" 1071 vpc_id = "${aws_vpc.foo.id}" 1072 } 1073 1074 resource "aws_instance" "foo" { 1075 # us-west-2 1076 ami = "ami-4fccb37f" 1077 instance_type = "m1.small" 1078 subnet_id = "${aws_subnet.foo.id}" 1079 source_dest_check = false 1080 } 1081 ` 1082 1083 func testAccInstanceConfigDisableAPITermination(val bool) string { 1084 return fmt.Sprintf(` 1085 resource "aws_vpc" "foo" { 1086 cidr_block = "10.1.0.0/16" 1087 } 1088 1089 resource "aws_subnet" "foo" { 1090 cidr_block = "10.1.1.0/24" 1091 vpc_id = "${aws_vpc.foo.id}" 1092 } 1093 1094 resource "aws_instance" "foo" { 1095 # us-west-2 1096 ami = "ami-4fccb37f" 1097 instance_type = "m1.small" 1098 subnet_id = "${aws_subnet.foo.id}" 1099 disable_api_termination = %t 1100 } 1101 `, val) 1102 } 1103 1104 const testAccInstanceConfigVPC = ` 1105 resource "aws_vpc" "foo" { 1106 cidr_block = "10.1.0.0/16" 1107 } 1108 1109 resource "aws_subnet" "foo" { 1110 cidr_block = "10.1.1.0/24" 1111 vpc_id = "${aws_vpc.foo.id}" 1112 } 1113 1114 resource "aws_instance" "foo" { 1115 # us-west-2 1116 ami = "ami-4fccb37f" 1117 instance_type = "m1.small" 1118 subnet_id = "${aws_subnet.foo.id}" 1119 associate_public_ip_address = true 1120 tenancy = "dedicated" 1121 # pre-encoded base64 data 1122 user_data = "3dc39dda39be1205215e776bad998da361a5955d" 1123 } 1124 ` 1125 1126 const testAccInstanceConfigMultipleRegions = ` 1127 provider "aws" { 1128 alias = "west" 1129 region = "us-west-2" 1130 } 1131 1132 provider "aws" { 1133 alias = "east" 1134 region = "us-east-1" 1135 } 1136 1137 resource "aws_instance" "foo" { 1138 # us-west-2 1139 provider = "aws.west" 1140 ami = "ami-4fccb37f" 1141 instance_type = "m1.small" 1142 } 1143 1144 resource "aws_instance" "bar" { 1145 # us-east-1 1146 provider = "aws.east" 1147 ami = "ami-8c6ea9e4" 1148 instance_type = "m1.small" 1149 } 1150 ` 1151 1152 const testAccCheckInstanceConfigTags = ` 1153 resource "aws_instance" "foo" { 1154 ami = "ami-4fccb37f" 1155 instance_type = "m1.small" 1156 tags { 1157 foo = "bar" 1158 } 1159 } 1160 ` 1161 1162 const testAccCheckInstanceConfigTagsUpdate = ` 1163 resource "aws_instance" "foo" { 1164 ami = "ami-4fccb37f" 1165 instance_type = "m1.small" 1166 tags { 1167 bar = "baz" 1168 } 1169 } 1170 ` 1171 1172 const testAccInstanceConfigPrivateIP = ` 1173 resource "aws_vpc" "foo" { 1174 cidr_block = "10.1.0.0/16" 1175 } 1176 1177 resource "aws_subnet" "foo" { 1178 cidr_block = "10.1.1.0/24" 1179 vpc_id = "${aws_vpc.foo.id}" 1180 } 1181 1182 resource "aws_instance" "foo" { 1183 ami = "ami-c5eabbf5" 1184 instance_type = "t2.micro" 1185 subnet_id = "${aws_subnet.foo.id}" 1186 private_ip = "10.1.1.42" 1187 } 1188 ` 1189 1190 const testAccInstanceConfigAssociatePublicIPAndPrivateIP = ` 1191 resource "aws_vpc" "foo" { 1192 cidr_block = "10.1.0.0/16" 1193 } 1194 1195 resource "aws_subnet" "foo" { 1196 cidr_block = "10.1.1.0/24" 1197 vpc_id = "${aws_vpc.foo.id}" 1198 } 1199 1200 resource "aws_instance" "foo" { 1201 ami = "ami-c5eabbf5" 1202 instance_type = "t2.micro" 1203 subnet_id = "${aws_subnet.foo.id}" 1204 associate_public_ip_address = true 1205 private_ip = "10.1.1.42" 1206 } 1207 ` 1208 1209 const testAccInstanceNetworkInstanceSecurityGroups = ` 1210 resource "aws_internet_gateway" "gw" { 1211 vpc_id = "${aws_vpc.foo.id}" 1212 } 1213 1214 resource "aws_vpc" "foo" { 1215 cidr_block = "10.1.0.0/16" 1216 tags { 1217 Name = "tf-network-test" 1218 } 1219 } 1220 1221 resource "aws_security_group" "tf_test_foo" { 1222 name = "tf_test_foo" 1223 description = "foo" 1224 vpc_id="${aws_vpc.foo.id}" 1225 1226 ingress { 1227 protocol = "icmp" 1228 from_port = -1 1229 to_port = -1 1230 cidr_blocks = ["0.0.0.0/0"] 1231 } 1232 } 1233 1234 resource "aws_subnet" "foo" { 1235 cidr_block = "10.1.1.0/24" 1236 vpc_id = "${aws_vpc.foo.id}" 1237 } 1238 1239 resource "aws_instance" "foo_instance" { 1240 ami = "ami-21f78e11" 1241 instance_type = "t1.micro" 1242 vpc_security_group_ids = ["${aws_security_group.tf_test_foo.id}"] 1243 subnet_id = "${aws_subnet.foo.id}" 1244 associate_public_ip_address = true 1245 depends_on = ["aws_internet_gateway.gw"] 1246 } 1247 1248 resource "aws_eip" "foo_eip" { 1249 instance = "${aws_instance.foo_instance.id}" 1250 vpc = true 1251 depends_on = ["aws_internet_gateway.gw"] 1252 } 1253 ` 1254 1255 const testAccInstanceNetworkInstanceVPCSecurityGroupIDs = ` 1256 resource "aws_internet_gateway" "gw" { 1257 vpc_id = "${aws_vpc.foo.id}" 1258 } 1259 1260 resource "aws_vpc" "foo" { 1261 cidr_block = "10.1.0.0/16" 1262 tags { 1263 Name = "tf-network-test" 1264 } 1265 } 1266 1267 resource "aws_security_group" "tf_test_foo" { 1268 name = "tf_test_foo" 1269 description = "foo" 1270 vpc_id="${aws_vpc.foo.id}" 1271 1272 ingress { 1273 protocol = "icmp" 1274 from_port = -1 1275 to_port = -1 1276 cidr_blocks = ["0.0.0.0/0"] 1277 } 1278 } 1279 1280 resource "aws_subnet" "foo" { 1281 cidr_block = "10.1.1.0/24" 1282 vpc_id = "${aws_vpc.foo.id}" 1283 } 1284 1285 resource "aws_instance" "foo_instance" { 1286 ami = "ami-21f78e11" 1287 instance_type = "t1.micro" 1288 vpc_security_group_ids = ["${aws_security_group.tf_test_foo.id}"] 1289 subnet_id = "${aws_subnet.foo.id}" 1290 depends_on = ["aws_internet_gateway.gw"] 1291 } 1292 1293 resource "aws_eip" "foo_eip" { 1294 instance = "${aws_instance.foo_instance.id}" 1295 vpc = true 1296 depends_on = ["aws_internet_gateway.gw"] 1297 } 1298 ` 1299 1300 const testAccInstanceConfigKeyPair = ` 1301 provider "aws" { 1302 region = "us-east-1" 1303 } 1304 1305 resource "aws_key_pair" "debugging" { 1306 key_name = "tmp-key" 1307 public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 phodgson@thoughtworks.com" 1308 } 1309 1310 resource "aws_instance" "foo" { 1311 ami = "ami-408c7f28" 1312 instance_type = "t1.micro" 1313 key_name = "${aws_key_pair.debugging.key_name}" 1314 tags { 1315 Name = "testAccInstanceConfigKeyPair_TestAMI" 1316 } 1317 } 1318 ` 1319 1320 const testAccInstanceConfigRootBlockDeviceMismatch = ` 1321 resource "aws_vpc" "foo" { 1322 cidr_block = "10.1.0.0/16" 1323 } 1324 1325 resource "aws_subnet" "foo" { 1326 cidr_block = "10.1.1.0/24" 1327 vpc_id = "${aws_vpc.foo.id}" 1328 } 1329 1330 resource "aws_instance" "foo" { 1331 // This is an AMI with RootDeviceName: "/dev/sda1"; actual root: "/dev/sda" 1332 ami = "ami-ef5b69df" 1333 instance_type = "t1.micro" 1334 subnet_id = "${aws_subnet.foo.id}" 1335 root_block_device { 1336 volume_size = 13 1337 } 1338 } 1339 ` 1340 1341 const testAccInstanceConfigForceNewAndTagsDrift = ` 1342 resource "aws_vpc" "foo" { 1343 cidr_block = "10.1.0.0/16" 1344 } 1345 1346 resource "aws_subnet" "foo" { 1347 cidr_block = "10.1.1.0/24" 1348 vpc_id = "${aws_vpc.foo.id}" 1349 } 1350 1351 resource "aws_instance" "foo" { 1352 ami = "ami-22b9a343" 1353 instance_type = "t2.nano" 1354 subnet_id = "${aws_subnet.foo.id}" 1355 } 1356 ` 1357 1358 const testAccInstanceConfigForceNewAndTagsDrift_Update = ` 1359 resource "aws_vpc" "foo" { 1360 cidr_block = "10.1.0.0/16" 1361 } 1362 1363 resource "aws_subnet" "foo" { 1364 cidr_block = "10.1.1.0/24" 1365 vpc_id = "${aws_vpc.foo.id}" 1366 } 1367 1368 resource "aws_instance" "foo" { 1369 ami = "ami-22b9a343" 1370 instance_type = "t2.micro" 1371 subnet_id = "${aws_subnet.foo.id}" 1372 } 1373 `