TVD: update port migration for V -> T instances
The patch does the following: 1. set instance vNIC to a common network interface 2. Live migrates to T cluster 3. Updates the instance vNIC to opaque network Example: nsxadmin -r ports -o nsx-migrate-v-v3 \ --property project-id=01dd52ff4c7047f79f6259f916c83790 \ --property host-moref=host-11 --property respool-moref=resgroup-9 \ --property datastore-moref=datastore-22 \ --plugin nsxv3 There is also an option to use net-name. The default here is 'VM Network' Change-Id: I24d9df3f7a3dbd11dffb86427367b809e2b49409
This commit is contained in:
parent
a1bfbe9256
commit
f634145a1e
@ -347,7 +347,7 @@ Ports
|
||||
|
||||
- Update the VMs ports (all or of a specific project) on the backend after migrating nsx-v -> nsx-v3::
|
||||
|
||||
nsxadmin -r ports -o nsx-migrate-v-v3 (--property project-id=<>)
|
||||
nsxadmin -r ports -o nsx-migrate-v-v3 (--property project-id=<> --property host-moref=<> --property respool-moref=<> --property net-name=<> --property datastore-moref=<>)) --plugin nsxv3
|
||||
|
||||
- Migrate exclude ports to use tags::
|
||||
|
||||
|
@ -569,6 +569,27 @@ class VMManager(VCManagerBase):
|
||||
LOG.error("Failed to reconfigure VM %(moref)s spec: %(e)s",
|
||||
{'moref': vm_moref.value, 'e': e})
|
||||
|
||||
def _build_vm_spec_update(self, devices):
|
||||
client_factory = self._session.vim.client.factory
|
||||
vm_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
|
||||
vm_spec.deviceChange = [devices]
|
||||
return vm_spec
|
||||
|
||||
def update_vm_interface(self, vm_moref, devices):
|
||||
update_spec = self._build_vm_spec_update(devices)
|
||||
task = self._session.invoke_api(self._session.vim,
|
||||
'ReconfigVM_Task',
|
||||
vm_moref,
|
||||
spec=update_spec)
|
||||
try:
|
||||
self._session.wait_for_task(task)
|
||||
LOG.info("Updated VM moref %(moref)s spec - "
|
||||
"attached an interface",
|
||||
{'moref': vm_moref.value})
|
||||
except Exception as e:
|
||||
LOG.error("Failed to reconfigure VM %(moref)s spec: %(e)s",
|
||||
{'moref': vm_moref.value, 'e': e})
|
||||
|
||||
def _build_vm_spec_detach(self, device):
|
||||
"""Builds the vif detach config spec."""
|
||||
# Code inspired by nova: get_network_detach_config_spec
|
||||
@ -622,6 +643,59 @@ class VMManager(VCManagerBase):
|
||||
if port:
|
||||
self._update_port_security_policy(dvs_moref, port, status)
|
||||
|
||||
def update_vm_network(self, device, name='VM Network'):
|
||||
# In order to live migrate need a common network for interfaces
|
||||
client_factory = self._session.vim.client.factory
|
||||
network_spec = client_factory.create('ns0:VirtualDeviceConfigSpec')
|
||||
network_spec.operation = 'edit'
|
||||
backing = client_factory.create(
|
||||
'ns0:VirtualEthernetCardNetworkBackingInfo')
|
||||
backing.deviceName = name
|
||||
device.backing = backing
|
||||
network_spec.device = device
|
||||
return network_spec
|
||||
|
||||
def update_vm_opaque_spec(self, vif_info, device):
|
||||
"""Updates the backing for the VIF spec."""
|
||||
client_factory = self._session.vim.client.factory
|
||||
network_spec = client_factory.create('ns0:VirtualDeviceConfigSpec')
|
||||
network_spec.operation = 'edit'
|
||||
backing = client_factory.create(
|
||||
'ns0:VirtualEthernetCardOpaqueNetworkBackingInfo')
|
||||
backing.opaqueNetworkId = vif_info['nsx_id']
|
||||
backing.opaqueNetworkType = 'nsx.LogicalSwitch'
|
||||
# Configure externalId
|
||||
device.externalId = vif_info['iface_id']
|
||||
device.backing = backing
|
||||
network_spec.device = device
|
||||
return network_spec
|
||||
|
||||
def relocate_vm_spec(self, client_factory, respool_moref=None,
|
||||
datastore_moref=None, host_moref=None,
|
||||
disk_move_type="moveAllDiskBackingsAndAllowSharing"):
|
||||
rel_spec = client_factory.create('ns0:VirtualMachineRelocateSpec')
|
||||
if datastore_moref:
|
||||
datastore = vim_util.get_moref(datastore_moref, 'Datastore')
|
||||
else:
|
||||
datastore = None
|
||||
rel_spec.datastore = datastore
|
||||
host = vim_util.get_moref(host_moref, 'HostSystem')
|
||||
rel_spec.host = host
|
||||
res_pool = vim_util.get_moref(respool_moref, 'ResourcePool')
|
||||
rel_spec.pool = res_pool
|
||||
return rel_spec
|
||||
|
||||
def relocate_vm(self, vm_ref, respool_moref=None, datastore_moref=None,
|
||||
host_moref=None,
|
||||
disk_move_type="moveAllDiskBackingsAndAllowSharing"):
|
||||
client_factory = self._session.vim.client.factory
|
||||
rel_spec = self.relocate_vm_spec(client_factory, respool_moref,
|
||||
datastore_moref, host_moref,
|
||||
disk_move_type)
|
||||
task = self._session.invoke_api(self._session.vim, "RelocateVM_Task",
|
||||
vm_ref, spec=rel_spec)
|
||||
self._session.wait_for_task(task)
|
||||
|
||||
|
||||
class ClusterManager(VCManagerBase):
|
||||
"""Management class for Cluster related VC tasks."""
|
||||
|
@ -232,6 +232,17 @@ def migrate_compute_ports_vms(resource, event, trigger, **kwargs):
|
||||
project = properties.get('project-id')
|
||||
if project:
|
||||
port_filters['project_id'] = [project]
|
||||
net_name = properties.get('net-name', 'VM Network')
|
||||
LOG.info("Common network name for migration %s", net_name)
|
||||
host_moref = properties.get('host-moref')
|
||||
# TODO(garyk): We can explore the option of passing the cluster
|
||||
# moref then this will remove the need for the host-moref and the
|
||||
# resource pool moref.
|
||||
respool_moref = properties.get('respool-moref')
|
||||
datastore_moref = properties.get('datastore-moref')
|
||||
if not host_moref:
|
||||
LOG.error("Unable to migrate with no host")
|
||||
return
|
||||
|
||||
# Go over all the ports from the plugin
|
||||
admin_cxt = neutron_context.get_admin_context()
|
||||
@ -266,22 +277,28 @@ def migrate_compute_ports_vms(resource, event, trigger, **kwargs):
|
||||
LOG.info("No need to update the spec of vm %s", device_id)
|
||||
continue
|
||||
|
||||
# find the old interface by it's mac and delete it
|
||||
device = get_vm_network_device(vm_mng, vm_moref, port['mac_address'])
|
||||
if device is None:
|
||||
LOG.warning("No device with MAC address %s exists on the VM",
|
||||
port['mac_address'])
|
||||
continue
|
||||
device_type = device.__class__.__name__
|
||||
|
||||
LOG.info("Detaching old interface from VM %s", device_id)
|
||||
vm_mng.detach_vm_interface(vm_moref, device)
|
||||
|
||||
# add the new interface as OpaqueNetwork
|
||||
LOG.info("Attaching new interface to VM %s", device_id)
|
||||
nsx_net_id = get_network_nsx_id(admin_cxt.session, port['network_id'])
|
||||
vm_mng.attach_vm_interface(vm_moref, port['id'], port['mac_address'],
|
||||
nsx_net_id, device_type)
|
||||
# Update interface to be common network
|
||||
devices = [vm_mng.update_vm_network(device, name=net_name)]
|
||||
LOG.info("Update instance %s to common network", device_id)
|
||||
vm_mng.update_vm_interface(vm_moref, devices=devices)
|
||||
LOG.info("Migrate instance %s to host %s", device_id, host_moref)
|
||||
vm_mng.relocate_vm(vm_moref, host_moref=host_moref,
|
||||
datastore_moref=datastore_moref,
|
||||
respool_moref=respool_moref)
|
||||
LOG.info("Update instance %s to opaque network", device_id)
|
||||
device = get_vm_network_device(vm_mng, vm_moref, port['mac_address'])
|
||||
vif_info = {'nsx_id': get_network_nsx_id(admin_cxt.session,
|
||||
port['network_id']),
|
||||
'iface_id': port['id']}
|
||||
devices = [vm_mng.update_vm_opaque_spec(vif_info, device)]
|
||||
vm_mng.update_vm_interface(vm_moref, devices=devices)
|
||||
LOG.info("Instance %s successfully migrated!", device_id)
|
||||
|
||||
|
||||
def migrate_exclude_ports(resource, event, trigger, **kwargs):
|
||||
|
Loading…
Reference in New Issue
Block a user