Merge "[Admin-Utils] NSX-V3 upgrade vm ports after migration"

This commit is contained in:
Jenkins 2016-09-19 05:56:27 +00:00 committed by Gerrit Code Review
commit 438792f8b1
4 changed files with 211 additions and 12 deletions

View File

@ -174,6 +174,10 @@ Ports
nsxadmin -r ports -o list-mismatches nsxadmin -r ports -o list-mismatches
- Update the VMs ports on the backend after migrating nsx-v -> nsx-v3
nsxadmin -r ports -o nsx-migrate-v-v3
Security Groups Security Groups
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~

View File

@ -308,7 +308,17 @@ class DvsManager(object):
{'net_id': net_id, {'net_id': net_id,
'dvs': self._dvs_moref.value}) 'dvs': self._dvs_moref.value})
def get_vm_moref(self, instance_uuid): def get_portgroup_info(self, pg_moref):
"""Get portgroup information."""
# Expand the properties to collect on need basis.
properties = ['name']
pg_info = self._session.invoke_api(vim_util,
'get_object_properties_dict',
self._session.vim,
pg_moref, properties)
return pg_info
def get_vm_moref_obj(self, instance_uuid):
"""Get reference to the VM. """Get reference to the VM.
The method will make use of FindAllByUuid to get the VM reference. The method will make use of FindAllByUuid to get the VM reference.
This method finds all VM's on the backend that match the This method finds all VM's on the backend that match the
@ -323,14 +333,105 @@ class DvsManager(object):
vmSearch=True, vmSearch=True,
instanceUuid=True) instanceUuid=True)
if vm_refs: if vm_refs:
return vm_refs[0].value return vm_refs[0]
def get_portgroup_info(self, pg_moref): def get_vm_moref(self, instance_uuid):
"""Get portgroup information.""" """Get reference to the VM.
# Expand the properties to collect on need basis. """
properties = ['name'] vm_ref = self.get_vm_moref_obj(instance_uuid)
pg_info = self._session.invoke_api(vim_util, if vm_ref:
'get_object_properties_dict', return vm_ref.value
def get_vm_spec(self, vm_moref):
vm_spec = self._session.invoke_api(vim_util,
'get_object_properties',
self._session.vim, self._session.vim,
pg_moref, properties) vm_moref, ['network'])[0]
return pg_info return vm_spec
def _build_vm_spec_attach(self, neutron_port_id, port_mac,
nsx_net_id, device_type):
# Code inspired by nova: _create_vif_spec
client_factory = self._session.vim.client.factory
vm_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
device_change = client_factory.create('ns0:VirtualDeviceConfigSpec')
device_change.operation = "add"
net_device = client_factory.create('ns0:' + device_type)
net_device.key = -47
net_device.addressType = "manual"
# configure the neutron port id and mac
net_device.externalId = neutron_port_id
net_device.macAddress = port_mac
net_device.wakeOnLanEnabled = True
backing = client_factory.create(
'ns0:VirtualEthernetCardOpaqueNetworkBackingInfo')
# configure the NSX network Id
backing.opaqueNetworkId = nsx_net_id
backing.opaqueNetworkType = "nsx.LogicalSwitch"
net_device.backing = backing
connectable_spec = client_factory.create(
'ns0:VirtualDeviceConnectInfo')
connectable_spec.startConnected = True
connectable_spec.allowGuestControl = True
connectable_spec.connected = True
net_device.connectable = connectable_spec
device_change.device = net_device
vm_spec.deviceChange = [device_change]
return vm_spec
def attach_vm_interface(self, vm_moref, neutron_port_id,
port_mac, nsx_net_id, device_type):
new_spec = self._build_vm_spec_attach(
neutron_port_id, port_mac, nsx_net_id, device_type)
task = self._session.invoke_api(self._session.vim,
'ReconfigVM_Task',
vm_moref,
spec=new_spec)
try:
self._session.wait_for_task(task)
LOG.info(_LI("Updated VM moref %(moref)s spec - "
"attached an interface"),
{'moref': vm_moref.value})
except Exception as e:
LOG.error(_LE("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
client_factory = self._session.vim.client.factory
config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
virtual_device_config = client_factory.create(
'ns0:VirtualDeviceConfigSpec')
virtual_device_config.operation = "remove"
virtual_device_config.device = device
config_spec.deviceChange = [virtual_device_config]
return config_spec
def detach_vm_interface(self, vm_moref, device):
new_spec = self._build_vm_spec_detach(device)
task = self._session.invoke_api(self._session.vim,
'ReconfigVM_Task',
vm_moref,
spec=new_spec)
try:
self._session.wait_for_task(task)
LOG.info(_LI("Updated VM %(moref)s spec - detached an interface"),
{'moref': vm_moref.value})
except Exception as e:
LOG.error(_LE("Failed to reconfigure vm moref %(moref)s: %(e)s"),
{'moref': vm_moref.value, 'e': e})
def get_vm_interfaces_info(self, vm_moref):
hardware_devices = self._session.invoke_api(vim_util,
"get_object_property",
self._session.vim,
vm_moref,
"config.hardware.device")
return hardware_devices

View File

@ -17,10 +17,11 @@ import logging
from sqlalchemy.orm import exc from sqlalchemy.orm import exc
from vmware_nsx._i18n import _LI, _LW from vmware_nsx._i18n import _LE, _LI, _LW
from vmware_nsx.common import exceptions as nsx_exc from vmware_nsx.common import exceptions as nsx_exc
from vmware_nsx.db import db as nsx_db from vmware_nsx.db import db as nsx_db
from vmware_nsx.db import nsx_models from vmware_nsx.db import nsx_models
from vmware_nsx.dvs import dvs
from vmware_nsx.nsxlib.v3 import resources from vmware_nsx.nsxlib.v3 import resources
from vmware_nsx.plugins.nsx_v3 import plugin from vmware_nsx.plugins.nsx_v3 import plugin
from vmware_nsx.services.qos.common import utils as qos_utils from vmware_nsx.services.qos.common import utils as qos_utils
@ -58,6 +59,20 @@ def get_port_nsx_id(session, neutron_id):
pass pass
def get_network_nsx_id(session, neutron_id):
# get the nsx switch id from the DB mapping
mappings = nsx_db.get_nsx_switch_ids(session, neutron_id)
if not mappings or len(mappings) == 0:
LOG.debug("Unable to find NSX mappings for neutron "
"network %s.", neutron_id)
# fallback in case we didn't find the id in the db mapping
# This should not happen, but added here in case the network was
# created before this code was added.
return neutron_id
else:
return mappings[0]
def get_port_and_profile_clients(): def get_port_and_profile_clients():
_nsx_client = v3_utils.get_nsxv3_client() _nsx_client = v3_utils.get_nsxv3_client()
return (resources.LogicalPort(_nsx_client), return (resources.LogicalPort(_nsx_client),
@ -168,6 +183,83 @@ def list_missing_ports(resource, event, trigger, **kwargs):
LOG.info(_LI("All internal ports verified on the NSX manager")) LOG.info(_LI("All internal ports verified on the NSX manager"))
def get_vm_network_device(dvs_mng, vm_moref, mac_address):
"""Return the network device with MAC 'mac_address'.
This code was inspired by Nova vif.get_network_device
"""
hardware_devices = dvs_mng.get_vm_interfaces_info(vm_moref)
if hardware_devices.__class__.__name__ == "ArrayOfVirtualDevice":
hardware_devices = hardware_devices.VirtualDevice
for device in hardware_devices:
if hasattr(device, 'macAddress'):
if device.macAddress == mac_address:
return device
def migrate_compute_ports_vms(resource, event, trigger, **kwargs):
"""Update the VMs ports on the backend after migrating nsx-v -> nsx-v3
After using api_replay to migrate the neutron data from NSX-V to NSX-T
we need to update the VM ports to use OpaqueNetwork instead of
DistributedVirtualPortgroup
"""
# Connect to the DVS manager, using the configuration parameters
try:
dvs_mng = dvs.DvsManager()
except Exception as e:
LOG.error(_LE("Cannot connect to the DVS: Please update the [dvs] "
"section in the nsx.ini file: %s"), e)
return
# Go over all the compute ports from the plugin
plugin = PortsPlugin()
admin_cxt = neutron_context.get_admin_context()
port_filters = {'device_owner': ['compute:None']}
neutron_ports = plugin.get_ports(admin_cxt, filters=port_filters)
for port in neutron_ports:
device_id = port.get('device_id')
# get the vm moref & spec from the DVS
vm_moref = dvs_mng.get_vm_moref_obj(device_id)
vm_spec = dvs_mng.get_vm_spec(vm_moref)
# Go over the VM interfaces and check if it should be updated
update_spec = False
for prop in vm_spec.propSet:
if (prop.name == 'network' and
hasattr(prop.val, 'ManagedObjectReference')):
for net in prop.val.ManagedObjectReference:
if net._type == 'DistributedVirtualPortgroup':
update_spec = True
if not update_spec:
LOG.info(_LI("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(dvs_mng, vm_moref, port['mac_address'])
if device is None:
LOG.warning(_LW("No device with MAC address %s exists on the VM"),
port['mac_address'])
continue
device_type = device.__class__.__name__
LOG.info(_LI("Detaching old interface from VM %s"), device_id)
dvs_mng.detach_vm_interface(vm_moref, device)
# add the new interface as OpaqueNetwork
LOG.info(_LI("Attaching new interface to VM %s"), device_id)
nsx_net_id = get_network_nsx_id(admin_cxt.session, port['network_id'])
dvs_mng.attach_vm_interface(vm_moref, port['id'], port['mac_address'],
nsx_net_id, device_type)
registry.subscribe(list_missing_ports, registry.subscribe(list_missing_ports,
constants.PORTS, constants.PORTS,
shell.Operations.LIST_MISMATCHES.value) shell.Operations.LIST_MISMATCHES.value)
registry.subscribe(migrate_compute_ports_vms,
constants.PORTS,
shell.Operations.NSX_MIGRATE_V_V3.value)

View File

@ -46,6 +46,7 @@ class Operations(enum.Enum):
NSX_UPDATE_SECRET = 'nsx-update-secret' NSX_UPDATE_SECRET = 'nsx-update-secret'
NSX_RECREATE = 'nsx-recreate' NSX_RECREATE = 'nsx-recreate'
MIGRATE_TO_DYNAMIC_CRITERIA = 'migrate-to-dynamic-criteria' MIGRATE_TO_DYNAMIC_CRITERIA = 'migrate-to-dynamic-criteria'
NSX_MIGRATE_V_V3 = 'nsx-migrate-v-v3'
STATUS = 'status' STATUS = 'status'
ops = [op.value for op in Operations] ops = [op.value for op in Operations]
@ -73,7 +74,8 @@ nsxv3_resources = {
constants.NETWORKS: Resource(constants.NETWORKS, constants.NETWORKS: Resource(constants.NETWORKS,
[Operations.LIST_MISMATCHES.value]), [Operations.LIST_MISMATCHES.value]),
constants.PORTS: Resource(constants.PORTS, constants.PORTS: Resource(constants.PORTS,
[Operations.LIST_MISMATCHES.value]), [Operations.LIST_MISMATCHES.value,
Operations.NSX_MIGRATE_V_V3.value]),
constants.ROUTERS: Resource(constants.ROUTERS, constants.ROUTERS: Resource(constants.ROUTERS,
[Operations.LIST_MISMATCHES.value]), [Operations.LIST_MISMATCHES.value]),
constants.DHCP_BINDING: Resource(constants.DHCP_BINDING, constants.DHCP_BINDING: Resource(constants.DHCP_BINDING,