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

fix(migrate): recovery removes the disk copies of a migration whose worker stopped

A worker that stopped during the copy left the partial files on the
destination: libvirt ends the migration and the VM stays, but the files
took the space and refused the next try, as a copy never replaces a
file. The job records the copies before libvirt makes them, and
recovery deletes them while the destination has no VM of it.

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:08 +03:00
parent d2a637cf33
commit aadf5270f2
5 changed files with 69 additions and 7 deletions

View file

@ -116,7 +116,7 @@ def _rate(before, after, seconds, scale=1):
class wvmInstances(wvmConnect):
def moveto(self, conn, name, live, unsafe, offline, autoconverge=False, compress=False, uri=None,
pools=None):
pools=None, on_copy=None):
"""Migrates the VM of conn (a wvmInstance on the source) here.
The mode follows the VM's state, read once: a running VM migrates
@ -128,9 +128,10 @@ class wvmInstances(wvmConnect):
(tcp://address) on the destination; None lets libvirt use the
destination's own hostname. pools: {target: pool here} of the disks
libvirt copies into those pools during the migration (disk_copies);
the other disks must be on storage both hosts share. Returns the mode
and options used, for the log, and each copied disk's path and the
path of its copy here."""
the other disks must be on storage both hosts share. on_copy is
called with the copies ({pool, dest}: a pool here and its path) before
libvirt makes them. Returns the mode and options used, for the log,
and each copied disk's path and the path of its copy here."""
state = conn.get_status()
if state == 5:
mode = ["offline"]
@ -193,6 +194,8 @@ class wvmInstances(wvmConnect):
# the TPM state is a file of the source host: a live migration carries it
tpm_state = etree.fromstring(definitions[0]).xpath("devices/tpm/backend[@type='emulator']")
if copies or (state == 5 and tpm_state):
if copies and on_copy is not None:
on_copy([{"pool": copy["pool"].name(), "dest": copy["dest"]} for copy in copies])
note = self.migrate_running(conn, state, flags, uri, copies)
if note:
mode.append(note)