vsphere/resource_vsphere_virtual_machine.go
func resourceVSphereVirtualMachineUpdateLocation(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG] %s: Checking for pending migration operations", resourceVSphereVirtualMachineIDString(d))
	client := meta.(*VSphereClient).vimClient

	// A little bit of duplication of VM object data is done here to keep the
	// method signature lean.
	id := d.Id()
	vm, err := virtualmachine.FromUUID(client, id)
	if err != nil {
		return fmt.Errorf("cannot locate virtual machine with UUID %q: %s", id, err)
	}

	// Determine if we are performing any storage vMotion tasks. This will generate the relocators if there are any.
	vprops, err := virtualmachine.Properties(vm)
	if err != nil {
		return fmt.Errorf("error fetching VM properties: %s", err)
	}
	devices := object.VirtualDeviceList(vprops.Config.Hardware.Device)
	relocators, diskRelocateOK, err := virtualdevice.DiskMigrateRelocateOperation(d, client, devices)
	if err != nil {
		return err
	}
	// If we don't have any changes, stop here.
	if !d.HasChange("resource_pool_id") && !d.HasChange("host_system_id") && !d.HasChange("datastore_id") && !diskRelocateOK {
		log.Printf("[DEBUG] %s: No migration operations found", resourceVSphereVirtualMachineIDString(d))
		return nil
	}
	log.Printf("[DEBUG] %s: Migration operations found, proceeding with migration", resourceVSphereVirtualMachineIDString(d))

	// Fetch and validate pool and host
	poolID := d.Get("resource_pool_id").(string)
	pool, err := resourcepool.FromID(client, poolID)
	if err != nil {
		return fmt.Errorf("could not find resource pool ID %q: %s", poolID, err)
	}
	var hs *object.HostSystem
	if v, ok := d.GetOk("host_system_id"); ok {
		hsID := v.(string)
		var err error
		if hs, err = hostsystem.FromID(client, hsID); err != nil {
			return fmt.Errorf("error locating host system at ID %q: %s", hsID, err)
		}
	}
	if err := resourcepool.ValidateHost(client, pool, hs); err != nil {
		return err
	}

	// Start building the spec
	spec := types.VirtualMachineRelocateSpec{
		Pool: types.NewReference(pool.Reference()),
	}

	// Fetch the datastore
	if dsID, ok := d.GetOk("datastore_id"); ok {
		ds, err := datastore.FromID(client, dsID.(string))
		if err != nil {
			return fmt.Errorf("error locating datastore for VM: %s", err)
		}
		spec.Datastore = types.NewReference(ds.Reference())
	}

	if hs != nil {
		hsRef := hs.Reference()
		spec.Host = &hsRef
	}

	spec.Disk = relocators

	// Ready to perform migration
	timeout := d.Get("migrate_wait_timeout").(int)
	if _, ok := d.GetOk("datastore_cluster_id"); ok {
		err = resourceVSphereVirtualMachineUpdateLocationRelocateWithSDRS(d, meta, vm, spec, timeout)
	} else {
		err = virtualmachine.Relocate(vm, spec, timeout)
	}
	return err
}
func resourceVSphereVirtualMachineUpdateLocation(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG] %s: Checking for pending migration operations", resourceVSphereVirtualMachineIDString(d))
	client := meta.(*VSphereClient).vimClient

	// A little bit of duplication of VM object data is done here to keep the
	// method signature lean.
	id := d.Id()
	vm, err := virtualmachine.FromUUID(client, id)
	if err != nil {
		return fmt.Errorf("cannot locate virtual machine with UUID %q: %s", id, err)
	}

	// Determine if we are performing any storage vMotion tasks. This will generate the relocators if there are any.
	vprops, err := virtualmachine.Properties(vm)
	if err != nil {
		return fmt.Errorf("error fetching VM properties: %s", err)
	}
	devices := object.VirtualDeviceList(vprops.Config.Hardware.Device)
	relocators, diskRelocateOK, err := virtualdevice.DiskMigrateRelocateOperation(d, client, devices)
	if err != nil {
		return err
	}
	// If we don't have any changes, stop here.
	if !d.HasChange("resource_pool_id") && !d.HasChange("host_system_id") && !d.HasChange("datastore_id") && !diskRelocateOK {
		log.Printf("[DEBUG] %s: No migration operations found", resourceVSphereVirtualMachineIDString(d))
		return nil
	}
	log.Printf("[DEBUG] %s: Migration operations found, proceeding with migration", resourceVSphereVirtualMachineIDString(d))

	// Fetch and validate pool and host
	poolID := d.Get("resource_pool_id").(string)
	pool, err := resourcepool.FromID(client, poolID)
	if err != nil {
		return fmt.Errorf("could not find resource pool ID %q: %s", poolID, err)
	}
	var hs *object.HostSystem
	if v, ok := d.GetOk("host_system_id"); ok {
		hsID := v.(string)
		var err error
		if hs, err = hostsystem.FromID(client, hsID); err != nil {
			return fmt.Errorf("error locating host system at ID %q: %s", hsID, err)
		}
	}
	if err := resourcepool.ValidateHost(client, pool, hs); err != nil {
		return err
	}

	// Start building the spec
	spec := types.VirtualMachineRelocateSpec{
		Pool: types.NewReference(pool.Reference()),
	}

	// Fetch the datastore
	if dsID, ok := d.GetOk("datastore_id"); ok {
		ds, err := datastore.FromID(client, dsID.(string))
		if err != nil {
			return fmt.Errorf("error locating datastore for VM: %s", err)
		}
		spec.Datastore = types.NewReference(ds.Reference())
	}

	if hs != nil {
		hsRef := hs.Reference()
		spec.Host = &hsRef
	}

	spec.Disk = relocators

	// Ready to perform migration
	timeout := d.Get("migrate_wait_timeout").(int)
	if _, ok := d.GetOk("datastore_cluster_id"); ok {
		err = resourceVSphereVirtualMachineUpdateLocationRelocateWithSDRS(d, meta, vm, spec, timeout)
	} else {
		err = virtualmachine.Relocate(vm, spec, timeout)
	}
	return err
}
// resourceVSphereVirtualMachineUpdateLocation manages vMotion. This includes
// the migration of a VM from one host to another, or from one datastore to
// another (storage vMotion).
//
// This function is responsible for building the top-level relocate spec. For
// disks, we call out to relocate functionality in the disk sub-resource.