@@ -18589,6 +18589,7 @@ def _test_attach_detach_interface_get_config(self, method_name):
1858918589 lambda self, instance: FakeVirtDomain())
1859018590
1859118591 instance = objects.Instance(**self.test_instance)
18592+ instance.info_cache = None
1859218593 network_info = _fake_network_info(self)
1859318594 drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
1859418595
@@ -22957,23 +22958,20 @@ def _test_detach_interface(self, state, device_not_found=False):
2295722958 # This will trigger _detach_with_retry to raise
2295822959 # DeviceNotFound
2295922960 get_interface_calls = [
22960- expected_cfg, # detach_interface() itself gets the config
2296122961 expected_cfg, # _detach_with_retry: persistent config
2296222962 None, # _detach_with_retry: no device in live config
2296322963 None, # _detach_with_retry: persistent config gone as detached
2296422964 ]
2296522965 else:
2296622966 if state in (power_state.RUNNING, power_state.PAUSED):
2296722967 get_interface_calls = [
22968- expected_cfg, # detach_interface() itself gets the config
2296922968 expected_cfg, # _detach_with_retry: persistent config
2297022969 expected_cfg, # _detach_with_retry: live config
2297122970 None, # _detach_with_retry: persistent config gone
2297222971 None # _detach_with_retry: live config gone
2297322972 ]
2297422973 else:
2297522974 get_interface_calls = [
22976- expected_cfg, # detach_interface() itself gets the config
2297722975 expected_cfg, # _detach_with_retry: persistent config
2297822976 None, # _detach_with_retry: persistent config gone
2297922977 ]
@@ -23008,7 +23006,6 @@ def _test_detach_interface(self, state, device_not_found=False):
2300823006 flags=fakelibvirt.VIR_DOMAIN_AFFECT_CONFIG)
2300923007 mock_get_interface.assert_has_calls(
2301023008 [
23011- mock.call(expected_cfg),
2301223009 mock.call(expected_cfg, from_persistent_config=True),
2301323010 mock.call(expected_cfg),
2301423011 mock.call(expected_cfg, from_persistent_config=True),
@@ -23026,7 +23023,6 @@ def _test_detach_interface(self, state, device_not_found=False):
2302623023 ])
2302723024 mock_get_interface.assert_has_calls(
2302823025 [
23029- mock.call(expected_cfg),
2303023026 mock.call(expected_cfg, from_persistent_config=True),
2303123027 mock.call(expected_cfg),
2303223028 mock.call(expected_cfg, from_persistent_config=True),
@@ -23038,7 +23034,6 @@ def _test_detach_interface(self, state, device_not_found=False):
2303823034 flags=fakelibvirt.VIR_DOMAIN_AFFECT_CONFIG)
2303923035 mock_get_interface.assert_has_calls(
2304023036 [
23041- mock.call(expected_cfg),
2304223037 mock.call(expected_cfg, from_persistent_config=True),
2304323038 mock.call(expected_cfg, from_persistent_config=True),
2304423039 ])
@@ -23064,6 +23059,7 @@ def test_detach_interface_device_not_found(self, mock_log):
2306423059 # Asserts that we don't log an error when the interface device is not
2306523060 # found on the guest after a libvirt error during detach.
2306623061 instance = self._create_instance()
23062+ instance.info_cache = None
2306723063 vif = _fake_network_info(self)[0]
2306823064 guest = mock.Mock(spec=libvirt_guest.Guest)
2306923065 guest.get_power_state = mock.Mock()
@@ -23081,36 +23077,6 @@ def test_detach_interface_device_not_found(self, mock_log):
2308123077 self.assertIn('the device is no longer found on the guest',
2308223078 str(mock_log.warning.call_args[0]))
2308323079
23084- @mock.patch('nova.virt.libvirt.driver.LibvirtDriver.'
23085- '_detach_with_retry')
23086- @mock.patch('nova.virt.libvirt.driver.LOG')
23087- def test_detach_interface_guest_not_found_after_detach(
23088- self, mock_log, mock_detach_with_retry
23089- ):
23090- # Asserts that we don't raise an exception when the guest is gone
23091- # after a libvirt error during detach.
23092- instance = self._create_instance()
23093- vif = _fake_network_info(self, 1)[0]
23094- guest = mock.MagicMock()
23095- guest.get_power_state.return_value = power_state.RUNNING
23096- guest.get_interface_by_cfg.return_value = (
23097- vconfig.LibvirtConfigGuestInterface())
23098- get_guest_mock = mock.Mock()
23099- # Host.get_guest should be called twice: the first time it is found,
23100- # the second time it is gone.
23101- get_guest_mock.side_effect = (
23102- guest, exception.InstanceNotFound(instance_id=instance.uuid))
23103- self.drvr._host.get_guest = get_guest_mock
23104- error = fakelibvirt.libvirtError(
23105- 'internal error: End of file from qemu monitor')
23106- error.err = (fakelibvirt.VIR_ERR_OPERATION_FAILED,)
23107- mock_detach_with_retry.side_effect = error
23108- self.drvr.detach_interface(self.context, instance, vif)
23109- self.assertEqual(1, mock_log.info.call_count)
23110- self.assertIn('Instance disappeared while detaching interface',
23111- mock_log.info.call_args[0][0])
23112- get_guest_mock.assert_has_calls([mock.call(instance)] * 2)
23113-
2311423080 @mock.patch('threading.Event.wait', new=mock.Mock())
2311523081 @mock.patch.object(FakeVirtDomain, 'info')
2311623082 @mock.patch.object(FakeVirtDomain, 'detachDeviceFlags')
@@ -23154,7 +23120,6 @@ def test_detach_interface_device_with_same_mac_address(
2315423120 mock.patch.object(
2315523121 libvirt_guest.Guest, 'get_interface_by_cfg',
2315623122 side_effect=[
23157- expected, # detach_interface gets the config
2315823123 expected, # _detach_with_retry: persistent config
2315923124 expected, # _detach_with_retry: live config
2316023125 None, # _detach_with_retry: persistent gone
@@ -23168,14 +23133,12 @@ def test_detach_interface_device_with_same_mac_address(
2316823133
2316923134 mock_get_interface.assert_has_calls(
2317023135 [
23171- mock.call(expected, ),
2317223136 mock.call(expected, from_persistent_config=True),
2317323137 mock.call(expected),
2317423138 mock.call(expected, from_persistent_config=True),
2317523139 mock.call(expected),
2317623140 ]
2317723141 )
23178- self.assertEqual(5, mock_get_interface.call_count)
2317923142 mock_get_config.assert_called_once_with(
2318023143 instance, network_info[0], test.MatchType(objects.ImageMeta),
2318123144 test.MatchType(objects.Flavor), CONF.libvirt.virt_type)
@@ -23197,7 +23160,6 @@ def test_detach_interface_guest_set_metadata(self):
2319723160 instance = self._create_instance()
2319823161 network_info = _fake_network_info(self, num_networks=3)
2319923162 vif = network_info[0]
23200- interface = vconfig.LibvirtConfigGuestInterface()
2320123163 image_meta = objects.ImageMeta.from_dict({})
2320223164 disk_info = blockinfo.get_disk_info(
2320323165 CONF.libvirt.virt_type, instance, image_meta)
@@ -23210,8 +23172,6 @@ def test_detach_interface_guest_set_metadata(self):
2321023172 self.drvr._host, 'get_guest', return_value=guest),
2321123173 mock.patch.object(
2321223174 self.drvr.vif_driver, 'get_config', return_value=cfg),
23213- mock.patch.object(
23214- guest, 'get_interface_by_cfg', return_value=interface),
2321523175 mock.patch.object(
2321623176 instance, 'get_network_info', return_value=network_info),
2321723177 mock.patch.object(
@@ -23220,16 +23180,15 @@ def test_detach_interface_guest_set_metadata(self):
2322023180 self.drvr, '_get_guest_config_meta', return_value=config_meta),
2322123181 mock.patch.object(guest, 'set_metadata')
2322223182 ) as (
23223- mock_get_guest, mock_get_config, mock_get_interface_by_cfg ,
23224- mock_get_network_info, mock_detach_with_retry ,
23225- mock_get_guest_config_meta, mock_set_metadata
23183+ mock_get_guest, mock_get_config, mock_get_network_info ,
23184+ mock_detach_with_retry, mock_get_guest_config_meta ,
23185+ mock_set_metadata
2322623186 ):
2322723187 self.drvr.detach_interface(self.context, instance, vif)
2322823188 mock_get_guest.assert_called_once_with(instance)
2322923189 mock_get_config.assert_called_once_with(
2323023190 instance, vif, test.MatchType(objects.ImageMeta),
2323123191 test.MatchType(objects.Flavor), CONF.libvirt.virt_type)
23232- mock_get_interface_by_cfg.assert_called_once_with(cfg)
2323323192 mock_detach_with_retry.assert_called_once_with(
2323423193 guest, instance.uuid, mock.ANY, device_name=None)
2323523194 mock_get_network_info.assert_called_once_with()
@@ -23791,6 +23750,56 @@ def test__detach_with_retry_libvirt_reports_not_found_give_up(self):
2379123750 mock_guest.detach_device.assert_called_once_with(
2379223751 mock_dev, persistent=True, live=False)
2379323752
23753+ @mock.patch.object(libvirt_driver.LOG, 'warning')
23754+ def test__detach_with_retry_libvirt_reports_domain_not_found(
23755+ self, mock_warning
23756+ ):
23757+ """Test that libvirt reports that the domain is not found and assert
23758+ that it is only logged.
23759+ """
23760+ drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
23761+ mock_guest = mock.Mock(spec=libvirt_guest.Guest)
23762+ mock_guest.get_power_state.return_value = power_state.SHUTDOWN
23763+
23764+ mock_dev = mock.Mock(spec=vconfig.LibvirtConfigGuestDisk)
23765+ mock_dev.alias = 'virtio-disk1'
23766+
23767+ mock_get_device_conf_func = mock.Mock(
23768+ # The first call is to get the device from the persistent domain
23769+ # before the detach. The second calls to double check that the
23770+ # device is gone after libvirt returned. This second call is
23771+ # pointless in the current case as libvirt returned that the domain
23772+ # does not exists. So the code could know that there is no device.
23773+ # Still for simplicity the call is made and expected to return None
23774+ side_effect=[
23775+ mock_dev,
23776+ None,
23777+ ]
23778+ )
23779+
23780+ mock_guest.detach_device.side_effect = fakelibvirt.make_libvirtError(
23781+ fakelibvirt.libvirtError,
23782+ msg='error',
23783+ error_code=fakelibvirt.VIR_ERR_NO_DOMAIN)
23784+
23785+ drvr._detach_with_retry(
23786+ mock_guest,
23787+ uuids.instance_uuid,
23788+ mock_get_device_conf_func,
23789+ device_name='vdb',
23790+ )
23791+
23792+ mock_guest.has_persistent_configuration.assert_called_once_with()
23793+ mock_get_device_conf_func.assert_has_calls([
23794+ mock.call(from_persistent_config=True),
23795+ mock.call(from_persistent_config=True),
23796+ ])
23797+ mock_guest.detach_device.assert_called_once_with(
23798+ mock_dev, persistent=True, live=False)
23799+ mock_warning.assert_called_once_with(
23800+ 'During device detach, instance disappeared.',
23801+ instance_uuid=uuids.instance_uuid)
23802+
2379423803 @ddt.data(power_state.RUNNING, power_state.PAUSED)
2379523804 def test__detach_with_retry_other_sync_libvirt_error(self, state):
2379623805 """Test that libvirt reports non device related error during detach
@@ -23809,7 +23818,7 @@ def test__detach_with_retry_other_sync_libvirt_error(self, state):
2380923818 mock_guest.detach_device.side_effect = fakelibvirt.make_libvirtError(
2381023819 fakelibvirt.libvirtError,
2381123820 msg='error',
23812- error_code=fakelibvirt.VIR_ERR_NO_DOMAIN )
23821+ error_code=fakelibvirt.VIR_ERR_INTERNAL_ERROR )
2381323822
2381423823 self.assertRaises(
2381523824 fakelibvirt.libvirtError,
0 commit comments