From b78985f1bdbda01cd19db1966a7be040b4e44a38 Mon Sep 17 00:00:00 2001 From: Bill Rich Date: Thu, 9 Aug 2018 10:16:58 -0700 Subject: [PATCH 1/2] r/virtual_machine: Relocate VMs after create The host attribute of CreateVM_Task is being ignored in vCenter 6.7. Adding a host check and reloaction step to ensure that VMs land on the correct host. --- vsphere/resource_vsphere_virtual_machine.go | 25 +++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/vsphere/resource_vsphere_virtual_machine.go b/vsphere/resource_vsphere_virtual_machine.go index 9464d1c58..50d1a09be 100644 --- a/vsphere/resource_vsphere_virtual_machine.go +++ b/vsphere/resource_vsphere_virtual_machine.go @@ -266,6 +266,31 @@ func resourceVSphereVirtualMachineCreate(d *schema.ResourceData, meta interface{ } } + // The host attribute of CreateVM_Task seems to be ignored in vCenter 6.7. + // Ensure that VMs are on the correct host and relocate if necessary. Do this + // near the end of the VM creation since it involves updating the + // ResourceData. + vprops, err := virtualmachine.Properties(vm) + if err != nil { + return err + } + if d.Get("host_system_id").(string) != vprops.Runtime.Host.Reference().Value { + hid := d.Get("host_system_id").(string) + err = resourceVSphereVirtualMachineRead(d, meta) + if err != nil { + return err + } + // Restore the old host_system_id so we can still tell if a relocation is + // necessary. + err = d.Set("host_system_id", hid) + if err != nil { + return err + } + if err = resourceVSphereVirtualMachineUpdateLocation(d, meta); err != nil { + return err + } + } + // Wait for a routable address if we have been set to wait for one err = virtualmachine.WaitForGuestNet( client, From 6f7df392177dff0d62100e6d2fd7acd31bb49055 Mon Sep 17 00:00:00 2001 From: Bill Rich Date: Wed, 22 Aug 2018 10:20:35 -0700 Subject: [PATCH 2/2] r/virtual_machine: Add test for host relocation --- .../resource_vsphere_virtual_machine_test.go | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/vsphere/resource_vsphere_virtual_machine_test.go b/vsphere/resource_vsphere_virtual_machine_test.go index d01293209..fe1c7ac6b 100644 --- a/vsphere/resource_vsphere_virtual_machine_test.go +++ b/vsphere/resource_vsphere_virtual_machine_test.go @@ -2085,6 +2085,36 @@ func TestAccResourceVSphereVirtualMachine_windowsTemplateCustomizationEventsAndP }) } +func TestAccResourceVSphereVirtualMachine_hostCheck(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccResourceVSphereVirtualMachinePreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccResourceVSphereVirtualMachineCheckExists(false), + Steps: []resource.TestStep{ + { + Config: testAccResourceVSphereVirtualMachineConfigHostCheck(os.Getenv("VSPHERE_ESXI_HOST")), + Check: resource.ComposeTestCheckFunc( + testAccResourceVSphereVirtualMachineCheckExists(true), + testAccResourceVSphereVirtualMachineCheckHost(os.Getenv("VSPHERE_ESXI_HOST")), + ), + }, + { + Config: testAccResourceVSphereEmpty, + }, + { + Config: testAccResourceVSphereVirtualMachineConfigHostCheck(os.Getenv("VSPHERE_ESXI_HOST2")), + Check: resource.ComposeTestCheckFunc( + testAccResourceVSphereVirtualMachineCheckExists(true), + testAccResourceVSphereVirtualMachineCheckHost(os.Getenv("VSPHERE_ESXI_HOST2")), + ), + }, + }, + }) +} + func TestAccResourceVSphereVirtualMachine_hostVMotion(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -8564,6 +8594,108 @@ resource "vsphere_virtual_machine" "vm" { ) } +func testAccResourceVSphereVirtualMachineConfigHostCheck(host string) string { + return fmt.Sprintf(` +variable "datacenter" { + default = "%s" +} + +variable "resource_pool" { + default = "%s" +} + +variable "network_label" { + default = "%s" +} + +variable "ipv4_address" { + default = "%s" +} + +variable "ipv4_netmask" { + default = "%s" +} + +variable "ipv4_gateway" { + default = "%s" +} + +variable "dns_server" { + default = "%s" +} + +variable "datastore" { + default = "%s" +} + +variable "linked_clone" { + default = "%s" +} + +variable "host" { + default = "%s" +} + +data "vsphere_datacenter" "dc" { + name = "${var.datacenter}" +} + +data "vsphere_datastore" "datastore" { + name = "${var.datastore}" + datacenter_id = "${data.vsphere_datacenter.dc.id}" +} + +data "vsphere_resource_pool" "pool" { + name = "${var.resource_pool}" + datacenter_id = "${data.vsphere_datacenter.dc.id}" +} + +data "vsphere_host" "host" { + name = "${var.host}" + datacenter_id = "${data.vsphere_datacenter.dc.id}" +} + +data "vsphere_network" "network" { + name = "${var.network_label}" + datacenter_id = "${data.vsphere_datacenter.dc.id}" +} + +resource "vsphere_virtual_machine" "vm" { + name = "terraform-test" + resource_pool_id = "${data.vsphere_resource_pool.pool.id}" + host_system_id = "${data.vsphere_host.host.id}" + datastore_id = "${data.vsphere_datastore.datastore.id}" + + num_cpus = 2 + memory = 2048 + guest_id = "ubuntu64Guest" + wait_for_guest_net_timeout = -1 + + network_interface { + network_id = "${data.vsphere_network.network.id}" + } + + disk { + label = "disk0" + size = "1" + eagerly_scrub = false + thin_provisioned = true + } +} +`, + os.Getenv("VSPHERE_DATACENTER"), + os.Getenv("VSPHERE_RESOURCE_POOL"), + os.Getenv("VSPHERE_NETWORK_LABEL"), + os.Getenv("VSPHERE_IPV4_ADDRESS"), + os.Getenv("VSPHERE_IPV4_PREFIX"), + os.Getenv("VSPHERE_IPV4_GATEWAY"), + os.Getenv("VSPHERE_DNS"), + os.Getenv("VSPHERE_DATASTORE"), + os.Getenv("VSPHERE_USE_LINKED_CLONE"), + host, + ) +} + func testAccResourceVSphereVirtualMachineConfigHostVMotion(host string) string { return fmt.Sprintf(` variable "datacenter" {