1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-09 11:46:49 +00:00

fix(logs): a row says what happened: a recovered migration, a failed clone step, a device not there

- A migration whose libvirt call failed but which recovery finds moved (or
  cannot tell) gets a row of that end; only a failure already logged by
  migrate_instance is not logged twice.
- A clone made with its resize or start failed, and a recovered migration
  whose autostart or NVRAM step failed, write a failed row of that step, as
  migrate_instance does for its later steps.
- Setting the link state of an interface or the video model of a VM that
  has none is refused: it changed nothing and was logged as done.
- The rows of a removed VM record (deleted or expired) name its host, VM
  and UUID, so the VM's history has them.
This commit is contained in:
catborise 2026-11-07 14:22:47 +03:00
parent 470cc9860e
commit 528b4492f6
14 changed files with 390 additions and 304 deletions

View file

@ -1666,6 +1666,7 @@ class wvmInstance(wvmConnect):
new_model.set("primary", video_model.get("primary"))
self._defineXML(etree.tostring(tree).decode())
return
raise util.OperationError(gettext_noop("The VM has no video card"))
def resize_cpu(self, cur_vcpu, vcpu):
"""
@ -2940,14 +2941,18 @@ class wvmInstance(wvmConnect):
raise util.OperationError(gettext_noop("The VM has no such USB device"))
def set_link_state(self, mac_address, state):
found = False
for xml_flags, affect in self._definitions():
nic = self._nic(xml_flags, mac_address)
if nic is None:
continue
found = True
for link in nic.findall("link"):
nic.remove(link)
etree.SubElement(nic, "link", state=state)
self.instance.updateDeviceFlags(etree.tostring(nic).decode(), affect)
if not found:
raise util.OperationError(gettext_noop("The VM has no network interface %(mac)s"), mac=mac_address)
def _set_options(self, tree, options):
for o in ["title", "description"]:

View file

@ -110,6 +110,18 @@ class DeviceEditsTestCase(unittest.TestCase):
self.assertEqual(model.attrib, {"type": "vga' heads='9"})
p._defineXML.assert_called_once()
def test_a_device_the_vm_does_not_have_is_refused(self):
# a stale form: no change, and the audit row says it failed
p = proxy()
p._definitions = lambda: [(PERSISTENT_XML, VIR_DOMAIN_AFFECT_CONFIG)]
with self.assertRaisesRegex(util.OperationError, "no network interface 52:54:10:00:00:09"):
p.set_link_state("52:54:10:00:00:09", "down")
p._XMLDesc = lambda flags: PERSISTENT.replace("<video><model type='vga'/></video>", "")
with self.assertRaisesRegex(util.OperationError, "no video card"):
p.set_video_model("virtio")
p.instance.updateDeviceFlags.assert_not_called()
p._defineXML.assert_not_called()
def test_qos_changes_go_through_define_xml(self):
for change in (
lambda p: p.set_qos("52:54:10:00:00:01", "outbound", 1, 2, 3),