github.com/nicgrayson/terraform@v0.4.3-0.20150415203910-c4de50829380/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/hashicorp/aws-sdk-go/aws" 9 "github.com/hashicorp/aws-sdk-go/gen/ec2" 10 "github.com/hashicorp/terraform/helper/resource" 11 "github.com/hashicorp/terraform/helper/schema" 12 "github.com/hashicorp/terraform/terraform" 13 ) 14 15 func TestAccAWSInstance_normal(t *testing.T) { 16 var v ec2.Instance 17 var vol *ec2.Volume 18 19 testCheck := func(*terraform.State) error { 20 if *v.Placement.AvailabilityZone != "us-west-2a" { 21 return fmt.Errorf("bad availability zone: %#v", *v.Placement.AvailabilityZone) 22 } 23 24 if len(v.SecurityGroups) == 0 { 25 return fmt.Errorf("no security groups: %#v", v.SecurityGroups) 26 } 27 if *v.SecurityGroups[0].GroupName != "tf_test_foo" { 28 return fmt.Errorf("no security groups: %#v", v.SecurityGroups) 29 } 30 31 return nil 32 } 33 34 resource.Test(t, resource.TestCase{ 35 PreCheck: func() { testAccPreCheck(t) }, 36 Providers: testAccProviders, 37 CheckDestroy: testAccCheckInstanceDestroy, 38 Steps: []resource.TestStep{ 39 // Create a volume to cover #1249 40 resource.TestStep{ 41 // Need a resource in this config so the provisioner will be available 42 Config: testAccInstanceConfig_pre, 43 Check: func(*terraform.State) error { 44 conn := testAccProvider.Meta().(*AWSClient).ec2conn 45 var err error 46 vol, err = conn.CreateVolume(&ec2.CreateVolumeRequest{ 47 AvailabilityZone: aws.String("us-west-2a"), 48 Size: aws.Integer(5), 49 }) 50 return err 51 }, 52 }, 53 54 resource.TestStep{ 55 Config: testAccInstanceConfig, 56 Check: resource.ComposeTestCheckFunc( 57 testAccCheckInstanceExists( 58 "aws_instance.foo", &v), 59 testCheck, 60 resource.TestCheckResourceAttr( 61 "aws_instance.foo", 62 "user_data", 63 "3dc39dda39be1205215e776bad998da361a5955d"), 64 resource.TestCheckResourceAttr( 65 "aws_instance.foo", "ebs_block_device.#", "0"), 66 ), 67 }, 68 69 // We repeat the exact same test so that we can be sure 70 // that the user data hash stuff is working without generating 71 // an incorrect diff. 72 resource.TestStep{ 73 Config: testAccInstanceConfig, 74 Check: resource.ComposeTestCheckFunc( 75 testAccCheckInstanceExists( 76 "aws_instance.foo", &v), 77 testCheck, 78 resource.TestCheckResourceAttr( 79 "aws_instance.foo", 80 "user_data", 81 "3dc39dda39be1205215e776bad998da361a5955d"), 82 resource.TestCheckResourceAttr( 83 "aws_instance.foo", "ebs_block_device.#", "0"), 84 ), 85 }, 86 87 // Clean up volume created above 88 resource.TestStep{ 89 Config: testAccInstanceConfig, 90 Check: func(*terraform.State) error { 91 conn := testAccProvider.Meta().(*AWSClient).ec2conn 92 return conn.DeleteVolume(&ec2.DeleteVolumeRequest{VolumeID: vol.VolumeID}) 93 }, 94 }, 95 }, 96 }) 97 } 98 99 func TestAccAWSInstance_blockDevices(t *testing.T) { 100 var v ec2.Instance 101 102 testCheck := func() resource.TestCheckFunc { 103 return func(*terraform.State) error { 104 105 // Map out the block devices by name, which should be unique. 106 blockDevices := make(map[string]ec2.InstanceBlockDeviceMapping) 107 for _, blockDevice := range v.BlockDeviceMappings { 108 blockDevices[*blockDevice.DeviceName] = blockDevice 109 } 110 111 // Check if the root block device exists. 112 if _, ok := blockDevices["/dev/sda1"]; !ok { 113 fmt.Errorf("block device doesn't exist: /dev/sda1") 114 } 115 116 // Check if the secondary block device exists. 117 if _, ok := blockDevices["/dev/sdb"]; !ok { 118 fmt.Errorf("block device doesn't exist: /dev/sdb") 119 } 120 121 // Check if the third block device exists. 122 if _, ok := blockDevices["/dev/sdc"]; !ok { 123 fmt.Errorf("block device doesn't exist: /dev/sdc") 124 } 125 126 return nil 127 } 128 } 129 130 resource.Test(t, resource.TestCase{ 131 PreCheck: func() { testAccPreCheck(t) }, 132 Providers: testAccProviders, 133 CheckDestroy: testAccCheckInstanceDestroy, 134 Steps: []resource.TestStep{ 135 resource.TestStep{ 136 Config: testAccInstanceConfigBlockDevices, 137 Check: resource.ComposeTestCheckFunc( 138 testAccCheckInstanceExists( 139 "aws_instance.foo", &v), 140 resource.TestCheckResourceAttr( 141 "aws_instance.foo", "root_block_device.#", "1"), 142 resource.TestCheckResourceAttr( 143 "aws_instance.foo", "root_block_device.0.volume_size", "11"), 144 resource.TestCheckResourceAttr( 145 "aws_instance.foo", "root_block_device.0.volume_type", "gp2"), 146 resource.TestCheckResourceAttr( 147 "aws_instance.foo", "ebs_block_device.#", "2"), 148 resource.TestCheckResourceAttr( 149 "aws_instance.foo", "ebs_block_device.2576023345.device_name", "/dev/sdb"), 150 resource.TestCheckResourceAttr( 151 "aws_instance.foo", "ebs_block_device.2576023345.volume_size", "9"), 152 resource.TestCheckResourceAttr( 153 "aws_instance.foo", "ebs_block_device.2576023345.volume_type", "standard"), 154 resource.TestCheckResourceAttr( 155 "aws_instance.foo", "ebs_block_device.2554893574.device_name", "/dev/sdc"), 156 resource.TestCheckResourceAttr( 157 "aws_instance.foo", "ebs_block_device.2554893574.volume_size", "10"), 158 resource.TestCheckResourceAttr( 159 "aws_instance.foo", "ebs_block_device.2554893574.volume_type", "io1"), 160 resource.TestCheckResourceAttr( 161 "aws_instance.foo", "ebs_block_device.2554893574.iops", "100"), 162 resource.TestCheckResourceAttr( 163 "aws_instance.foo", "ephemeral_block_device.#", "1"), 164 resource.TestCheckResourceAttr( 165 "aws_instance.foo", "ephemeral_block_device.1692014856.device_name", "/dev/sde"), 166 resource.TestCheckResourceAttr( 167 "aws_instance.foo", "ephemeral_block_device.1692014856.virtual_name", "ephemeral0"), 168 testCheck(), 169 ), 170 }, 171 }, 172 }) 173 } 174 175 func TestAccAWSInstance_sourceDestCheck(t *testing.T) { 176 var v ec2.Instance 177 178 testCheck := func(enabled bool) resource.TestCheckFunc { 179 return func(*terraform.State) error { 180 if *v.SourceDestCheck != enabled { 181 return fmt.Errorf("bad source_dest_check: %#v", *v.SourceDestCheck) 182 } 183 184 return nil 185 } 186 } 187 188 resource.Test(t, resource.TestCase{ 189 PreCheck: func() { testAccPreCheck(t) }, 190 Providers: testAccProviders, 191 CheckDestroy: testAccCheckInstanceDestroy, 192 Steps: []resource.TestStep{ 193 resource.TestStep{ 194 Config: testAccInstanceConfigSourceDestDisable, 195 Check: resource.ComposeTestCheckFunc( 196 testAccCheckInstanceExists("aws_instance.foo", &v), 197 testCheck(false), 198 ), 199 }, 200 201 resource.TestStep{ 202 Config: testAccInstanceConfigSourceDestEnable, 203 Check: resource.ComposeTestCheckFunc( 204 testAccCheckInstanceExists("aws_instance.foo", &v), 205 testCheck(true), 206 ), 207 }, 208 209 resource.TestStep{ 210 Config: testAccInstanceConfigSourceDestDisable, 211 Check: resource.ComposeTestCheckFunc( 212 testAccCheckInstanceExists("aws_instance.foo", &v), 213 testCheck(false), 214 ), 215 }, 216 }, 217 }) 218 } 219 220 func TestAccAWSInstance_vpc(t *testing.T) { 221 var v ec2.Instance 222 223 resource.Test(t, resource.TestCase{ 224 PreCheck: func() { testAccPreCheck(t) }, 225 Providers: testAccProviders, 226 CheckDestroy: testAccCheckInstanceDestroy, 227 Steps: []resource.TestStep{ 228 resource.TestStep{ 229 Config: testAccInstanceConfigVPC, 230 Check: resource.ComposeTestCheckFunc( 231 testAccCheckInstanceExists( 232 "aws_instance.foo", &v), 233 ), 234 }, 235 }, 236 }) 237 } 238 239 func TestAccAWSInstance_NetworkInstanceSecurityGroups(t *testing.T) { 240 var v ec2.Instance 241 242 resource.Test(t, resource.TestCase{ 243 PreCheck: func() { testAccPreCheck(t) }, 244 Providers: testAccProviders, 245 CheckDestroy: testAccCheckInstanceDestroy, 246 Steps: []resource.TestStep{ 247 resource.TestStep{ 248 Config: testAccInstanceNetworkInstanceSecurityGroups, 249 Check: resource.ComposeTestCheckFunc( 250 testAccCheckInstanceExists( 251 "aws_instance.foo_instance", &v), 252 ), 253 }, 254 }, 255 }) 256 } 257 258 func TestAccAWSInstance_NetworkInstanceVPCSecurityGroupIDs(t *testing.T) { 259 var v ec2.Instance 260 261 resource.Test(t, resource.TestCase{ 262 PreCheck: func() { testAccPreCheck(t) }, 263 Providers: testAccProviders, 264 CheckDestroy: testAccCheckInstanceDestroy, 265 Steps: []resource.TestStep{ 266 resource.TestStep{ 267 Config: testAccInstanceNetworkInstanceVPCSecurityGroupIDs, 268 Check: resource.ComposeTestCheckFunc( 269 testAccCheckInstanceExists( 270 "aws_instance.foo_instance", &v), 271 ), 272 }, 273 }, 274 }) 275 } 276 277 func TestAccAWSInstance_tags(t *testing.T) { 278 var v ec2.Instance 279 280 resource.Test(t, resource.TestCase{ 281 PreCheck: func() { testAccPreCheck(t) }, 282 Providers: testAccProviders, 283 CheckDestroy: testAccCheckInstanceDestroy, 284 Steps: []resource.TestStep{ 285 resource.TestStep{ 286 Config: testAccCheckInstanceConfigTags, 287 Check: resource.ComposeTestCheckFunc( 288 testAccCheckInstanceExists("aws_instance.foo", &v), 289 testAccCheckTags(&v.Tags, "foo", "bar"), 290 // Guard against regression of https://github.com/hashicorp/terraform/issues/914 291 testAccCheckTags(&v.Tags, "#", ""), 292 ), 293 }, 294 295 resource.TestStep{ 296 Config: testAccCheckInstanceConfigTagsUpdate, 297 Check: resource.ComposeTestCheckFunc( 298 testAccCheckInstanceExists("aws_instance.foo", &v), 299 testAccCheckTags(&v.Tags, "foo", ""), 300 testAccCheckTags(&v.Tags, "bar", "baz"), 301 ), 302 }, 303 }, 304 }) 305 } 306 307 func TestAccAWSInstance_privateIP(t *testing.T) { 308 var v ec2.Instance 309 310 testCheckPrivateIP := func() resource.TestCheckFunc { 311 return func(*terraform.State) error { 312 if *v.PrivateIPAddress != "10.1.1.42" { 313 return fmt.Errorf("bad private IP: %s", *v.PrivateIPAddress) 314 } 315 316 return nil 317 } 318 } 319 320 resource.Test(t, resource.TestCase{ 321 PreCheck: func() { testAccPreCheck(t) }, 322 Providers: testAccProviders, 323 CheckDestroy: testAccCheckInstanceDestroy, 324 Steps: []resource.TestStep{ 325 resource.TestStep{ 326 Config: testAccInstanceConfigPrivateIP, 327 Check: resource.ComposeTestCheckFunc( 328 testAccCheckInstanceExists("aws_instance.foo", &v), 329 testCheckPrivateIP(), 330 ), 331 }, 332 }, 333 }) 334 } 335 336 func TestAccAWSInstance_associatePublicIPAndPrivateIP(t *testing.T) { 337 var v ec2.Instance 338 339 testCheckPrivateIP := func() resource.TestCheckFunc { 340 return func(*terraform.State) error { 341 if *v.PrivateIPAddress != "10.1.1.42" { 342 return fmt.Errorf("bad private IP: %s", *v.PrivateIPAddress) 343 } 344 345 return nil 346 } 347 } 348 349 resource.Test(t, resource.TestCase{ 350 PreCheck: func() { testAccPreCheck(t) }, 351 Providers: testAccProviders, 352 CheckDestroy: testAccCheckInstanceDestroy, 353 Steps: []resource.TestStep{ 354 resource.TestStep{ 355 Config: testAccInstanceConfigAssociatePublicIPAndPrivateIP, 356 Check: resource.ComposeTestCheckFunc( 357 testAccCheckInstanceExists("aws_instance.foo", &v), 358 testCheckPrivateIP(), 359 ), 360 }, 361 }, 362 }) 363 } 364 365 func testAccCheckInstanceDestroy(s *terraform.State) error { 366 conn := testAccProvider.Meta().(*AWSClient).ec2conn 367 368 for _, rs := range s.RootModule().Resources { 369 if rs.Type != "aws_instance" { 370 continue 371 } 372 373 // Try to find the resource 374 resp, err := conn.DescribeInstances(&ec2.DescribeInstancesRequest{ 375 InstanceIDs: []string{rs.Primary.ID}, 376 }) 377 if err == nil { 378 if len(resp.Reservations) > 0 { 379 return fmt.Errorf("still exist.") 380 } 381 382 return nil 383 } 384 385 // Verify the error is what we want 386 ec2err, ok := err.(aws.APIError) 387 if !ok { 388 return err 389 } 390 if ec2err.Code != "InvalidInstanceID.NotFound" { 391 return err 392 } 393 } 394 395 return nil 396 } 397 398 func testAccCheckInstanceExists(n string, i *ec2.Instance) resource.TestCheckFunc { 399 return func(s *terraform.State) error { 400 rs, ok := s.RootModule().Resources[n] 401 if !ok { 402 return fmt.Errorf("Not found: %s", n) 403 } 404 405 if rs.Primary.ID == "" { 406 return fmt.Errorf("No ID is set") 407 } 408 409 conn := testAccProvider.Meta().(*AWSClient).ec2conn 410 resp, err := conn.DescribeInstances(&ec2.DescribeInstancesRequest{ 411 InstanceIDs: []string{rs.Primary.ID}, 412 }) 413 if err != nil { 414 return err 415 } 416 if len(resp.Reservations) == 0 { 417 return fmt.Errorf("Instance not found") 418 } 419 420 *i = resp.Reservations[0].Instances[0] 421 422 return nil 423 } 424 } 425 426 func TestInstanceTenancySchema(t *testing.T) { 427 actualSchema := resourceAwsInstance().Schema["tenancy"] 428 expectedSchema := &schema.Schema{ 429 Type: schema.TypeString, 430 Optional: true, 431 Computed: true, 432 ForceNew: true, 433 } 434 if !reflect.DeepEqual(actualSchema, expectedSchema) { 435 t.Fatalf( 436 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 437 actualSchema, 438 expectedSchema) 439 } 440 } 441 442 const testAccInstanceConfig_pre = ` 443 resource "aws_security_group" "tf_test_foo" { 444 name = "tf_test_foo" 445 description = "foo" 446 447 ingress { 448 protocol = "icmp" 449 from_port = -1 450 to_port = -1 451 cidr_blocks = ["0.0.0.0/0"] 452 } 453 } 454 ` 455 456 const testAccInstanceConfig = ` 457 resource "aws_security_group" "tf_test_foo" { 458 name = "tf_test_foo" 459 description = "foo" 460 461 ingress { 462 protocol = "icmp" 463 from_port = -1 464 to_port = -1 465 cidr_blocks = ["0.0.0.0/0"] 466 } 467 } 468 469 resource "aws_instance" "foo" { 470 # us-west-2 471 ami = "ami-4fccb37f" 472 availability_zone = "us-west-2a" 473 474 instance_type = "m1.small" 475 security_groups = ["${aws_security_group.tf_test_foo.name}"] 476 user_data = "foo:-with-character's" 477 } 478 ` 479 480 const testAccInstanceConfigBlockDevices = ` 481 resource "aws_instance" "foo" { 482 # us-west-2 483 ami = "ami-55a7ea65" 484 instance_type = "m1.small" 485 486 root_block_device { 487 volume_type = "gp2" 488 volume_size = 11 489 } 490 ebs_block_device { 491 device_name = "/dev/sdb" 492 volume_size = 9 493 } 494 ebs_block_device { 495 device_name = "/dev/sdc" 496 volume_size = 10 497 volume_type = "io1" 498 iops = 100 499 } 500 ephemeral_block_device { 501 device_name = "/dev/sde" 502 virtual_name = "ephemeral0" 503 } 504 } 505 ` 506 507 const testAccInstanceConfigSourceDestEnable = ` 508 resource "aws_vpc" "foo" { 509 cidr_block = "10.1.0.0/16" 510 } 511 512 resource "aws_subnet" "foo" { 513 cidr_block = "10.1.1.0/24" 514 vpc_id = "${aws_vpc.foo.id}" 515 } 516 517 resource "aws_instance" "foo" { 518 # us-west-2 519 ami = "ami-4fccb37f" 520 instance_type = "m1.small" 521 subnet_id = "${aws_subnet.foo.id}" 522 source_dest_check = true 523 } 524 ` 525 526 const testAccInstanceConfigSourceDestDisable = ` 527 resource "aws_vpc" "foo" { 528 cidr_block = "10.1.0.0/16" 529 } 530 531 resource "aws_subnet" "foo" { 532 cidr_block = "10.1.1.0/24" 533 vpc_id = "${aws_vpc.foo.id}" 534 } 535 536 resource "aws_instance" "foo" { 537 # us-west-2 538 ami = "ami-4fccb37f" 539 instance_type = "m1.small" 540 subnet_id = "${aws_subnet.foo.id}" 541 source_dest_check = false 542 } 543 ` 544 545 const testAccInstanceConfigVPC = ` 546 resource "aws_vpc" "foo" { 547 cidr_block = "10.1.0.0/16" 548 } 549 550 resource "aws_subnet" "foo" { 551 cidr_block = "10.1.1.0/24" 552 vpc_id = "${aws_vpc.foo.id}" 553 } 554 555 resource "aws_instance" "foo" { 556 # us-west-2 557 ami = "ami-4fccb37f" 558 instance_type = "m1.small" 559 subnet_id = "${aws_subnet.foo.id}" 560 associate_public_ip_address = true 561 tenancy = "dedicated" 562 } 563 ` 564 565 const testAccCheckInstanceConfigTags = ` 566 resource "aws_instance" "foo" { 567 ami = "ami-4fccb37f" 568 instance_type = "m1.small" 569 tags { 570 foo = "bar" 571 } 572 } 573 ` 574 575 const testAccCheckInstanceConfigTagsUpdate = ` 576 resource "aws_instance" "foo" { 577 ami = "ami-4fccb37f" 578 instance_type = "m1.small" 579 tags { 580 bar = "baz" 581 } 582 } 583 ` 584 585 const testAccInstanceConfigPrivateIP = ` 586 resource "aws_vpc" "foo" { 587 cidr_block = "10.1.0.0/16" 588 } 589 590 resource "aws_subnet" "foo" { 591 cidr_block = "10.1.1.0/24" 592 vpc_id = "${aws_vpc.foo.id}" 593 } 594 595 resource "aws_instance" "foo" { 596 ami = "ami-c5eabbf5" 597 instance_type = "t2.micro" 598 subnet_id = "${aws_subnet.foo.id}" 599 private_ip = "10.1.1.42" 600 } 601 ` 602 603 const testAccInstanceConfigAssociatePublicIPAndPrivateIP = ` 604 resource "aws_vpc" "foo" { 605 cidr_block = "10.1.0.0/16" 606 } 607 608 resource "aws_subnet" "foo" { 609 cidr_block = "10.1.1.0/24" 610 vpc_id = "${aws_vpc.foo.id}" 611 } 612 613 resource "aws_instance" "foo" { 614 ami = "ami-c5eabbf5" 615 instance_type = "t2.micro" 616 subnet_id = "${aws_subnet.foo.id}" 617 associate_public_ip_address = true 618 private_ip = "10.1.1.42" 619 } 620 ` 621 622 const testAccInstanceNetworkInstanceSecurityGroups = ` 623 resource "aws_internet_gateway" "gw" { 624 vpc_id = "${aws_vpc.foo.id}" 625 } 626 627 resource "aws_vpc" "foo" { 628 cidr_block = "10.1.0.0/16" 629 tags { 630 Name = "tf-network-test" 631 } 632 } 633 634 resource "aws_security_group" "tf_test_foo" { 635 name = "tf_test_foo" 636 description = "foo" 637 vpc_id="${aws_vpc.foo.id}" 638 639 ingress { 640 protocol = "icmp" 641 from_port = -1 642 to_port = -1 643 cidr_blocks = ["0.0.0.0/0"] 644 } 645 } 646 647 resource "aws_subnet" "foo" { 648 cidr_block = "10.1.1.0/24" 649 vpc_id = "${aws_vpc.foo.id}" 650 } 651 652 resource "aws_instance" "foo_instance" { 653 ami = "ami-21f78e11" 654 instance_type = "t1.micro" 655 security_groups = ["${aws_security_group.tf_test_foo.id}"] 656 subnet_id = "${aws_subnet.foo.id}" 657 associate_public_ip_address = true 658 depends_on = ["aws_internet_gateway.gw"] 659 } 660 661 resource "aws_eip" "foo_eip" { 662 instance = "${aws_instance.foo_instance.id}" 663 vpc = true 664 depends_on = ["aws_internet_gateway.gw"] 665 } 666 ` 667 668 const testAccInstanceNetworkInstanceVPCSecurityGroupIDs = ` 669 resource "aws_internet_gateway" "gw" { 670 vpc_id = "${aws_vpc.foo.id}" 671 } 672 673 resource "aws_vpc" "foo" { 674 cidr_block = "10.1.0.0/16" 675 tags { 676 Name = "tf-network-test" 677 } 678 } 679 680 resource "aws_security_group" "tf_test_foo" { 681 name = "tf_test_foo" 682 description = "foo" 683 vpc_id="${aws_vpc.foo.id}" 684 685 ingress { 686 protocol = "icmp" 687 from_port = -1 688 to_port = -1 689 cidr_blocks = ["0.0.0.0/0"] 690 } 691 } 692 693 resource "aws_subnet" "foo" { 694 cidr_block = "10.1.1.0/24" 695 vpc_id = "${aws_vpc.foo.id}" 696 } 697 698 resource "aws_instance" "foo_instance" { 699 ami = "ami-21f78e11" 700 instance_type = "t1.micro" 701 vpc_security_group_ids = ["${aws_security_group.tf_test_foo.id}"] 702 subnet_id = "${aws_subnet.foo.id}" 703 depends_on = ["aws_internet_gateway.gw"] 704 } 705 706 resource "aws_eip" "foo_eip" { 707 instance = "${aws_instance.foo_instance.id}" 708 vpc = true 709 depends_on = ["aws_internet_gateway.gw"] 710 } 711 `