1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 11:16:47 +00:00

fix(migrate): a shut-off VM whose NVRAM file is outside libvirt's directory is refused

Only a file in libvirt's NVRAM directory was copied; one elsewhere was
skipped without a word, and the VM started on the destination from the
firmware's template, its saved boot entries lost. Such a VM is now
refused before anything changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kk4h2TcUiaWmU5MUszYSea
This commit is contained in:
catborise 2026-11-07 22:47:59 +03:00
parent aadf5270f2
commit 50ed08f3ca
6 changed files with 630 additions and 602 deletions

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -424,10 +424,16 @@ class wvmInstances(wvmConnect):
def copy_nvram(self, conn):
"""Copies the UEFI variables file of the shut-off VM of conn (on the
source) from libvirt's NVRAM directory there to the same path here,
unless both hosts share that directory. Returns the copy's name."""
unless both hosts share that directory. Returns the copy's name. A
file elsewhere is refused: it would stay behind, and the VM start
here from the firmware's template."""
path = conn.get_nvram()
if not path or os.path.dirname(path) != NVRAM_DIR:
if not path:
return None
if os.path.dirname(path) != NVRAM_DIR:
raise util.OperationError(gettext_noop(
"The NVRAM file %(path)s is not in libvirt's NVRAM directory %(dir)s and cannot be copied"),
path=path, dir=NVRAM_DIR)
name = os.path.basename(path)
with conn._nvram_pool() as source, self._nvram_pool() as target:
vol = self._find_volume(source, name)

View file

@ -296,6 +296,12 @@ class NvramCopyTestCase(unittest.TestCase):
copy.upload.assert_called_once_with(self.dest.wvm.newStream.return_value, 0, 4, 0)
self.assertEqual(self.host.defined, ["<domain><name>vm</name></domain>"])
def test_a_file_outside_libvirt_s_directory_stops_the_move(self):
self.source.nvram = "/srv/vms/vm_VARS.fd"
with self.assertRaisesRegex(util.OperationError, "/srv/vms/vm_VARS.fd is not in libvirt's NVRAM directory"):
self.move()
self.assertEqual(self.host.defined, [])
def test_a_failed_download_aborts_its_stream(self):
stream = self.source.wvm.newStream.return_value
stream.recvAll.side_effect = libvirt.libvirtError("download failed")