github.com/danrjohnson/terraform@v0.7.0-rc2.0.20160627135212-d0fc1fa086ff/builtin/providers/vsphere/resource_vsphere_virtual_machine_test.go (about)

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