From 940e639149701541fbc09cc5f230b93c93eebd99 Mon Sep 17 00:00:00 2001 From: catborise Date: Sun, 1 Nov 2026 17:46:17 +0300 Subject: [PATCH] fix(instances): a failed migration says what libvirt said A live migration whose source host could not resolve the destination's name for the migration stream failed with "The host of this virtual machine cannot be reached right now": libvirt reports that failure as a connection error, and a job's error hides those behind that sentence so as not to name hosts. Only superusers migrate, so the migration job now fails with libvirt's own words, here "Unable to resolve address ...", which points at the destination's Migration address. --- instances/jobs.py | 6 ++++-- instances/tests/test_migrate_job.py | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/instances/jobs.py b/instances/jobs.py index 242e3d72..8e4d2282 100644 --- a/instances/jobs.py +++ b/instances/jobs.py @@ -898,11 +898,13 @@ class MigrateInstance(Kind): utils.migrate_instance(Compute.objects.get(pk=p["target"]), instance, op.user, disk_pools=p["disk_pools"], **{k: p[k] for k in MIGRATE_OPTIONS}) - except libvirtError: + except libvirtError as err: op.refresh_from_db(fields=["cancel_requested"]) if op.cancel_requested: raise Cancelled from None - raise + # a superuser's job: libvirt's words, which a host the source cannot + # reach for the migration would hide behind "cannot be reached" + raise util.OperationError(str(err)) from err return {} def progress(self, op): diff --git a/instances/tests/test_migrate_job.py b/instances/tests/test_migrate_job.py index 00037b7d..ed4ef8f1 100644 --- a/instances/tests/test_migrate_job.py +++ b/instances/tests/test_migrate_job.py @@ -11,9 +11,10 @@ from appsettings.settings import get_settings from computes.models import Compute from instances.jobs import MigrateInstance from instances.models import Instance -from libvirt import VIR_DOMAIN_XML_INACTIVE, libvirtError +from libvirt import VIR_DOMAIN_XML_INACTIVE, VIR_ERR_SYSTEM_ERROR, VIR_FROM_RPC, libvirtError from operations.jobs import Cancelled, Context, get_kind from operations.models import Claim, Operation, acquire +from operations.utils import public_error_text UUID = "31313131-4242-5353-6464-757575757575" @@ -156,6 +157,18 @@ class MigrateJobTestCase(TransactionTestCase): self.vm.refresh_from_db() self.assertEqual(self.vm.compute, self.source) + def test_a_failed_migration_says_what_libvirt_said(self): + # libvirt reports the source host's failure to reach the destination's migration + # port as a connection error; only superusers migrate, so its text is shown + op = self.queue(live_migrate="true") + ctx = self.start(op) + err = libvirtError("Unable to resolve address 'kvm2.example.com' service '49152': Name or service not known") + err.err = (VIR_ERR_SYSTEM_ERROR, VIR_FROM_RPC, str(err), 2, None, None, None, 0, 0) + self.dest_conn.moveto.side_effect = err + with self.assertRaises(Exception) as raised: + get_kind(op.kind).run(op, ctx) + self.assertIn("Unable to resolve address 'kvm2.example.com'", public_error_text(raised.exception)) + def test_cancel_and_progress_ask_the_source_vm(self): op = self.queue(live_migrate="true") with patch("instances.jobs.wvmInstance") as proxy: