From 6c3e8bc48e460c96f4fc8d975a63ef76e6f55694 Mon Sep 17 00:00:00 2001 From: Matt Riedemann Date: Mon, 15 Oct 2018 16:45:14 -0400 Subject: [PATCH] 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 --- nova/tests/unit/virt/libvirt/test_driver.py | 26 +++++++++++++++++++++ nova/virt/libvirt/driver.py | 7 ++++++ 2 files changed, 33 insertions(+) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 2d4bed09733b..d77a5153cc1f 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -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') diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 5f7258f2bffe..546ef0abef87 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -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.',