From 80b8d7fc91234cbe2117e75ba0ffac2e068aa6df Mon Sep 17 00:00:00 2001 From: catborise Date: Thu, 5 Nov 2026 15:56:56 +0300 Subject: [PATCH] fix(instances): a failed disk check on another host names it only to administrators Deleting a VM with its disks checks every other compute for the files. A compute that could not be read raised an OperationError whose text already held that compute's name and libvirt's error, so owners who do not see hosts got both. It is now a ConnectionFailed, which users who do not see hosts get as "cannot be reached"; libvirt's text comes from the error itself, so a connection that never opened no longer reads "None". --- instances/tests/test_destroy.py | 8 ++++++-- instances/utils.py | 11 ++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/instances/tests/test_destroy.py b/instances/tests/test_destroy.py index 0115cad8..80f4f3df 100644 --- a/instances/tests/test_destroy.py +++ b/instances/tests/test_destroy.py @@ -9,7 +9,8 @@ from django.urls import reverse from instances.models import Instance from instances.utils import paths_used_on_other_computes from libvirt import VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_NVRAM, libvirtError -from vrtManager.util import OperationError +from operations.utils import public_error_text +from vrtManager.util import ConnectionFailed, OperationError class DestroyOrderTestCase(TestCase): @@ -243,5 +244,8 @@ class OtherComputesTestCase(TestCase): hosts = self.hosts({"192.0.2.61": set(), "192.0.2.62": set()}) hosts["192.0.2.61"].paths_in_use.side_effect = libvirtError("connection refused") with patch("instances.utils.wvmConnect", side_effect=lambda host, *args: hosts[host]): - with self.assertRaisesMessage(OperationError, "The disk files cannot be checked on host-b"): + with self.assertRaises(ConnectionFailed) as caught: paths_used_on_other_computes(self.source, ["/nfs/a.qcow2"]) + self.assertEqual(caught.exception.args[0], "The disk files cannot be checked on host-b: connection refused") + # users who do not see hosts get neither the host nor libvirt's text + self.assertEqual(public_error_text(caught.exception), "The host of this virtual machine cannot be reached right now.") diff --git a/instances/utils.py b/instances/utils.py index 0cbc4567..6ba709ac 100644 --- a/instances/utils.py +++ b/instances/utils.py @@ -16,7 +16,7 @@ from logs.audit import reason, write from operations.models import Operation from vrtManager.connection import other_hosts, wvmConnect from vrtManager.instance import wvmInstance, wvmInstances -from vrtManager.util import OperationError, message +from vrtManager.util import ConnectionFailed, message from .models import Instance @@ -52,8 +52,9 @@ def get_clone_free_names(size=10): def paths_used_on_other_computes(compute, own): """The paths in own that the VMs and volumes of the panel's other computes use (paths_in_use): shared storage holds a file at the same path on every - host that mounts it, as migration needs. OperationError naming a compute - that cannot be read: it might use them.""" + host that mounts it, as migration needs. ConnectionFailed naming a compute + that cannot be read, which might use them: users who do not see hosts + learn only that a host cannot be reached.""" used = set() host = wvmConnect(compute.hostname, compute.login, compute.password, compute.type).host_uuid() for other in Compute.objects.exclude(pk=compute.pk): @@ -63,8 +64,8 @@ def paths_used_on_other_computes(compute, own): continue # the VM's own host under another record: its VM is the one going used |= conn.paths_in_use(own=own) except libvirtError as err: - raise OperationError(_("The disk files cannot be checked on %(host)s: %(err)s") % { - "host": other.name, "err": err.get_error_message()}) from err + raise ConnectionFailed(gettext_noop("The disk files cannot be checked on %(host)s: %(err)s"), + host=other.name, err=err) from err return used & set(own)