Merge "xenapi: Support live migration in pooled multi-nodes environment"

This commit is contained in:
Zuul
2018-04-12 19:12:52 +00:00
committed by Gerrit Code Review
7 changed files with 323 additions and 96 deletions

View File

@@ -227,13 +227,9 @@ class XenAPIOpenVswitchDriverTestCase(XenVIFDriverTestBase):
instance = {'name': "fake_instance"}
vm_ref = "fake_vm_ref"
mock_network_get_VIFs = self.mock_patch_object(
self._session.network, 'get_VIFs', return_val=None)
self.ovs_driver.unplug(instance, fake_vif, vm_ref)
self.assertTrue(mock_super_unplug.called)
self.assertTrue(mock_find_network_with_name_label.called)
self.assertTrue(mock_network_get_VIFs.called)
self.assertTrue(mock_delete_network_bridge.called)
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_bridge')
@@ -241,30 +237,200 @@ class XenAPIOpenVswitchDriverTestCase(XenVIFDriverTestBase):
@mock.patch.object(os_xenapi.client.host_network, 'ovs_del_br')
@mock.patch.object(os_xenapi.client.host_network, 'ovs_del_port')
@mock.patch.object(network_utils, 'find_network_with_name_label')
def test_delete_network_and_bridge(self, mock_find_network,
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_get_network_by_vif')
def test_delete_network_and_bridge(self, mock_get_network,
mock_find_network,
mock_ovs_del_port, mock_ovs_del_br,
mock_delete_linux_port,
mock_delete_linux_bridge):
mock_find_network.return_value = 'fake_network'
# Delete network and bridge
mock_get_network.return_value = 'fake_network'
instance = {'name': 'fake_instance'}
vif = {'id': 'fake_vif'}
self._session.network = mock.Mock()
self.ovs_driver.delete_network_and_bridge(instance, vif)
self._session.network.get_VIFs.return_value = None
self.ovs_driver.delete_network_and_bridge(instance, 'fake_vif_id')
self._session.network.get_bridge.assert_called_once_with(
'fake_network')
self._session.network.destroy.assert_called_once_with('fake_network')
self.assertTrue(mock_find_network.called)
self.assertEqual(mock_ovs_del_port.call_count, 2)
self.assertEqual(mock_delete_linux_port.call_count, 2)
self.assertTrue(mock_delete_linux_bridge.called)
self.assertTrue(mock_ovs_del_br.called)
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_bridge')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_port')
@mock.patch.object(os_xenapi.client.host_network, 'ovs_del_br')
@mock.patch.object(os_xenapi.client.host_network, 'ovs_del_port')
@mock.patch.object(network_utils, 'find_network_with_name_label')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_get_network_by_vif')
def test_delete_network_and_bridge_with_remote_vif_on(
self,
mock_get_network,
mock_find_network,
mock_ovs_del_port,
mock_ovs_del_br,
mock_delete_linux_port,
mock_delete_linux_bridge):
# If still has vifs attached to the network on remote hosts, delete
# network function would not be called, while the bridge would
# be deleted
mock_get_network.return_value = 'fake_network'
instance = {'name': 'fake_instance'}
fake_local_host_ref = 'fake_host_ref'
fake_vif_id = 'fake_vif_id'
expected_qbr_name = 'qbr' + fake_vif_id
self._session.host_ref = fake_local_host_ref
self.mock_patch_object(
self._session.network, 'get_VIFs',
return_val=['fake_vif'])
self.mock_patch_object(
self._session.VIF, 'get_all_records_where',
return_val={'rec': 'fake_rec'})
self.mock_patch_object(
self._session.VIF, 'get_VM',
return_val='fake_vm_ref')
self.mock_patch_object(
self._session.network, 'get_bridge',
return_val='fake_bridge')
# The host ref which the remain vif resident on doesn't match the local
# host
self.mock_patch_object(
self._session.VM, 'get_resident_on',
return_val='fake_host_ref_remote')
self.ovs_driver.delete_network_and_bridge(instance, fake_vif_id)
self._session.network.get_bridge.assert_called_once_with(
'fake_network')
self._session.network.destroy.assert_not_called()
self.assertEqual(2, mock_ovs_del_port.call_count)
self.assertEqual(2, mock_delete_linux_port.call_count)
mock_delete_linux_bridge.assert_called_once_with(expected_qbr_name)
mock_ovs_del_br.assert_called_once_with(self._session, 'fake_bridge')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_bridge')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_port')
@mock.patch.object(os_xenapi.client.host_network, 'ovs_del_br')
@mock.patch.object(os_xenapi.client.host_network, 'ovs_del_port')
@mock.patch.object(network_utils, 'find_network_with_name_label')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_get_network_by_vif')
def test_delete_network_and_bridge_abort(
self,
mock_get_network,
mock_find_network,
mock_ovs_del_port,
mock_ovs_del_br,
mock_delete_linux_port,
mock_delete_linux_bridge):
# If still has vifs attached to the network on local hosts, all the
# operations would be abort
mock_get_network.return_value = 'fake_network'
instance = {'name': 'fake_instance'}
fake_local_host_ref = 'fake_host_ref'
self._session.host_ref = fake_local_host_ref
self.mock_patch_object(
self._session.network, 'get_VIFs',
return_val=['fake_vif'])
self.mock_patch_object(
self._session.VIF, 'get_all_records_where',
return_val={'rec': 'fake_rec'})
self.mock_patch_object(
self._session.VIF, 'get_VM',
return_val='fake_vm_ref')
# The host ref which the remain vif resident on match the local host
self.mock_patch_object(
self._session.VM, 'get_resident_on',
return_val=fake_local_host_ref)
self.ovs_driver.delete_network_and_bridge(instance, 'fake_vif_id')
self._session.network.get_bridge.assert_called_once_with(
'fake_network')
self._session.network.destroy.assert_not_called()
mock_ovs_del_port.assert_not_called()
mock_delete_linux_port.assert_not_called()
mock_delete_linux_bridge.assert_not_called()
mock_ovs_del_br.assert_not_called()
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_bridge')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_port')
@mock.patch.object(os_xenapi.client.host_network, 'ovs_del_br')
@mock.patch.object(os_xenapi.client.host_network, 'ovs_del_port')
@mock.patch.object(network_utils, 'find_network_with_name_label')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_get_network_by_vif')
@mock.patch.object(vif.XenAPIOpenVswitchDriver,
'_get_patch_port_pair_names')
def test_delete_network_and_bridge_del_port_exc(self, mock_get_port_name,
mock_get_network,
mock_find_network,
mock_ovs_del_port,
mock_ovs_del_br,
mock_delete_linux_port,
mock_delete_linux_bridge):
# Get an exception when deleting the patch port pair
mock_get_network.return_value = 'fake_network'
instance = {'name': 'fake_instance'}
self._session.network = mock.Mock()
self._session.network.get_VIFs.return_value = None
self._session.network.get_bridge.return_value = 'fake_bridge'
mock_get_port_name.return_value = ['fake_port', 'fake_tap']
mock_ovs_del_port.side_effect = test.TestingException
self.assertRaises(exception.VirtualInterfaceUnplugException,
self.ovs_driver.delete_network_and_bridge, instance,
'fake_vif_id')
self._session.network.get_bridge.assert_called_once_with(
'fake_network')
self._session.network.destroy.assert_called_once_with('fake_network')
mock_ovs_del_port.assert_called_once_with(self._session,
'fake_bridge',
'fake_port')
mock_delete_linux_port.assert_not_called()
mock_delete_linux_bridge.assert_not_called()
mock_ovs_del_br.assert_not_called()
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_bridge')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_port')
@mock.patch.object(os_xenapi.client.host_network, 'ovs_del_br')
@mock.patch.object(os_xenapi.client.host_network, 'ovs_del_port')
@mock.patch.object(network_utils, 'find_network_with_name_label')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_get_network_by_vif')
@mock.patch.object(vif.XenAPIOpenVswitchDriver,
'_get_patch_port_pair_names')
def test_delete_network_and_bridge_del_br_exc(self, mock_get_port_name,
mock_get_network,
mock_find_network,
mock_ovs_del_port,
mock_ovs_del_br,
mock_delete_linux_port,
mock_delete_linux_bridge):
# Get an exception when deleting the bridge and the patch ports
# existing on this bridge
mock_get_network.return_value = 'fake_network'
instance = {'name': 'fake_instance'}
self._session.network = mock.Mock()
self._session.network.get_VIFs.return_value = None
self._session.network.get_bridge.return_value = 'fake_bridge'
mock_get_port_name.return_value = ['fake_port', 'fake_tap']
mock_ovs_del_br.side_effect = test.TestingException
self.assertRaises(exception.VirtualInterfaceUnplugException,
self.ovs_driver.delete_network_and_bridge, instance,
'fake_vif_id')
self._session.network.get_bridge.assert_called_once_with(
'fake_network')
self._session.network.destroy.assert_called_once_with('fake_network')
mock_ovs_del_port.assert_called_once_with(self._session,
'fake_bridge',
'fake_port')
mock_delete_linux_port.assert_not_called()
mock_delete_linux_bridge.assert_not_called()
mock_ovs_del_br.assert_called_once_with(self._session, 'fake_bridge')
@mock.patch.object(os_xenapi.client.host_network, 'ovs_del_port')
@mock.patch.object(network_utils, 'find_network_with_name_label',
return_value='fake_network')
def test_delete_network_and_bridge_destroy_exception(self,
mock_find_network,
mock_ovs_del_port):
def test_delete_network_and_bridge_destroy_network_exception(
self,
mock_find_network,
mock_ovs_del_port):
# Get an exception when destroying the network
instance = {'name': "fake_instance"}
self.mock_patch_object(
self._session.network, 'get_VIFs', return_val=None)
@@ -276,9 +442,8 @@ class XenAPIOpenVswitchDriverTestCase(XenVIFDriverTestBase):
self.assertRaises(exception.VirtualInterfaceUnplugException,
self.ovs_driver.delete_network_and_bridge, instance,
fake_vif)
'fake_vif_id')
self.assertTrue(mock_find_network.called)
self.assertTrue(mock_ovs_del_port.called)
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_device_exists')
@mock.patch.object(os_xenapi.client.host_network, 'brctl_add_if')

View File

@@ -1746,12 +1746,15 @@ class LiveMigrateHelperTestCase(VMOpsTestBase):
"_generate_vdi_map") as mock_gen_vdi_map, \
mock.patch.object(self.vmops._session,
'call_xenapi') as mock_call_xenapi, \
mock.patch.object(vm_utils, 'host_in_this_pool'
) as mock_host_in_this_pool, \
mock.patch.object(self.vmops,
"_generate_vif_network_map") as mock_vif_map:
mock_call_xenapi.side_effect = side_effect
mock_gen_vdi_map.side_effect = [
{"vdi": "sr_ref"}, {"vdi": "sr_ref_2"}]
mock_vif_map.return_value = {"vif_ref1": "dest_net_ref"}
mock_host_in_this_pool.return_value = False
self.vmops._call_live_migrate_command(command_name,
vm_ref, migrate_data)
@@ -1924,7 +1927,7 @@ class LiveMigrateHelperTestCase(VMOpsTestBase):
def test_delete_networks_and_bridges(self):
self.vmops.vif_driver = mock.Mock()
network_info = ['fake_vif']
network_info = [{'id': 'fake_vif'}]
self.vmops._delete_networks_and_bridges('fake_instance', network_info)
self.vmops.vif_driver.delete_network_and_bridge.\
assert_called_once_with('fake_instance', 'fake_vif')

View File

@@ -3502,20 +3502,26 @@ class XenAPILiveMigrateTestCase(stubs.XenAPITestBaseNoDB):
self.conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
self.stubs.Set(vm_utils, "safe_find_sr", lambda _x: "asdf")
expected = {'block_migration': True,
'is_volume_backed': False,
'migrate_data': {
'migrate_send_data': {'value': 'fake_migrate_data'},
'destination_sr_ref': 'asdf'
with mock.patch.object(self.conn._vmops._session, "host_ref") as \
fake_host_ref, mock.patch.object(
self.conn._vmops, '_get_network_ref') as \
fake_get_network_ref:
fake_host_ref.return_value = 'fake_host_ref'
fake_get_network_ref.return_value = 'fake_network_ref'
expected = {'block_migration': True,
'is_volume_backed': False,
'migrate_data': {
'migrate_send_data': {'value':
'fake_migrate_data'},
'destination_sr_ref': 'asdf'}
}
}
result = self.conn.check_can_live_migrate_destination(self.context,
{'host': 'host'},
{}, {},
True, False)
result.is_volume_backed = False
self.assertEqual(expected, result.to_legacy_dict())
result = self.conn.check_can_live_migrate_destination(
self.context,
{'host': 'host'},
{}, {},
True, False)
result.is_volume_backed = False
self.assertEqual(expected, result.to_legacy_dict())
def test_check_live_migrate_destination_verifies_ip(self):
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
@@ -3659,17 +3665,21 @@ class XenAPILiveMigrateTestCase(stubs.XenAPITestBaseNoDB):
def test_check_can_live_migrate_works(self, mock_get_by_host):
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
self.conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
metadata = {'host': 'test_host_uuid'}
aggregate = objects.Aggregate(metadata=metadata)
aggregate_list = objects.AggregateList(objects=[aggregate])
mock_get_by_host.return_value = aggregate_list
instance = objects.Instance(host='host')
self.conn.check_can_live_migrate_destination(
self.context, instance, None, None)
mock_get_by_host.assert_called_once_with(
self.context, CONF.host, key='hypervisor_pool')
with mock.patch.object(self.conn._vmops._session, "host_ref") as \
fake_host_ref, \
mock.patch.object(self.conn._vmops,
'_get_network_ref') as fake_get_network_ref:
fake_host_ref.return_value = 'fake_host_ref'
fake_get_network_ref.return_value = 'fake_network_ref'
metadata = {'host': 'test_host_uuid'}
aggregate = objects.Aggregate(metadata=metadata)
aggregate_list = objects.AggregateList(objects=[aggregate])
mock_get_by_host.return_value = aggregate_list
instance = objects.Instance(host='host')
self.conn.check_can_live_migrate_destination(
self.context, instance, None, None)
mock_get_by_host.assert_called_once_with(
self.context, CONF.host, key='hypervisor_pool')
@mock.patch.object(objects.AggregateList, 'get_by_host')
def test_check_can_live_migrate_fails(self, mock_get_by_host):

View File

@@ -355,7 +355,8 @@ def _create_local_pif(host_ref):
'IP': '10.1.1.1',
'IPv6': '',
'uuid': '',
'management': 'true'})
'management': 'true',
'host': 'fake_host_ref'})
_db_content['PIF'][pif_ref]['uuid'] = pif_ref
return pif_ref

View File

@@ -127,7 +127,7 @@ class XenVIFDriver(object):
def create_vif_interim_network(self, vif):
pass
def delete_network_and_bridge(self, instance, vif):
def delete_network_and_bridge(self, instance, vif_id):
pass
@@ -283,69 +283,76 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
return vif_ref
def unplug(self, instance, vif, vm_ref):
"""unplug vif:
super(XenAPIOpenVswitchDriver, self).unplug(instance, vif, vm_ref)
self.delete_network_and_bridge(instance, vif['id'])
def delete_network_and_bridge(self, instance, vif_id):
"""Delete network and bridge:
1. delete the patch port pair between the integration bridge and
the qbr linux bridge(if exist) and the interim network.
2. destroy the interim network
3. delete the OVS bridge service for the interim network
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['id'])
network = network_utils.find_network_with_name_label(
self._session, net_name)
if network is None:
network = self._get_network_by_vif(vif_id)
if not network:
return
vifs = self._session.network.get_VIFs(network)
if vifs:
# only remove the interim network when it's empty.
# for resize/migrate on local host, vifs on both of the
# 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)
patch_port1, tap_name = self._get_patch_port_pair_names(vif['id'])
if vifs:
# Still has vifs attached to this network
for remain_vif in vifs:
# if remain vifs are on the local server, give up all the
# operations. If remain vifs are on the remote hosts, keep
# the network and delete the bridge
if self._get_host_by_vif(remain_vif) == self._session.host_ref:
return
else:
# No vif left, delete the network
try:
self._session.network.destroy(network)
except Exception as e:
LOG.warning("Failed to destroy network for vif (id=%(if)s), "
"exception:%(exception)s",
{'if': vif_id, 'exception': e}, instance=instance)
raise exception.VirtualInterfaceUnplugException(
reason=_("Failed to destroy network"))
# Two cases:
# 1) No vif left, just delete the bridge
# 2) For resize/intra-pool migrate, vifs on both of the
# source and target VM will be connected to the same
# interim network. If the VM is resident on a remote host,
# linux bridge on current host will be deleted.
self.delete_bridge(instance, vif_id, bridge_name)
def delete_bridge(self, instance, vif_id, bridge_name):
LOG.debug('destroying patch port pair for vif id: vif_id=%(vif_id)s',
{'vif_id': vif_id})
patch_port1, tap_name = self._get_patch_port_pair_names(vif_id)
try:
# delete the patch port pair
host_network.ovs_del_port(self._session, bridge_name, patch_port1)
except Exception as e:
LOG.warning("Failed to delete patch port pair for vif %(if)s,"
LOG.warning("Failed to delete patch port pair for vif id %(if)s,"
" exception:%(exception)s",
{'if': vif, 'exception': e}, instance=instance)
{'if': vif_id, 'exception': e}, instance=instance)
raise exception.VirtualInterfaceUnplugException(
reason=_("Failed to delete patch port pair"))
LOG.debug('destroying network: network=%(network)s,'
'bridge=%(br)s',
{'network': network, 'br': bridge_name})
LOG.debug('destroying bridge: bridge=%(br)s', {'br': bridge_name})
try:
self._session.network.destroy(network)
# delete bridge if it still exists.
# As there is patch port existing on this bridge when destroying
# the VM vif (which happens when shutdown the VM), the bridge
# won't be destroyed automatically by XAPI. So let's destroy it
# at here.
# As there are patch ports existing on this bridge when
# destroying won't be destroyed automatically by XAPI, let's
# destroy it at here.
host_network.ovs_del_br(self._session, bridge_name)
qbr_name = self._get_qbr_name(vif['id'])
qvb_name, qvo_name = self._get_veth_pair_names(vif['id'])
qbr_name = self._get_qbr_name(vif_id)
qvb_name, qvo_name = self._get_veth_pair_names(vif_id)
if self._device_exists(qbr_name):
# delete tap port, qvb port and qbr
LOG.debug(
"destroy linux bridge %(qbr)s when unplug vif %(vif)s",
{'qbr': qbr_name, 'vif': vif['id']})
"destroy linux bridge %(qbr)s when unplug vif id"
" %(vif_id)s", {'qbr': qbr_name, 'vif_id': vif_id})
self._delete_linux_port(qbr_name, tap_name)
self._delete_linux_port(qbr_name, qvb_name)
self._delete_linux_bridge(qbr_name)
@@ -353,12 +360,35 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
CONF.xenserver.ovs_integration_bridge,
qvo_name)
except Exception as e:
LOG.warning("Failed to delete bridge for vif %(if)s, "
LOG.warning("Failed to delete bridge for vif id %(if)s, "
"exception:%(exception)s",
{'if': vif, 'exception': e}, instance=instance)
{'if': vif_id, 'exception': e}, instance=instance)
raise exception.VirtualInterfaceUnplugException(
reason=_("Failed to delete bridge"))
def _get_network_by_vif(self, vif_id):
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("Failed to find network for vif id %(if)s",
{'if': vif_id})
return
return network
def _get_host_by_vif(self, vif_id):
network = self._get_network_by_vif(vif_id)
if not network:
return
vif_info = self._session.VIF.get_all_records_where(
'field "network" = "%s"' % network)
if not vif_info or len(vif_info) != 1:
raise exception.NovaException(
"Couldn't find vif id information in network %s"
% network)
vm_ref = self._session.VIF.get_VM(list(vif_info.keys())[0])
return self._session.VM.get_resident_on(vm_ref)
def hot_plug(self, vif, instance, vm_ref, vif_ref):
# hot plug vif only when VM's power state is running
LOG.debug("Hot plug vif, vif: %s", vif, instance=instance)
@@ -491,9 +521,13 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
def create_vif_interim_network(self, vif):
net_name = self.get_vif_interim_net_name(vif['id'])
# In a pooled environment, make the network to be shared to ensure it
# can also be used in the target host while live migration. It will
# make no change if the environment is not pooled.
network_rec = {'name_label': net_name,
'name_description': "interim network for vif",
'other_config': {}}
'name_description': "interim network for vif[%s]"
% vif['id'],
'other_config': {'assume_network_is_shared': 'true'}}
network_ref = network_utils.find_network_with_name_label(
self._session, net_name)
if network_ref:

View File

@@ -814,9 +814,14 @@ def _find_cached_images(session, sr_ref):
def _find_cached_image(session, image_id, sr_ref):
"""Returns the vdi-ref of the cached image."""
name_label = _get_image_vdi_label(image_id)
recs = session.call_xenapi("VDI.get_all_records_where",
'field "name__label"="%s"'
% name_label)
# For not pooled hosts, only name_lable is enough to get a cached image.
# When in a xapi pool, each host may have a cached image using the
# same name while xapi api will search all of them. Add SR to the filter
# to ensure only one image returns.
expr = ('field "name__label"="%(name_label)s" and field "SR" = "%(SR)s"'
% {'name_label': name_label, 'SR': sr_ref})
recs = session.call_xenapi("VDI.get_all_records_where", expr)
number_found = len(recs)
if number_found > 0:
if number_found > 1:
@@ -2618,3 +2623,8 @@ def set_other_config_pci(session, vm_ref, params):
other_config = session.call_xenapi("VM.get_other_config", vm_ref)
other_config['pci'] = params
session.call_xenapi("VM.set_other_config", vm_ref, other_config)
def host_in_this_pool(session, host_ref):
rec_dict = session.host.get_all_records()
return host_ref in rec_dict.keys()

View File

@@ -2249,7 +2249,8 @@ class VMOps(object):
# This is the one associated with the pif marked management. From cli:
# uuid=`xe pif-list --minimal management=true`
# xe pif-param-get param-name=network-uuid uuid=$uuid
expr = 'field "management" = "true"'
expr = ('field "management" = "true" and field "host" = "%s"' %
self._session.host_ref)
pifs = self._session.call_xenapi('PIF.get_all_records_where',
expr)
if len(pifs) != 1:
@@ -2492,12 +2493,15 @@ 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)
# For block migration, need to pass vif map to the destination hosts.
if not vm_utils.host_in_this_pool(self._session,
migrate_send_data.get('host')):
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,
@@ -2641,7 +2645,7 @@ class VMOps(object):
# Unplug VIFs and delete networks
for vif in network_info:
try:
self.vif_driver.delete_network_and_bridge(instance, vif)
self.vif_driver.delete_network_and_bridge(instance, vif['id'])
except Exception:
LOG.exception(_('Failed to delete networks and bridges with '
'VIF %s'), vif['id'], instance=instance)