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"}
|
instance = {'name': "fake_instance"}
|
||||||
vm_ref = "fake_vm_ref"
|
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.ovs_driver.unplug(instance, fake_vif, vm_ref)
|
||||||
|
|
||||||
self.assertTrue(mock_super_unplug.called)
|
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)
|
self.assertTrue(mock_delete_network_bridge.called)
|
||||||
|
|
||||||
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_bridge')
|
@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_br')
|
||||||
@mock.patch.object(os_xenapi.client.host_network, 'ovs_del_port')
|
@mock.patch.object(os_xenapi.client.host_network, 'ovs_del_port')
|
||||||
@mock.patch.object(network_utils, 'find_network_with_name_label')
|
@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_ovs_del_port, mock_ovs_del_br,
|
||||||
mock_delete_linux_port,
|
mock_delete_linux_port,
|
||||||
mock_delete_linux_bridge):
|
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'}
|
instance = {'name': 'fake_instance'}
|
||||||
vif = {'id': 'fake_vif'}
|
|
||||||
self._session.network = mock.Mock()
|
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(
|
self._session.network.get_bridge.assert_called_once_with(
|
||||||
'fake_network')
|
'fake_network')
|
||||||
self._session.network.destroy.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_ovs_del_port.call_count, 2)
|
||||||
self.assertEqual(mock_delete_linux_port.call_count, 2)
|
self.assertEqual(mock_delete_linux_port.call_count, 2)
|
||||||
self.assertTrue(mock_delete_linux_bridge.called)
|
self.assertTrue(mock_delete_linux_bridge.called)
|
||||||
self.assertTrue(mock_ovs_del_br.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(os_xenapi.client.host_network, 'ovs_del_port')
|
||||||
@mock.patch.object(network_utils, 'find_network_with_name_label',
|
@mock.patch.object(network_utils, 'find_network_with_name_label',
|
||||||
return_value='fake_network')
|
return_value='fake_network')
|
||||||
def test_delete_network_and_bridge_destroy_exception(self,
|
def test_delete_network_and_bridge_destroy_network_exception(
|
||||||
|
self,
|
||||||
mock_find_network,
|
mock_find_network,
|
||||||
mock_ovs_del_port):
|
mock_ovs_del_port):
|
||||||
|
# Get an exception when destroying the network
|
||||||
instance = {'name': "fake_instance"}
|
instance = {'name': "fake_instance"}
|
||||||
self.mock_patch_object(
|
self.mock_patch_object(
|
||||||
self._session.network, 'get_VIFs', return_val=None)
|
self._session.network, 'get_VIFs', return_val=None)
|
||||||
@@ -276,9 +442,8 @@ class XenAPIOpenVswitchDriverTestCase(XenVIFDriverTestBase):
|
|||||||
|
|
||||||
self.assertRaises(exception.VirtualInterfaceUnplugException,
|
self.assertRaises(exception.VirtualInterfaceUnplugException,
|
||||||
self.ovs_driver.delete_network_and_bridge, instance,
|
self.ovs_driver.delete_network_and_bridge, instance,
|
||||||
fake_vif)
|
'fake_vif_id')
|
||||||
self.assertTrue(mock_find_network.called)
|
self.assertTrue(mock_find_network.called)
|
||||||
self.assertTrue(mock_ovs_del_port.called)
|
|
||||||
|
|
||||||
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_device_exists')
|
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_device_exists')
|
||||||
@mock.patch.object(os_xenapi.client.host_network, 'brctl_add_if')
|
@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, \
|
"_generate_vdi_map") as mock_gen_vdi_map, \
|
||||||
mock.patch.object(self.vmops._session,
|
mock.patch.object(self.vmops._session,
|
||||||
'call_xenapi') as mock_call_xenapi, \
|
'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,
|
mock.patch.object(self.vmops,
|
||||||
"_generate_vif_network_map") as mock_vif_map:
|
"_generate_vif_network_map") as mock_vif_map:
|
||||||
mock_call_xenapi.side_effect = side_effect
|
mock_call_xenapi.side_effect = side_effect
|
||||||
mock_gen_vdi_map.side_effect = [
|
mock_gen_vdi_map.side_effect = [
|
||||||
{"vdi": "sr_ref"}, {"vdi": "sr_ref_2"}]
|
{"vdi": "sr_ref"}, {"vdi": "sr_ref_2"}]
|
||||||
mock_vif_map.return_value = {"vif_ref1": "dest_net_ref"}
|
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,
|
self.vmops._call_live_migrate_command(command_name,
|
||||||
vm_ref, migrate_data)
|
vm_ref, migrate_data)
|
||||||
@@ -1924,7 +1927,7 @@ class LiveMigrateHelperTestCase(VMOpsTestBase):
|
|||||||
|
|
||||||
def test_delete_networks_and_bridges(self):
|
def test_delete_networks_and_bridges(self):
|
||||||
self.vmops.vif_driver = mock.Mock()
|
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._delete_networks_and_bridges('fake_instance', network_info)
|
||||||
self.vmops.vif_driver.delete_network_and_bridge.\
|
self.vmops.vif_driver.delete_network_and_bridge.\
|
||||||
assert_called_once_with('fake_instance', 'fake_vif')
|
assert_called_once_with('fake_instance', 'fake_vif')
|
||||||
|
|||||||
@@ -3502,15 +3502,21 @@ class XenAPILiveMigrateTestCase(stubs.XenAPITestBaseNoDB):
|
|||||||
self.conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
|
self.conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
|
||||||
|
|
||||||
self.stubs.Set(vm_utils, "safe_find_sr", lambda _x: "asdf")
|
self.stubs.Set(vm_utils, "safe_find_sr", lambda _x: "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,
|
expected = {'block_migration': True,
|
||||||
'is_volume_backed': False,
|
'is_volume_backed': False,
|
||||||
'migrate_data': {
|
'migrate_data': {
|
||||||
'migrate_send_data': {'value': 'fake_migrate_data'},
|
'migrate_send_data': {'value':
|
||||||
'destination_sr_ref': 'asdf'
|
'fake_migrate_data'},
|
||||||
|
'destination_sr_ref': 'asdf'}
|
||||||
}
|
}
|
||||||
}
|
result = self.conn.check_can_live_migrate_destination(
|
||||||
result = self.conn.check_can_live_migrate_destination(self.context,
|
self.context,
|
||||||
{'host': 'host'},
|
{'host': 'host'},
|
||||||
{}, {},
|
{}, {},
|
||||||
True, False)
|
True, False)
|
||||||
@@ -3659,12 +3665,16 @@ class XenAPILiveMigrateTestCase(stubs.XenAPITestBaseNoDB):
|
|||||||
def test_check_can_live_migrate_works(self, mock_get_by_host):
|
def test_check_can_live_migrate_works(self, mock_get_by_host):
|
||||||
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
|
stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests)
|
||||||
self.conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
|
self.conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
|
||||||
|
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'}
|
metadata = {'host': 'test_host_uuid'}
|
||||||
aggregate = objects.Aggregate(metadata=metadata)
|
aggregate = objects.Aggregate(metadata=metadata)
|
||||||
aggregate_list = objects.AggregateList(objects=[aggregate])
|
aggregate_list = objects.AggregateList(objects=[aggregate])
|
||||||
mock_get_by_host.return_value = aggregate_list
|
mock_get_by_host.return_value = aggregate_list
|
||||||
|
|
||||||
instance = objects.Instance(host='host')
|
instance = objects.Instance(host='host')
|
||||||
self.conn.check_can_live_migrate_destination(
|
self.conn.check_can_live_migrate_destination(
|
||||||
self.context, instance, None, None)
|
self.context, instance, None, None)
|
||||||
|
|||||||
@@ -355,7 +355,8 @@ def _create_local_pif(host_ref):
|
|||||||
'IP': '10.1.1.1',
|
'IP': '10.1.1.1',
|
||||||
'IPv6': '',
|
'IPv6': '',
|
||||||
'uuid': '',
|
'uuid': '',
|
||||||
'management': 'true'})
|
'management': 'true',
|
||||||
|
'host': 'fake_host_ref'})
|
||||||
_db_content['PIF'][pif_ref]['uuid'] = pif_ref
|
_db_content['PIF'][pif_ref]['uuid'] = pif_ref
|
||||||
return pif_ref
|
return pif_ref
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ class XenVIFDriver(object):
|
|||||||
def create_vif_interim_network(self, vif):
|
def create_vif_interim_network(self, vif):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def delete_network_and_bridge(self, instance, vif):
|
def delete_network_and_bridge(self, instance, vif_id):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -283,69 +283,76 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
|||||||
return vif_ref
|
return vif_ref
|
||||||
|
|
||||||
def unplug(self, instance, vif, vm_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
|
1. delete the patch port pair between the integration bridge and
|
||||||
the qbr linux bridge(if exist) and the interim network.
|
the qbr linux bridge(if exist) and the interim network.
|
||||||
2. destroy the interim network
|
2. destroy the interim network
|
||||||
3. delete the OVS bridge service for the interim network
|
3. delete the OVS bridge service for the interim network
|
||||||
4. delete linux bridge qbr and related ports if exist
|
4. delete linux bridge qbr and related ports if exist
|
||||||
"""
|
"""
|
||||||
super(XenAPIOpenVswitchDriver, self).unplug(instance, vif, vm_ref)
|
network = self._get_network_by_vif(vif_id)
|
||||||
net_name = self.get_vif_interim_net_name(vif['id'])
|
if not network:
|
||||||
network = network_utils.find_network_with_name_label(
|
|
||||||
self._session, net_name)
|
|
||||||
if network is None:
|
|
||||||
return
|
return
|
||||||
vifs = self._session.network.get_VIFs(network)
|
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)
|
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:
|
try:
|
||||||
# delete the patch port pair
|
# delete the patch port pair
|
||||||
host_network.ovs_del_port(self._session, bridge_name, patch_port1)
|
host_network.ovs_del_port(self._session, bridge_name, patch_port1)
|
||||||
except Exception as e:
|
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",
|
" exception:%(exception)s",
|
||||||
{'if': vif, 'exception': e}, instance=instance)
|
{'if': vif_id, 'exception': e}, instance=instance)
|
||||||
raise exception.VirtualInterfaceUnplugException(
|
raise exception.VirtualInterfaceUnplugException(
|
||||||
reason=_("Failed to delete patch port pair"))
|
reason=_("Failed to delete patch port pair"))
|
||||||
|
|
||||||
LOG.debug('destroying network: network=%(network)s,'
|
LOG.debug('destroying bridge: bridge=%(br)s', {'br': bridge_name})
|
||||||
'bridge=%(br)s',
|
|
||||||
{'network': network, 'br': bridge_name})
|
|
||||||
try:
|
try:
|
||||||
self._session.network.destroy(network)
|
|
||||||
# delete bridge if it still exists.
|
# delete bridge if it still exists.
|
||||||
# As there is patch port existing on this bridge when destroying
|
# As there are patch ports existing on this bridge when
|
||||||
# the VM vif (which happens when shutdown the VM), the bridge
|
# destroying won't be destroyed automatically by XAPI, let's
|
||||||
# won't be destroyed automatically by XAPI. So let's destroy it
|
# destroy it at here.
|
||||||
# at here.
|
|
||||||
host_network.ovs_del_br(self._session, bridge_name)
|
host_network.ovs_del_br(self._session, bridge_name)
|
||||||
|
qbr_name = self._get_qbr_name(vif_id)
|
||||||
qbr_name = self._get_qbr_name(vif['id'])
|
qvb_name, qvo_name = self._get_veth_pair_names(vif_id)
|
||||||
qvb_name, qvo_name = self._get_veth_pair_names(vif['id'])
|
|
||||||
if self._device_exists(qbr_name):
|
if self._device_exists(qbr_name):
|
||||||
# delete tap port, qvb port and qbr
|
# delete tap port, qvb port and qbr
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
"destroy linux bridge %(qbr)s when unplug vif %(vif)s",
|
"destroy linux bridge %(qbr)s when unplug vif id"
|
||||||
{'qbr': qbr_name, 'vif': 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, tap_name)
|
||||||
self._delete_linux_port(qbr_name, qvb_name)
|
self._delete_linux_port(qbr_name, qvb_name)
|
||||||
self._delete_linux_bridge(qbr_name)
|
self._delete_linux_bridge(qbr_name)
|
||||||
@@ -353,12 +360,35 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
|||||||
CONF.xenserver.ovs_integration_bridge,
|
CONF.xenserver.ovs_integration_bridge,
|
||||||
qvo_name)
|
qvo_name)
|
||||||
except Exception as e:
|
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",
|
"exception:%(exception)s",
|
||||||
{'if': vif, 'exception': e}, instance=instance)
|
{'if': vif_id, 'exception': e}, instance=instance)
|
||||||
raise exception.VirtualInterfaceUnplugException(
|
raise exception.VirtualInterfaceUnplugException(
|
||||||
reason=_("Failed to delete bridge"))
|
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):
|
def hot_plug(self, vif, instance, vm_ref, vif_ref):
|
||||||
# hot plug vif only when VM's power state is running
|
# hot plug vif only when VM's power state is running
|
||||||
LOG.debug("Hot plug vif, vif: %s", vif, instance=instance)
|
LOG.debug("Hot plug vif, vif: %s", vif, instance=instance)
|
||||||
@@ -491,9 +521,13 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
|||||||
|
|
||||||
def create_vif_interim_network(self, vif):
|
def create_vif_interim_network(self, vif):
|
||||||
net_name = self.get_vif_interim_net_name(vif['id'])
|
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,
|
network_rec = {'name_label': net_name,
|
||||||
'name_description': "interim network for vif",
|
'name_description': "interim network for vif[%s]"
|
||||||
'other_config': {}}
|
% vif['id'],
|
||||||
|
'other_config': {'assume_network_is_shared': 'true'}}
|
||||||
network_ref = network_utils.find_network_with_name_label(
|
network_ref = network_utils.find_network_with_name_label(
|
||||||
self._session, net_name)
|
self._session, net_name)
|
||||||
if network_ref:
|
if network_ref:
|
||||||
|
|||||||
@@ -814,9 +814,14 @@ def _find_cached_images(session, sr_ref):
|
|||||||
def _find_cached_image(session, image_id, sr_ref):
|
def _find_cached_image(session, image_id, sr_ref):
|
||||||
"""Returns the vdi-ref of the cached image."""
|
"""Returns the vdi-ref of the cached image."""
|
||||||
name_label = _get_image_vdi_label(image_id)
|
name_label = _get_image_vdi_label(image_id)
|
||||||
recs = session.call_xenapi("VDI.get_all_records_where",
|
# For not pooled hosts, only name_lable is enough to get a cached image.
|
||||||
'field "name__label"="%s"'
|
# When in a xapi pool, each host may have a cached image using the
|
||||||
% name_label)
|
# 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)
|
number_found = len(recs)
|
||||||
if number_found > 0:
|
if number_found > 0:
|
||||||
if number_found > 1:
|
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 = session.call_xenapi("VM.get_other_config", vm_ref)
|
||||||
other_config['pci'] = params
|
other_config['pci'] = params
|
||||||
session.call_xenapi("VM.set_other_config", vm_ref, other_config)
|
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:
|
# This is the one associated with the pif marked management. From cli:
|
||||||
# uuid=`xe pif-list --minimal management=true`
|
# uuid=`xe pif-list --minimal management=true`
|
||||||
# xe pif-param-get param-name=network-uuid uuid=$uuid
|
# 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',
|
pifs = self._session.call_xenapi('PIF.get_all_records_where',
|
||||||
expr)
|
expr)
|
||||||
if len(pifs) != 1:
|
if len(pifs) != 1:
|
||||||
@@ -2492,6 +2493,9 @@ class VMOps(object):
|
|||||||
self._generate_vdi_map(
|
self._generate_vdi_map(
|
||||||
sr_uuid_map[sr_uuid], vm_ref, sr_ref))
|
sr_uuid_map[sr_uuid], vm_ref, sr_ref))
|
||||||
vif_map = {}
|
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
|
vif_uuid_map = None
|
||||||
if 'vif_uuid_map' in migrate_data:
|
if 'vif_uuid_map' in migrate_data:
|
||||||
vif_uuid_map = migrate_data.vif_uuid_map
|
vif_uuid_map = migrate_data.vif_uuid_map
|
||||||
@@ -2641,7 +2645,7 @@ class VMOps(object):
|
|||||||
# Unplug VIFs and delete networks
|
# Unplug VIFs and delete networks
|
||||||
for vif in network_info:
|
for vif in network_info:
|
||||||
try:
|
try:
|
||||||
self.vif_driver.delete_network_and_bridge(instance, vif)
|
self.vif_driver.delete_network_and_bridge(instance, vif['id'])
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception(_('Failed to delete networks and bridges with '
|
LOG.exception(_('Failed to delete networks and bridges with '
|
||||||
'VIF %s'), vif['id'], instance=instance)
|
'VIF %s'), vif['id'], instance=instance)
|
||||||
|
|||||||
Reference in New Issue
Block a user