vsphere/resource_vsphere_virtual_machine_migrate.go
func migrateVSphereVirtualMachineStateV2(is *terraform.InstanceState, meta interface{}) error {
	// All we really preserve from the old state is the UUID of the virtual
	// machine. We leverage some of the special parts of the import functionality
	// - namely validating disks, and flagging the VM as imported in the state to
	// guard against someone adding customization to the configuration and
	// accidentally forcing a new resource. To assist with the migration of state
	// from V1 to V3 as well, we now pull in disk attribute data that is
	// populated during the import process.
	//
	// Read will handle most of the population post-migration as it does for
	// import, and there will be an unavoidable diff for TF-only options on the
	// next plan. This diff should not require a reconfigure of the virtual
	// machine.
	client := meta.(*VSphereClient).vimClient
	name := is.ID
	id := is.Attributes["uuid"]
	if id == "" {
		return fmt.Errorf("resource ID %s has no UUID. State cannot be migrated", name)
	}

	log.Printf("[DEBUG] Migrate state for VM resource %q: UUID %q", name, id)
	vm, err := virtualmachine.FromUUID(client, id)
	if err != nil {
		return fmt.Errorf("error fetching virtual machine: %s", err)
	}
	props, err := virtualmachine.Properties(vm)
	if err != nil {
		return fmt.Errorf("error fetching virtual machine properties: %s", err)
	}

	// Validate the disks in the VM to make sure that they will work with the new
	// version of the resource. This is mainly ensuring that all disks are SCSI
	// disks.
	//
	// NOTE: This uses the current version of the resource to make this check,
	// which at some point in time may end up being a higher schema version than
	// version 2. At this point in time, there is nothing here that would cause
	// issues (nothing in the sub-resource read logic is reliant on schema
	// versions), and an empty ResourceData is sent anyway.
	diskCnt, _ := strconv.Atoi(is.Attributes["disk.#"])
	maxBus := diskCnt / 15
	l := object.VirtualDeviceList(props.Config.Hardware.Device)
	for k, v := range is.Attributes {
		if !regexp.MustCompile("disk\\.[0-9]+\\.key").MatchString(k) {
			continue
		}
		key, _ := strconv.Atoi(v)
		if key < 1 {
			continue
		}
		device := l.FindByKey(int32(key))
		if device == nil {
			continue
		}
		ctlr := l.FindByKey(device.GetVirtualDevice().ControllerKey)
		if ctlr == nil {
			continue
		}
		if sc, ok := ctlr.(types.BaseVirtualSCSIController); ok && sc.GetVirtualSCSIController().BusNumber > int32(maxBus) {
			maxBus = int(sc.GetVirtualSCSIController().BusNumber)
		}
	}

	d := resourceVSphereVirtualMachine().Data(&terraform.InstanceState{})
	d.Set("scsi_controller_count", maxBus+1)
	if err := virtualdevice.DiskImportOperation(d, client, object.VirtualDeviceList(props.Config.Hardware.Device)); err != nil {
		return err
	}

	rs := resourceVSphereVirtualMachine().Schema
	var guestNetTimeout string
	switch is.Attributes["wait_for_guest_net"] {
	case "false":
		guestNetTimeout = "-1"
	default:
		guestNetTimeout = fmt.Sprintf("%v", rs["wait_for_guest_net_timeout"].Default)
	}

	// The VM should be ready for reading now
	is.Attributes = make(map[string]string)
	is.ID = id
	is.Attributes["imported"] = "true"

	// Set some defaults. This helps possibly prevent diffs where these values
	// have not been changed.
	is.Attributes["scsi_controller_count"] = fmt.Sprintf("%v", rs["scsi_controller_count"].Default)
	is.Attributes["force_power_off"] = fmt.Sprintf("%v", rs["force_power_off"].Default)
	is.Attributes["migrate_wait_timeout"] = fmt.Sprintf("%v", rs["migrate_wait_timeout"].Default)
	is.Attributes["shutdown_wait_timeout"] = fmt.Sprintf("%v", rs["shutdown_wait_timeout"].Default)
	is.Attributes["wait_for_guest_net_timeout"] = guestNetTimeout
	is.Attributes["wait_for_guest_net_routable"] = fmt.Sprintf("%v", rs["wait_for_guest_net_routable"].Default)
	is.Attributes["scsi_controller_count"] = fmt.Sprintf("%v", maxBus+1)

	// Populate our disk data from the fake state.
	d.SetId(id)
	for k, v := range d.State().Attributes {
		if strings.HasPrefix(k, "disk.") {
			is.Attributes[k] = v
		}
	}

	log.Printf("[DEBUG] %s: Migration to V2 complete", resourceVSphereVirtualMachineIDString(d))
	return nil
}
func migrateVSphereVirtualMachineStateV2(is *terraform.InstanceState, meta interface{}) error {
	// All we really preserve from the old state is the UUID of the virtual
	// machine. We leverage some of the special parts of the import functionality
	// - namely validating disks, and flagging the VM as imported in the state to
	// guard against someone adding customization to the configuration and
	// accidentally forcing a new resource. To assist with the migration of state
	// from V1 to V3 as well, we now pull in disk attribute data that is
	// populated during the import process.
	//
	// Read will handle most of the population post-migration as it does for
	// import, and there will be an unavoidable diff for TF-only options on the
	// next plan. This diff should not require a reconfigure of the virtual
	// machine.
	client := meta.(*VSphereClient).vimClient
	name := is.ID
	id := is.Attributes["uuid"]
	if id == "" {
		return fmt.Errorf("resource ID %s has no UUID. State cannot be migrated", name)
	}

	log.Printf("[DEBUG] Migrate state for VM resource %q: UUID %q", name, id)
	vm, err := virtualmachine.FromUUID(client, id)
	if err != nil {
		return fmt.Errorf("error fetching virtual machine: %s", err)
	}
	props, err := virtualmachine.Properties(vm)
	if err != nil {
		return fmt.Errorf("error fetching virtual machine properties: %s", err)
	}

	// Validate the disks in the VM to make sure that they will work with the new
	// version of the resource. This is mainly ensuring that all disks are SCSI
	// disks.
	//
	// NOTE: This uses the current version of the resource to make this check,
	// which at some point in time may end up being a higher schema version than
	// version 2. At this point in time, there is nothing here that would cause
	// issues (nothing in the sub-resource read logic is reliant on schema
	// versions), and an empty ResourceData is sent anyway.
	diskCnt, _ := strconv.Atoi(is.Attributes["disk.#"])
	maxBus := diskCnt / 15
	l := object.VirtualDeviceList(props.Config.Hardware.Device)
	for k, v := range is.Attributes {
		if !regexp.MustCompile("disk\\.[0-9]+\\.key").MatchString(k) {
			continue
		}
		key, _ := strconv.Atoi(v)
		if key < 1 {
			continue
		}
		device := l.FindByKey(int32(key))
		if device == nil {
			continue
		}
		ctlr := l.FindByKey(device.GetVirtualDevice().ControllerKey)
		if ctlr == nil {
			continue
		}
		if sc, ok := ctlr.(types.BaseVirtualSCSIController); ok && sc.GetVirtualSCSIController().BusNumber > int32(maxBus) {
			maxBus = int(sc.GetVirtualSCSIController().BusNumber)
		}
	}

	d := resourceVSphereVirtualMachine().Data(&terraform.InstanceState{})
	d.Set("scsi_controller_count", maxBus+1)
	if err := virtualdevice.DiskImportOperation(d, client, object.VirtualDeviceList(props.Config.Hardware.Device)); err != nil {
		return err
	}

	rs := resourceVSphereVirtualMachine().Schema
	var guestNetTimeout string
	switch is.Attributes["wait_for_guest_net"] {
	case "false":
		guestNetTimeout = "-1"
	default:
		guestNetTimeout = fmt.Sprintf("%v", rs["wait_for_guest_net_timeout"].Default)
	}

	// The VM should be ready for reading now
	is.Attributes = make(map[string]string)
	is.ID = id
	is.Attributes["imported"] = "true"

	// Set some defaults. This helps possibly prevent diffs where these values
	// have not been changed.
	is.Attributes["scsi_controller_count"] = fmt.Sprintf("%v", rs["scsi_controller_count"].Default)
	is.Attributes["force_power_off"] = fmt.Sprintf("%v", rs["force_power_off"].Default)
	is.Attributes["migrate_wait_timeout"] = fmt.Sprintf("%v", rs["migrate_wait_timeout"].Default)
	is.Attributes["shutdown_wait_timeout"] = fmt.Sprintf("%v", rs["shutdown_wait_timeout"].Default)
	is.Attributes["wait_for_guest_net_timeout"] = guestNetTimeout
	is.Attributes["wait_for_guest_net_routable"] = fmt.Sprintf("%v", rs["wait_for_guest_net_routable"].Default)
	is.Attributes["scsi_controller_count"] = fmt.Sprintf("%v", maxBus+1)

	// Populate our disk data from the fake state.
	d.SetId(id)
	for k, v := range d.State().Attributes {
		if strings.HasPrefix(k, "disk.") {
			is.Attributes[k] = v
		}
	}

	log.Printf("[DEBUG] %s: Migration to V2 complete", resourceVSphereVirtualMachineIDString(d))
	return nil
}
func migrateVSphereVirtualMachineStateV2 ( is * terraform . InstanceState , meta interface { } ) error { // All we really preserve from the old state is the UUID of the virtual // machine. We leverage some of the special parts of the import functionality // - namely validating disks, and flagging the VM as imported in the state to // guard against someone adding customization to the configuration and // accidentally forcing a new resource. To assist with the migration of state // from V1 to V3 as well, we now pull in disk attribute data that is // populated during the import process. // // Read will handle most of the population post-migration as it does for // import, and there will be an unavoidable diff for TF-only options on the // next plan. This diff should not require a reconfigure of the virtual // machine. client := meta . ( * VSphereClient ) . vimClient name := is . ID id := is . Attributes [ " " ] if id == " " { return fmt . Errorf ( " " , name ) } log . Printf ( " " , name , id ) vm , err := virtualmachine . FromUUID ( client , id ) if err != nil { return fmt . Errorf ( " " , err ) } props , err := virtualmachine . Properties ( vm ) if err != nil { return fmt . Errorf ( " " , err ) } // Validate the disks in the VM to make sure that they will work with the new // version of the resource. This is mainly ensuring that all disks are SCSI // disks. // // NOTE: This uses the current version of the resource to make this check, // which at some point in time may end up being a higher schema version than // version 2. At this point in time, there is nothing here that would cause // issues (nothing in the sub-resource read logic is reliant on schema // versions), and an empty ResourceData is sent anyway. diskCnt , _ := strconv . Atoi ( is . Attributes [ " " ] ) maxBus := diskCnt / 15 l := object . VirtualDeviceList ( props . Config . Hardware . Device ) for k , v := range is . Attributes { if ! regexp . MustCompile ( " \\ \\ " ) . MatchString ( k ) { continue } key , _ := strconv . Atoi ( v ) if key < 1 { continue } device := l . FindByKey ( int32 ( key ) ) if device == nil { continue } ctlr := l . FindByKey ( device . GetVirtualDevice ( ) . ControllerKey ) if ctlr == nil { continue } if sc , ok := ctlr . ( types . BaseVirtualSCSIController ) ; ok && sc . GetVirtualSCSIController ( ) . BusNumber > int32 ( maxBus ) { maxBus = int ( sc . GetVirtualSCSIController ( ) . BusNumber ) } } d := resourceVSphereVirtualMachine ( ) . Data ( & terraform . InstanceState { } ) d . Set ( " " , maxBus + 1 ) if err := virtualdevice . DiskImportOperation ( d , client , object . VirtualDeviceList ( props . Config . Hardware . Device ) ) ; err != nil { return err } rs := resourceVSphereVirtualMachine ( ) . Schema var guestNetTimeout string switch is . Attributes [ " " ] { case " " : guestNetTimeout = " " default : guestNetTimeout = fmt . Sprintf ( " " , rs [ " " ] . Default ) } // The VM should be ready for reading now is . Attributes = make ( map [ string ] string ) is . ID = id is . Attributes [ " " ] = " " // Set some defaults. This helps possibly prevent diffs where these values // have not been changed. is . Attributes [ " " ] = fmt . Sprintf ( " " , rs [ " " ] . Default ) is . Attributes [ " " ] = fmt . Sprintf ( " " , rs [ " " ] . Default ) is . Attributes [ " " ] = fmt . Sprintf ( " " , rs [ " " ] . Default ) is . Attributes [ " " ] = fmt . Sprintf ( " " , rs [ " " ] . Default ) is . Attributes [ " " ] = guestNetTimeout is . Attributes [ " " ] = fmt . Sprintf ( " " , rs [ " " ] . Default ) is . Attributes [ " " ] = fmt . Sprintf ( " " , maxBus + 1 ) // Populate our disk data from the fake state. d . SetId ( id ) for k , v := range d . State ( ) . Attributes { if strings . HasPrefix ( k , " " ) { is . Attributes [ k ] = v } } log . Printf ( " " , resourceVSphereVirtualMachineIDString ( d ) ) return nil }
// migrateVSphereVirtualMachineStateV2 migrates the state of the
// vsphere_virtual_machine from version 1 to version 2.
migrateVSphereVirtualMachineStateV2 migrates the state of the vsphere_virtual_machine from version 1 to version 2 .