From 9ef56fa86639f97f63d853dbb2213415dcd5691b Mon Sep 17 00:00:00 2001 From: Hongbin Lu Date: Tue, 10 Oct 2017 23:05:14 +0000 Subject: [PATCH] Handle not found error on taking snapshot If there is a request to create a snapshot of an instance and another request to delete the instance at the same time, the snapshot task might fail with libvirt error and this error is not handled correctly by compute manager. As a result, tracestack was printed in the compute log. This patch fixes it by handling libvirt exception during live snapshot and raise instance not found exception if the libvirt exception is raised due to domain not found. Change-Id: I585b7b03753ed1d28a313ce443e6918687d76a8b Closes-Bug: #1722571 --- nova/tests/unit/virt/libvirt/test_driver.py | 18 ++++++++++++++++++ nova/virt/libvirt/driver.py | 14 ++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 3fd5f63145..3f4762dee8 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -19911,6 +19911,24 @@ class LibvirtSnapshotTests(_BaseSnapshotTests): self._test_snapshot(disk_format='qcow2', extra_properties=extra_properties) + @mock.patch.object(host.Host, 'get_guest') + @mock.patch.object(host.Host, 'write_instance_config') + def test_failing_domain_not_found(self, mock_write_config, mock_get_guest): + self.flags(disable_libvirt_livesnapshot=False, group='workarounds') + mock_dev = mock.Mock(spec=libvirt_guest.BlockDevice) + mock_guest = mock.Mock(spec=libvirt_guest.Guest) + mock_guest.get_power_state.return_value = power_state.RUNNING + mock_guest.get_block_device.return_value = mock_dev + mock_guest._domain = mock.Mock() + mock_get_guest.return_value = mock_guest + ex = fakelibvirt.make_libvirtError( + fakelibvirt.libvirtError, + "No such domain", + error_code=fakelibvirt.VIR_ERR_NO_DOMAIN) + mock_dev.rebase.side_effect = ex + self.assertRaises(exception.InstanceNotFound, self._test_snapshot, + disk_format='qcow2') + @mock.patch.object(rbd_utils, 'RBDDriver') @mock.patch.object(rbd_utils, 'rbd') def test_raw_with_rbd_clone(self, mock_rbd, mock_driver): diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 9f054c8e34..f8d99f78c1 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -1837,6 +1837,20 @@ class LibvirtDriver(driver.ComputeDriver): root_disk.snapshot_extract(out_path, image_format) LOG.info("Snapshot extracted, beginning image upload", instance=instance) + except libvirt.libvirtError as ex: + error_code = ex.get_error_code() + if error_code == libvirt.VIR_ERR_NO_DOMAIN: + LOG.info('Instance %(instance_name)s disappeared ' + 'while taking snapshot of it: [Error Code ' + '%(error_code)s] %(ex)s', + {'instance_name': instance.name, + 'error_code': error_code, + 'ex': ex}, + instance=instance) + raise exception.InstanceNotFound( + instance_id=instance.uuid) + else: + raise finally: self._snapshot_domain(context, live_snapshot, virt_dom, state, instance)