github.com/danrjohnson/terraform@v0.7.0-rc2.0.20160627135212-d0fc1fa086ff/builtin/providers/vsphere/resource_vsphere_virtual_machine_test.go (about) 1 package vsphere 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "testing" 8 9 "path/filepath" 10 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/terraform" 13 "github.com/vmware/govmomi" 14 "github.com/vmware/govmomi/find" 15 "github.com/vmware/govmomi/object" 16 "github.com/vmware/govmomi/property" 17 "github.com/vmware/govmomi/vim25/mo" 18 "github.com/vmware/govmomi/vim25/types" 19 "golang.org/x/net/context" 20 ) 21 22 /////// 23 // Various ENV vars are used to setup these tests. Look for `os.Getenv` 24 /////// 25 26 // Base setup function to check that a template, and nic information is set 27 // TODO needs some TLC - determine exactly how we want to do this 28 func testBasicPreCheck(t *testing.T) { 29 30 testAccPreCheck(t) 31 32 if v := os.Getenv("VSPHERE_TEMPLATE"); v == "" { 33 t.Fatal("env variable VSPHERE_TEMPLATE must be set for acceptance tests") 34 } 35 36 if v := os.Getenv("VSPHERE_IPV4_GATEWAY"); v == "" { 37 t.Fatal("env variable VSPHERE_IPV4_GATEWAY must be set for acceptance tests") 38 } 39 40 if v := os.Getenv("VSPHERE_IPV4_ADDRESS"); v == "" { 41 t.Fatal("env variable VSPHERE_IPV4_ADDRESS must be set for acceptance tests") 42 } 43 44 if v := os.Getenv("VSPHERE_NETWORK_LABEL"); v == "" { 45 t.Fatal("env variable VSPHERE_NETWORK_LABEL must be set for acceptance tests") 46 } 47 } 48 49 //// 50 // Collects optional env vars used in the tests 51 //// 52 func setupBaseVars() (string, string) { 53 var locationOpt string 54 var datastoreOpt string 55 56 if v := os.Getenv("VSPHERE_DATACENTER"); v != "" { 57 locationOpt += fmt.Sprintf(" datacenter = \"%s\"\n", v) 58 } 59 if v := os.Getenv("VSPHERE_CLUSTER"); v != "" { 60 locationOpt += fmt.Sprintf(" cluster = \"%s\"\n", v) 61 } 62 if v := os.Getenv("VSPHERE_RESOURCE_POOL"); v != "" { 63 locationOpt += fmt.Sprintf(" resource_pool = \"%s\"\n", v) 64 } 65 if v := os.Getenv("VSPHERE_DATASTORE"); v != "" { 66 datastoreOpt = fmt.Sprintf(" datastore = \"%s\"\n", v) 67 } 68 69 return locationOpt, datastoreOpt 70 } 71 72 //// 73 // Structs and funcs used with DHCP data template 74 //// 75 type TestDHCPBodyData struct { 76 template string 77 locationOpt string 78 datastoreOpt string 79 label string 80 } 81 82 func (body TestDHCPBodyData) parseDHCPTemplateConfigWithTemplate(template string) string { 83 return fmt.Sprintf( 84 template, 85 body.locationOpt, 86 body.label, 87 body.datastoreOpt, 88 body.template, 89 ) 90 91 } 92 93 const testAccCheckVSphereTemplate_dhcp = ` 94 %s 95 vcpu = 2 96 memory = 1024 97 network_interface { 98 label = "%s" 99 } 100 disk { 101 %s 102 template = "%s" 103 } 104 } 105 ` 106 107 // replaces data in the above template 108 func (body TestDHCPBodyData) parseDHCPTemplateConfig() string { 109 return fmt.Sprintf( 110 testAccCheckVSphereTemplate_dhcp, 111 body.locationOpt, 112 body.label, 113 body.datastoreOpt, 114 body.template, 115 ) 116 } 117 118 func (body TestDHCPBodyData) testSprintfDHCPTemplateBodySecondArgDynamic(template string, arg string) string { 119 return fmt.Sprintf( 120 template, 121 body.locationOpt, 122 arg, 123 body.label, 124 body.datastoreOpt, 125 body.template, 126 ) 127 } 128 129 // returns variables that are used in DHCP tests 130 func setupTemplateFuncDHCPData() TestDHCPBodyData { 131 132 locationOpt, datastoreOpt := setupBaseVars() 133 data := TestDHCPBodyData{ 134 template: os.Getenv("VSPHERE_TEMPLATE"), 135 label: os.Getenv("VSPHERE_NETWORK_LABEL_DHCP"), 136 locationOpt: locationOpt, 137 datastoreOpt: datastoreOpt, 138 } 139 // log.Printf("[DEBUG] basic vars= %v", data) 140 return data 141 142 } 143 144 //// 145 // Structs and funcs used with static ip data templates 146 //// 147 type TemplateBasicBodyVars struct { 148 locationOpt string 149 label string 150 ipv4IpAddress string 151 ipv4Prefix string 152 ipv4Gateway string 153 datastoreOpt string 154 template string 155 } 156 157 // Takes a base template that has seven "%s" values in it, used by most fixed ip 158 // tests 159 func (body TemplateBasicBodyVars) testSprintfTemplateBody(template string) string { 160 161 return fmt.Sprintf( 162 template, 163 body.locationOpt, 164 body.label, 165 body.ipv4IpAddress, 166 body.ipv4Prefix, 167 body.ipv4Gateway, 168 body.datastoreOpt, 169 body.template, 170 ) 171 } 172 173 // setups variables used by fixed ip tests 174 func setupTemplateBasicBodyVars() TemplateBasicBodyVars { 175 176 locationOpt, datastoreOpt := setupBaseVars() 177 prefix := os.Getenv("VSPHERE_IPV4_PREFIX") 178 if prefix == "" { 179 prefix = "24" 180 } 181 data := TemplateBasicBodyVars{ 182 template: os.Getenv("VSPHERE_TEMPLATE"), 183 ipv4Gateway: os.Getenv("VSPHERE_IPV4_GATEWAY"), 184 label: os.Getenv("VSPHERE_NETWORK_LABEL"), 185 ipv4IpAddress: os.Getenv("VSPHERE_IPV4_ADDRESS"), 186 ipv4Prefix: prefix, 187 locationOpt: locationOpt, 188 datastoreOpt: datastoreOpt, 189 } 190 // log.Printf("[DEBUG] basic vars= %v", data) 191 return data 192 } 193 194 //// 195 // Basic data to create series of testing functions 196 //// 197 type TestFuncData struct { 198 vm virtualMachine 199 label string 200 vmName string 201 vmResource string 202 numDisks string 203 numCPU string 204 mem string 205 } 206 207 // returns TestCheckFunc's that are used in many of our tests 208 // mem defaults to 1024 209 // cpu defaults to 2 210 // disks defatuls to 1 211 // vmResource defaults to "terraform-test" 212 // vmName defaults to "vsphere_virtual_machine.foo 213 func (test TestFuncData) testCheckFuncBasic() ( 214 resource.TestCheckFunc, resource.TestCheckFunc, resource.TestCheckFunc, resource.TestCheckFunc, 215 resource.TestCheckFunc, resource.TestCheckFunc, resource.TestCheckFunc) { 216 // log.Printf("[DEBUG] data= %v", test) 217 mem := test.mem 218 if mem == "" { 219 mem = "1024" 220 } 221 cpu := test.numCPU 222 if cpu == "" { 223 cpu = "2" 224 } 225 disks := test.numDisks 226 if disks == "" { 227 disks = "1" 228 } 229 res := test.vmResource 230 if res == "" { 231 res = "terraform-test" 232 } 233 vmName := test.vmName 234 if vmName == "" { 235 vmName = "vsphere_virtual_machine.foo" 236 } 237 return testAccCheckVSphereVirtualMachineExists(vmName, &test.vm), 238 resource.TestCheckResourceAttr(vmName, "name", res), 239 resource.TestCheckResourceAttr(vmName, "vcpu", cpu), 240 resource.TestCheckResourceAttr(vmName, "memory", mem), 241 resource.TestCheckResourceAttr(vmName, "disk.#", disks), 242 resource.TestCheckResourceAttr(vmName, "network_interface.#", "1"), 243 resource.TestCheckResourceAttr(vmName, "network_interface.0.label", test.label) 244 } 245 246 const testAccCheckVSphereVirtualMachineConfig_really_basic = ` 247 resource "vsphere_virtual_machine" "foo" { 248 name = "terraform-test" 249 ` + testAccTemplateBasicBodyWithEnd 250 251 // WARNING this is one of the base templates. You change this and you will 252 // be impacting multiple tests 253 const testAccTemplateBasicBody = ` 254 %s 255 vcpu = 2 256 memory = 1024 257 network_interface { 258 label = "%s" 259 ipv4_address = "%s" 260 ipv4_prefix_length = %s 261 ipv4_gateway = "%s" 262 } 263 disk { 264 %s 265 template = "%s" 266 iops = 500 267 } 268 ` 269 const testAccTemplateBasicBodyWithEnd = testAccTemplateBasicBody + ` 270 }` 271 272 func TestAccVSphereVirtualMachine_basic(t *testing.T) { 273 var vm virtualMachine 274 basic_vars := setupTemplateBasicBodyVars() 275 config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_really_basic) 276 277 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_really_basic) 278 log.Printf("[DEBUG] template config= %s", config) 279 280 resource.Test(t, resource.TestCase{ 281 PreCheck: func() { testBasicPreCheck(t) }, 282 Providers: testAccProviders, 283 CheckDestroy: testAccCheckVSphereVirtualMachineDestroy, 284 Steps: []resource.TestStep{ 285 resource.TestStep{ 286 Config: config, 287 Check: resource.ComposeTestCheckFunc( 288 TestFuncData{vm: vm, label: basic_vars.label}.testCheckFuncBasic(), 289 ), 290 }, 291 }, 292 }) 293 } 294 295 const testAccCheckVSphereVirtualMachineConfig_debug = ` 296 provider "vsphere" { 297 client_debug = true 298 } 299 300 ` + testAccCheckVSphereVirtualMachineConfig_really_basic 301 302 func TestAccVSphereVirtualMachine_client_debug(t *testing.T) { 303 var vm virtualMachine 304 basic_vars := setupTemplateBasicBodyVars() 305 config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_debug) 306 307 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_debug) 308 log.Printf("[DEBUG] template config= %s", config) 309 310 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label := 311 TestFuncData{vm: vm, label: basic_vars.label}.testCheckFuncBasic() 312 313 resource.Test(t, resource.TestCase{ 314 PreCheck: func() { testBasicPreCheck(t) }, 315 Providers: testAccProviders, 316 CheckDestroy: testAccCheckVSphereVirtualMachineDestroy, 317 Steps: []resource.TestStep{ 318 resource.TestStep{ 319 Config: config, 320 Check: resource.ComposeTestCheckFunc( 321 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label, 322 testAccCheckDebugExists(), 323 ), 324 }, 325 }, 326 }) 327 } 328 329 const testAccCheckVSphereVirtualMachineConfig_initType = ` 330 resource "vsphere_virtual_machine" "thin" { 331 name = "terraform-test" 332 ` + testAccTemplateBasicBody + ` 333 disk { 334 size = 1 335 iops = 500 336 controller_type = "scsi" 337 name = "one" 338 } 339 disk { 340 size = 1 341 controller_type = "ide" 342 type = "eager_zeroed" 343 name = "two" 344 } 345 } 346 ` 347 348 func TestAccVSphereVirtualMachine_diskInitType(t *testing.T) { 349 var vm virtualMachine 350 basic_vars := setupTemplateBasicBodyVars() 351 config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_initType) 352 353 vmName := "vsphere_virtual_machine.thin" 354 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label := 355 TestFuncData{vm: vm, label: basic_vars.label, vmName: vmName, numDisks: "3"}.testCheckFuncBasic() 356 357 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_initType) 358 log.Printf("[DEBUG] template config= %s", config) 359 360 resource.Test(t, resource.TestCase{ 361 PreCheck: func() { testAccPreCheck(t) }, 362 Providers: testAccProviders, 363 CheckDestroy: testAccCheckVSphereVirtualMachineDestroy, 364 Steps: []resource.TestStep{ 365 resource.TestStep{ 366 Config: config, 367 Check: resource.ComposeTestCheckFunc( 368 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label, 369 // FIXME dynmically calculate the hashes 370 resource.TestCheckResourceAttr(vmName, "disk.294918912.type", "eager_zeroed"), 371 resource.TestCheckResourceAttr(vmName, "disk.294918912.controller_type", "ide"), 372 resource.TestCheckResourceAttr(vmName, "disk.1380467090.controller_type", "scsi"), 373 ), 374 }, 375 }, 376 }) 377 } 378 379 const testAccCheckVSphereVirtualMachineConfig_dhcp = ` 380 resource "vsphere_virtual_machine" "bar" { 381 name = "terraform-test" 382 ` 383 384 func TestAccVSphereVirtualMachine_dhcp(t *testing.T) { 385 var vm virtualMachine 386 data := setupTemplateFuncDHCPData() 387 config := testAccCheckVSphereVirtualMachineConfig_dhcp + data.parseDHCPTemplateConfigWithTemplate(testAccCheckVSphereTemplate_dhcp) 388 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_dhcp+testAccCheckVSphereTemplate_dhcp) 389 log.Printf("[DEBUG] config= %s", config) 390 391 resource.Test(t, resource.TestCase{ 392 PreCheck: func() { testAccPreCheck(t) }, 393 Providers: testAccProviders, 394 CheckDestroy: testAccCheckVSphereVirtualMachineDestroy, 395 Steps: []resource.TestStep{ 396 resource.TestStep{ 397 Config: config, 398 Check: resource.ComposeTestCheckFunc( 399 TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(), 400 ), 401 }, 402 }, 403 }) 404 } 405 406 const testAccCheckVSphereVirtualMachineConfig_custom_configs = ` 407 resource "vsphere_virtual_machine" "car" { 408 name = "terraform-test-custom" 409 custom_configuration_parameters { 410 "foo" = "bar" 411 "car" = "ferrari" 412 "num" = 42 413 } 414 enable_disk_uuid = true 415 ` 416 417 func TestAccVSphereVirtualMachine_custom_configs(t *testing.T) { 418 419 var vm virtualMachine 420 data := setupTemplateFuncDHCPData() 421 config := testAccCheckVSphereVirtualMachineConfig_custom_configs + data.parseDHCPTemplateConfigWithTemplate(testAccCheckVSphereTemplate_dhcp) 422 vmName := "vsphere_virtual_machine.car" 423 res := "terraform-test-custom" 424 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label := 425 TestFuncData{vm: vm, label: data.label, vmName: vmName, vmResource: res}.testCheckFuncBasic() 426 427 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_custom_configs+testAccCheckVSphereTemplate_dhcp) 428 log.Printf("[DEBUG] config= %s", config) 429 430 resource.Test(t, resource.TestCase{ 431 PreCheck: func() { testAccPreCheck(t) }, 432 Providers: testAccProviders, 433 CheckDestroy: testAccCheckVSphereVirtualMachineDestroy, 434 Steps: []resource.TestStep{ 435 resource.TestStep{ 436 Config: config, 437 Check: resource.ComposeTestCheckFunc( 438 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label, 439 testAccCheckVSphereVirtualMachineExistsHasCustomConfig(vmName, &vm), 440 resource.TestCheckResourceAttr(vmName, "custom_configuration_parameters.foo", "bar"), 441 resource.TestCheckResourceAttr(vmName, "custom_configuration_parameters.car", "ferrari"), 442 resource.TestCheckResourceAttr(vmName, "custom_configuration_parameters.num", "42"), 443 resource.TestCheckResourceAttr(vmName, "enable_disk_uuid", "true"), 444 ), 445 }, 446 }, 447 }) 448 } 449 450 const testAccCheckVSphereVirtualMachineConfig_createInFolder = ` 451 resource "vsphere_virtual_machine" "folder" { 452 name = "terraform-test-folder" 453 folder = "%s" 454 ` 455 456 func TestAccVSphereVirtualMachine_createInExistingFolder(t *testing.T) { 457 var vm virtualMachine 458 datacenter := os.Getenv("VSPHERE_DATACENTER") 459 460 folder := "tf_test_cpureateInExistingFolder" 461 462 data := setupTemplateFuncDHCPData() 463 config := fmt.Sprintf(testAccCheckVSphereVirtualMachineConfig_createInFolder, 464 folder, 465 ) + data.parseDHCPTemplateConfig() 466 467 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_createInFolder) 468 log.Printf("[DEBUG] template config= %s", config) 469 470 resource.Test(t, resource.TestCase{ 471 PreCheck: func() { testAccPreCheck(t) }, 472 Providers: testAccProviders, 473 CheckDestroy: resource.ComposeTestCheckFunc( 474 testAccCheckVSphereVirtualMachineDestroy, 475 removeVSphereFolder(datacenter, folder, ""), 476 ), 477 Steps: []resource.TestStep{ 478 resource.TestStep{ 479 PreConfig: func() { createVSphereFolder(datacenter, folder) }, 480 Config: config, 481 Check: resource.ComposeTestCheckFunc( 482 TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.folder", vmResource: "terraform-test-folder"}.testCheckFuncBasic(), 483 ), 484 }, 485 }, 486 }) 487 } 488 489 const testAccCheckVSphereVirtualMachineConfig_createWithFolder = ` 490 resource "vsphere_folder" "with_folder" { 491 path = "%s" 492 %s 493 } 494 resource "vsphere_virtual_machine" "with_folder" { 495 name = "terraform-test-with-folder" 496 folder = "${vsphere_folder.with_folder.path}" 497 ` 498 499 func TestAccVSphereVirtualMachine_createWithFolder(t *testing.T) { 500 var vm virtualMachine 501 var folderLocationOpt string 502 var f folder 503 504 if v := os.Getenv("VSPHERE_DATACENTER"); v != "" { 505 folderLocationOpt = fmt.Sprintf(" datacenter = \"%s\"\n", v) 506 } 507 508 folder := "tf_test_cpureateWithFolder" 509 510 data := setupTemplateFuncDHCPData() 511 vmName := "vsphere_virtual_machine.with_folder" 512 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label := 513 TestFuncData{vm: vm, label: data.label, vmName: vmName, vmResource: "terraform-test-with-folder"}.testCheckFuncBasic() 514 515 config := fmt.Sprintf(testAccCheckVSphereVirtualMachineConfig_createWithFolder, 516 folder, 517 folderLocationOpt, 518 ) + data.parseDHCPTemplateConfig() 519 520 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_createWithFolder+testAccCheckVSphereTemplate_dhcp) 521 log.Printf("[DEBUG] template config= %s", config) 522 523 resource.Test(t, resource.TestCase{ 524 PreCheck: func() { testAccPreCheck(t) }, 525 Providers: testAccProviders, 526 CheckDestroy: resource.ComposeTestCheckFunc( 527 testAccCheckVSphereVirtualMachineDestroy, 528 testAccCheckVSphereFolderDestroy, 529 ), 530 Steps: []resource.TestStep{ 531 resource.TestStep{ 532 Config: config, 533 Check: resource.ComposeTestCheckFunc( 534 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label, 535 testAccCheckVSphereFolderExists(vmName, &f), 536 resource.TestCheckResourceAttr(vmName, "folder", folder), 537 ), 538 }, 539 }, 540 }) 541 } 542 543 const testAccCheckVsphereVirtualMachineConfig_cdrom = ` 544 resource "vsphere_virtual_machine" "with_cdrom" { 545 name = "terraform-test-with-cdrom" 546 cdrom { 547 datastore = "%s" 548 path = "%s" 549 } 550 ` 551 552 func TestAccVSphereVirtualMachine_createWithCdrom(t *testing.T) { 553 var vm virtualMachine 554 555 // FIXME check that these exist 556 cdromDatastore := os.Getenv("VSPHERE_CDROM_DATASTORE") 557 cdromPath := os.Getenv("VSPHERE_CDROM_PATH") 558 vmName := "vsphere_virtual_machine.with_cdrom" 559 560 data := setupTemplateFuncDHCPData() 561 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label := 562 TestFuncData{vm: vm, label: data.label, vmName: vmName, vmResource: "terraform-test-with-cdrom"}.testCheckFuncBasic() 563 564 config := fmt.Sprintf( 565 testAccCheckVsphereVirtualMachineConfig_cdrom, 566 cdromDatastore, 567 cdromPath, 568 ) + data.parseDHCPTemplateConfig() 569 570 log.Printf("[DEBUG] template= %s", testAccCheckVsphereVirtualMachineConfig_cdrom) 571 log.Printf("[DEBUG] template config= %s", config) 572 573 resource.Test(t, resource.TestCase{ 574 PreCheck: func() { testAccPreCheck(t) }, 575 Providers: testAccProviders, 576 CheckDestroy: testAccCheckVSphereVirtualMachineDestroy, 577 Steps: []resource.TestStep{ 578 resource.TestStep{ 579 Config: config, 580 Check: resource.ComposeTestCheckFunc( 581 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label, 582 //resource.TestCheckResourceAttr( 583 // "vsphere_virtual_machine.with_cdrom", "disk.4088143748.template", template), 584 resource.TestCheckResourceAttr(vmName, "cdrom.#", "1"), 585 resource.TestCheckResourceAttr(vmName, "cdrom.0.datastore", cdromDatastore), 586 resource.TestCheckResourceAttr(vmName, "cdrom.0.path", cdromPath), 587 ), 588 }, 589 }, 590 }) 591 } 592 593 const testAccCheckVSphereVirtualMachineConfig_withExistingVmdk = ` 594 resource "vsphere_virtual_machine" "with_existing_vmdk" { 595 name = "terraform-test-with-existing-vmdk" 596 %s 597 vcpu = 2 598 memory = 1024 599 network_interface { 600 label = "%s" 601 } 602 disk { 603 %s 604 vmdk = "%s" 605 bootable = true 606 } 607 } 608 ` 609 610 func TestAccVSphereVirtualMachine_createWithExistingVmdk(t *testing.T) { 611 var vm virtualMachine 612 vmdk_path := os.Getenv("VSPHERE_VMDK_PATH") 613 614 data := setupTemplateFuncDHCPData() 615 config := fmt.Sprintf( 616 testAccCheckVSphereVirtualMachineConfig_withExistingVmdk, 617 data.locationOpt, 618 data.label, 619 data.datastoreOpt, 620 vmdk_path, 621 ) 622 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_withExistingVmdk) 623 log.Printf("[DEBUG] template config= %s", config) 624 625 resource.Test(t, resource.TestCase{ 626 PreCheck: func() { testAccPreCheck(t) }, 627 Providers: testAccProviders, 628 CheckDestroy: testAccCheckVSphereVirtualMachineDestroy, 629 Steps: []resource.TestStep{ 630 resource.TestStep{ 631 Config: config, 632 Check: resource.ComposeTestCheckFunc( 633 TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.with_existing_vmdk", 634 vmResource: "terraform-test-with-existing-vmdk"}.testCheckFuncBasic(), 635 //resource.TestCheckResourceAttr( 636 // "vsphere_virtual_machine.with_existing_vmdk", "disk.2393891804.vmdk", vmdk_path), 637 //resource.TestCheckResourceAttr( 638 // "vsphere_virtual_machine.with_existing_vmdk", "disk.2393891804.bootable", "true"), 639 ), 640 }, 641 }, 642 }) 643 } 644 645 const testAccCheckVSphereVirtualMachineConfig_updateMemory = ` 646 resource "vsphere_virtual_machine" "bar" { 647 name = "terraform-test" 648 %s 649 vcpu = 2 650 memory = %s 651 network_interface { 652 label = "%s" 653 } 654 disk { 655 %s 656 template = "%s" 657 } 658 } 659 ` 660 661 func TestAccVSphereVirtualMachine_updateMemory(t *testing.T) { 662 var vm virtualMachine 663 data := setupTemplateFuncDHCPData() 664 665 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_updateMemory) 666 667 config := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateMemory, "1024") 668 log.Printf("[DEBUG] template config= %s", config) 669 670 configUpdate := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateMemory, "2048") 671 log.Printf("[DEBUG] template configUpdate= %s", configUpdate) 672 673 resource.Test(t, resource.TestCase{ 674 PreCheck: func() { testAccPreCheck(t) }, 675 Providers: testAccProviders, 676 CheckDestroy: testAccCheckVSphereVirtualMachineDestroy, 677 Steps: []resource.TestStep{ 678 resource.TestStep{ 679 Config: config, 680 Check: resource.ComposeTestCheckFunc( 681 TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(), 682 ), 683 }, 684 resource.TestStep{ 685 Config: configUpdate, 686 Check: resource.ComposeTestCheckFunc( 687 TestFuncData{vm: vm, label: data.label, mem: "2048", vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(), 688 ), 689 }, 690 }, 691 }) 692 } 693 694 const testAccCheckVSphereVirtualMachineConfig_updateVcpu = ` 695 resource "vsphere_virtual_machine" "bar" { 696 name = "terraform-test" 697 %s 698 vcpu = %s 699 memory = 1024 700 network_interface { 701 label = "%s" 702 } 703 disk { 704 %s 705 template = "%s" 706 } 707 } 708 ` 709 710 func TestAccVSphereVirtualMachine_updateVcpu(t *testing.T) { 711 var vm virtualMachine 712 data := setupTemplateFuncDHCPData() 713 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_updateVcpu) 714 715 config := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateVcpu, "2") 716 log.Printf("[DEBUG] template config= %s", config) 717 718 configUpdate := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateVcpu, "4") 719 log.Printf("[DEBUG] template configUpdate= %s", configUpdate) 720 721 resource.Test(t, resource.TestCase{ 722 PreCheck: func() { testAccPreCheck(t) }, 723 Providers: testAccProviders, 724 CheckDestroy: testAccCheckVSphereVirtualMachineDestroy, 725 Steps: []resource.TestStep{ 726 resource.TestStep{ 727 Config: config, 728 Check: resource.ComposeTestCheckFunc( 729 TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(), 730 ), 731 }, 732 resource.TestStep{ 733 Config: configUpdate, 734 Check: resource.ComposeTestCheckFunc( 735 TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar", numCPU: "4"}.testCheckFuncBasic(), 736 ), 737 }, 738 }, 739 }) 740 } 741 742 const testAccCheckVSphereVirtualMachineConfig_ipv4Andipv6 = ` 743 resource "vsphere_virtual_machine" "ipv4ipv6" { 744 name = "terraform-test-ipv4-ipv6" 745 %s 746 vcpu = 2 747 memory = 1024 748 network_interface { 749 label = "%s" 750 ipv4_address = "%s" 751 ipv4_prefix_length = %s 752 ipv4_gateway = "%s" 753 ipv6_address = "%s" 754 ipv6_prefix_length = 64 755 ipv6_gateway = "%s" 756 } 757 disk { 758 %s 759 template = "%s" 760 iops = 500 761 } 762 disk { 763 size = 1 764 iops = 500 765 name = "one" 766 } 767 } 768 ` 769 770 func TestAccVSphereVirtualMachine_ipv4Andipv6(t *testing.T) { 771 var vm virtualMachine 772 data := setupTemplateBasicBodyVars() 773 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_ipv4Andipv6) 774 775 vmName := "vsphere_virtual_machine.ipv4ipv6" 776 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label := 777 TestFuncData{vm: vm, label: data.label, vmName: vmName, numDisks: "2", vmResource: "terraform-test-ipv4-ipv6"}.testCheckFuncBasic() 778 779 // FIXME test for this or warn?? 780 ipv6Address := os.Getenv("VSPHERE_IPV6_ADDRESS") 781 ipv6Gateway := os.Getenv("VSPHERE_IPV6_GATEWAY") 782 783 config := fmt.Sprintf( 784 testAccCheckVSphereVirtualMachineConfig_ipv4Andipv6, 785 data.locationOpt, 786 data.label, 787 data.ipv4IpAddress, 788 data.ipv4Prefix, 789 data.ipv4Gateway, 790 ipv6Address, 791 ipv6Gateway, 792 data.datastoreOpt, 793 data.template, 794 ) 795 796 log.Printf("[DEBUG] template config= %s", config) 797 798 resource.Test(t, resource.TestCase{ 799 PreCheck: func() { testAccPreCheck(t) }, 800 Providers: testAccProviders, 801 CheckDestroy: testAccCheckVSphereVirtualMachineDestroy, 802 Steps: []resource.TestStep{ 803 resource.TestStep{ 804 Config: config, 805 Check: resource.ComposeTestCheckFunc( 806 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label, 807 resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv4_address", data.ipv4IpAddress), 808 resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv4_gateway", data.ipv4Gateway), 809 resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv6_address", ipv6Address), 810 resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv6_gateway", ipv6Gateway), 811 ), 812 }, 813 }, 814 }) 815 } 816 817 const testAccCheckVSphereVirtualMachineConfig_updateAddDisks = ` 818 resource "vsphere_virtual_machine" "foo" { 819 name = "terraform-test" 820 ` + testAccTemplateBasicBody + ` 821 disk { 822 size = 1 823 iops = 500 824 name = "one" 825 } 826 disk { 827 size = 1 828 iops = 500 829 name = "two" 830 } 831 disk { 832 size = 1 833 iops = 500 834 name = "three" 835 } 836 } 837 ` 838 const testAccCheckVSphereVirtualMachineConfig_basic = ` 839 resource "vsphere_virtual_machine" "foo" { 840 name = "terraform-test" 841 ` + testAccTemplateBasicBody + ` 842 disk { 843 size = 1 844 iops = 500 845 name = "one" 846 } 847 } 848 ` 849 850 func TestAccVSphereVirtualMachine_updateDisks(t *testing.T) { 851 var vm virtualMachine 852 basic_vars := setupTemplateBasicBodyVars() 853 config_basic := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_basic) 854 855 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_basic) 856 log.Printf("[DEBUG] template config= %s", config_basic) 857 858 config_add := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_updateAddDisks) 859 860 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_basic) 861 log.Printf("[DEBUG] template config= %s", config_add) 862 863 config_del := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_really_basic) 864 865 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_really_basic) 866 log.Printf("[DEBUG] template config= %s", config_del) 867 868 resource.Test(t, resource.TestCase{ 869 PreCheck: func() { testAccPreCheck(t) }, 870 Providers: testAccProviders, 871 CheckDestroy: testAccCheckVSphereVirtualMachineDestroy, 872 Steps: []resource.TestStep{ 873 resource.TestStep{ 874 Config: config_basic, 875 Check: resource.ComposeTestCheckFunc( 876 TestFuncData{vm: vm, label: basic_vars.label, numDisks: "2"}.testCheckFuncBasic(), 877 ), 878 }, 879 resource.TestStep{ 880 Config: config_add, 881 Check: resource.ComposeTestCheckFunc( 882 TestFuncData{vm: vm, label: basic_vars.label, numDisks: "4"}.testCheckFuncBasic(), 883 ), 884 }, 885 resource.TestStep{ 886 Config: config_del, 887 Check: resource.ComposeTestCheckFunc( 888 TestFuncData{vm: vm, label: basic_vars.label, numDisks: "1"}.testCheckFuncBasic(), 889 ), 890 }, 891 }, 892 }) 893 } 894 895 const testAccCheckVSphereVirtualMachineConfig_mac_address = ` 896 resource "vsphere_virtual_machine" "mac_address" { 897 name = "terraform-mac-address" 898 %s 899 vcpu = 2 900 memory = 1024 901 network_interface { 902 label = "%s" 903 mac_address = "%s" 904 } 905 disk { 906 %s 907 template = "%s" 908 } 909 } 910 ` 911 912 // VSPHERE_NETWORK_MAC_ADDRESS needs to be set to run TestAccVSphereVirtualMachine_mac_address 913 // use a basic NIC MAC address like 6:5c:89:2b:a0:64 914 func testMacPreCheck(t *testing.T) { 915 916 testBasicPreCheck(t) 917 918 // TODO should start do parse values to ensure they are correct 919 // for instance 920 // func ParseMAC(s string) (hw HardwareAddr, err error) 921 if v := os.Getenv("VSPHERE_NETWORK_MAC_ADDRESS"); v == "" { 922 t.Fatal("env variable VSPHERE_NETWORK_MAC_ADDRESS must be set for this acceptance test") 923 } 924 } 925 926 // test new mac address feature 927 func TestAccVSphereVirtualMachine_mac_address(t *testing.T) { 928 var vm virtualMachine 929 data := setupTemplateFuncDHCPData() 930 vmName := "vsphere_virtual_machine.mac_address" 931 932 macAddress := os.Getenv("VSPHERE_NETWORK_MAC_ADDRESS") 933 934 log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_mac_address) 935 config := fmt.Sprintf( 936 testAccCheckVSphereVirtualMachineConfig_mac_address, 937 data.locationOpt, 938 data.label, 939 macAddress, 940 data.datastoreOpt, 941 data.template, 942 ) 943 log.Printf("[DEBUG] template config= %s", config) 944 945 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label := 946 TestFuncData{vm: vm, label: data.label, vmName: vmName, numDisks: "1", vmResource: "terraform-mac-address"}.testCheckFuncBasic() 947 948 resource.Test(t, resource.TestCase{ 949 PreCheck: func() { testMacPreCheck(t) }, 950 Providers: testAccProviders, 951 CheckDestroy: testAccCheckVSphereVirtualMachineDestroy, 952 Steps: []resource.TestStep{ 953 resource.TestStep{ 954 Config: config, 955 Check: resource.ComposeTestCheckFunc( 956 test_exists, test_name, test_cpu, test_mem, test_num_disk, test_num_of_nic, test_nic_label, 957 resource.TestCheckResourceAttr(vmName, "network_interface.0.mac_address", macAddress), 958 ), 959 }, 960 }, 961 }) 962 } 963 964 func testAccCheckVSphereVirtualMachineDestroy(s *terraform.State) error { 965 client := testAccProvider.Meta().(*govmomi.Client) 966 finder := find.NewFinder(client.Client, true) 967 968 for _, rs := range s.RootModule().Resources { 969 if rs.Type != "vsphere_virtual_machine" { 970 continue 971 } 972 973 dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"]) 974 if err != nil { 975 return fmt.Errorf("error %s", err) 976 } 977 978 dcFolders, err := dc.Folders(context.TODO()) 979 if err != nil { 980 return fmt.Errorf("error %s", err) 981 } 982 983 folder := dcFolders.VmFolder 984 if len(rs.Primary.Attributes["folder"]) > 0 { 985 si := object.NewSearchIndex(client.Client) 986 folderRef, err := si.FindByInventoryPath( 987 context.TODO(), fmt.Sprintf("%v/vm/%v", rs.Primary.Attributes["datacenter"], rs.Primary.Attributes["folder"])) 988 if err != nil { 989 return err 990 } else if folderRef != nil { 991 folder = folderRef.(*object.Folder) 992 } 993 } 994 995 v, err := object.NewSearchIndex(client.Client).FindChild(context.TODO(), folder, rs.Primary.Attributes["name"]) 996 997 if v != nil { 998 return fmt.Errorf("Record still exists") 999 } 1000 } 1001 1002 return nil 1003 } 1004 1005 func testAccCheckVSphereVirtualMachineExistsHasCustomConfig(n string, vm *virtualMachine) resource.TestCheckFunc { 1006 return func(s *terraform.State) error { 1007 1008 rs, ok := s.RootModule().Resources[n] 1009 if !ok { 1010 return fmt.Errorf("Not found: %s", n) 1011 } 1012 1013 if rs.Primary.ID == "" { 1014 return fmt.Errorf("No ID is set") 1015 } 1016 1017 client := testAccProvider.Meta().(*govmomi.Client) 1018 finder := find.NewFinder(client.Client, true) 1019 1020 dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"]) 1021 if err != nil { 1022 return fmt.Errorf("error %s", err) 1023 } 1024 1025 dcFolders, err := dc.Folders(context.TODO()) 1026 if err != nil { 1027 return fmt.Errorf("error %s", err) 1028 } 1029 1030 _, err = object.NewSearchIndex(client.Client).FindChild(context.TODO(), dcFolders.VmFolder, rs.Primary.Attributes["name"]) 1031 if err != nil { 1032 return fmt.Errorf("error %s", err) 1033 } 1034 1035 finder = finder.SetDatacenter(dc) 1036 instance, err := finder.VirtualMachine(context.TODO(), rs.Primary.Attributes["name"]) 1037 if err != nil { 1038 return fmt.Errorf("error %s", err) 1039 } 1040 1041 var mvm mo.VirtualMachine 1042 1043 collector := property.DefaultCollector(client.Client) 1044 1045 if err := collector.RetrieveOne(context.TODO(), instance.Reference(), []string{"config.extraConfig"}, &mvm); err != nil { 1046 return fmt.Errorf("error %s", err) 1047 } 1048 1049 var configMap = make(map[string]types.AnyType) 1050 if mvm.Config != nil && mvm.Config.ExtraConfig != nil && len(mvm.Config.ExtraConfig) > 0 { 1051 for _, v := range mvm.Config.ExtraConfig { 1052 value := v.GetOptionValue() 1053 configMap[value.Key] = value.Value 1054 } 1055 } else { 1056 return fmt.Errorf("error no ExtraConfig") 1057 } 1058 1059 if configMap["foo"] == nil { 1060 return fmt.Errorf("error no ExtraConfig for 'foo'") 1061 } 1062 1063 if configMap["foo"] != "bar" { 1064 return fmt.Errorf("error ExtraConfig 'foo' != bar") 1065 } 1066 1067 if configMap["car"] == nil { 1068 return fmt.Errorf("error no ExtraConfig for 'car'") 1069 } 1070 1071 if configMap["car"] != "ferrari" { 1072 return fmt.Errorf("error ExtraConfig 'car' != ferrari") 1073 } 1074 1075 if configMap["num"] == nil { 1076 return fmt.Errorf("error no ExtraConfig for 'num'") 1077 } 1078 1079 // todo this should be an int, getting back a string 1080 if configMap["num"] != "42" { 1081 return fmt.Errorf("error ExtraConfig 'num' != 42") 1082 } 1083 *vm = virtualMachine{ 1084 name: rs.Primary.ID, 1085 } 1086 1087 return nil 1088 } 1089 } 1090 1091 func testAccCheckDebugExists() resource.TestCheckFunc { 1092 return func(s *terraform.State) error { 1093 if _, err := os.Stat(filepath.Join(os.Getenv("HOME"), ".govmomi")); os.IsNotExist(err) { 1094 return fmt.Errorf("Debug logs not found") 1095 } 1096 1097 return nil 1098 } 1099 1100 } 1101 func testAccCheckVSphereVirtualMachineExists(n string, vm *virtualMachine) resource.TestCheckFunc { 1102 return func(s *terraform.State) error { 1103 if n == "" { 1104 return fmt.Errorf("No vm name passed in") 1105 } 1106 if vm == nil { 1107 return fmt.Errorf("No vm obj passed in") 1108 } 1109 rs, ok := s.RootModule().Resources[n] 1110 if !ok { 1111 return fmt.Errorf("Not found: %s", n) 1112 } 1113 1114 if rs.Primary.ID == "" { 1115 return fmt.Errorf("No ID is set") 1116 } 1117 1118 client := testAccProvider.Meta().(*govmomi.Client) 1119 finder := find.NewFinder(client.Client, true) 1120 1121 dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"]) 1122 if err != nil { 1123 return fmt.Errorf("error %s", err) 1124 } 1125 1126 dcFolders, err := dc.Folders(context.TODO()) 1127 if err != nil { 1128 return fmt.Errorf("error %s", err) 1129 } 1130 1131 folder := dcFolders.VmFolder 1132 if len(rs.Primary.Attributes["folder"]) > 0 { 1133 si := object.NewSearchIndex(client.Client) 1134 folderRef, err := si.FindByInventoryPath( 1135 context.TODO(), fmt.Sprintf("%v/vm/%v", rs.Primary.Attributes["datacenter"], rs.Primary.Attributes["folder"])) 1136 if err != nil { 1137 return err 1138 } else if folderRef != nil { 1139 folder = folderRef.(*object.Folder) 1140 } 1141 } 1142 1143 _, err = object.NewSearchIndex(client.Client).FindChild(context.TODO(), folder, rs.Primary.Attributes["name"]) 1144 1145 *vm = virtualMachine{ 1146 name: rs.Primary.ID, 1147 } 1148 1149 return nil 1150 } 1151 }