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