diff --git a/nova/tests/unit/virt/libvirt/test_guest.py b/nova/tests/unit/virt/libvirt/test_guest.py index 70d438d816a..47e9ba4b623 100644 --- a/nova/tests/unit/virt/libvirt/test_guest.py +++ b/nova/tests/unit/virt/libvirt/test_guest.py @@ -1040,3 +1040,25 @@ def test_job_info_operation_invalid(self, mock_stats, mock_info): mock_stats.assert_called_once_with() mock_info.assert_called_once_with() + + @mock.patch.object(fakelibvirt.virDomain, "jobInfo") + @mock.patch.object(fakelibvirt.virDomain, "jobStats") + def test_job_stats_no_ram(self, mock_stats, mock_info): + mock_stats.side_effect = fakelibvirt.make_libvirtError( + fakelibvirt.libvirtError, + "internal error: migration was active, but no RAM info was set", + error_code=fakelibvirt.VIR_ERR_INTERNAL_ERROR, + error_message="migration was active, but no RAM info was set") + + info = self.guest.get_job_info() + + self.assertIsInstance(info, libvirt_guest.JobInfo) + self.assertEqual(fakelibvirt.VIR_DOMAIN_JOB_NONE, info.type) + self.assertEqual(0, info.time_elapsed) + self.assertEqual(0, info.time_remaining) + self.assertEqual(0, info.memory_total) + self.assertEqual(0, info.memory_processed) + self.assertEqual(0, info.memory_remaining) + + mock_stats.assert_called_once_with() + self.assertFalse(mock_info.called) diff --git a/nova/virt/libvirt/guest.py b/nova/virt/libvirt/guest.py index 53080e41f0b..68bd4ca5b07 100644 --- a/nova/virt/libvirt/guest.py +++ b/nova/virt/libvirt/guest.py @@ -655,6 +655,7 @@ def get_job_info(self): stats = self._domain.jobStats() return JobInfo(**stats) except libvirt.libvirtError as ex: + errmsg = ex.get_error_message() if ex.get_error_code() == libvirt.VIR_ERR_NO_SUPPORT: # Remote libvirt doesn't support new API LOG.debug("Missing remote virDomainGetJobStats: %s", ex) @@ -667,6 +668,12 @@ def get_job_info(self): # away completclsely LOG.debug("Domain has shutdown/gone away: %s", ex) return JobInfo(type=libvirt.VIR_DOMAIN_JOB_COMPLETED) + elif (ex.get_error_code() == libvirt.VIR_ERR_INTERNAL_ERROR and + errmsg and "migration was active, " + "but no RAM info was set" in errmsg): + LOG.debug("Migration is active or completed but " + "virDomainGetJobStats is missing ram: %s", ex) + return JobInfo(type=libvirt.VIR_DOMAIN_JOB_NONE) else: LOG.debug("Failed to get job stats: %s", ex) raise diff --git a/releasenotes/notes/bug-1982284-libvirt-handle-no-ram-info-was-set-99784934ed80fd72.yaml b/releasenotes/notes/bug-1982284-libvirt-handle-no-ram-info-was-set-99784934ed80fd72.yaml new file mode 100644 index 00000000000..943aa99a436 --- /dev/null +++ b/releasenotes/notes/bug-1982284-libvirt-handle-no-ram-info-was-set-99784934ed80fd72.yaml @@ -0,0 +1,11 @@ +--- +other: + - | + A workaround has been added to the libvirt driver to catch and pass + migrations that were previously failing with the error: + + ``libvirt.libvirtError: internal error: migration was active, but no RAM info was set`` + + See `bug 1982284`_ for more details. + + .. _bug 1982284: https://bugs.launchpad.net/nova/+bug/1982284