fix(vm): keep the volume migration set atomic and finalized#2670
Closed
danilrwx wants to merge 21 commits into
Closed
fix(vm): keep the volume migration set atomic and finalized#2670danilrwx wants to merge 21 commits into
danilrwx wants to merge 21 commits into
Conversation
danilrwx
force-pushed
the
fix/vm/atomic-volume-migration-set
branch
from
July 14, 2026 14:06
9a55f66 to
c3a42f6
Compare
Live volume migration of a multi-disk VM built the migration volume set
non-atomically, so KubeVirt could be handed an inconsistent set: some disks on
this round's target while others still point at a previous round's PVC, or a
local disk left out of the set entirely. KubeVirt then rejects the transition
("the volume can only be reverted to the previous version during the update")
and the migration hangs, or completes a migration that never copied a local
disk, leaving the domain broken on the target node — reported as success but
requiring a restart.
SyncVolumes now:
- waits until all ReadWriteOnce local disks migrate together, never patching a
set that mixes disks from different rounds (completeness);
- refuses to start a new migration while a volume migration is already in
progress (VMI condition VolumesChange=True) that targets different
destinations, since KubeVirt only accepts continuing the current round or a
clean revert to source (serialization).
Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
… consistent Add an e2e case to RWOVirtualDiskMigration that migrates a VM with a root disk plus three ReadWriteOnce local disks several times in a row, asserting each migration succeeds, all disks stay Ready on their targets, and the VM is never left restart-required — the symptom of a non-atomic volume set. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
danilrwx
force-pushed
the
fix/vm/atomic-volume-migration-set
branch
from
July 14, 2026 15:33
a7b41e6 to
5889710
Compare
…tead of skipping Drop the skip-on-known-failure for VolumesUpdateError and reverted VD migrations so these specs surface the failure they are meant to guard. The client-socket-closed KubeVirt flake stays skipped for now. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
The volume-update inconsistency ("the volume can only be reverted to the
previous version during the update") only reproduces when the whole RWO set
is migrated repeatedly while a restart is pending. Induce the restart before
the migration rounds so the spec exercises that path.
Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
Migrate the whole RWO set once so the disks leave their base PVCs, start a second migration, and request a restart while it is still in flight. The restart reconcile must not push a conflicting volume update over the unfinalized set. Combined with failing (not skipping) on VolumesUpdateError, this guards the volume-consistency path; the race itself is exercised aggressively by the manual repro. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
danilrwx
marked this pull request as ready for review
July 14, 2026 17:22
Dropping the fragile in-flight catch: on instant (replicated) storage the migration finalizes before it can be observed mid-flight, which timed out. Just request the restart right after the migration starts so it races the unfinalized set on copy-based storage and lands right after on instant storage; both must finalize cleanly. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
A volume migration whose target disks never synchronize (e.g. the target PVCs stay Pending or a previous round left the state uncleaned) keeps the VMOP Pending with reason WaitingForVirtualMachineToBeReadyToMigrate forever, with no time bound. Bound the wait and fail the operation so the disk migration revert path can recover the VM, and requeue while pending so the deadline fires without further watch events. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
When a volume migration cannot proceed and no operation is in progress, KVVM may be left pointing at a dead migration target (e.g. the target PVC was removed) while KVVMI stays on the source. kubevirt keeps requeuing on the missing target and the kvvmiSynced barrier never lets us revert, so the VM wedges forever. Force-revert KVVM to the source volumes in that case. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
…revert Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
Reflecting the KVVM RestartRequired condition logged a generic sentence at error level with an empty err, polluting error logs and alerts for an expected VM state while hiding why kubevirt asked for a restart. Log it at info and attach the underlying KVVM condition reason and message. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
A finished migration could leave updateVolumesStrategy=Migration on KVVM while KVVM and KVVMI already agree on the volumes. KubeVirt then keeps treating the VM as mid-migration. When no migration is in progress and only the strategy is stale (volumes already match the desired set), clear it. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
A healthy migration reaches ReadyToMigrate within about a minute, so 5 minutes is a wide margin over the happy path while recovering a wedge sooner. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
The KVVM RestartRequired condition is latched by kubevirt until an actual restart, so reflecting it logged the same line every reconcile. Log only when the VM newly transitions into the awaiting-restart state. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
The in-flight destination check only verified that recorded migrated volumes keep their destinations, so a set that migrates an extra volume on top of the running round, keeps a volume at source mid-migration, or drops an in-flight (hotplugged) volume slipped through and was rejected by KubeVirt, leaving the controller retrying noisily until the round finalized. Compare both directions: a patch is allowed mid-migration only if it purely continues the current round. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
… guards The stale-strategy clearing and force-revert guards compared built volumes (normalized with the VMI's containerdisk pull policies) against the raw in-cluster KVVM, which never carries them. For a VM with a containerdisk volume the equality never held, so a stale updateVolumesStrategy was never cleared and the no-op check of the force revert never suppressed a patch. Compare against the normalized copy used by the kvvmi sync check instead. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
The recovery force-revert fired for any kvvm/kvvmi volume divergence with no running migration, including a benign hotplug volume mid-attach, tearing the attachment down (VMBDA stuck InProgress). Gate it on updateVolumesStrategy= Migration so only a genuinely stuck migration is reverted; other divergence is left to sync as before. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
…active A storage class change round runs without any VMOP: the migration itself is driven by KubeVirt's workload-updater. In the window between patching KVVM with the round's targets and KubeVirt syncing them to the KVVMI, the recovery force-revert saw a diverged KVVM with no in-progress VMOP and rolled the just-started round back to the source, churning the round start. Skip the revert while the disks still demand a migration round. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
The volume patch replaces the whole volumes array from a read snapshot. KubeVirt concurrently persists hotplugged (addvolume) volumes into the same array, so a patch built from a stale read silently dropped the just-persisted hotplug volume and the attachment never completed: with local (WFFC) disks the node affinity legitimately evolves while PVCs bind, each shift re-patched the volumes, and a VMBDA could stay InProgress indefinitely. Assert the kvvm resourceVersion in the patch so a concurrent change fails it and the next reconcile rebuilds from a fresh read. Signed-off-by: Daniil Antoshin <daniil.antoshin@flant.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
A live migration of a VM with several local disks could be reported as successful yet leave the VM demanding a restart and its next migrations hanging. A migration could also get stuck outright and never complete. Node drains, firmware and workload updates on such VMs stall.
The cause: the controller built the set of volumes to migrate non-atomically, violating the rules KubeVirt enforces for volume migration. The fix makes it follow them:
Why do we need it, and what problem does it solve?
Multi-disk VMs on local storage are common (a boot disk plus data disks). Without this fix their migration is flaky: it may succeed on paper but leave the VM needing a manual restart, or hang and block node drains indefinitely with no way to recover except manual intervention.
What is the expected result?
For a running VM with a root disk and several local (ReadWriteOnce) disks:
Checklist
Changelog entries