e4ab4f95bc
There are some important patches in nova computes introduced recently, this patch it to apply these patches and add corresponding Change_Id: compute node: 1. live-migration-iscsi.patch 2. support-vif-hotplug.patch 3. fix-rescue-vm.patch 4. live-migration-vifmapping.patch 5. assert_can_migrated.patch controller node: 1. live-migration-vifmapping-controller.patch Change-Id: Ib0bfb97fa61323d101ea49faaf410d1576ca111b
254 lines
11 KiB
Diff
254 lines
11 KiB
Diff
diff --git a/nova/objects/migrate_data.py b/nova/objects/migrate_data.py
|
|
index 44dce4f..07a16ea 100644
|
|
--- a/nova/objects/migrate_data.py
|
|
+++ b/nova/objects/migrate_data.py
|
|
@@ -210,7 +210,9 @@ class LibvirtLiveMigrateData(LiveMigrateData):
|
|
|
|
@obj_base.NovaObjectRegistry.register
|
|
class XenapiLiveMigrateData(LiveMigrateData):
|
|
- VERSION = '1.0'
|
|
+ # Version 1.0: Initial version
|
|
+ # Version 1.1: Added vif_uuid_map
|
|
+ VERSION = '1.1'
|
|
|
|
fields = {
|
|
'block_migration': fields.BooleanField(nullable=True),
|
|
@@ -219,6 +221,7 @@ class XenapiLiveMigrateData(LiveMigrateData):
|
|
'sr_uuid_map': fields.DictOfStringsField(),
|
|
'kernel_file': fields.StringField(),
|
|
'ramdisk_file': fields.StringField(),
|
|
+ 'vif_uuid_map': fields.DictOfStringsField(),
|
|
}
|
|
|
|
def to_legacy_dict(self, pre_migration_result=False):
|
|
@@ -233,6 +236,8 @@ class XenapiLiveMigrateData(LiveMigrateData):
|
|
live_result = {
|
|
'sr_uuid_map': ('sr_uuid_map' in self and self.sr_uuid_map
|
|
or {}),
|
|
+ 'vif_uuid_map': ('vif_uuid_map' in self and self.vif_uuid_map
|
|
+ or {}),
|
|
}
|
|
if pre_migration_result:
|
|
legacy['pre_live_migration_result'] = live_result
|
|
@@ -252,6 +257,16 @@ class XenapiLiveMigrateData(LiveMigrateData):
|
|
if 'pre_live_migration_result' in legacy:
|
|
self.sr_uuid_map = \
|
|
legacy['pre_live_migration_result']['sr_uuid_map']
|
|
+ self.vif_uuid_map = \
|
|
+ legacy['pre_live_migration_result'].get('vif_uuid_map', {})
|
|
+
|
|
+ def obj_make_compatible(self, primitive, target_version):
|
|
+ super(XenapiLiveMigrateData, self).obj_make_compatible(
|
|
+ primitive, target_version)
|
|
+ target_version = versionutils.convert_version_to_tuple(target_version)
|
|
+ if target_version < (1, 1):
|
|
+ if 'vif_uuid_map' in primitive:
|
|
+ del primitive['vif_uuid_map']
|
|
|
|
|
|
@obj_base.NovaObjectRegistry.register
|
|
diff --git a/nova/virt/xenapi/driver.py b/nova/virt/xenapi/driver.py
|
|
index 899c083..1639861 100644
|
|
--- a/nova/virt/xenapi/driver.py
|
|
+++ b/nova/virt/xenapi/driver.py
|
|
@@ -569,6 +569,7 @@ class XenAPIDriver(driver.ComputeDriver):
|
|
# any volume that was attached to the destination during
|
|
# live migration. XAPI should take care of all other cleanup.
|
|
self._vmops.rollback_live_migration_at_destination(instance,
|
|
+ network_info,
|
|
block_device_info)
|
|
|
|
def pre_live_migration(self, context, instance, block_device_info,
|
|
@@ -594,6 +595,16 @@ class XenAPIDriver(driver.ComputeDriver):
|
|
"""
|
|
self._vmops.post_live_migration(context, instance, migrate_data)
|
|
|
|
+ def post_live_migration_at_source(self, context, instance, network_info):
|
|
+ """Unplug VIFs from networks at source.
|
|
+
|
|
+ :param context: security context
|
|
+ :param instance: instance object reference
|
|
+ :param network_info: instance network information
|
|
+ """
|
|
+ self._vmops.post_live_migration_at_source(context, instance,
|
|
+ network_info)
|
|
+
|
|
def post_live_migration_at_destination(self, context, instance,
|
|
network_info,
|
|
block_migration=False,
|
|
diff --git a/nova/virt/xenapi/vif.py b/nova/virt/xenapi/vif.py
|
|
index ac271e3..6925426 100644
|
|
--- a/nova/virt/xenapi/vif.py
|
|
+++ b/nova/virt/xenapi/vif.py
|
|
@@ -88,6 +88,9 @@ class XenVIFDriver(object):
|
|
raise exception.NovaException(
|
|
reason=_("Failed to unplug vif %s") % vif)
|
|
|
|
+ def get_vif_interim_net_name(self, vif_id):
|
|
+ return ("net-" + vif_id)[:network_model.NIC_NAME_LEN]
|
|
+
|
|
def hot_plug(self, vif, instance, vm_ref, vif_ref):
|
|
"""hotplug virtual interface to running instance.
|
|
:param nova.network.model.VIF vif:
|
|
@@ -126,10 +129,20 @@ class XenVIFDriver(object):
|
|
"""
|
|
pass
|
|
|
|
+ def create_vif_interim_network(self, vif):
|
|
+ pass
|
|
+
|
|
+ def delete_network_and_bridge(self, instance, vif):
|
|
+ pass
|
|
+
|
|
|
|
class XenAPIBridgeDriver(XenVIFDriver):
|
|
"""VIF Driver for XenAPI that uses XenAPI to create Networks."""
|
|
|
|
+ # NOTE(huanxie): This driver uses linux bridge as backend for XenServer,
|
|
+ # it only supports nova network, for using neutron, you should use
|
|
+ # XenAPIOpenVswitchDriver
|
|
+
|
|
def plug(self, instance, vif, vm_ref=None, device=None):
|
|
if not vm_ref:
|
|
vm_ref = vm_utils.lookup(self._session, instance['name'])
|
|
@@ -279,8 +292,7 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
|
4. delete linux bridge qbr and related ports if exist
|
|
"""
|
|
super(XenAPIOpenVswitchDriver, self).unplug(instance, vif, vm_ref)
|
|
-
|
|
- net_name = self.get_vif_interim_net_name(vif)
|
|
+ net_name = self.get_vif_interim_net_name(vif['id'])
|
|
network = network_utils.find_network_with_name_label(
|
|
self._session, net_name)
|
|
if network is None:
|
|
@@ -292,6 +304,16 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
|
# source and target VM will be connected to the same
|
|
# interim network.
|
|
return
|
|
+ self.delete_network_and_bridge(instance, vif)
|
|
+
|
|
+ def delete_network_and_bridge(self, instance, vif):
|
|
+ net_name = self.get_vif_interim_net_name(vif['id'])
|
|
+ network = network_utils.find_network_with_name_label(
|
|
+ self._session, net_name)
|
|
+ if network is None:
|
|
+ LOG.debug("Didn't find network by name %s", net_name,
|
|
+ instance=instance)
|
|
+ return
|
|
LOG.debug('destroying patch port pair for vif: vif_id=%(vif_id)s',
|
|
{'vif_id': vif['id']})
|
|
bridge_name = self._session.network.get_bridge(network)
|
|
@@ -473,11 +495,8 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
|
# Add port to interim bridge
|
|
self._ovs_add_port(bridge_name, patch_port1)
|
|
|
|
- def get_vif_interim_net_name(self, vif):
|
|
- return ("net-" + vif['id'])[:network_model.NIC_NAME_LEN]
|
|
-
|
|
def create_vif_interim_network(self, vif):
|
|
- net_name = self.get_vif_interim_net_name(vif)
|
|
+ net_name = self.get_vif_interim_net_name(vif['id'])
|
|
network_rec = {'name_label': net_name,
|
|
'name_description': "interim network for vif",
|
|
'other_config': {}}
|
|
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
|
|
index e44117e..82a9aef 100644
|
|
--- a/nova/virt/xenapi/vmops.py
|
|
+++ b/nova/virt/xenapi/vmops.py
|
|
@@ -2388,11 +2388,41 @@ class VMOps(object):
|
|
self._generate_vdi_map(
|
|
sr_uuid_map[sr_uuid], vm_ref, sr_ref))
|
|
vif_map = {}
|
|
+ vif_uuid_map = None
|
|
+ if 'vif_uuid_map' in migrate_data:
|
|
+ vif_uuid_map = migrate_data.vif_uuid_map
|
|
+ if vif_uuid_map:
|
|
+ vif_map = self._generate_vif_network_map(vm_ref, vif_uuid_map)
|
|
+ LOG.debug("Generated vif_map for live migration: %s", vif_map)
|
|
options = {}
|
|
self._session.call_xenapi(command_name, vm_ref,
|
|
migrate_send_data, True,
|
|
vdi_map, vif_map, options)
|
|
|
|
+ def _generate_vif_network_map(self, vm_ref, vif_uuid_map):
|
|
+ # Generate a mapping dictionary of src_vif_ref: dest_network_ref
|
|
+ vif_map = {}
|
|
+ # vif_uuid_map is dictionary of neutron_vif_uuid: dest_network_ref
|
|
+ vifs = self._session.VM.get_VIFs(vm_ref)
|
|
+ for vif in vifs:
|
|
+ other_config = self._session.VIF.get_other_config(vif)
|
|
+ neutron_id = other_config.get('nicira-iface-id')
|
|
+ if neutron_id is None or neutron_id not in vif_uuid_map.keys():
|
|
+ raise exception.MigrationError(
|
|
+ reason=_('No mapping for source network %s') % (
|
|
+ neutron_id))
|
|
+ network_ref = vif_uuid_map[neutron_id]
|
|
+ vif_map[vif] = network_ref
|
|
+ return vif_map
|
|
+
|
|
+ def create_interim_networks(self, network_info):
|
|
+ # Creating an interim bridge in destination host before live_migration
|
|
+ vif_map = {}
|
|
+ for vif in network_info:
|
|
+ network_ref = self.vif_driver.create_vif_interim_network(vif)
|
|
+ vif_map.update({vif['id']: network_ref})
|
|
+ return vif_map
|
|
+
|
|
def pre_live_migration(self, context, instance, block_device_info,
|
|
network_info, disk_info, migrate_data):
|
|
if migrate_data is None:
|
|
@@ -2401,6 +2431,11 @@ class VMOps(object):
|
|
|
|
migrate_data.sr_uuid_map = self.connect_block_device_volumes(
|
|
block_device_info)
|
|
+ migrate_data.vif_uuid_map = self.create_interim_networks(network_info)
|
|
+ LOG.debug("pre_live_migration, vif_uuid_map: %(vif_map)s, "
|
|
+ "sr_uuid_map: %(sr_map)s",
|
|
+ {'vif_map': migrate_data.vif_uuid_map,
|
|
+ 'sr_map': migrate_data.sr_uuid_map}, instance=instance)
|
|
return migrate_data
|
|
|
|
def live_migrate(self, context, instance, destination_hostname,
|
|
@@ -2457,6 +2492,11 @@ class VMOps(object):
|
|
migrate_data.kernel_file,
|
|
migrate_data.ramdisk_file)
|
|
|
|
+ def post_live_migration_at_source(self, context, instance, network_info):
|
|
+ LOG.debug('post_live_migration_at_source, delete networks and bridges',
|
|
+ instance=instance)
|
|
+ self._delete_networks_and_bridges(instance, network_info)
|
|
+
|
|
def post_live_migration_at_destination(self, context, instance,
|
|
network_info, block_migration,
|
|
block_device_info):
|
|
@@ -2471,7 +2511,7 @@ class VMOps(object):
|
|
vm_ref = self._get_vm_opaque_ref(instance)
|
|
vm_utils.strip_base_mirror_from_vdis(self._session, vm_ref)
|
|
|
|
- def rollback_live_migration_at_destination(self, instance,
|
|
+ def rollback_live_migration_at_destination(self, instance, network_info,
|
|
block_device_info):
|
|
bdms = block_device_info['block_device_mapping'] or []
|
|
|
|
@@ -2488,6 +2528,20 @@ class VMOps(object):
|
|
LOG.exception(_LE('Failed to forget the SR for volume %s'),
|
|
params['id'], instance=instance)
|
|
|
|
+ # delete VIF and network in destination host
|
|
+ LOG.debug('rollback_live_migration_at_destination, delete networks '
|
|
+ 'and bridges', instance=instance)
|
|
+ self._delete_networks_and_bridges(instance, network_info)
|
|
+
|
|
+ def _delete_networks_and_bridges(self, instance, network_info):
|
|
+ # Unplug VIFs and delete networks
|
|
+ for vif in network_info:
|
|
+ try:
|
|
+ self.vif_driver.delete_network_and_bridge(instance, vif)
|
|
+ except Exception:
|
|
+ LOG.exception(_LE('Failed to delete networks and bridges with '
|
|
+ 'VIF %s'), vif['id'], instance=instance)
|
|
+
|
|
def get_per_instance_usage(self):
|
|
"""Get usage info about each active instance."""
|
|
usage = {}
|