github.com/boyvanduuren/terraform@v0.7.0-rc2.0.20160805175930-de822d909c40/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_initType = `
   402  resource "vsphere_virtual_machine" "thin" {
   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_diskInitType(t *testing.T) {
   421  	var vm virtualMachine
   422  	basic_vars := setupTemplateBasicBodyVars()
   423  	config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_initType)
   424  
   425  	vmName := "vsphere_virtual_machine.thin"
   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_initType)
   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_dhcp = `
   453  resource "vsphere_virtual_machine" "bar" {
   454      name = "terraform-test"
   455  `
   456  
   457  func TestAccVSphereVirtualMachine_dhcp(t *testing.T) {
   458  	var vm virtualMachine
   459  	data := setupTemplateFuncDHCPData()
   460  	config := testAccCheckVSphereVirtualMachineConfig_dhcp + data.parseDHCPTemplateConfigWithTemplate(testAccCheckVSphereTemplate_dhcp)
   461  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_dhcp+testAccCheckVSphereTemplate_dhcp)
   462  	log.Printf("[DEBUG] config= %s", config)
   463  
   464  	resource.Test(t, resource.TestCase{
   465  		PreCheck:     func() { testAccPreCheck(t) },
   466  		Providers:    testAccProviders,
   467  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   468  		Steps: []resource.TestStep{
   469  			resource.TestStep{
   470  				Config: config,
   471  				Check: resource.ComposeTestCheckFunc(
   472  					TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(),
   473  				),
   474  			},
   475  		},
   476  	})
   477  }
   478  
   479  const testAccCheckVSphereVirtualMachineConfig_custom_configs = `
   480  resource "vsphere_virtual_machine" "car" {
   481      name = "terraform-test-custom"
   482      custom_configuration_parameters {
   483        "foo" = "bar"
   484        "car" = "ferrari"
   485        "num" = 42
   486      }
   487  	enable_disk_uuid = true
   488  `
   489  
   490  func TestAccVSphereVirtualMachine_custom_configs(t *testing.T) {
   491  
   492  	var vm virtualMachine
   493  	data := setupTemplateFuncDHCPData()
   494  	config := testAccCheckVSphereVirtualMachineConfig_custom_configs + data.parseDHCPTemplateConfigWithTemplate(testAccCheckVSphereTemplate_dhcp)
   495  	vmName := "vsphere_virtual_machine.car"
   496  	res := "terraform-test-custom"
   497  
   498  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
   499  		TestFuncData{vm: vm, label: data.label, vmName: vmName, vmResource: res}.testCheckFuncBasic()
   500  
   501  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_custom_configs+testAccCheckVSphereTemplate_dhcp)
   502  	log.Printf("[DEBUG] config= %s", config)
   503  
   504  	resource.Test(t, resource.TestCase{
   505  		PreCheck:     func() { testAccPreCheck(t) },
   506  		Providers:    testAccProviders,
   507  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   508  		Steps: []resource.TestStep{
   509  			resource.TestStep{
   510  				Config: config,
   511  				Check: resource.ComposeTestCheckFunc(
   512  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
   513  					testAccCheckVSphereVirtualMachineExistsHasCustomConfig(vmName, &vm),
   514  					resource.TestCheckResourceAttr(vmName, "custom_configuration_parameters.foo", "bar"),
   515  					resource.TestCheckResourceAttr(vmName, "custom_configuration_parameters.car", "ferrari"),
   516  					resource.TestCheckResourceAttr(vmName, "custom_configuration_parameters.num", "42"),
   517  					resource.TestCheckResourceAttr(vmName, "enable_disk_uuid", "true"),
   518  				),
   519  			},
   520  		},
   521  	})
   522  }
   523  
   524  const testAccCheckVSphereVirtualMachineConfig_createInFolder = `
   525  resource "vsphere_virtual_machine" "folder" {
   526      name = "terraform-test-folder"
   527      folder = "%s"
   528  `
   529  
   530  func TestAccVSphereVirtualMachine_createInExistingFolder(t *testing.T) {
   531  	var vm virtualMachine
   532  	datacenter := os.Getenv("VSPHERE_DATACENTER")
   533  
   534  	folder := "tf_test_cpureateInExistingFolder"
   535  
   536  	data := setupTemplateFuncDHCPData()
   537  	config := fmt.Sprintf(testAccCheckVSphereVirtualMachineConfig_createInFolder,
   538  		folder,
   539  	) + data.parseDHCPTemplateConfig()
   540  
   541  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_createInFolder)
   542  	log.Printf("[DEBUG] template config= %s", config)
   543  
   544  	resource.Test(t, resource.TestCase{
   545  		PreCheck:  func() { testAccPreCheck(t) },
   546  		Providers: testAccProviders,
   547  		CheckDestroy: resource.ComposeTestCheckFunc(
   548  			testAccCheckVSphereVirtualMachineDestroy,
   549  			removeVSphereFolder(datacenter, folder, ""),
   550  		),
   551  		Steps: []resource.TestStep{
   552  			resource.TestStep{
   553  				PreConfig: func() { createVSphereFolder(datacenter, folder) },
   554  				Config:    config,
   555  				Check: resource.ComposeTestCheckFunc(
   556  					TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.folder", vmResource: "terraform-test-folder"}.testCheckFuncBasic(),
   557  				),
   558  			},
   559  		},
   560  	})
   561  }
   562  
   563  const testAccCheckVSphereVirtualMachineConfig_createWithFolder = `
   564  resource "vsphere_folder" "with_folder" {
   565  	path = "%s"
   566  %s
   567  }
   568  resource "vsphere_virtual_machine" "with_folder" {
   569      name = "terraform-test-with-folder"
   570      folder = "${vsphere_folder.with_folder.path}"
   571  `
   572  
   573  func TestAccVSphereVirtualMachine_createWithFolder(t *testing.T) {
   574  	var vm virtualMachine
   575  	var folderLocationOpt string
   576  	var f folder
   577  
   578  	if v := os.Getenv("VSPHERE_DATACENTER"); v != "" {
   579  		folderLocationOpt = fmt.Sprintf("    datacenter = \"%s\"\n", v)
   580  	}
   581  
   582  	folder := "tf_test_cpureateWithFolder"
   583  
   584  	data := setupTemplateFuncDHCPData()
   585  	vmName := "vsphere_virtual_machine.with_folder"
   586  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
   587  		TestFuncData{vm: vm, label: data.label, vmName: vmName, vmResource: "terraform-test-with-folder"}.testCheckFuncBasic()
   588  
   589  	config := fmt.Sprintf(testAccCheckVSphereVirtualMachineConfig_createWithFolder,
   590  		folder,
   591  		folderLocationOpt,
   592  	) + data.parseDHCPTemplateConfig()
   593  
   594  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_createWithFolder+testAccCheckVSphereTemplate_dhcp)
   595  	log.Printf("[DEBUG] template config= %s", config)
   596  
   597  	resource.Test(t, resource.TestCase{
   598  		PreCheck:  func() { testAccPreCheck(t) },
   599  		Providers: testAccProviders,
   600  		CheckDestroy: resource.ComposeTestCheckFunc(
   601  			testAccCheckVSphereVirtualMachineDestroy,
   602  			testAccCheckVSphereFolderDestroy,
   603  		),
   604  		Steps: []resource.TestStep{
   605  			resource.TestStep{
   606  				Config: config,
   607  				Check: resource.ComposeTestCheckFunc(
   608  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
   609  					testAccCheckVSphereFolderExists(vmName, &f),
   610  					resource.TestCheckResourceAttr(vmName, "folder", folder),
   611  				),
   612  			},
   613  		},
   614  	})
   615  }
   616  
   617  const testAccCheckVsphereVirtualMachineConfig_cdrom = `
   618  resource "vsphere_virtual_machine" "with_cdrom" {
   619      name = "terraform-test-with-cdrom"
   620      cdrom {
   621          datastore = "%s"
   622          path = "%s"
   623      }
   624  `
   625  
   626  func TestAccVSphereVirtualMachine_createWithCdrom(t *testing.T) {
   627  	var vm virtualMachine
   628  
   629  	// FIXME check that these exist
   630  	cdromDatastore := os.Getenv("VSPHERE_CDROM_DATASTORE")
   631  	cdromPath := os.Getenv("VSPHERE_CDROM_PATH")
   632  	vmName := "vsphere_virtual_machine.with_cdrom"
   633  
   634  	data := setupTemplateFuncDHCPData()
   635  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
   636  		TestFuncData{vm: vm, label: data.label, vmName: vmName, vmResource: "terraform-test-with-cdrom"}.testCheckFuncBasic()
   637  
   638  	config := fmt.Sprintf(
   639  		testAccCheckVsphereVirtualMachineConfig_cdrom,
   640  		cdromDatastore,
   641  		cdromPath,
   642  	) + data.parseDHCPTemplateConfig()
   643  
   644  	log.Printf("[DEBUG] template= %s", testAccCheckVsphereVirtualMachineConfig_cdrom)
   645  	log.Printf("[DEBUG] template config= %s", config)
   646  
   647  	resource.Test(t, resource.TestCase{
   648  		PreCheck:     func() { testAccPreCheck(t) },
   649  		Providers:    testAccProviders,
   650  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   651  		Steps: []resource.TestStep{
   652  			resource.TestStep{
   653  				Config: config,
   654  				Check: resource.ComposeTestCheckFunc(
   655  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
   656  					//resource.TestCheckResourceAttr(
   657  					//	"vsphere_virtual_machine.with_cdrom", "disk.4088143748.template", template),
   658  					resource.TestCheckResourceAttr(vmName, "cdrom.#", "1"),
   659  					resource.TestCheckResourceAttr(vmName, "cdrom.0.datastore", cdromDatastore),
   660  					resource.TestCheckResourceAttr(vmName, "cdrom.0.path", cdromPath),
   661  				),
   662  			},
   663  		},
   664  	})
   665  }
   666  
   667  const testAccCheckVSphereVirtualMachineConfig_withExistingVmdk = `
   668  resource "vsphere_virtual_machine" "with_existing_vmdk" {
   669      name = "terraform-test-with-existing-vmdk"
   670  %s
   671      vcpu = 2
   672      memory = 1024
   673      network_interface {
   674          label = "%s"
   675      }
   676      disk {
   677  %s
   678          vmdk = "%s"
   679  		bootable = true
   680      }
   681      disk {
   682          size = 1
   683          iops = 500
   684  		name = "one"
   685      }
   686  }
   687  `
   688  
   689  func TestAccVSphereVirtualMachine_createWithExistingVmdk(t *testing.T) {
   690  	var vm virtualMachine
   691  	vmdk_path := os.Getenv("VSPHERE_VMDK_PATH")
   692  
   693  	data := setupTemplateFuncDHCPData()
   694  	config := fmt.Sprintf(
   695  		testAccCheckVSphereVirtualMachineConfig_withExistingVmdk,
   696  		data.locationOpt,
   697  		data.label,
   698  		data.datastoreOpt,
   699  		vmdk_path,
   700  	)
   701  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_withExistingVmdk)
   702  	log.Printf("[DEBUG] template config= %s", config)
   703  
   704  	resource.Test(t, resource.TestCase{
   705  		PreCheck:     func() { testAccPreCheck(t) },
   706  		Providers:    testAccProviders,
   707  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   708  		Steps: []resource.TestStep{
   709  			resource.TestStep{
   710  				Config: config,
   711  				Check: resource.ComposeTestCheckFunc(
   712  					TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.with_existing_vmdk",
   713  						vmResource: "terraform-test-with-existing-vmdk", numDisks: "2"}.testCheckFuncBasic(),
   714  					//resource.TestCheckResourceAttr(
   715  					//	"vsphere_virtual_machine.with_existing_vmdk", "disk.2393891804.vmdk", vmdk_path),
   716  					//resource.TestCheckResourceAttr(
   717  					//	"vsphere_virtual_machine.with_existing_vmdk", "disk.2393891804.bootable", "true"),
   718  				),
   719  			},
   720  		},
   721  	})
   722  }
   723  
   724  const testAccCheckVSphereVirtualMachineConfig_updateMemory = `
   725  resource "vsphere_virtual_machine" "bar" {
   726      name = "terraform-test"
   727  %s
   728      vcpu = 2
   729      memory = %s
   730      network_interface {
   731          label = "%s"
   732      }
   733      disk {
   734  %s
   735        template = "%s"
   736      }
   737  }
   738  `
   739  
   740  func TestAccVSphereVirtualMachine_updateMemory(t *testing.T) {
   741  	var vm virtualMachine
   742  	data := setupTemplateFuncDHCPData()
   743  
   744  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_updateMemory)
   745  
   746  	config := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateMemory, "1024")
   747  	log.Printf("[DEBUG] template config= %s", config)
   748  
   749  	configUpdate := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateMemory, "2048")
   750  	log.Printf("[DEBUG] template configUpdate= %s", configUpdate)
   751  
   752  	resource.Test(t, resource.TestCase{
   753  		PreCheck:     func() { testAccPreCheck(t) },
   754  		Providers:    testAccProviders,
   755  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   756  		Steps: []resource.TestStep{
   757  			resource.TestStep{
   758  				Config: config,
   759  				Check: resource.ComposeTestCheckFunc(
   760  					TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(),
   761  				),
   762  			},
   763  			resource.TestStep{
   764  				Config: configUpdate,
   765  				Check: resource.ComposeTestCheckFunc(
   766  					TestFuncData{vm: vm, label: data.label, mem: "2048", vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(),
   767  				),
   768  			},
   769  		},
   770  	})
   771  }
   772  
   773  const testAccCheckVSphereVirtualMachineConfig_updateVcpu = `
   774  resource "vsphere_virtual_machine" "bar" {
   775      name = "terraform-test"
   776  %s
   777      vcpu = %s
   778      memory = 1024
   779      network_interface {
   780          label = "%s"
   781      }
   782      disk {
   783  %s
   784          template = "%s"
   785      }
   786  }
   787  `
   788  
   789  func TestAccVSphereVirtualMachine_updateVcpu(t *testing.T) {
   790  	var vm virtualMachine
   791  	data := setupTemplateFuncDHCPData()
   792  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_updateVcpu)
   793  
   794  	config := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateVcpu, "2")
   795  	log.Printf("[DEBUG] template config= %s", config)
   796  
   797  	configUpdate := data.testSprintfDHCPTemplateBodySecondArgDynamic(testAccCheckVSphereVirtualMachineConfig_updateVcpu, "4")
   798  	log.Printf("[DEBUG] template configUpdate= %s", configUpdate)
   799  
   800  	resource.Test(t, resource.TestCase{
   801  		PreCheck:     func() { testAccPreCheck(t) },
   802  		Providers:    testAccProviders,
   803  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   804  		Steps: []resource.TestStep{
   805  			resource.TestStep{
   806  				Config: config,
   807  				Check: resource.ComposeTestCheckFunc(
   808  					TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar"}.testCheckFuncBasic(),
   809  				),
   810  			},
   811  			resource.TestStep{
   812  				Config: configUpdate,
   813  				Check: resource.ComposeTestCheckFunc(
   814  					TestFuncData{vm: vm, label: data.label, vmName: "vsphere_virtual_machine.bar", numCPU: "4"}.testCheckFuncBasic(),
   815  				),
   816  			},
   817  		},
   818  	})
   819  }
   820  
   821  const testAccCheckVSphereVirtualMachineConfig_ipv4Andipv6 = `
   822  resource "vsphere_virtual_machine" "ipv4ipv6" {
   823      name = "terraform-test-ipv4-ipv6"
   824  %s
   825      vcpu = 2
   826      memory = 1024
   827      network_interface {
   828          label = "%s"
   829          ipv4_address = "%s"
   830          ipv4_prefix_length = %s
   831          ipv4_gateway = "%s"
   832          ipv6_address = "%s"
   833          ipv6_prefix_length = 64
   834          ipv6_gateway = "%s"
   835      }
   836      disk {
   837  %s
   838          template = "%s"
   839          iops = 500
   840      }
   841      disk {
   842          size = 1
   843          iops = 500
   844  		name = "one"
   845      }
   846  }
   847  `
   848  
   849  func TestAccVSphereVirtualMachine_ipv4Andipv6(t *testing.T) {
   850  	var vm virtualMachine
   851  	data := setupTemplateBasicBodyVars()
   852  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_ipv4Andipv6)
   853  
   854  	vmName := "vsphere_virtual_machine.ipv4ipv6"
   855  
   856  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
   857  		TestFuncData{vm: vm, label: data.label, vmName: vmName, numDisks: "2", vmResource: "terraform-test-ipv4-ipv6"}.testCheckFuncBasic()
   858  
   859  	// FIXME test for this or warn??
   860  	ipv6Address := os.Getenv("VSPHERE_IPV6_ADDRESS")
   861  	ipv6Gateway := os.Getenv("VSPHERE_IPV6_GATEWAY")
   862  
   863  	config := fmt.Sprintf(
   864  		testAccCheckVSphereVirtualMachineConfig_ipv4Andipv6,
   865  		data.locationOpt,
   866  		data.label,
   867  		data.ipv4IpAddress,
   868  		data.ipv4Prefix,
   869  		data.ipv4Gateway,
   870  		ipv6Address,
   871  		ipv6Gateway,
   872  		data.datastoreOpt,
   873  		data.template,
   874  	)
   875  
   876  	log.Printf("[DEBUG] template config= %s", config)
   877  
   878  	resource.Test(t, resource.TestCase{
   879  		PreCheck:     func() { testAccPreCheck(t) },
   880  		Providers:    testAccProviders,
   881  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   882  		Steps: []resource.TestStep{
   883  			resource.TestStep{
   884  				Config: config,
   885  				Check: resource.ComposeTestCheckFunc(
   886  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
   887  					resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv4_address", data.ipv4IpAddress),
   888  					resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv4_gateway", data.ipv4Gateway),
   889  					resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv6_address", ipv6Address),
   890  					resource.TestCheckResourceAttr(vmName, "network_interface.0.ipv6_gateway", ipv6Gateway),
   891  				),
   892  			},
   893  		},
   894  	})
   895  }
   896  
   897  const testAccCheckVSphereVirtualMachineConfig_updateAddDisks = `
   898  resource "vsphere_virtual_machine" "foo" {
   899      name = "terraform-test"
   900  ` + testAccTemplateBasicBody + `
   901      disk {
   902          size = 1
   903          iops = 500
   904  	name = "one"
   905      }
   906  	disk {
   907          size = 1
   908          iops = 500
   909  	name = "two"
   910      }
   911  	disk {
   912          size = 1
   913          iops = 500
   914  	name = "three"
   915      }
   916  }
   917  `
   918  const testAccCheckVSphereVirtualMachineConfig_basic = `
   919  resource "vsphere_virtual_machine" "foo" {
   920      name = "terraform-test"
   921  ` + testAccTemplateBasicBody + `
   922      disk {
   923          size = 1
   924          iops = 500
   925  	name = "one"
   926      }
   927  }
   928  `
   929  
   930  func TestAccVSphereVirtualMachine_updateDisks(t *testing.T) {
   931  	var vm virtualMachine
   932  	basic_vars := setupTemplateBasicBodyVars()
   933  	config_basic := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_basic)
   934  
   935  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_basic)
   936  	log.Printf("[DEBUG] template config= %s", config_basic)
   937  
   938  	config_add := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_updateAddDisks)
   939  
   940  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_basic)
   941  	log.Printf("[DEBUG] template config= %s", config_add)
   942  
   943  	config_del := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_really_basic)
   944  
   945  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_really_basic)
   946  	log.Printf("[DEBUG] template config= %s", config_del)
   947  
   948  	resource.Test(t, resource.TestCase{
   949  		PreCheck:     func() { testAccPreCheck(t) },
   950  		Providers:    testAccProviders,
   951  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
   952  		Steps: []resource.TestStep{
   953  			resource.TestStep{
   954  				Config: config_basic,
   955  				Check: resource.ComposeTestCheckFunc(
   956  					TestFuncData{vm: vm, label: basic_vars.label, numDisks: "2"}.testCheckFuncBasic(),
   957  				),
   958  			},
   959  			resource.TestStep{
   960  				Config: config_add,
   961  				Check: resource.ComposeTestCheckFunc(
   962  					TestFuncData{vm: vm, label: basic_vars.label, numDisks: "4"}.testCheckFuncBasic(),
   963  				),
   964  			},
   965  			resource.TestStep{
   966  				Config: config_del,
   967  				Check: resource.ComposeTestCheckFunc(
   968  					TestFuncData{vm: vm, label: basic_vars.label, numDisks: "1"}.testCheckFuncBasic(),
   969  				),
   970  			},
   971  		},
   972  	})
   973  }
   974  
   975  const testAccCheckVSphereVirtualMachineConfig_mac_address = `
   976  resource "vsphere_virtual_machine" "mac_address" {
   977      name = "terraform-mac-address"
   978  %s
   979      vcpu = 2
   980      memory = 1024
   981      network_interface {
   982          label = "%s"
   983          mac_address = "%s"
   984      }
   985      disk {
   986  %s
   987          template = "%s"
   988      }
   989  }
   990  `
   991  
   992  // VSPHERE_NETWORK_MAC_ADDRESS needs to be set to run TestAccVSphereVirtualMachine_mac_address
   993  // use a basic NIC MAC address like 6:5c:89:2b:a0:64
   994  func testMacPreCheck(t *testing.T) {
   995  
   996  	testBasicPreCheck(t)
   997  
   998  	// TODO should start do parse values to ensure they are correct
   999  	// for instance
  1000  	//  func ParseMAC(s string) (hw HardwareAddr, err error)
  1001  	if v := os.Getenv("VSPHERE_NETWORK_MAC_ADDRESS"); v == "" {
  1002  		t.Fatal("env variable VSPHERE_NETWORK_MAC_ADDRESS must be set for this acceptance test")
  1003  	}
  1004  }
  1005  
  1006  // test new mac address feature
  1007  func TestAccVSphereVirtualMachine_mac_address(t *testing.T) {
  1008  	var vm virtualMachine
  1009  	data := setupTemplateFuncDHCPData()
  1010  	vmName := "vsphere_virtual_machine.mac_address"
  1011  
  1012  	macAddress := os.Getenv("VSPHERE_NETWORK_MAC_ADDRESS")
  1013  
  1014  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_mac_address)
  1015  	config := fmt.Sprintf(
  1016  		testAccCheckVSphereVirtualMachineConfig_mac_address,
  1017  		data.locationOpt,
  1018  		data.label,
  1019  		macAddress,
  1020  		data.datastoreOpt,
  1021  		data.template,
  1022  	)
  1023  	log.Printf("[DEBUG] template config= %s", config)
  1024  
  1025  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
  1026  		TestFuncData{vm: vm, label: data.label, vmName: vmName, numDisks: "1", vmResource: "terraform-mac-address"}.testCheckFuncBasic()
  1027  
  1028  	resource.Test(t, resource.TestCase{
  1029  		PreCheck:     func() { testMacPreCheck(t) },
  1030  		Providers:    testAccProviders,
  1031  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
  1032  		Steps: []resource.TestStep{
  1033  			resource.TestStep{
  1034  				Config: config,
  1035  				Check: resource.ComposeTestCheckFunc(
  1036  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
  1037  					resource.TestCheckResourceAttr(vmName, "network_interface.0.mac_address", macAddress),
  1038  				),
  1039  			},
  1040  		},
  1041  	})
  1042  }
  1043  
  1044  func testAccCheckVSphereVirtualMachineDestroy(s *terraform.State) error {
  1045  	client := testAccProvider.Meta().(*govmomi.Client)
  1046  	finder := find.NewFinder(client.Client, true)
  1047  
  1048  	for _, rs := range s.RootModule().Resources {
  1049  		if rs.Type != "vsphere_virtual_machine" {
  1050  			continue
  1051  		}
  1052  
  1053  		dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"])
  1054  		if err != nil {
  1055  			return fmt.Errorf("error %s", err)
  1056  		}
  1057  
  1058  		dcFolders, err := dc.Folders(context.TODO())
  1059  		if err != nil {
  1060  			return fmt.Errorf("error %s", err)
  1061  		}
  1062  
  1063  		folder := dcFolders.VmFolder
  1064  		if len(rs.Primary.Attributes["folder"]) > 0 {
  1065  			si := object.NewSearchIndex(client.Client)
  1066  			folderRef, err := si.FindByInventoryPath(
  1067  				context.TODO(), fmt.Sprintf("%v/vm/%v", rs.Primary.Attributes["datacenter"], rs.Primary.Attributes["folder"]))
  1068  			if err != nil {
  1069  				return err
  1070  			} else if folderRef != nil {
  1071  				folder = folderRef.(*object.Folder)
  1072  			}
  1073  		}
  1074  
  1075  		v, err := object.NewSearchIndex(client.Client).FindChild(context.TODO(), folder, rs.Primary.Attributes["name"])
  1076  
  1077  		if v != nil {
  1078  			return fmt.Errorf("Record still exists")
  1079  		}
  1080  	}
  1081  
  1082  	return nil
  1083  }
  1084  
  1085  func testAccCheckVSphereVirtualMachineExistsHasCustomConfig(n string, vm *virtualMachine) resource.TestCheckFunc {
  1086  	return func(s *terraform.State) error {
  1087  
  1088  		rs, ok := s.RootModule().Resources[n]
  1089  		if !ok {
  1090  			return fmt.Errorf("Not found: %s", n)
  1091  		}
  1092  
  1093  		if rs.Primary.ID == "" {
  1094  			return fmt.Errorf("No ID is set")
  1095  		}
  1096  
  1097  		client := testAccProvider.Meta().(*govmomi.Client)
  1098  		finder := find.NewFinder(client.Client, true)
  1099  
  1100  		dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"])
  1101  		if err != nil {
  1102  			return fmt.Errorf("error %s", err)
  1103  		}
  1104  
  1105  		dcFolders, err := dc.Folders(context.TODO())
  1106  		if err != nil {
  1107  			return fmt.Errorf("error %s", err)
  1108  		}
  1109  
  1110  		_, err = object.NewSearchIndex(client.Client).FindChild(context.TODO(), dcFolders.VmFolder, rs.Primary.Attributes["name"])
  1111  		if err != nil {
  1112  			return fmt.Errorf("error %s", err)
  1113  		}
  1114  
  1115  		finder = finder.SetDatacenter(dc)
  1116  		instance, err := finder.VirtualMachine(context.TODO(), rs.Primary.Attributes["name"])
  1117  		if err != nil {
  1118  			return fmt.Errorf("error %s", err)
  1119  		}
  1120  
  1121  		var mvm mo.VirtualMachine
  1122  
  1123  		collector := property.DefaultCollector(client.Client)
  1124  
  1125  		if err := collector.RetrieveOne(context.TODO(), instance.Reference(), []string{"config.extraConfig"}, &mvm); err != nil {
  1126  			return fmt.Errorf("error %s", err)
  1127  		}
  1128  
  1129  		var configMap = make(map[string]types.AnyType)
  1130  		if mvm.Config != nil && mvm.Config.ExtraConfig != nil && len(mvm.Config.ExtraConfig) > 0 {
  1131  			for _, v := range mvm.Config.ExtraConfig {
  1132  				value := v.GetOptionValue()
  1133  				configMap[value.Key] = value.Value
  1134  			}
  1135  		} else {
  1136  			return fmt.Errorf("error no ExtraConfig")
  1137  		}
  1138  
  1139  		if configMap["foo"] == nil {
  1140  			return fmt.Errorf("error no ExtraConfig for 'foo'")
  1141  		}
  1142  
  1143  		if configMap["foo"] != "bar" {
  1144  			return fmt.Errorf("error ExtraConfig 'foo' != bar")
  1145  		}
  1146  
  1147  		if configMap["car"] == nil {
  1148  			return fmt.Errorf("error no ExtraConfig for 'car'")
  1149  		}
  1150  
  1151  		if configMap["car"] != "ferrari" {
  1152  			return fmt.Errorf("error ExtraConfig 'car' != ferrari")
  1153  		}
  1154  
  1155  		if configMap["num"] == nil {
  1156  			return fmt.Errorf("error no ExtraConfig for 'num'")
  1157  		}
  1158  
  1159  		// todo this should be an int, getting back a string
  1160  		if configMap["num"] != "42" {
  1161  			return fmt.Errorf("error ExtraConfig 'num' != 42")
  1162  		}
  1163  		*vm = virtualMachine{
  1164  			name: rs.Primary.ID,
  1165  		}
  1166  
  1167  		return nil
  1168  	}
  1169  }
  1170  
  1171  func testAccCheckDebugExists() resource.TestCheckFunc {
  1172  	return func(s *terraform.State) error {
  1173  		if _, err := os.Stat(filepath.Join(os.Getenv("HOME"), ".govmomi")); os.IsNotExist(err) {
  1174  			return fmt.Errorf("Debug logs not found")
  1175  		}
  1176  
  1177  		return nil
  1178  	}
  1179  
  1180  }
  1181  func testAccCheckVSphereVirtualMachineExists(n string, vm *virtualMachine) resource.TestCheckFunc {
  1182  	return func(s *terraform.State) error {
  1183  		if n == "" {
  1184  			return fmt.Errorf("No vm name passed in")
  1185  		}
  1186  		if vm == nil {
  1187  			return fmt.Errorf("No vm obj passed in")
  1188  		}
  1189  		rs, ok := s.RootModule().Resources[n]
  1190  		if !ok {
  1191  			return fmt.Errorf("Not found: %s", n)
  1192  		}
  1193  
  1194  		if rs.Primary.ID == "" {
  1195  			return fmt.Errorf("No ID is set")
  1196  		}
  1197  
  1198  		client := testAccProvider.Meta().(*govmomi.Client)
  1199  		finder := find.NewFinder(client.Client, true)
  1200  
  1201  		dc, err := finder.Datacenter(context.TODO(), rs.Primary.Attributes["datacenter"])
  1202  		if err != nil {
  1203  			return fmt.Errorf("error %s", err)
  1204  		}
  1205  
  1206  		dcFolders, err := dc.Folders(context.TODO())
  1207  		if err != nil {
  1208  			return fmt.Errorf("error %s", err)
  1209  		}
  1210  
  1211  		folder := dcFolders.VmFolder
  1212  		if len(rs.Primary.Attributes["folder"]) > 0 {
  1213  			si := object.NewSearchIndex(client.Client)
  1214  			folderRef, err := si.FindByInventoryPath(
  1215  				context.TODO(), fmt.Sprintf("%v/vm/%v", rs.Primary.Attributes["datacenter"], rs.Primary.Attributes["folder"]))
  1216  			if err != nil {
  1217  				return err
  1218  			} else if folderRef != nil {
  1219  				folder = folderRef.(*object.Folder)
  1220  			}
  1221  		}
  1222  
  1223  		_, err = object.NewSearchIndex(client.Client).FindChild(context.TODO(), folder, rs.Primary.Attributes["name"])
  1224  
  1225  		*vm = virtualMachine{
  1226  			name: rs.Primary.ID,
  1227  		}
  1228  
  1229  		return nil
  1230  	}
  1231  }
  1232  
  1233  const testAccCheckVSphereVirtualMachineConfig_keepOnRemove = `
  1234  resource "vsphere_virtual_machine" "keep_disk" {
  1235      name = "terraform-test"
  1236  ` + testAccTemplateBasicBody + `
  1237      disk {
  1238          size = 1
  1239          iops = 500
  1240  		controller_type = "scsi"
  1241  		name = "one"
  1242  		keep_on_remove = true
  1243      }
  1244  }
  1245  `
  1246  
  1247  func TestAccVSphereVirtualMachine_keepOnRemove(t *testing.T) {
  1248  	var vm virtualMachine
  1249  	basic_vars := setupTemplateBasicBodyVars()
  1250  	config := basic_vars.testSprintfTemplateBody(testAccCheckVSphereVirtualMachineConfig_keepOnRemove)
  1251  	var datastore string
  1252  	if v := os.Getenv("VSPHERE_DATASTORE"); v != "" {
  1253  		datastore = v
  1254  	}
  1255  	var datacenter string
  1256  	if v := os.Getenv("VSPHERE_DATACENTER"); v != "" {
  1257  		datacenter = v
  1258  	}
  1259  
  1260  	vmName := "vsphere_virtual_machine.keep_disk"
  1261  	test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label :=
  1262  		TestFuncData{vm: vm, label: basic_vars.label, vmName: vmName, numDisks: "2"}.testCheckFuncBasic()
  1263  
  1264  	log.Printf("[DEBUG] template= %s", testAccCheckVSphereVirtualMachineConfig_keepOnRemove)
  1265  	log.Printf("[DEBUG] template config= %s", config)
  1266  
  1267  	resource.Test(t, resource.TestCase{
  1268  		PreCheck:     func() { testAccPreCheck(t) },
  1269  		Providers:    testAccProviders,
  1270  		CheckDestroy: testAccCheckVSphereVirtualMachineDestroy,
  1271  		Steps: []resource.TestStep{
  1272  			resource.TestStep{
  1273  				Config: config,
  1274  				Check: resource.ComposeTestCheckFunc(
  1275  					test_exists, test_name, test_cpu, test_uuid, test_mem, test_num_disk, test_num_of_nic, test_nic_label,
  1276  				),
  1277  			},
  1278  			resource.TestStep{
  1279  				Config: " ",
  1280  				Check:  checkForDisk(datacenter, datastore, "terraform-test", "one.vmdk"),
  1281  			},
  1282  		},
  1283  	})
  1284  }
  1285  
  1286  func checkForDisk(datacenter string, datastore string, vmName string, path string) resource.TestCheckFunc {
  1287  	return func(s *terraform.State) error {
  1288  		client := testAccProvider.Meta().(*govmomi.Client)
  1289  		finder := find.NewFinder(client.Client, true)
  1290  
  1291  		dc, err := getDatacenter(client, datacenter)
  1292  		if err != nil {
  1293  			return err
  1294  		}
  1295  		finder.SetDatacenter(dc)
  1296  
  1297  		ds, err := finder.Datastore(context.TODO(), datastore)
  1298  		if err != nil {
  1299  			log.Printf("[ERROR] checkForDisk - Couldn't find Datastore '%v': %v", datastore, err)
  1300  			return err
  1301  		}
  1302  
  1303  		diskPath := vmName + "/" + path
  1304  
  1305  		_, err = ds.Stat(context.TODO(), diskPath)
  1306  		if err != nil {
  1307  			log.Printf("[ERROR] checkForDisk - Couldn't stat file '%v': %v", diskPath, err)
  1308  			return err
  1309  		}
  1310  
  1311  		// Cleanup
  1312  		fileManager := object.NewFileManager(client.Client)
  1313  		task, err := fileManager.DeleteDatastoreFile(context.TODO(), ds.Path(vmName), dc)
  1314  		if err != nil {
  1315  			log.Printf("[ERROR] checkForDisk - Couldn't delete vm folder '%v': %v", vmName, err)
  1316  			return err
  1317  		}
  1318  
  1319  		_, err = task.WaitForResult(context.TODO(), nil)
  1320  		if err != nil {
  1321  			log.Printf("[ERROR] checForDisk - Failed while deleting vm folder '%v': %v", vmName, err)
  1322  			return err
  1323  		}
  1324  
  1325  		return nil
  1326  	}
  1327  }