github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/digitalocean/resource_digitalocean_droplet_test.go (about) 1 package digitalocean 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 "testing" 8 9 "github.com/digitalocean/godo" 10 "github.com/hashicorp/terraform/helper/acctest" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/terraform" 13 ) 14 15 func TestAccDigitalOceanDroplet_Basic(t *testing.T) { 16 var droplet godo.Droplet 17 rInt := acctest.RandInt() 18 19 resource.Test(t, resource.TestCase{ 20 PreCheck: func() { testAccPreCheck(t) }, 21 Providers: testAccProviders, 22 CheckDestroy: testAccCheckDigitalOceanDropletDestroy, 23 Steps: []resource.TestStep{ 24 { 25 Config: testAccCheckDigitalOceanDropletConfig_basic(rInt), 26 Check: resource.ComposeTestCheckFunc( 27 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &droplet), 28 testAccCheckDigitalOceanDropletAttributes(&droplet), 29 resource.TestCheckResourceAttr( 30 "digitalocean_droplet.foobar", "name", fmt.Sprintf("foo-%d", rInt)), 31 resource.TestCheckResourceAttr( 32 "digitalocean_droplet.foobar", "size", "512mb"), 33 resource.TestCheckResourceAttr( 34 "digitalocean_droplet.foobar", "price_hourly", "0.00744"), 35 resource.TestCheckResourceAttr( 36 "digitalocean_droplet.foobar", "price_monthly", "5"), 37 resource.TestCheckResourceAttr( 38 "digitalocean_droplet.foobar", "image", "centos-7-x64"), 39 resource.TestCheckResourceAttr( 40 "digitalocean_droplet.foobar", "region", "nyc3"), 41 resource.TestCheckResourceAttr( 42 "digitalocean_droplet.foobar", "user_data", "foobar"), 43 ), 44 Destroy: false, 45 }, 46 { 47 Config: testAccCheckDigitalOceanDropletConfig_basic(rInt), 48 PlanOnly: true, 49 }, 50 }, 51 }) 52 } 53 54 func TestAccDigitalOceanDroplet_withSSH(t *testing.T) { 55 var droplet godo.Droplet 56 rInt := acctest.RandInt() 57 58 resource.Test(t, resource.TestCase{ 59 PreCheck: func() { testAccPreCheck(t) }, 60 Providers: testAccProviders, 61 CheckDestroy: testAccCheckDigitalOceanDropletDestroy, 62 Steps: []resource.TestStep{ 63 { 64 Config: testAccCheckDigitalOceanDropletConfig_withSSH(rInt), 65 Check: resource.ComposeTestCheckFunc( 66 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &droplet), 67 testAccCheckDigitalOceanDropletAttributes(&droplet), 68 resource.TestCheckResourceAttr( 69 "digitalocean_droplet.foobar", "name", fmt.Sprintf("foo-%d", rInt)), 70 resource.TestCheckResourceAttr( 71 "digitalocean_droplet.foobar", "size", "512mb"), 72 resource.TestCheckResourceAttr( 73 "digitalocean_droplet.foobar", "image", "centos-7-x64"), 74 resource.TestCheckResourceAttr( 75 "digitalocean_droplet.foobar", "region", "nyc3"), 76 resource.TestCheckResourceAttr( 77 "digitalocean_droplet.foobar", "user_data", "foobar"), 78 ), 79 }, 80 }, 81 }) 82 } 83 84 func TestAccDigitalOceanDroplet_Update(t *testing.T) { 85 var droplet godo.Droplet 86 rInt := acctest.RandInt() 87 88 resource.Test(t, resource.TestCase{ 89 PreCheck: func() { testAccPreCheck(t) }, 90 Providers: testAccProviders, 91 CheckDestroy: testAccCheckDigitalOceanDropletDestroy, 92 Steps: []resource.TestStep{ 93 { 94 Config: testAccCheckDigitalOceanDropletConfig_basic(rInt), 95 Check: resource.ComposeTestCheckFunc( 96 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &droplet), 97 testAccCheckDigitalOceanDropletAttributes(&droplet), 98 resource.TestCheckResourceAttr( 99 "digitalocean_droplet.foobar", "name", fmt.Sprintf("foo-%d", rInt)), 100 ), 101 }, 102 103 { 104 Config: testAccCheckDigitalOceanDropletConfig_RenameAndResize(rInt), 105 Check: resource.ComposeTestCheckFunc( 106 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &droplet), 107 testAccCheckDigitalOceanDropletRenamedAndResized(&droplet), 108 resource.TestCheckResourceAttr( 109 "digitalocean_droplet.foobar", "name", fmt.Sprintf("baz-%d", rInt)), 110 resource.TestCheckResourceAttr( 111 "digitalocean_droplet.foobar", "size", "1gb"), 112 resource.TestCheckResourceAttr( 113 "digitalocean_droplet.foobar", "disk", "30"), 114 ), 115 }, 116 }, 117 }) 118 } 119 120 func TestAccDigitalOceanDroplet_ResizeWithOutDisk(t *testing.T) { 121 var droplet godo.Droplet 122 rInt := acctest.RandInt() 123 124 resource.Test(t, resource.TestCase{ 125 PreCheck: func() { testAccPreCheck(t) }, 126 Providers: testAccProviders, 127 CheckDestroy: testAccCheckDigitalOceanDropletDestroy, 128 Steps: []resource.TestStep{ 129 { 130 Config: testAccCheckDigitalOceanDropletConfig_basic(rInt), 131 Check: resource.ComposeTestCheckFunc( 132 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &droplet), 133 testAccCheckDigitalOceanDropletAttributes(&droplet), 134 resource.TestCheckResourceAttr( 135 "digitalocean_droplet.foobar", "name", fmt.Sprintf("foo-%d", rInt)), 136 ), 137 }, 138 139 { 140 Config: testAccCheckDigitalOceanDropletConfig_resize_without_disk(rInt), 141 Check: resource.ComposeTestCheckFunc( 142 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &droplet), 143 testAccCheckDigitalOceanDropletResizeWithOutDisk(&droplet), 144 resource.TestCheckResourceAttr( 145 "digitalocean_droplet.foobar", "name", fmt.Sprintf("foo-%d", rInt)), 146 resource.TestCheckResourceAttr( 147 "digitalocean_droplet.foobar", "size", "1gb"), 148 resource.TestCheckResourceAttr( 149 "digitalocean_droplet.foobar", "disk", "20"), 150 ), 151 }, 152 }, 153 }) 154 } 155 156 func TestAccDigitalOceanDroplet_ResizeOnlyDisk(t *testing.T) { 157 var droplet godo.Droplet 158 rInt := acctest.RandInt() 159 160 resource.Test(t, resource.TestCase{ 161 PreCheck: func() { testAccPreCheck(t) }, 162 Providers: testAccProviders, 163 CheckDestroy: testAccCheckDigitalOceanDropletDestroy, 164 Steps: []resource.TestStep{ 165 { 166 Config: testAccCheckDigitalOceanDropletConfig_basic(rInt), 167 Check: resource.ComposeTestCheckFunc( 168 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &droplet), 169 testAccCheckDigitalOceanDropletAttributes(&droplet), 170 resource.TestCheckResourceAttr( 171 "digitalocean_droplet.foobar", "name", fmt.Sprintf("foo-%d", rInt)), 172 ), 173 }, 174 175 { 176 Config: testAccCheckDigitalOceanDropletConfig_resize_without_disk(rInt), 177 Check: resource.ComposeTestCheckFunc( 178 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &droplet), 179 testAccCheckDigitalOceanDropletResizeWithOutDisk(&droplet), 180 resource.TestCheckResourceAttr( 181 "digitalocean_droplet.foobar", "name", fmt.Sprintf("foo-%d", rInt)), 182 resource.TestCheckResourceAttr( 183 "digitalocean_droplet.foobar", "size", "1gb"), 184 resource.TestCheckResourceAttr( 185 "digitalocean_droplet.foobar", "disk", "20"), 186 ), 187 }, 188 189 { 190 Config: testAccCheckDigitalOceanDropletConfig_resize_only_disk(rInt), 191 Check: resource.ComposeTestCheckFunc( 192 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &droplet), 193 testAccCheckDigitalOceanDropletResizeOnlyDisk(&droplet), 194 resource.TestCheckResourceAttr( 195 "digitalocean_droplet.foobar", "name", fmt.Sprintf("foo-%d", rInt)), 196 resource.TestCheckResourceAttr( 197 "digitalocean_droplet.foobar", "size", "1gb"), 198 resource.TestCheckResourceAttr( 199 "digitalocean_droplet.foobar", "disk", "30"), 200 ), 201 }, 202 }, 203 }) 204 } 205 206 func TestAccDigitalOceanDroplet_UpdateUserData(t *testing.T) { 207 var afterCreate, afterUpdate godo.Droplet 208 rInt := acctest.RandInt() 209 210 resource.Test(t, resource.TestCase{ 211 PreCheck: func() { testAccPreCheck(t) }, 212 Providers: testAccProviders, 213 CheckDestroy: testAccCheckDigitalOceanDropletDestroy, 214 Steps: []resource.TestStep{ 215 { 216 Config: testAccCheckDigitalOceanDropletConfig_basic(rInt), 217 Check: resource.ComposeTestCheckFunc( 218 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &afterCreate), 219 testAccCheckDigitalOceanDropletAttributes(&afterCreate), 220 resource.TestCheckResourceAttr( 221 "digitalocean_droplet.foobar", "name", fmt.Sprintf("foo-%d", rInt)), 222 ), 223 }, 224 225 { 226 Config: testAccCheckDigitalOceanDropletConfig_userdata_update(rInt), 227 Check: resource.ComposeTestCheckFunc( 228 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &afterUpdate), 229 resource.TestCheckResourceAttr( 230 "digitalocean_droplet.foobar", "name", fmt.Sprintf("foo-%d", rInt)), 231 resource.TestCheckResourceAttr( 232 "digitalocean_droplet.foobar", 233 "user_data", 234 "foobar foobar"), 235 testAccCheckDigitalOceanDropletRecreated( 236 t, &afterCreate, &afterUpdate), 237 ), 238 }, 239 }, 240 }) 241 } 242 243 func TestAccDigitalOceanDroplet_UpdateTags(t *testing.T) { 244 var afterCreate, afterUpdate godo.Droplet 245 rInt := acctest.RandInt() 246 247 resource.Test(t, resource.TestCase{ 248 PreCheck: func() { testAccPreCheck(t) }, 249 Providers: testAccProviders, 250 CheckDestroy: testAccCheckDigitalOceanDropletDestroy, 251 Steps: []resource.TestStep{ 252 { 253 Config: testAccCheckDigitalOceanDropletConfig_basic(rInt), 254 Check: resource.ComposeTestCheckFunc( 255 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &afterCreate), 256 testAccCheckDigitalOceanDropletAttributes(&afterCreate), 257 resource.TestCheckResourceAttr( 258 "digitalocean_droplet.foobar", "name", fmt.Sprintf("foo-%d", rInt)), 259 ), 260 }, 261 262 { 263 Config: testAccCheckDigitalOceanDropletConfig_tag_update(rInt), 264 Check: resource.ComposeTestCheckFunc( 265 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &afterUpdate), 266 resource.TestCheckResourceAttr( 267 "digitalocean_droplet.foobar", "name", fmt.Sprintf("foo-%d", rInt)), 268 resource.TestCheckResourceAttr( 269 "digitalocean_droplet.foobar", 270 "tags.#", 271 "1"), 272 resource.TestCheckResourceAttr( 273 "digitalocean_droplet.foobar", 274 "tags.0", 275 "barbaz"), 276 ), 277 }, 278 }, 279 }) 280 } 281 282 func TestAccDigitalOceanDroplet_PrivateNetworkingIpv6(t *testing.T) { 283 var droplet godo.Droplet 284 rInt := acctest.RandInt() 285 286 resource.Test(t, resource.TestCase{ 287 PreCheck: func() { testAccPreCheck(t) }, 288 Providers: testAccProviders, 289 CheckDestroy: testAccCheckDigitalOceanDropletDestroy, 290 Steps: []resource.TestStep{ 291 { 292 Config: testAccCheckDigitalOceanDropletConfig_PrivateNetworkingIpv6(rInt), 293 Check: resource.ComposeTestCheckFunc( 294 testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &droplet), 295 testAccCheckDigitalOceanDropletAttributes_PrivateNetworkingIpv6(&droplet), 296 resource.TestCheckResourceAttr( 297 "digitalocean_droplet.foobar", "private_networking", "true"), 298 resource.TestCheckResourceAttr( 299 "digitalocean_droplet.foobar", "ipv6", "true"), 300 ), 301 }, 302 }, 303 }) 304 } 305 306 func testAccCheckDigitalOceanDropletDestroy(s *terraform.State) error { 307 client := testAccProvider.Meta().(*godo.Client) 308 309 for _, rs := range s.RootModule().Resources { 310 if rs.Type != "digitalocean_droplet" { 311 continue 312 } 313 314 id, err := strconv.Atoi(rs.Primary.ID) 315 if err != nil { 316 return err 317 } 318 319 // Try to find the Droplet 320 _, _, err = client.Droplets.Get(id) 321 322 // Wait 323 324 if err != nil && !strings.Contains(err.Error(), "404") { 325 return fmt.Errorf( 326 "Error waiting for droplet (%s) to be destroyed: %s", 327 rs.Primary.ID, err) 328 } 329 } 330 331 return nil 332 } 333 334 func testAccCheckDigitalOceanDropletAttributes(droplet *godo.Droplet) resource.TestCheckFunc { 335 return func(s *terraform.State) error { 336 337 if droplet.Image.Slug != "centos-7-x64" { 338 return fmt.Errorf("Bad image_slug: %s", droplet.Image.Slug) 339 } 340 341 if droplet.Size.Slug != "512mb" { 342 return fmt.Errorf("Bad size_slug: %s", droplet.Size.Slug) 343 } 344 345 if droplet.Size.PriceHourly != 0.00744 { 346 return fmt.Errorf("Bad price_hourly: %v", droplet.Size.PriceHourly) 347 } 348 349 if droplet.Size.PriceMonthly != 5.0 { 350 return fmt.Errorf("Bad price_monthly: %v", droplet.Size.PriceMonthly) 351 } 352 353 if droplet.Region.Slug != "nyc3" { 354 return fmt.Errorf("Bad region_slug: %s", droplet.Region.Slug) 355 } 356 357 return nil 358 } 359 } 360 361 func testAccCheckDigitalOceanDropletRenamedAndResized(droplet *godo.Droplet) resource.TestCheckFunc { 362 return func(s *terraform.State) error { 363 364 if droplet.Size.Slug != "1gb" { 365 return fmt.Errorf("Bad size_slug: %s", droplet.SizeSlug) 366 } 367 368 if droplet.Disk != 30 { 369 return fmt.Errorf("Bad disk: %d", droplet.Disk) 370 } 371 372 return nil 373 } 374 } 375 376 func testAccCheckDigitalOceanDropletResizeWithOutDisk(droplet *godo.Droplet) resource.TestCheckFunc { 377 return func(s *terraform.State) error { 378 379 if droplet.Size.Slug != "1gb" { 380 return fmt.Errorf("Bad size_slug: %s", droplet.SizeSlug) 381 } 382 383 if droplet.Disk != 20 { 384 return fmt.Errorf("Bad disk: %d", droplet.Disk) 385 } 386 387 return nil 388 } 389 } 390 391 func testAccCheckDigitalOceanDropletResizeOnlyDisk(droplet *godo.Droplet) resource.TestCheckFunc { 392 return func(s *terraform.State) error { 393 394 if droplet.Size.Slug != "1gb" { 395 return fmt.Errorf("Bad size_slug: %s", droplet.SizeSlug) 396 } 397 398 if droplet.Disk != 30 { 399 return fmt.Errorf("Bad disk: %d", droplet.Disk) 400 } 401 402 return nil 403 } 404 } 405 406 func testAccCheckDigitalOceanDropletAttributes_PrivateNetworkingIpv6(droplet *godo.Droplet) resource.TestCheckFunc { 407 return func(s *terraform.State) error { 408 409 if droplet.Image.Slug != "centos-7-x64" { 410 return fmt.Errorf("Bad image_slug: %s", droplet.Image.Slug) 411 } 412 413 if droplet.Size.Slug != "1gb" { 414 return fmt.Errorf("Bad size_slug: %s", droplet.Size.Slug) 415 } 416 417 if droplet.Region.Slug != "sgp1" { 418 return fmt.Errorf("Bad region_slug: %s", droplet.Region.Slug) 419 } 420 421 if findIPv4AddrByType(droplet, "private") == "" { 422 return fmt.Errorf("No ipv4 private: %s", findIPv4AddrByType(droplet, "private")) 423 } 424 425 // if droplet.IPV6Address("private") == "" { 426 // return fmt.Errorf("No ipv6 private: %s", droplet.IPV6Address("private")) 427 // } 428 429 if findIPv4AddrByType(droplet, "public") == "" { 430 return fmt.Errorf("No ipv4 public: %s", findIPv4AddrByType(droplet, "public")) 431 } 432 433 if findIPv6AddrByType(droplet, "public") == "" { 434 return fmt.Errorf("No ipv6 public: %s", findIPv6AddrByType(droplet, "public")) 435 } 436 437 for _, rs := range s.RootModule().Resources { 438 if rs.Type != "digitalocean_droplet" { 439 continue 440 } 441 if rs.Primary.Attributes["ipv6_address"] != strings.ToLower(findIPv6AddrByType(droplet, "public")) { 442 return fmt.Errorf("IPV6 Address should be lowercase") 443 } 444 445 } 446 447 return nil 448 } 449 } 450 451 func testAccCheckDigitalOceanDropletExists(n string, droplet *godo.Droplet) resource.TestCheckFunc { 452 return func(s *terraform.State) error { 453 rs, ok := s.RootModule().Resources[n] 454 if !ok { 455 return fmt.Errorf("Not found: %s", n) 456 } 457 458 if rs.Primary.ID == "" { 459 return fmt.Errorf("No Droplet ID is set") 460 } 461 462 client := testAccProvider.Meta().(*godo.Client) 463 464 id, err := strconv.Atoi(rs.Primary.ID) 465 if err != nil { 466 return err 467 } 468 469 // Try to find the Droplet 470 retrieveDroplet, _, err := client.Droplets.Get(id) 471 472 if err != nil { 473 return err 474 } 475 476 if strconv.Itoa(retrieveDroplet.ID) != rs.Primary.ID { 477 return fmt.Errorf("Droplet not found") 478 } 479 480 *droplet = *retrieveDroplet 481 482 return nil 483 } 484 } 485 486 func testAccCheckDigitalOceanDropletRecreated(t *testing.T, 487 before, after *godo.Droplet) resource.TestCheckFunc { 488 return func(s *terraform.State) error { 489 if before.ID == after.ID { 490 t.Fatalf("Expected change of droplet IDs, but both were %v", before.ID) 491 } 492 return nil 493 } 494 } 495 496 func testAccCheckDigitalOceanDropletConfig_basic(rInt int) string { 497 return fmt.Sprintf(` 498 resource "digitalocean_droplet" "foobar" { 499 name = "foo-%d" 500 size = "512mb" 501 image = "centos-7-x64" 502 region = "nyc3" 503 user_data = "foobar" 504 }`, rInt) 505 } 506 507 func testAccCheckDigitalOceanDropletConfig_withSSH(rInt int) string { 508 return fmt.Sprintf(` 509 resource "digitalocean_ssh_key" "foobar" { 510 name = "foobar-%d" 511 public_key = "%s" 512 } 513 514 resource "digitalocean_droplet" "foobar" { 515 name = "foo-%d" 516 size = "512mb" 517 image = "centos-7-x64" 518 region = "nyc3" 519 user_data = "foobar" 520 ssh_keys = ["${digitalocean_ssh_key.foobar.id}"] 521 }`, rInt, testAccValidPublicKey, rInt) 522 } 523 524 func testAccCheckDigitalOceanDropletConfig_tag_update(rInt int) string { 525 return fmt.Sprintf(` 526 resource "digitalocean_tag" "barbaz" { 527 name = "barbaz" 528 } 529 530 resource "digitalocean_droplet" "foobar" { 531 name = "foo-%d" 532 size = "512mb" 533 image = "centos-7-x64" 534 region = "nyc3" 535 user_data = "foobar" 536 tags = ["${digitalocean_tag.barbaz.id}"] 537 } 538 `, rInt) 539 } 540 541 func testAccCheckDigitalOceanDropletConfig_userdata_update(rInt int) string { 542 return fmt.Sprintf(` 543 resource "digitalocean_droplet" "foobar" { 544 name = "foo-%d" 545 size = "512mb" 546 image = "centos-7-x64" 547 region = "nyc3" 548 user_data = "foobar foobar" 549 } 550 `, rInt) 551 } 552 553 func testAccCheckDigitalOceanDropletConfig_RenameAndResize(rInt int) string { 554 return fmt.Sprintf(` 555 resource "digitalocean_droplet" "foobar" { 556 name = "baz-%d" 557 size = "1gb" 558 image = "centos-7-x64" 559 region = "nyc3" 560 } 561 `, rInt) 562 } 563 564 func testAccCheckDigitalOceanDropletConfig_resize_without_disk(rInt int) string { 565 return fmt.Sprintf(` 566 resource "digitalocean_droplet" "foobar" { 567 name = "foo-%d" 568 size = "1gb" 569 image = "centos-7-x64" 570 region = "nyc3" 571 user_data = "foobar" 572 resize_disk = false 573 } 574 `, rInt) 575 } 576 577 func testAccCheckDigitalOceanDropletConfig_resize_only_disk(rInt int) string { 578 return fmt.Sprintf(` 579 resource "digitalocean_droplet" "foobar" { 580 name = "foo-%d" 581 size = "1gb" 582 image = "centos-7-x64" 583 region = "nyc3" 584 user_data = "foobar" 585 resize_disk = true 586 } 587 `, rInt) 588 } 589 590 // IPV6 only in singapore 591 func testAccCheckDigitalOceanDropletConfig_PrivateNetworkingIpv6(rInt int) string { 592 return fmt.Sprintf(` 593 resource "digitalocean_droplet" "foobar" { 594 name = "baz-%d" 595 size = "1gb" 596 image = "centos-7-x64" 597 region = "sgp1" 598 ipv6 = true 599 private_networking = true 600 } 601 `, rInt) 602 } 603 604 var testAccValidPublicKey = `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR`