From c8d5397b0a671fddfa9b9c27bc7790a439a18caf Mon Sep 17 00:00:00 2001 From: Amit Uniyal Date: Thu, 4 Aug 2022 13:42:14 +0000 Subject: [PATCH] Adds check for VM snapshot fail while quiesce Added check if quiesce fails because libvirt fails to connect with qemu guest agent inside instance Closes-Bug: #1980720 Change-Id: I134a4060ace2678f76ae3606bf117c07194a8d92 --- nova/api/openstack/compute/servers.py | 2 ++ nova/exception.py | 5 +++++ .../regressions/test_bug_1980720.py | 3 ++- nova/tests/unit/virt/libvirt/test_driver.py | 20 +++++++++++++++++++ nova/virt/libvirt/driver.py | 8 +++++++- 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index 6a9bf1fa92..946d5a7042 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -1353,6 +1353,8 @@ class ServersController(wsgi.Controller): except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'createImage', id) + except exception.InstanceQuiesceFailed as err: + raise exc.HTTPConflict(explanation=err.format_message()) except exception.Invalid as err: raise exc.HTTPBadRequest(explanation=err.format_message()) except exception.OverQuota as e: diff --git a/nova/exception.py b/nova/exception.py index 3d8e596312..cebaea4bee 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -217,6 +217,11 @@ class InvalidVIOMMUArchitecture(Invalid): "but given architecture %(arch)s.") +class InstanceQuiesceFailed(Invalid): + msg_fmt = _("Failed to quiesce instance: %(reason)s") + code = 409 + + class InvalidConfiguration(Invalid): msg_fmt = _("Configuration is Invalid.") diff --git a/nova/tests/functional/regressions/test_bug_1980720.py b/nova/tests/functional/regressions/test_bug_1980720.py index 416137123f..ad2e6e6ba2 100644 --- a/nova/tests/functional/regressions/test_bug_1980720.py +++ b/nova/tests/functional/regressions/test_bug_1980720.py @@ -58,10 +58,11 @@ class LibvirtDriverTests( nova_fixtures.libvirt.Domain, 'fsFreeze' ) as mock_obj: ex = nova_fixtures.libvirt.libvirtError("Error") + ex.err = (nova_fixtures.libvirt.VIR_ERR_AGENT_UNRESPONSIVE,) mock_obj.side_effect = ex excep = self.assertRaises( client.OpenStackApiException, self._snapshot_server, server, "snapshot-1" ) - self.assertEqual(500, excep.response.status_code) + self.assertEqual(409, excep.response.status_code) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index fee87d3bb5..1c5f79dc89 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -9244,6 +9244,26 @@ class LibvirtConnTestCase(test.NoDBTestCase, image_meta)) mock_fsthaw.assert_called_once_with() + def test_set_quiesced_agent_connection_fails(self): + # This is require to mock guest host + self.create_fake_libvirt_mock(lookupByUUIDString=self.fake_lookup) + + with mock.patch.object(FakeVirtDomain, "fsFreeze") as mock_fsfreeze: + error = fakelibvirt.make_libvirtError( + fakelibvirt.libvirtError, + "QEMU guest agent is not connected", + error_code=fakelibvirt.VIR_ERR_AGENT_UNRESPONSIVE) + + mock_fsfreeze.side_effect = error + mock_fsfreeze.error_code = error.get_error_code() + + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI()) + instance = objects.Instance(**self.test_instance) + image_meta = objects.ImageMeta.from_dict( + {"properties": {"hw_qemu_guest_agent": "yes", }}) + self.assertRaises(exception.InstanceQuiesceFailed, + drvr._set_quiesced, self.context, instance, image_meta, True) + def test_create_snapshot_metadata(self): base = objects.ImageMeta.from_dict( {'disk_format': 'raw'}) diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index ce884dfe30..7306e4a4c2 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -3250,7 +3250,13 @@ class LibvirtDriver(driver.ComputeDriver): '[Error Code %(error_code)s] %(ex)s') % {'instance_name': instance.name, 'error_code': error_code, 'ex': err_msg}) - raise exception.InternalError(msg) + + if error_code == libvirt.VIR_ERR_AGENT_UNRESPONSIVE: + msg += (", libvirt cannot connect to the qemu-guest-agent" + " inside the instance.") + raise exception.InstanceQuiesceFailed(reason=msg) + else: + raise exception.InternalError(msg) def quiesce(self, context, instance, image_meta): """Freeze the guest filesystems to prepare for snapshot.