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