libvirt: don't log error if guest gone during interface detach

Similar to change I8ae352ff3eeb760c97d1a6fa9d7a59e881d7aea1, if
we're processing a network-vif-deleted event while an instance
is being deleted, the asynchronous interface detach could fail
because the guest is gone from the hypervisor. The existing code
for handling this case was using a stale guest object so this
change tries to refresh the guest from the hypervisor and if the
guest is gone, the Host.get_guest() method should raise an
InstanceNotFound exception which we just trap, log and return.

Change-Id: Ic4c870cc5078d3f7ac6b2f96f8904c2a47de418e
Closes-Bug: #1797966
This commit is contained in:
Matt Riedemann 2018-10-15 16:45:14 -04:00 committed by John Garbutt
parent bb53370197
commit 6c3e8bc48e
2 changed files with 33 additions and 0 deletions

View File

@ -21778,6 +21778,32 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
self.assertIn('the device is no longer found on the guest',
six.text_type(mock_log.warning.call_args[0]))
@mock.patch('nova.virt.libvirt.driver.LOG')
def test_detach_interface_guest_not_found_after_detach(self, mock_log):
# Asserts that we don't raise an exception when the guest is gone
# after a libvirt error during detach.
instance = self._create_instance()
vif = _fake_network_info(self, 1)[0]
guest = mock.MagicMock()
guest.get_power_state.return_value = power_state.RUNNING
guest.get_interface_by_cfg.return_value = (
vconfig.LibvirtConfigGuestInterface())
get_guest_mock = mock.Mock()
# Host.get_guest should be called twice: the first time it is found,
# the second time it is gone.
get_guest_mock.side_effect = (
guest, exception.InstanceNotFound(instance_id=instance.uuid))
self.drvr._host.get_guest = get_guest_mock
error = fakelibvirt.libvirtError(
'internal error: End of file from qemu monitor')
error.err = (fakelibvirt.VIR_ERR_OPERATION_FAILED,)
guest.detach_device_with_retry.side_effect = error
self.drvr.detach_interface(self.context, instance, vif)
self.assertEqual(1, mock_log.info.call_count)
self.assertIn('Instance disappeared while detaching interface',
mock_log.info.call_args[0][0])
get_guest_mock.assert_has_calls([mock.call(instance)] * 2)
@mock.patch.object(FakeVirtDomain, 'info')
@mock.patch.object(FakeVirtDomain, 'detachDeviceFlags')
@mock.patch.object(host.Host, '_get_domain')

View File

@ -2078,6 +2078,13 @@ class LibvirtDriver(driver.ComputeDriver):
# then we can just log it as a warning rather than tracing an
# error.
mac = vif.get('address')
# Get a fresh instance of the guest in case it is gone.
try:
guest = self._host.get_guest(instance)
except exception.InstanceNotFound:
LOG.info("Instance disappeared while detaching interface "
"%s", vif['id'], instance=instance)
return
interface = guest.get_interface_by_cfg(cfg)
if interface:
LOG.error('detaching network adapter failed.',