Merge "xenapi: Support live migration in pooled multi-nodes environment"
This commit is contained in:
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user