github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/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_diskSCSICapacity = `
   332  resource "vsphere_virtual_machine" "scsiCapacity" {
   333      name = "terraform-test"
   334  ` + testAccTemplateBasicBody + `
   335      disk {
   336          size = 1
   337          controller_type = "scsi-paravirtual"
   338          name = "one"
   339      }
   340      disk {
   341          size = 1
   342          controller_type = "scsi-paravirtual"
   343          name = "two"
   344      }
   345  	disk {
   346          size = 1
   347          controller_type = "scsi-paravirtual"
   348          name = "three"
   349      }
   350  	disk {
   351          size = 1
   352          controller_type = "scsi-paravirtual"
   353          name = "four"
   354      }
   355  	disk {
   356          size = 1
   357          controller_type = "scsi-paravirtual"
   358          name = "five"
   359      }
   360  	disk {
   361          size = 1
   362          controller_type = "scsi-paravirtual"
   363          name = "six"
   364      }
   365  	disk {
   366          size = 1
   367          controller_type = "scsi-paravirtual"
   368          name = "seven"
   369      }
   370  }
   371  `
   372  
   373  func TestAccVSphereVirtualMachine_diskSCSICapacity(t *testing.T) {
   374  	var vm virtualMachine
   375  	basic_vars := setupTemplateBasicBodyVars()
   376  	config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_diskSCSICapacity)
   377  
   378  	vmName := "vsphere_virtual_machine.scsiCapacity"
   379  
   380  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
   381  		TestFuncData{vm: vm, label: basic_vars.label, vmName: vmName, numDisks: "8"}.testCheckFuncBasic()
   382  
   383  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_diskSCSICapacity)
   384  	log.Printf("[DEBUG] template config= %s", config)
   385  
   386  	resource.Test(t, resource.TestCase{
   387  		PreCheck:     func() { testAccPreCheck(t) },
   388  		Providers:    testAccProviders,
   389  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   390  		Steps: []resource.TestStep{
   391  			resource.TestStep{
   392  				Config: config,
   393  				Check: resource.ComposeTestCheckFunc(
   394  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
   395  				),
   396  			},
   397  		},
   398  	})
   399  }
   400  
   401  const testAccCheckVSphereVirtualMachineConfig_initTypeEager = `
   402  resource "vsphere_virtual_machine" "thickEagerZero" {
   403      name = "terraform-test"
   404  ` + testAccTemplateBasicBody + `
   405      disk {
   406  		size = 1
   407  		iops = 500
   408  		controller_type = "scsi"
   409  		name = "one"
   410      }
   411      disk {
   412  		size = 1
   413  		controller_type = "ide"
   414  		type = "eager_zeroed"
   415  		name = "two"
   416      }
   417  }
   418  `
   419  
   420  func TestAccVSphereVirtualMachine_diskInitTypeEager(t *testing.T) {
   421  	var vm virtualMachine
   422  	basic_vars := setupTemplateBasicBodyVars()
   423  	config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_initTypeEager)
   424  
   425  	vmName := "vsphere_virtual_machine.thickEagerZero"
   426  
   427  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
   428  		TestFuncData{vm: vm, label: basic_vars.label, vmName: vmName, numDisks: "3"}.testCheckFuncBasic()
   429  
   430  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_initTypeEager)
   431  	log.Printf("[DEBUG] template config= %s", config)
   432  
   433  	resource.Test(t, resource.TestCase{
   434  		PreCheck:     func() { testAccPreCheck(t) },
   435  		Providers:    testAccProviders,
   436  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   437  		Steps: []resource.TestStep{
   438  			resource.TestStep{
   439  				Config: config,
   440  				Check: resource.ComposeTestCheckFunc(
   441  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
   442  					// FIXME dynmically calculate the hashes
   443  					resource.TestCheckResourceAttr(vmName, "disk.294918912.type", "eager_zeroed"),
   444  					resource.TestCheckResourceAttr(vmName, "disk.294918912.controller_type", "ide"),
   445  					resource.TestCheckResourceAttr(vmName, "disk.1380467090.controller_type", "scsi"),
   446  				),
   447  			},
   448  		},
   449  	})
   450  }
   451  
   452  const testAccCheckVSphereVirtualMachineConfig_initTypeLazy = `
   453  resource "vsphere_virtual_machine" "lazy" {
   454      name = "terraform-test"
   455  ` + testAccTemplateBasicBody + `
   456      disk {
   457  		size = 1
   458  		iops = 500
   459  		controller_type = "scsi"
   460  		name = "one"
   461      }
   462      disk {
   463  		size = 1
   464  		controller_type = "ide"
   465  		type = "lazy"
   466  		name = "two"
   467      }
   468  }
   469  `
   470  
   471  func TestAccVSphereVirtualMachine_diskInitTypeLazy(t *testing.T) {
   472  	var vm virtualMachine
   473  	basic_vars := setupTemplateBasicBodyVars()
   474  	config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_initTypeLazy)
   475  
   476  	vmName := "vsphere_virtual_machine.lazy"
   477  
   478  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
   479  		TestFuncData{vm: vm, label: basic_vars.label, vmName: vmName, numDisks: "3"}.testCheckFuncBasic()
   480  
   481  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_initTypeLazy)
   482  	log.Printf("[DEBUG] template config= %s", config)
   483  
   484  	resource.Test(t, resource.TestCase{
   485  		PreCheck:     func() { testAccPreCheck(t) },
   486  		Providers:    testAccProviders,
   487  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   488  		Steps: []resource.TestStep{
   489  			resource.TestStep{
   490  				Config: config,
   491  				Check: resource.ComposeTestCheckFunc(
   492  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
   493  					// FIXME dynmically calculate the hashes
   494  					resource.TestCheckResourceAttr(vmName, "disk.692719290.type", "lazy"),
   495  					resource.TestCheckResourceAttr(vmName, "disk.692719290.controller_type", "ide"),
   496  					resource.TestCheckResourceAttr(vmName, "disk.531766495.controller_type", "scsi"),
   497  				),
   498  			},
   499  		},
   500  	})
   501  }
   502  
   503  const testAccCheckVSphereVirtualMachineConfig_dhcp = `
   504  resource "vsphere_virtual_machine" "bar" {
   505      name = "terraform-test"
   506  `
   507  
   508  func TestAccVSphereVirtualMachine_dhcp(t *testing.T) {
   509  	var vm virtualMachine
   510  	data := setupTemplateFuncDHCPData()
   511  	config := testAccCheckVSphereVirtualMachineConfig_dhcp + data.parseDHCPTemplateConfigWithTemplate(testAccCheckVSphereTemplate_dhcp)
   512  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_dhcp+testAccCheckVSphereTemplate_dhcp)
   513  	log.Printf("[DEBUG] config= %s", config)
   514  
   515  	resource.Test(t, resource.TestCase{
   516  		PreCheck:     func() { testAccPreCheck(t) },
   517  		Providers:    testAccProviders,
   518  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   519  		Steps: []resource.TestStep{
   520  			resource.TestStep{
   521  				Config: config,
   522  				Check: resource.ComposeTestCheckFunc(
   523  					TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(),
   524  				),
   525  			},
   526  		},
   527  	})
   528  }
   529  
   530  const testAccCheckVSphereVirtualMachineConfig_custom_configs = `
   531  resource "vsphere_virtual_machine" "car" {
   532      name = "terraform-test-custom"
   533      custom_configuration_parameters {
   534        "foo" = "bar"
   535        "car" = "ferrari"
   536        "num" = 42
   537      }
   538  	enable_disk_uuid = true
   539  `
   540  
   541  func TestAccVSphereVirtualMachine_custom_configs(t *testing.T) {
   542  
   543  	var vm virtualMachine
   544  	data := setupTemplateFuncDHCPData()
   545  	config := testAccCheckVSphereVirtualMachineConfig_custom_configs + data.parseDHCPTemplateConfigWithTemplate(testAccCheckVSphereTemplate_dhcp)
   546  	vmName := "vsphere_virtual_machine.car"
   547  	res := "terraform-test-custom"
   548  
   549  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
   550  		TestFuncData{vm: vm, label: data.label, vmName: vmName, vmResource: res}.testCheckFuncBasic()
   551  
   552  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_custom_configs+testAccCheckVSphereTemplate_dhcp)
   553  	log.Printf("[DEBUG] config= %s", config)
   554  
   555  	resource.Test(t, resource.TestCase{
   556  		PreCheck:     func() { testAccPreCheck(t) },
   557  		Providers:    testAccProviders,
   558  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   559  		Steps: []resource.TestStep{
   560  			resource.TestStep{
   561  				Config: config,
   562  				Check: resource.ComposeTestCheckFunc(
   563  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
   564  					testAccCheckVSphereVirtualMachineExistsHasCustomConfig(vmName, &vm),
   565  					resource.TestCheckResourceAttr(vmName, "custom_configuration_parameters.foo", "bar"),
   566  					resource.TestCheckResourceAttr(vmName, "custom_configuration_parameters.car", "ferrari"),
   567  					resource.TestCheckResourceAttr(vmName, "custom_configuration_parameters.num", "42"),
   568  					resource.TestCheckResourceAttr(vmName, "enable_disk_uuid", "true"),
   569  				),
   570  			},
   571  		},
   572  	})
   573  }
   574  
   575  const testAccCheckVSphereVirtualMachineConfig_createInFolder = `
   576  resource "vsphere_virtual_machine" "folder" {
   577      name = "terraform-test-folder"
   578      folder = "%s"
   579  `
   580  
   581  func TestAccVSphereVirtualMachine_createInExistingFolder(t *testing.T) {
   582  	var vm virtualMachine
   583  	datacenter := os.Getenv("VSPHERE_DATACENTER")
   584  
   585  	folder := "tf_test_cpureateInExistingFolder"
   586  
   587  	data := setupTemplateFuncDHCPData()
   588  	config := fmt.Sprintf(testAccCheckVSphereVirtualMachineConfig_createInFolder,
   589  		folder,
   590  	) + data.parseDHCPTemplateConfig()
   591  
   592  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_createInFolder)
   593  	log.Printf("[DEBUG] template config= %s", config)
   594  
   595  	resource.Test(t, resource.TestCase{
   596  		PreCheck:  func() { testAccPreCheck(t) },
   597  		Providers: testAccProviders,
   598  		CheckDestroy: resource.ComposeTestCheckFunc(
   599  			testAccCheckVSphereVirtualMachineDestroy,
   600  			removeVSphereFolder(datacenter, folder, ""),
   601  		),
   602  		Steps: []resource.TestStep{
   603  			resource.TestStep{
   604  				PreConfig: func() { createVSphereFolder(datacenter, folder) },
   605  				Config:    config,
   606  				Check: resource.ComposeTestCheckFunc(
   607  					TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.folder", vmResource: "terraform-test-folder"}.testCheckFuncBasic(),
   608  				),
   609  			},
   610  		},
   611  	})
   612  }
   613  
   614  const testAccCheckVSphereVirtualMachineConfig_createWithFolder = `
   615  resource "vsphere_folder" "with_folder" {
   616  	path = "%s"
   617  %s
   618  }
   619  resource "vsphere_virtual_machine" "with_folder" {
   620      name = "terraform-test-with-folder"
   621      folder = "${vsphere_folder.with_folder.path}"
   622  `
   623  
   624  func TestAccVSphereVirtualMachine_createWithFolder(t *testing.T) {
   625  	var vm virtualMachine
   626  	var folderLocationOpt string
   627  	var f folder
   628  
   629  	if v := os.Getenv("VSPHERE_DATACENTER"); v != "" {
   630  		folderLocationOpt = fmt.Sprintf("    datacenter = \"%s\"\n", v)
   631  	}
   632  
   633  	folder := "tf_test_cpureateWithFolder"
   634  
   635  	data := setupTemplateFuncDHCPData()
   636  	vmName := "vsphere_virtual_machine.with_folder"
   637  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
   638  		TestFuncData{vm: vm, label: data.label, vmName: vmName, vmResource: "terraform-test-with-folder"}.testCheckFuncBasic()
   639  
   640  	config := fmt.Sprintf(testAccCheckVSphereVirtualMachineConfig_createWithFolder,
   641  		folder,
   642  		folderLocationOpt,
   643  	) + data.parseDHCPTemplateConfig()
   644  
   645  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_createWithFolder+testAccCheckVSphereTemplate_dhcp)
   646  	log.Printf("[DEBUG] template config= %s", config)
   647  
   648  	resource.Test(t, resource.TestCase{
   649  		PreCheck:  func() { testAccPreCheck(t) },
   650  		Providers: testAccProviders,
   651  		CheckDestroy: resource.ComposeTestCheckFunc(
   652  			testAccCheckVSphereVirtualMachineDestroy,
   653  			testAccCheckVSphereFolderDestroy,
   654  		),
   655  		Steps: []resource.TestStep{
   656  			resource.TestStep{
   657  				Config: config,
   658  				Check: resource.ComposeTestCheckFunc(
   659  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
   660  					testAccCheckVSphereFolderExists(vmName, &f),
   661  					resource.TestCheckResourceAttr(vmName, "folder", folder),
   662  				),
   663  			},
   664  		},
   665  	})
   666  }
   667  
   668  const testAccCheckVsphereVirtualMachineConfig_cdrom = `
   669  resource "vsphere_virtual_machine" "with_cdrom" {
   670      name = "terraform-test-with-cdrom"
   671      cdrom {
   672          datastore = "%s"
   673          path = "%s"
   674      }
   675  `
   676  
   677  func TestAccVSphereVirtualMachine_createWithCdrom(t *testing.T) {
   678  	var vm virtualMachine
   679  
   680  	// FIXME check that these exist
   681  	cdromDatastore := os.Getenv("VSPHERE_CDROM_DATASTORE")
   682  	cdromPath := os.Getenv("VSPHERE_CDROM_PATH")
   683  	vmName := "vsphere_virtual_machine.with_cdrom"
   684  
   685  	data := setupTemplateFuncDHCPData()
   686  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
   687  		TestFuncData{vm: vm, label: data.label, vmName: vmName, vmResource: "terraform-test-with-cdrom"}.testCheckFuncBasic()
   688  
   689  	config := fmt.Sprintf(
   690  		testAccCheckVsphereVirtualMachineConfig_cdrom,
   691  		cdromDatastore,
   692  		cdromPath,
   693  	) + data.parseDHCPTemplateConfig()
   694  
   695  	log.Printf("[DEBUG] template= %s", testAccCheckVsphereVirtualMachineConfig_cdrom)
   696  	log.Printf("[DEBUG] template config= %s", config)
   697  
   698  	resource.Test(t, resource.TestCase{
   699  		PreCheck:     func() { testAccPreCheck(t) },
   700  		Providers:    testAccProviders,
   701  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   702  		Steps: []resource.TestStep{
   703  			resource.TestStep{
   704  				Config: config,
   705  				Check: resource.ComposeTestCheckFunc(
   706  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
   707  					//resource.TestCheckResourceAttr(
   708  					//	"vsphere_virtual_machine.with_cdrom", "disk.4088143748.template", template),
   709  					resource.TestCheckResourceAttr(vmName, "cdrom.#", "1"),
   710  					resource.TestCheckResourceAttr(vmName, "cdrom.0.datastore", cdromDatastore),
   711  					resource.TestCheckResourceAttr(vmName, "cdrom.0.path", cdromPath),
   712  				),
   713  			},
   714  		},
   715  	})
   716  }
   717  
   718  const testAccCheckVSphereVirtualMachineConfig_withExistingVmdk = `
   719  resource "vsphere_virtual_machine" "with_existing_vmdk" {
   720      name = "terraform-test-with-existing-vmdk"
   721  %s
   722      vcpu = 2
   723      memory = 1024
   724      network_interface {
   725          label = "%s"
   726      }
   727      disk {
   728  %s
   729          vmdk = "%s"
   730  		bootable = true
   731      }
   732      disk {
   733          size = 1
   734          iops = 500
   735  		name = "one"
   736      }
   737  }
   738  `
   739  
   740  func TestAccVSphereVirtualMachine_createWithExistingVmdk(t *testing.T) {
   741  	var vm virtualMachine
   742  	vmdk_path := os.Getenv("VSPHERE_VMDK_PATH")
   743  
   744  	data := setupTemplateFuncDHCPData()
   745  	config := fmt.Sprintf(
   746  		testAccCheckVSphereVirtualMachineConfig_withExistingVmdk,
   747  		data.locationOpt,
   748  		data.label,
   749  		data.datastoreOpt,
   750  		vmdk_path,
   751  	)
   752  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_withExistingVmdk)
   753  	log.Printf("[DEBUG] template config= %s", config)
   754  
   755  	resource.Test(t, resource.TestCase{
   756  		PreCheck:     func() { testAccPreCheck(t) },
   757  		Providers:    testAccProviders,
   758  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   759  		Steps: []resource.TestStep{
   760  			resource.TestStep{
   761  				Config: config,
   762  				Check: resource.ComposeTestCheckFunc(
   763  					TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.with_existing_vmdk",
   764  						vmResource: "terraform-test-with-existing-vmdk", numDisks: "2"}.testCheckFuncBasic(),
   765  					//resource.TestCheckResourceAttr(
   766  					//	"vsphere_virtual_machine.with_existing_vmdk", "disk.2393891804.vmdk", vmdk_path),
   767  					//resource.TestCheckResourceAttr(
   768  					//	"vsphere_virtual_machine.with_existing_vmdk", "disk.2393891804.bootable", "true"),
   769  				),
   770  			},
   771  		},
   772  	})
   773  }
   774  
   775  const testAccCheckVSphereVirtualMachineConfig_updateMemory = `
   776  resource "vsphere_virtual_machine" "bar" {
   777      name = "terraform-test"
   778  %s
   779      vcpu = 2
   780      memory = %s
   781      network_interface {
   782          label = "%s"
   783      }
   784      disk {
   785  %s
   786        template = "%s"
   787      }
   788  }
   789  `
   790  
   791  func TestAccVSphereVirtualMachine_updateMemory(t *testing.T) {
   792  	var vm virtualMachine
   793  	data := setupTemplateFuncDHCPData()
   794  
   795  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_updateMemory)
   796  
   797  	config := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateMemory, "1024")
   798  	log.Printf("[DEBUG] template config= %s", config)
   799  
   800  	configUpdate := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateMemory, "2048")
   801  	log.Printf("[DEBUG] template configUpdate= %s", configUpdate)
   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  					TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(),
   812  				),
   813  			},
   814  			resource.TestStep{
   815  				Config: configUpdate,
   816  				Check: resource.ComposeTestCheckFunc(
   817  					TestFuncData{vm: vm, label: data.label, mem: "2048", vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(),
   818  				),
   819  			},
   820  		},
   821  	})
   822  }
   823  
   824  const testAccCheckVSphereVirtualMachineConfig_updateVcpu = `
   825  resource "vsphere_virtual_machine" "bar" {
   826      name = "terraform-test"
   827  %s
   828      vcpu = %s
   829      memory = 1024
   830      network_interface {
   831          label = "%s"
   832      }
   833      disk {
   834  %s
   835          template = "%s"
   836      }
   837  }
   838  `
   839  
   840  func TestAccVSphereVirtualMachine_updateVcpu(t *testing.T) {
   841  	var vm virtualMachine
   842  	data := setupTemplateFuncDHCPData()
   843  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_updateVcpu)
   844  
   845  	config := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateVcpu, "2")
   846  	log.Printf("[DEBUG] template config= %s", config)
   847  
   848  	configUpdate := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateVcpu, "4")
   849  	log.Printf("[DEBUG] template configUpdate= %s", configUpdate)
   850  
   851  	resource.Test(t, resource.TestCase{
   852  		PreCheck:     func() { testAccPreCheck(t) },
   853  		Providers:    testAccProviders,
   854  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   855  		Steps: []resource.TestStep{
   856  			resource.TestStep{
   857  				Config: config,
   858  				Check: resource.ComposeTestCheckFunc(
   859  					TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(),
   860  				),
   861  			},
   862  			resource.TestStep{
   863  				Config: configUpdate,
   864  				Check: resource.ComposeTestCheckFunc(
   865  					TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar", numCPU: "4"}.testCheckFuncBasic(),
   866  				),
   867  			},
   868  		},
   869  	})
   870  }
   871  
   872  const testAccCheckVSphereVirtualMachineConfig_ipv6 = `
   873  resource "vsphere_virtual_machine" "ipv6" {
   874      name = "terraform-test-ipv6"
   875  %s
   876      vcpu = 2
   877      memory = 1024
   878      network_interface {
   879          label = "%s"
   880          %s
   881          ipv6_address = "%s"
   882          ipv6_prefix_length = 64
   883          ipv6_gateway = "%s"
   884      }
   885      disk {
   886  %s
   887          template = "%s"
   888          iops = 500
   889      }
   890      disk {
   891          size = 1
   892          iops = 500
   893  		name = "one"
   894      }
   895  }
   896  `
   897  
   898  func TestAccVSphereVirtualMachine_ipv4Andipv6(t *testing.T) {
   899  	var vm virtualMachine
   900  	data := setupTemplateBasicBodyVars()
   901  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_ipv6)
   902  
   903  	vmName := "vsphere_virtual_machine.ipv6"
   904  
   905  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
   906  		TestFuncData{vm: vm, label: data.label, vmName: vmName, numDisks: "2", vmResource: "terraform-test-ipv6"}.testCheckFuncBasic()
   907  
   908  	// FIXME test for this or warn??
   909  	ipv6Address := os.Getenv("VSPHERE_IPV6_ADDRESS")
   910  	ipv6Gateway := os.Getenv("VSPHERE_IPV6_GATEWAY")
   911  
   912  	ipv4Settings := fmt.Sprintf(`
   913  		ipv4_address = "%s"
   914          ipv4_prefix_length = %s
   915          ipv4_gateway = "%s"
   916  	`, data.ipv4IpAddress, data.ipv4Prefix, data.ipv4Gateway)
   917  
   918  	config := fmt.Sprintf(
   919  		testAccCheckVSphereVirtualMachineConfig_ipv6,
   920  		data.locationOpt,
   921  		data.label,
   922  		ipv4Settings,
   923  		ipv6Address,
   924  		ipv6Gateway,
   925  		data.datastoreOpt,
   926  		data.template,
   927  	)
   928  
   929  	log.Printf("[DEBUG] template config= %s", config)
   930  
   931  	resource.Test(t, resource.TestCase{
   932  		PreCheck:     func() { testAccPreCheck(t) },
   933  		Providers:    testAccProviders,
   934  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   935  		Steps: []resource.TestStep{
   936  			resource.TestStep{
   937  				Config: config,
   938  				Check: resource.ComposeTestCheckFunc(
   939  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
   940  					resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv4_address", data.ipv4IpAddress),
   941  					resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv4_gateway", data.ipv4Gateway),
   942  					resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv6_address", ipv6Address),
   943  					resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv6_gateway", ipv6Gateway),
   944  				),
   945  			},
   946  		},
   947  	})
   948  }
   949  
   950  func TestAccVSphereVirtualMachine_ipv6Only(t *testing.T) {
   951  	var vm virtualMachine
   952  	data := setupTemplateBasicBodyVars()
   953  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_ipv6)
   954  
   955  	vmName := "vsphere_virtual_machine.ipv6"
   956  
   957  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
   958  		TestFuncData{vm: vm, label: data.label, vmName: vmName, numDisks: "2", vmResource: "terraform-test-ipv6"}.testCheckFuncBasic()
   959  
   960  	// Checks for this will be handled when this code is merged with https://github.com/hashicorp/terraform/pull/7575.
   961  	ipv6Address := os.Getenv("VSPHERE_IPV6_ADDRESS")
   962  	ipv6Gateway := os.Getenv("VSPHERE_IPV6_GATEWAY")
   963  
   964  	config := fmt.Sprintf(
   965  		testAccCheckVSphereVirtualMachineConfig_ipv6,
   966  		data.locationOpt,
   967  		data.label,
   968  		"",
   969  		ipv6Address,
   970  		ipv6Gateway,
   971  		data.datastoreOpt,
   972  		data.template,
   973  	)
   974  
   975  	log.Printf("[DEBUG] template config= %s", config)
   976  
   977  	resource.Test(t, resource.TestCase{
   978  		PreCheck:     func() { testAccPreCheck(t) },
   979  		Providers:    testAccProviders,
   980  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   981  		Steps: []resource.TestStep{
   982  			resource.TestStep{
   983  				Config: config,
   984  				Check: resource.ComposeTestCheckFunc(
   985  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
   986  					resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv6_address", ipv6Address),
   987  					resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv6_gateway", ipv6Gateway),
   988  				),
   989  			},
   990  		},
   991  	})
   992  }
   993  
   994  const testAccCheckVSphereVirtualMachineConfig_updateAddDisks = `
   995  resource "vsphere_virtual_machine" "foo" {
   996      name = "terraform-test"
   997  ` + testAccTemplateBasicBody + `
   998      disk {
   999          size = 1
  1000          iops = 500
  1001          name = "one"
  1002  %s
  1003      }
  1004  	disk {
  1005          size = 1
  1006          iops = 500
  1007          name = "two"
  1008  %s
  1009      }
  1010  	disk {
  1011          size = 1
  1012          iops = 500
  1013          name = "three"
  1014  %s
  1015      }
  1016  }
  1017  `
  1018  const testAccCheckVSphereVirtualMachineConfig_basic = `
  1019  resource "vsphere_virtual_machine" "foo" {
  1020      name = "terraform-test"
  1021  ` + testAccTemplateBasicBody + `
  1022      disk {
  1023          size = 1
  1024          iops = 500
  1025  	name = "one"
  1026      }
  1027  }
  1028  `
  1029  
  1030  func TestAccVSphereVirtualMachine_updateDisks(t *testing.T) {
  1031  	var vm virtualMachine
  1032  	basic_vars := setupTemplateBasicBodyVars()
  1033  	config_basic := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_basic)
  1034  
  1035  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_basic)
  1036  	log.Printf("[DEBUG] template config= %s", config_basic)
  1037  
  1038  	config_add := fmt.Sprintf(
  1039  		testAccCheckVSphereVirtualMachineConfig_updateAddDisks,
  1040  		basic_vars.locationOpt,
  1041  		basic_vars.label,
  1042  		basic_vars.ipv4IpAddress,
  1043  		basic_vars.ipv4Prefix,
  1044  		basic_vars.ipv4Gateway,
  1045  		basic_vars.datastoreOpt,
  1046  		basic_vars.template,
  1047  		basic_vars.datastoreOpt,
  1048  		basic_vars.datastoreOpt,
  1049  		basic_vars.datastoreOpt,
  1050  	)
  1051  
  1052  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_basic)
  1053  	log.Printf("[DEBUG] template config= %s", config_add)
  1054  
  1055  	config_del := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_really_basic)
  1056  
  1057  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_really_basic)
  1058  	log.Printf("[DEBUG] template config= %s", config_del)
  1059  
  1060  	resource.Test(t, resource.TestCase{
  1061  		PreCheck:     func() { testAccPreCheck(t) },
  1062  		Providers:    testAccProviders,
  1063  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
  1064  		Steps: []resource.TestStep{
  1065  			resource.TestStep{
  1066  				Config: config_basic,
  1067  				Check: resource.ComposeTestCheckFunc(
  1068  					TestFuncData{vm: vm, label: basic_vars.label, numDisks: "2"}.testCheckFuncBasic(),
  1069  				),
  1070  			},
  1071  			resource.TestStep{
  1072  				Config: config_add,
  1073  				Check: resource.ComposeTestCheckFunc(
  1074  					TestFuncData{vm: vm, label: basic_vars.label, numDisks: "4"}.testCheckFuncBasic(),
  1075  				),
  1076  			},
  1077  			resource.TestStep{
  1078  				Config: config_del,
  1079  				Check: resource.ComposeTestCheckFunc(
  1080  					TestFuncData{vm: vm, label: basic_vars.label, numDisks: "1"}.testCheckFuncBasic(),
  1081  				),
  1082  			},
  1083  		},
  1084  	})
  1085  }
  1086  
  1087  const testAccCheckVSphereVirtualMachineConfig_mac_address = `
  1088  resource "vsphere_virtual_machine" "mac_address" {
  1089      name = "terraform-mac-address"
  1090  %s
  1091      vcpu = 2
  1092      memory = 1024
  1093      network_interface {
  1094          label = "%s"
  1095          mac_address = "%s"
  1096      }
  1097      disk {
  1098  %s
  1099          template = "%s"
  1100      }
  1101  }
  1102  `
  1103  
  1104  // VSPHERE_NETWORK_MAC_ADDRESS needs to be set to run TestAccVSphereVirtualMachine_mac_address
  1105  // use a basic NIC MAC address like 6:5c:89:2b:a0:64
  1106  func testMacPreCheck(t *testing.T) {
  1107  
  1108  	testBasicPreCheck(t)
  1109  
  1110  	// TODO should start do parse values to ensure they are correct
  1111  	// for instance
  1112  	//  func ParseMAC(s string) (hw HardwareAddr, err error)
  1113  	if v := os.Getenv("VSPHERE_NETWORK_MAC_ADDRESS"); v == "" {
  1114  		t.Fatal("env variable VSPHERE_NETWORK_MAC_ADDRESS must be set for this acceptance test")
  1115  	}
  1116  }
  1117  
  1118  // test new mac address feature
  1119  func TestAccVSphereVirtualMachine_mac_address(t *testing.T) {
  1120  	var vm virtualMachine
  1121  	data := setupTemplateFuncDHCPData()
  1122  	vmName := "vsphere_virtual_machine.mac_address"
  1123  
  1124  	macAddress := os.Getenv("VSPHERE_NETWORK_MAC_ADDRESS")
  1125  
  1126  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_mac_address)
  1127  	config := fmt.Sprintf(
  1128  		testAccCheckVSphereVirtualMachineConfig_mac_address,
  1129  		data.locationOpt,
  1130  		data.label,
  1131  		macAddress,
  1132  		data.datastoreOpt,
  1133  		data.template,
  1134  	)
  1135  	log.Printf("[DEBUG] template config= %s", config)
  1136  
  1137  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
  1138  		TestFuncData{vm: vm, label: data.label, vmName: vmName, numDisks: "1", vmResource: "terraform-mac-address"}.testCheckFuncBasic()
  1139  
  1140  	resource.Test(t, resource.TestCase{
  1141  		PreCheck:     func() { testMacPreCheck(t) },
  1142  		Providers:    testAccProviders,
  1143  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
  1144  		Steps: []resource.TestStep{
  1145  			resource.TestStep{
  1146  				Config: config,
  1147  				Check: resource.ComposeTestCheckFunc(
  1148  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
  1149  					resource.TestCheckResourceAttr(vmName, "network_interface.0.mac_address", macAddress),
  1150  				),
  1151  			},
  1152  		},
  1153  	})
  1154  }
  1155  
  1156  func testAccCheckVSphereVirtualMachineDestroy(s *terraform.State) error {
  1157  	client := testAccProvider.Meta().(*govmomi.Client)
  1158  	finder := find.NewFinder(client.Client, true)
  1159  
  1160  	for _, rs := range s.RootModule().Resources {
  1161  		if rs.Type != "vsphere_virtual_machine" {
  1162  			continue
  1163  		}
  1164  
  1165  		dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"])
  1166  		if err != nil {
  1167  			return fmt.Errorf("error %s", err)
  1168  		}
  1169  
  1170  		dcFolders, err := dc.Folders(context.TODO())
  1171  		if err != nil {
  1172  			return fmt.Errorf("error %s", err)
  1173  		}
  1174  
  1175  		folder := dcFolders.VmFolder
  1176  		if len(rs.Primary.Attributes["folder"]) > 0 {
  1177  			si := object.NewSearchIndex(client.Client)
  1178  			folderRef, err := si.FindByInventoryPath(
  1179  				context.TODO(), fmt.Sprintf("%v/vm/%v", rs.Primary.Attributes["datacenter"], rs.Primary.Attributes["folder"]))
  1180  			if err != nil {
  1181  				return err
  1182  			} else if folderRef != nil {
  1183  				folder = folderRef.(*object.Folder)
  1184  			}
  1185  		}
  1186  
  1187  		v, err := object.NewSearchIndex(client.Client).FindChild(context.TODO(), folder, rs.Primary.Attributes["name"])
  1188  
  1189  		if v != nil {
  1190  			return fmt.Errorf("Record still exists")
  1191  		}
  1192  	}
  1193  
  1194  	return nil
  1195  }
  1196  
  1197  func testAccCheckVSphereVirtualMachineExistsHasCustomConfig(n string, vm *virtualMachine) resource.TestCheckFunc {
  1198  	return func(s *terraform.State) error {
  1199  
  1200  		rs, ok := s.RootModule().Resources[n]
  1201  		if !ok {
  1202  			return fmt.Errorf("Not found: %s", n)
  1203  		}
  1204  
  1205  		if rs.Primary.ID == "" {
  1206  			return fmt.Errorf("No ID is set")
  1207  		}
  1208  
  1209  		client := testAccProvider.Meta().(*govmomi.Client)
  1210  		finder := find.NewFinder(client.Client, true)
  1211  
  1212  		dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"])
  1213  		if err != nil {
  1214  			return fmt.Errorf("error %s", err)
  1215  		}
  1216  
  1217  		dcFolders, err := dc.Folders(context.TODO())
  1218  		if err != nil {
  1219  			return fmt.Errorf("error %s", err)
  1220  		}
  1221  
  1222  		_, err = object.NewSearchIndex(client.Client).FindChild(context.TODO(), dcFolders.VmFolder, rs.Primary.Attributes["name"])
  1223  		if err != nil {
  1224  			return fmt.Errorf("error %s", err)
  1225  		}
  1226  
  1227  		finder = finder.SetDatacenter(dc)
  1228  		instance, err := finder.VirtualMachine(context.TODO(), rs.Primary.Attributes["name"])
  1229  		if err != nil {
  1230  			return fmt.Errorf("error %s", err)
  1231  		}
  1232  
  1233  		var mvm mo.VirtualMachine
  1234  
  1235  		collector := property.DefaultCollector(client.Client)
  1236  
  1237  		if err := collector.RetrieveOne(context.TODO(), instance.Reference(), []string{"config.extraConfig"}, &mvm); err != nil {
  1238  			return fmt.Errorf("error %s", err)
  1239  		}
  1240  
  1241  		var configMap = make(map[string]types.AnyType)
  1242  		if mvm.Config != nil && mvm.Config.ExtraConfig != nil && len(mvm.Config.ExtraConfig) > 0 {
  1243  			for _, v := range mvm.Config.ExtraConfig {
  1244  				value := v.GetOptionValue()
  1245  				configMap[value.Key] = value.Value
  1246  			}
  1247  		} else {
  1248  			return fmt.Errorf("error no ExtraConfig")
  1249  		}
  1250  
  1251  		if configMap["foo"] == nil {
  1252  			return fmt.Errorf("error no ExtraConfig for 'foo'")
  1253  		}
  1254  
  1255  		if configMap["foo"] != "bar" {
  1256  			return fmt.Errorf("error ExtraConfig 'foo' != bar")
  1257  		}
  1258  
  1259  		if configMap["car"] == nil {
  1260  			return fmt.Errorf("error no ExtraConfig for 'car'")
  1261  		}
  1262  
  1263  		if configMap["car"] != "ferrari" {
  1264  			return fmt.Errorf("error ExtraConfig 'car' != ferrari")
  1265  		}
  1266  
  1267  		if configMap["num"] == nil {
  1268  			return fmt.Errorf("error no ExtraConfig for 'num'")
  1269  		}
  1270  
  1271  		// todo this should be an int, getting back a string
  1272  		if configMap["num"] != "42" {
  1273  			return fmt.Errorf("error ExtraConfig 'num' != 42")
  1274  		}
  1275  		*vm = virtualMachine{
  1276  			name: rs.Primary.ID,
  1277  		}
  1278  
  1279  		return nil
  1280  	}
  1281  }
  1282  
  1283  func testAccCheckDebugExists() resource.TestCheckFunc {
  1284  	return func(s *terraform.State) error {
  1285  		if _, err := os.Stat(filepath.Join(os.Getenv("HOME"), ".govmomi")); os.IsNotExist(err) {
  1286  			return fmt.Errorf("Debug logs not found")
  1287  		}
  1288  
  1289  		return nil
  1290  	}
  1291  
  1292  }
  1293  func testAccCheckVSphereVirtualMachineExists(n string, vm *virtualMachine) resource.TestCheckFunc {
  1294  	return func(s *terraform.State) error {
  1295  		if n == "" {
  1296  			return fmt.Errorf("No vm name passed in")
  1297  		}
  1298  		if vm == nil {
  1299  			return fmt.Errorf("No vm obj passed in")
  1300  		}
  1301  		rs, ok := s.RootModule().Resources[n]
  1302  		if !ok {
  1303  			return fmt.Errorf("Not found: %s", n)
  1304  		}
  1305  
  1306  		if rs.Primary.ID == "" {
  1307  			return fmt.Errorf("No ID is set")
  1308  		}
  1309  
  1310  		client := testAccProvider.Meta().(*govmomi.Client)
  1311  		finder := find.NewFinder(client.Client, true)
  1312  
  1313  		dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"])
  1314  		if err != nil {
  1315  			return fmt.Errorf("error %s", err)
  1316  		}
  1317  
  1318  		dcFolders, err := dc.Folders(context.TODO())
  1319  		if err != nil {
  1320  			return fmt.Errorf("error %s", err)
  1321  		}
  1322  
  1323  		folder := dcFolders.VmFolder
  1324  		if len(rs.Primary.Attributes["folder"]) > 0 {
  1325  			si := object.NewSearchIndex(client.Client)
  1326  			folderRef, err := si.FindByInventoryPath(
  1327  				context.TODO(), fmt.Sprintf("%v/vm/%v", rs.Primary.Attributes["datacenter"], rs.Primary.Attributes["folder"]))
  1328  			if err != nil {
  1329  				return err
  1330  			} else if folderRef != nil {
  1331  				folder = folderRef.(*object.Folder)
  1332  			}
  1333  		}
  1334  
  1335  		_, err = object.NewSearchIndex(client.Client).FindChild(context.TODO(), folder, rs.Primary.Attributes["name"])
  1336  
  1337  		*vm = virtualMachine{
  1338  			name: rs.Primary.ID,
  1339  		}
  1340  
  1341  		return nil
  1342  	}
  1343  }
  1344  
  1345  const testAccCheckVSphereVirtualMachineConfig_keepOnRemove = `
  1346  resource "vsphere_virtual_machine" "keep_disk" {
  1347      name = "terraform-test"
  1348  ` + testAccTemplateBasicBody + `
  1349      disk {
  1350          size = 1
  1351          iops = 500
  1352  	controller_type = "scsi"
  1353  	name = "one"
  1354  	keep_on_remove = true
  1355      }
  1356  }
  1357  `
  1358  
  1359  func TestAccVSphereVirtualMachine_keepOnRemove(t *testing.T) {
  1360  	var vm virtualMachine
  1361  	basic_vars := setupTemplateBasicBodyVars()
  1362  	config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_keepOnRemove)
  1363  	var datastore string
  1364  	if v := os.Getenv("VSPHERE_DATASTORE"); v != "" {
  1365  		datastore = v
  1366  	}
  1367  	var datacenter string
  1368  	if v := os.Getenv("VSPHERE_DATACENTER"); v != "" {
  1369  		datacenter = v
  1370  	}
  1371  
  1372  	vmName := "vsphere_virtual_machine.keep_disk"
  1373  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
  1374  		TestFuncData{vm: vm, label: basic_vars.label, vmName: vmName, numDisks: "2"}.testCheckFuncBasic()
  1375  
  1376  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_keepOnRemove)
  1377  	log.Printf("[DEBUG] template config= %s", config)
  1378  
  1379  	resource.Test(t, resource.TestCase{
  1380  		PreCheck:     func() { testAccPreCheck(t) },
  1381  		Providers:    testAccProviders,
  1382  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
  1383  		Steps: []resource.TestStep{
  1384  			resource.TestStep{
  1385  				Config: config,
  1386  				Check: resource.ComposeTestCheckFunc(
  1387  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
  1388  				),
  1389  			},
  1390  			resource.TestStep{
  1391  				Config: " ",
  1392  				Check:  checkForDisk(datacenter, datastore, "terraform-test", "one.vmdk", true, true),
  1393  			},
  1394  		},
  1395  	})
  1396  }
  1397  
  1398  const testAccVSphereVirtualMachine_DetachUnknownDisks = `
  1399  resource "vsphere_virtual_machine" "detach_unkown_disks" {
  1400      name = "terraform-test"
  1401  ` + testAccTemplateBasicBody + `
  1402      detach_unknown_disks_on_delete = true
  1403      disk {
  1404          size = 1
  1405          iops = 500
  1406  	controller_type = "scsi"
  1407  	name = "one"
  1408  	keep_on_remove = true
  1409      }
  1410      disk {
  1411          size = 2
  1412          iops = 500
  1413  	controller_type = "scsi"
  1414  	name = "two"
  1415  	keep_on_remove = false
  1416      }
  1417      disk {
  1418          size = 3
  1419          iops = 500
  1420  	controller_type = "scsi"
  1421  	name = "three"
  1422  	keep_on_remove = true
  1423      }
  1424  }
  1425  `
  1426  
  1427  func TestAccVSphereVirtualMachine_DetachUnknownDisks(t *testing.T) {
  1428  	var vm virtualMachine
  1429  	basic_vars := setupTemplateBasicBodyVars()
  1430  	config := basic_vars.testSprintfTemplateBody(testAccVSphereVirtualMachine_DetachUnknownDisks)
  1431  	var datastore string
  1432  	if v := os.Getenv("VSPHERE_DATASTORE"); v != "" {
  1433  		datastore = v
  1434  	}
  1435  	var datacenter string
  1436  	if v := os.Getenv("VSPHERE_DATACENTER"); v != "" {
  1437  		datacenter = v
  1438  	}
  1439  
  1440  	vmName := "vsphere_virtual_machine.detach_unkown_disks"
  1441  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
  1442  		TestFuncData{vm: vm, label: basic_vars.label, vmName: vmName, numDisks: "4"}.testCheckFuncBasic()
  1443  
  1444  	log.Printf("[DEBUG] template= %s", testAccVSphereVirtualMachine_DetachUnknownDisks)
  1445  	log.Printf("[DEBUG] template config= %s", config)
  1446  
  1447  	resource.Test(t, resource.TestCase{
  1448  		PreCheck:     func() { testAccPreCheck(t) },
  1449  		Providers:    testAccProviders,
  1450  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
  1451  		Steps: []resource.TestStep{
  1452  			resource.TestStep{
  1453  				Config: config,
  1454  				Check: resource.ComposeTestCheckFunc(
  1455  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
  1456  				),
  1457  			},
  1458  			resource.TestStep{
  1459  				PreConfig: func() {
  1460  					createAndAttachDisk(t, "terraform-test", 1, datastore, "terraform-test/tf_custom_disk.vmdk", "lazy", "scsi", datacenter)
  1461  				},
  1462  				Config: " ",
  1463  				Check: resource.ComposeTestCheckFunc(
  1464  					checkForDisk(datacenter, datastore, "terraform-test", "one.vmdk", true, false),
  1465  					checkForDisk(datacenter, datastore, "terraform-test", "two.vmdk", false, false),
  1466  					checkForDisk(datacenter, datastore, "terraform-test", "three.vmdk", true, false),
  1467  					checkForDisk(datacenter, datastore, "terraform-test", "tf_custom_disk.vmdk", true, true),
  1468  				),
  1469  			},
  1470  		},
  1471  	})
  1472  }
  1473  
  1474  func createAndAttachDisk(t *testing.T, vmName string, size int, datastore string, diskPath string, diskType string, adapterType string, datacenter string) {
  1475  	client := testAccProvider.Meta().(*govmomi.Client)
  1476  	finder := find.NewFinder(client.Client, true)
  1477  
  1478  	dc, err := finder.Datacenter(context.TODO(), datacenter)
  1479  	if err != nil {
  1480  		log.Printf("[ERROR] finding Datacenter %s: %v", datacenter, err)
  1481  		t.Fail()
  1482  		return
  1483  	}
  1484  	finder = finder.SetDatacenter(dc)
  1485  	ds, err := getDatastore(finder, datastore)
  1486  	if err != nil {
  1487  		log.Printf("[ERROR] getDatastore %s: %v", datastore, err)
  1488  		t.Fail()
  1489  		return
  1490  	}
  1491  	vm, err := finder.VirtualMachine(context.TODO(), vmName)
  1492  	if err != nil {
  1493  		log.Printf("[ERROR] finding VM %s: %v", vmName, err)
  1494  		t.Fail()
  1495  		return
  1496  	}
  1497  	err = addHardDisk(vm, int64(size), int64(0), diskType, ds, diskPath, adapterType)
  1498  	if err != nil {
  1499  		log.Printf("[ERROR] addHardDisk: %v", err)
  1500  		t.Fail()
  1501  		return
  1502  	}
  1503  }
  1504  
  1505  func vmCleanup(dc *object.Datacenter, ds *object.Datastore, vmName string) error {
  1506  	client := testAccProvider.Meta().(*govmomi.Client)
  1507  	fileManager := object.NewFileManager(client.Client)
  1508  	task, err := fileManager.DeleteDatastoreFile(context.TODO(), ds.Path(vmName), dc)
  1509  	if err != nil {
  1510  		log.Printf("[ERROR] checkForDisk - Couldn't delete vm folder '%v': %v", vmName, err)
  1511  		return err
  1512  	}
  1513  
  1514  	_, err = task.WaitForResult(context.TODO(), nil)
  1515  	if err != nil {
  1516  		log.Printf("[ERROR] checForDisk - Failed while deleting vm folder '%v': %v", vmName, err)
  1517  		return err
  1518  	}
  1519  	return nil
  1520  }
  1521  
  1522  func checkForDisk(datacenter string, datastore string, vmName string, path string, exists bool, cleanup bool) resource.TestCheckFunc {
  1523  	return func(s *terraform.State) error {
  1524  		client := testAccProvider.Meta().(*govmomi.Client)
  1525  		finder := find.NewFinder(client.Client, true)
  1526  
  1527  		dc, err := getDatacenter(client, datacenter)
  1528  		if err != nil {
  1529  			return err
  1530  		}
  1531  		finder.SetDatacenter(dc)
  1532  
  1533  		ds, err := finder.Datastore(context.TODO(), datastore)
  1534  		if err != nil {
  1535  			log.Printf("[ERROR] checkForDisk - Couldn't find Datastore '%v': %v", datastore, err)
  1536  			return err
  1537  		}
  1538  
  1539  		diskPath := vmName + "/" + path
  1540  
  1541  		_, err = ds.Stat(context.TODO(), diskPath)
  1542  		if err != nil && exists {
  1543  			log.Printf("[ERROR] checkForDisk - Couldn't stat file '%v': %v", diskPath, err)
  1544  			return err
  1545  		} else if err == nil && !exists {
  1546  			errorMessage := fmt.Sprintf("checkForDisk - disk %s still exists", diskPath)
  1547  			err = vmCleanup(dc, ds, vmName)
  1548  			if err != nil {
  1549  				return fmt.Errorf("[ERROR] %s, cleanup also failed: %v", errorMessage, err)
  1550  			}
  1551  			return fmt.Errorf("[ERROR] %s", errorMessage)
  1552  		}
  1553  
  1554  		if !cleanup || !exists {
  1555  			return nil
  1556  		}
  1557  
  1558  		err = vmCleanup(dc, ds, vmName)
  1559  		if err != nil {
  1560  			return fmt.Errorf("[ERROR] cleanup failed: %v", err)
  1561  		}
  1562  
  1563  		return nil
  1564  	}
  1565  }