github.com/jefferai/terraform@v0.3.7-0.20150310153852-f7512ca29fcf/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/terraform/helper/resource" 9 "github.com/hashicorp/terraform/helper/schema" 10 "github.com/hashicorp/terraform/terraform" 11 "github.com/mitchellh/goamz/ec2" 12 ) 13 14 func TestAccAWSInstance_normal(t *testing.T) { 15 var v ec2.Instance 16 17 testCheck := func(*terraform.State) error { 18 if v.AvailZone != "us-west-2a" { 19 return fmt.Errorf("bad availability zone: %#v", v.AvailZone) 20 } 21 22 if len(v.SecurityGroups) == 0 { 23 return fmt.Errorf("no security groups: %#v", v.SecurityGroups) 24 } 25 if v.SecurityGroups[0].Name != "tf_test_foo" { 26 return fmt.Errorf("no security groups: %#v", v.SecurityGroups) 27 } 28 29 return nil 30 } 31 32 resource.Test(t, resource.TestCase{ 33 PreCheck: func() { testAccPreCheck(t) }, 34 Providers: testAccProviders, 35 CheckDestroy: testAccCheckInstanceDestroy, 36 Steps: []resource.TestStep{ 37 resource.TestStep{ 38 Config: testAccInstanceConfig, 39 Check: resource.ComposeTestCheckFunc( 40 testAccCheckInstanceExists( 41 "aws_instance.foo", &v), 42 testCheck, 43 resource.TestCheckResourceAttr( 44 "aws_instance.foo", 45 "user_data", 46 "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), 47 ), 48 }, 49 50 // We repeat the exact same test so that we can be sure 51 // that the user data hash stuff is working without generating 52 // an incorrect diff. 53 resource.TestStep{ 54 Config: testAccInstanceConfig, 55 Check: resource.ComposeTestCheckFunc( 56 testAccCheckInstanceExists( 57 "aws_instance.foo", &v), 58 testCheck, 59 resource.TestCheckResourceAttr( 60 "aws_instance.foo", 61 "user_data", 62 "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), 63 ), 64 }, 65 }, 66 }) 67 } 68 69 func TestAccAWSInstance_blockDevices(t *testing.T) { 70 var v ec2.Instance 71 72 testCheck := func() resource.TestCheckFunc { 73 return func(*terraform.State) error { 74 75 // Map out the block devices by name, which should be unique. 76 blockDevices := make(map[string]ec2.BlockDevice) 77 for _, blockDevice := range v.BlockDevices { 78 blockDevices[blockDevice.DeviceName] = blockDevice 79 } 80 81 // Check if the root block device exists. 82 if _, ok := blockDevices["/dev/sda1"]; !ok { 83 fmt.Errorf("block device doesn't exist: /dev/sda1") 84 } 85 86 // Check if the secondary block device exists. 87 if _, ok := blockDevices["/dev/sdb"]; !ok { 88 fmt.Errorf("block device doesn't exist: /dev/sdb") 89 } 90 91 // Check if the third block device exists. 92 if _, ok := blockDevices["/dev/sdc"]; !ok { 93 fmt.Errorf("block device doesn't exist: /dev/sdc") 94 } 95 96 return nil 97 } 98 } 99 100 resource.Test(t, resource.TestCase{ 101 PreCheck: func() { testAccPreCheck(t) }, 102 Providers: testAccProviders, 103 CheckDestroy: testAccCheckInstanceDestroy, 104 Steps: []resource.TestStep{ 105 resource.TestStep{ 106 Config: testAccInstanceConfigBlockDevices, 107 Check: resource.ComposeTestCheckFunc( 108 testAccCheckInstanceExists( 109 "aws_instance.foo", &v), 110 resource.TestCheckResourceAttr( 111 "aws_instance.foo", "root_block_device.#", "1"), 112 resource.TestCheckResourceAttr( 113 "aws_instance.foo", "root_block_device.0.device_name", "/dev/sda1"), 114 resource.TestCheckResourceAttr( 115 "aws_instance.foo", "root_block_device.0.volume_size", "11"), 116 // this one is important because it's the only root_block_device 117 // attribute that comes back from the API. so checking it verifies 118 // that we set state properly 119 resource.TestCheckResourceAttr( 120 "aws_instance.foo", "root_block_device.0.volume_type", "gp2"), 121 resource.TestCheckResourceAttr( 122 "aws_instance.foo", "block_device.#", "2"), 123 resource.TestCheckResourceAttr( 124 "aws_instance.foo", "block_device.172787947.device_name", "/dev/sdb"), 125 resource.TestCheckResourceAttr( 126 "aws_instance.foo", "block_device.172787947.volume_size", "9"), 127 resource.TestCheckResourceAttr( 128 "aws_instance.foo", "block_device.172787947.iops", "0"), 129 // Check provisioned SSD device 130 resource.TestCheckResourceAttr( 131 "aws_instance.foo", "block_device.3336996981.volume_type", "io1"), 132 resource.TestCheckResourceAttr( 133 "aws_instance.foo", "block_device.3336996981.device_name", "/dev/sdc"), 134 resource.TestCheckResourceAttr( 135 "aws_instance.foo", "block_device.3336996981.volume_size", "10"), 136 resource.TestCheckResourceAttr( 137 "aws_instance.foo", "block_device.3336996981.iops", "100"), 138 testCheck(), 139 ), 140 }, 141 }, 142 }) 143 } 144 145 func TestAccAWSInstance_sourceDestCheck(t *testing.T) { 146 var v ec2.Instance 147 148 testCheck := func(enabled bool) resource.TestCheckFunc { 149 return func(*terraform.State) error { 150 if v.SourceDestCheck != enabled { 151 return fmt.Errorf("bad source_dest_check: %#v", v.SourceDestCheck) 152 } 153 154 return nil 155 } 156 } 157 158 resource.Test(t, resource.TestCase{ 159 PreCheck: func() { testAccPreCheck(t) }, 160 Providers: testAccProviders, 161 CheckDestroy: testAccCheckInstanceDestroy, 162 Steps: []resource.TestStep{ 163 resource.TestStep{ 164 Config: testAccInstanceConfigSourceDestDisable, 165 Check: resource.ComposeTestCheckFunc( 166 testAccCheckInstanceExists("aws_instance.foo", &v), 167 testCheck(false), 168 ), 169 }, 170 171 resource.TestStep{ 172 Config: testAccInstanceConfigSourceDestEnable, 173 Check: resource.ComposeTestCheckFunc( 174 testAccCheckInstanceExists("aws_instance.foo", &v), 175 testCheck(true), 176 ), 177 }, 178 179 resource.TestStep{ 180 Config: testAccInstanceConfigSourceDestDisable, 181 Check: resource.ComposeTestCheckFunc( 182 testAccCheckInstanceExists("aws_instance.foo", &v), 183 testCheck(false), 184 ), 185 }, 186 }, 187 }) 188 } 189 190 func TestAccAWSInstance_vpc(t *testing.T) { 191 var v ec2.Instance 192 193 resource.Test(t, resource.TestCase{ 194 PreCheck: func() { testAccPreCheck(t) }, 195 Providers: testAccProviders, 196 CheckDestroy: testAccCheckInstanceDestroy, 197 Steps: []resource.TestStep{ 198 resource.TestStep{ 199 Config: testAccInstanceConfigVPC, 200 Check: resource.ComposeTestCheckFunc( 201 testAccCheckInstanceExists( 202 "aws_instance.foo", &v), 203 ), 204 }, 205 }, 206 }) 207 } 208 209 func TestAccInstance_tags(t *testing.T) { 210 var v ec2.Instance 211 212 resource.Test(t, resource.TestCase{ 213 PreCheck: func() { testAccPreCheck(t) }, 214 Providers: testAccProviders, 215 CheckDestroy: testAccCheckInstanceDestroy, 216 Steps: []resource.TestStep{ 217 resource.TestStep{ 218 Config: testAccCheckInstanceConfigTags, 219 Check: resource.ComposeTestCheckFunc( 220 testAccCheckInstanceExists("aws_instance.foo", &v), 221 testAccCheckTags(&v.Tags, "foo", "bar"), 222 // Guard against regression of https://github.com/hashicorp/terraform/issues/914 223 testAccCheckTags(&v.Tags, "#", ""), 224 ), 225 }, 226 227 resource.TestStep{ 228 Config: testAccCheckInstanceConfigTagsUpdate, 229 Check: resource.ComposeTestCheckFunc( 230 testAccCheckInstanceExists("aws_instance.foo", &v), 231 testAccCheckTags(&v.Tags, "foo", ""), 232 testAccCheckTags(&v.Tags, "bar", "baz"), 233 ), 234 }, 235 }, 236 }) 237 } 238 239 func TestAccInstance_privateIP(t *testing.T) { 240 var v ec2.Instance 241 242 testCheckPrivateIP := func() resource.TestCheckFunc { 243 return func(*terraform.State) error { 244 if v.PrivateIpAddress != "10.1.1.42" { 245 return fmt.Errorf("bad private IP: %s", v.PrivateIpAddress) 246 } 247 248 return nil 249 } 250 } 251 252 resource.Test(t, resource.TestCase{ 253 PreCheck: func() { testAccPreCheck(t) }, 254 Providers: testAccProviders, 255 CheckDestroy: testAccCheckInstanceDestroy, 256 Steps: []resource.TestStep{ 257 resource.TestStep{ 258 Config: testAccInstanceConfigPrivateIP, 259 Check: resource.ComposeTestCheckFunc( 260 testAccCheckInstanceExists("aws_instance.foo", &v), 261 testCheckPrivateIP(), 262 ), 263 }, 264 }, 265 }) 266 } 267 268 func TestAccInstance_associatePublicIPAndPrivateIP(t *testing.T) { 269 var v ec2.Instance 270 271 testCheckPrivateIP := func() resource.TestCheckFunc { 272 return func(*terraform.State) error { 273 if v.PrivateIpAddress != "10.1.1.42" { 274 return fmt.Errorf("bad private IP: %s", v.PrivateIpAddress) 275 } 276 277 return nil 278 } 279 } 280 281 resource.Test(t, resource.TestCase{ 282 PreCheck: func() { testAccPreCheck(t) }, 283 Providers: testAccProviders, 284 CheckDestroy: testAccCheckInstanceDestroy, 285 Steps: []resource.TestStep{ 286 resource.TestStep{ 287 Config: testAccInstanceConfigAssociatePublicIPAndPrivateIP, 288 Check: resource.ComposeTestCheckFunc( 289 testAccCheckInstanceExists("aws_instance.foo", &v), 290 testCheckPrivateIP(), 291 ), 292 }, 293 }, 294 }) 295 } 296 297 func testAccCheckInstanceDestroy(s *terraform.State) error { 298 conn := testAccProvider.Meta().(*AWSClient).ec2conn 299 300 for _, rs := range s.RootModule().Resources { 301 if rs.Type != "aws_instance" { 302 continue 303 } 304 305 // Try to find the resource 306 resp, err := conn.Instances( 307 []string{rs.Primary.ID}, ec2.NewFilter()) 308 if err == nil { 309 if len(resp.Reservations) > 0 { 310 return fmt.Errorf("still exist.") 311 } 312 313 return nil 314 } 315 316 // Verify the error is what we want 317 ec2err, ok := err.(*ec2.Error) 318 if !ok { 319 return err 320 } 321 if ec2err.Code != "InvalidInstanceID.NotFound" { 322 return err 323 } 324 } 325 326 return nil 327 } 328 329 func testAccCheckInstanceExists(n string, i *ec2.Instance) resource.TestCheckFunc { 330 return func(s *terraform.State) error { 331 rs, ok := s.RootModule().Resources[n] 332 if !ok { 333 return fmt.Errorf("Not found: %s", n) 334 } 335 336 if rs.Primary.ID == "" { 337 return fmt.Errorf("No ID is set") 338 } 339 340 conn := testAccProvider.Meta().(*AWSClient).ec2conn 341 resp, err := conn.Instances( 342 []string{rs.Primary.ID}, ec2.NewFilter()) 343 if err != nil { 344 return err 345 } 346 if len(resp.Reservations) == 0 { 347 return fmt.Errorf("Instance not found") 348 } 349 350 *i = resp.Reservations[0].Instances[0] 351 352 return nil 353 } 354 } 355 356 func TestInstanceTenancySchema(t *testing.T) { 357 actualSchema := resourceAwsInstance().Schema["tenancy"] 358 expectedSchema := &schema.Schema{ 359 Type: schema.TypeString, 360 Optional: true, 361 Computed: true, 362 ForceNew: true, 363 } 364 if !reflect.DeepEqual(actualSchema, expectedSchema) { 365 t.Fatalf( 366 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 367 actualSchema, 368 expectedSchema) 369 } 370 } 371 372 const testAccInstanceConfig = ` 373 resource "aws_security_group" "tf_test_foo" { 374 name = "tf_test_foo" 375 description = "foo" 376 377 ingress { 378 protocol = "icmp" 379 from_port = -1 380 to_port = -1 381 cidr_blocks = ["0.0.0.0/0"] 382 } 383 } 384 385 resource "aws_instance" "foo" { 386 # us-west-2 387 ami = "ami-4fccb37f" 388 availability_zone = "us-west-2a" 389 390 instance_type = "m1.small" 391 security_groups = ["${aws_security_group.tf_test_foo.name}"] 392 user_data = "foo" 393 } 394 ` 395 396 const testAccInstanceConfigBlockDevices = ` 397 resource "aws_instance" "foo" { 398 # us-west-2 399 ami = "ami-55a7ea65" 400 instance_type = "m1.small" 401 root_block_device { 402 device_name = "/dev/sda1" 403 volume_type = "gp2" 404 volume_size = 11 405 } 406 block_device { 407 device_name = "/dev/sdb" 408 volume_size = 9 409 } 410 block_device { 411 device_name = "/dev/sdc" 412 volume_size = 10 413 volume_type = "io1" 414 iops = 100 415 } 416 } 417 ` 418 419 const testAccInstanceConfigSourceDestEnable = ` 420 resource "aws_vpc" "foo" { 421 cidr_block = "10.1.0.0/16" 422 } 423 424 resource "aws_subnet" "foo" { 425 cidr_block = "10.1.1.0/24" 426 vpc_id = "${aws_vpc.foo.id}" 427 } 428 429 resource "aws_instance" "foo" { 430 # us-west-2 431 ami = "ami-4fccb37f" 432 instance_type = "m1.small" 433 subnet_id = "${aws_subnet.foo.id}" 434 source_dest_check = true 435 } 436 ` 437 438 const testAccInstanceConfigSourceDestDisable = ` 439 resource "aws_vpc" "foo" { 440 cidr_block = "10.1.0.0/16" 441 } 442 443 resource "aws_subnet" "foo" { 444 cidr_block = "10.1.1.0/24" 445 vpc_id = "${aws_vpc.foo.id}" 446 } 447 448 resource "aws_instance" "foo" { 449 # us-west-2 450 ami = "ami-4fccb37f" 451 instance_type = "m1.small" 452 subnet_id = "${aws_subnet.foo.id}" 453 source_dest_check = false 454 } 455 ` 456 457 const testAccInstanceConfigVPC = ` 458 resource "aws_vpc" "foo" { 459 cidr_block = "10.1.0.0/16" 460 } 461 462 resource "aws_subnet" "foo" { 463 cidr_block = "10.1.1.0/24" 464 vpc_id = "${aws_vpc.foo.id}" 465 } 466 467 resource "aws_instance" "foo" { 468 # us-west-2 469 ami = "ami-4fccb37f" 470 instance_type = "m1.small" 471 subnet_id = "${aws_subnet.foo.id}" 472 associate_public_ip_address = true 473 tenancy = "dedicated" 474 } 475 ` 476 477 const testAccCheckInstanceConfigTags = ` 478 resource "aws_instance" "foo" { 479 ami = "ami-4fccb37f" 480 instance_type = "m1.small" 481 tags { 482 foo = "bar" 483 } 484 } 485 ` 486 487 const testAccCheckInstanceConfigTagsUpdate = ` 488 resource "aws_instance" "foo" { 489 ami = "ami-4fccb37f" 490 instance_type = "m1.small" 491 tags { 492 bar = "baz" 493 } 494 } 495 ` 496 497 const testAccInstanceConfigPrivateIP = ` 498 resource "aws_vpc" "foo" { 499 cidr_block = "10.1.0.0/16" 500 } 501 502 resource "aws_subnet" "foo" { 503 cidr_block = "10.1.1.0/24" 504 vpc_id = "${aws_vpc.foo.id}" 505 } 506 507 resource "aws_instance" "foo" { 508 ami = "ami-c5eabbf5" 509 instance_type = "t2.micro" 510 subnet_id = "${aws_subnet.foo.id}" 511 private_ip = "10.1.1.42" 512 } 513 ` 514 515 const testAccInstanceConfigAssociatePublicIPAndPrivateIP = ` 516 resource "aws_vpc" "foo" { 517 cidr_block = "10.1.0.0/16" 518 } 519 520 resource "aws_subnet" "foo" { 521 cidr_block = "10.1.1.0/24" 522 vpc_id = "${aws_vpc.foo.id}" 523 } 524 525 resource "aws_instance" "foo" { 526 ami = "ami-c5eabbf5" 527 instance_type = "t2.micro" 528 subnet_id = "${aws_subnet.foo.id}" 529 associate_public_ip_address = true 530 private_ip = "10.1.1.42" 531 } 532 `