VMware to KVM: cold (VDDK) and warm (CBT) migration into Ceph/RBD and Linstor, plus importVm adoption of existing RBD root volumes and Linstor root/data volumes - #13656
Conversation
Operator-driven warm VMware-to-KVM migration built on VDDK and VMware Changed Block Tracking (CBT). Keeps a source-equivalent KVM-side replica current through delta cycles, then finalizes with virt-v2v in-place at cutover. Supports both filesystem (qcow2) and native Ceph/RBD (raw image) primary storage targets, with preflight validation, async lifecycle operations, persisted migration state, and Import/Export UI integration. Signed-off-by: Andrija Panic <andrija.panic@gmail.com>
Extends the existing VDDK + virt-v2v VMware-to-KVM import path so the converted disk can be written straight into an RBD pool as a raw image, with in-place virt-v2v finalization. Adds host-capability detection for qemu-img RBD support, RBD qemu copy, virt-v2v in-place, and direct RBD import, advertised via ReadyCommand and reconciled by the agent manager. Signed-off-by: Andrija Panic <andrija.panic@gmail.com>
Extends the KVM unmanaged import / manage-volume flow so an existing raw RBD image can be adopted directly as a VM root volume, including the RBD-format check in the volume orchestrator and the libvirt volume inspection path. Signed-off-by: Andrija Panic <andrija.panic@gmail.com>
Unifies the host-capability keys that the CBT warm-migration and VDDK direct-RBD-import features introduced independently under different names, using feature-neutral names that describe what is probed: host.vmware.cbt.support -> host.vddk.blockcopy.support host.vmware.cbt.in.place.finalization.support -> host.vddk.blockcopy.inplace.finalization.support host.vmware.cbt.rbd.support -> host.vddk.blockcopy.rbd.support host.qemu.img.rbd.support -> host.qemu.rbd.support host.virt.v2v.inplace.support / host.virtv2v.in.place.version -> host.virtv2v.inplace.* Drops the redundant host.rbd.qemu.copy.support alias (identical to host.qemu.rbd.support) and its hostSupportsRbdQemuCopy() delegate. Signed-off-by: Andrija Panic <andrija.panic@gmail.com>
…isk import The "Manage Instances" source dropdown offered "Import QCOW2 image from Local/Shared Storage", but importVm now adopts an existing ROOT disk from Filesystem, NetworkFilesystem, SharedMountPoint and RBD (raw) pools, so the QCOW2-only wording is misleading. Rename both entries and their wizard title/description to "Import Instance using existing ROOT disk from Local/Shared Storage", across the en, pt_BR and te locales. Signed-off-by: Andrija Panic <andrija.panic@gmail.com>
docs/vmware-cbt/architecture.md and docs/vmware-cbt/README.md were added without the Apache license header, which failed the RAT license check and the pre-commit insert-license hook. Add the standard ASF header (identical to the one already present in docs/vmware-cbt-migration.md). Signed-off-by: Andrija Panic <andrija.panic@gmail.com>
…ey names State Apache CloudStack 4.24.0.0 as the target release (schema delivered via the 4.24.0.0 upgrade path, with a note that the DDL currently rides in schema-42210to42300.sql pending the main version bump), and replace the pre-consolidation host-capability key names with the current host.vddk.blockcopy.* / host.virtv2v.inplace.version names. Signed-off-by: Andrija Panic <andrija.panic@gmail.com>
Staged VMware-to-KVM imports (virt-v2v conversion to an NFS temporary location followed by a copy to the destination pool) can now target Linstor primary storage: - Linstor added to the staged-conversion destination pool types, so destination pool discovery considers cluster- and zone-wide Linstor pools alongside NFS and RBD. - The import host is validated to have access to each Linstor destination pool (it must be a LINSTOR satellite connected to the pool); the RBD qemu-copy capability check is preserved and the validation renamed to validateStagedImportHostSupport. - The KVM-side converted-disk move already dispatches by pool type to LinstorStorageAdaptor.copyPhysicalDisk, which spawns the resource from the pool's resource group and qemu-img converts the qcow2 into the DRBD block device; converted-disk metadata for Linstor pools now reports the pool UUID and volume name instead of parsing NFS mounts (Linstor pools have no local mount path). The imported volume keeps the copy-time UUID as its path; the Linstor driver addresses existing volumes by path, so later volume lifecycle operations (attach, resize, snapshot, delete) work unchanged.
Extends the direct (non-staged) VDDK import path, previously available only for Ceph/RBD, to Linstor primary storage. With usevddk=true and forceconverttopool=true on a Linstor conversion pool, the KVM host copies each VMware disk over nbdkit/VDDK straight into a pre-created DRBD block device and finalizes it with virt-v2v in place - no NFS staging and no intermediate qcow2 copy. Server side: - Linstor added to the VDDK direct-conversion pool allow-list; the RBD/Linstor "requires usevddk" validation is shared. - Conversion host selection for Linstor requires VDDK support, in-place virt-v2v support, and access to the Linstor pool (the host must be a LINSTOR satellite); explicit host selections are validated for pool access as well. - CheckConvertInstanceCommand carries a new in-place finalization check so unsupported hosts fail fast with a clear message. - The powered-off, non-cloned source VM requirement now applies to any direct block-storage import. KVM agent side: - The direct conversion routine handles both targets: for Linstor it pre-creates each resource at the source capacity through the storage adaptor (qemu-img cannot create DRBD devices, unlike RBD images), copies with qemu-img convert -n to the local DRBD device, and feeds virt-v2v-in-place a <disk type='block'> domain XML - no qemu URI or RBD-style network disks needed. - Storage access is probed with a 4 MiB test volume and a qemu-io write/read round-trip before any data transfer. - Linstor disk names use a shorter '-dNN' suffix: LINSTOR resource names are capped at 48 characters, which the RBD '-disk-NNN' scheme would exceed. - The forced-conversion import short-circuit accepts Linstor temporary locations, backed by a new LinstorStorageAdaptor.listPhysicalDisks implementation (resource definitions filtered by the pool's resource group), replacing the previous UnsupportedOperationException.
Extends the VMware CBT warm-migration framework, previously limited to qcow2 file and Ceph/RBD targets, with a generic raw-block-device target type backed by Linstor primary storage. The initial full sync, the incremental CBT delta cycles and the powered-off cutover all write straight into the DRBD block device of a pre-created Linstor volume. Target classification and orchestration: - New VmwareCbtTargetStorageType.RAW_BLOCK_DEVICE; Linstor pools classify as supported block-device targets that require in-place virt-v2v finalization (the qcow2 fallback cannot write to devices). - Linstor added to the CBT-compatible pool types for explicit and implicit destination pool selection. - Conversion host selection requires VMware CBT migration support, in-place finalization support and access to the Linstor pool (the host must be a LINSTOR satellite); both auto-selection filtering and explicit host validation enforce it. - The destination storage probe now covers block-device pools: the agent creates a 4 MiB volume through the storage adaptor, round-trips a qemu-io write/read on the local device and deletes it. Naming: block-device target volumes are named cbt-<mig8>-<diskId>, where mig8 is the first eight characters of the migration UUID. LINSTOR resource names are limited to 48 characters (the volume name gets a cs- prefix as a LINSTOR resource), so the RBD-style names carrying the full migration UUID do not fit. The short marker keeps cleanup guarded: both the management server and the agent only delete volumes whose names start with the marker derived from the migration UUID. Agent-side data path: - Initial sync pre-creates each Linstor volume at source capacity via the storage adaptor (qemu-img cannot create DRBD devices) and runs the nbdkit/VDDK captive copy with qemu-img convert -n to the local device path. - Delta cycles resolve the device path and patch changed extents with the existing qemu-io write mechanism; raw device targets are accepted by disk validation. - Cutover feeds virt-v2v-in-place a <disk type='block'> domain XML with the local device path - the qemu-nbd localhost bridges required for RBD are unnecessary for block devices. - Cleanup deletes only marker-guarded volumes through the adaptor. The finalized volumes are imported through the existing shared path; imported Linstor volumes keep the target name as their volume path, which the Linstor driver uses to address existing volumes.
Covers the release note for the three import modes (staged, direct VDDK, CBT warm migration), the operator guide's destination-specific host requirements and operational notes (satellite/node naming, single Primary writer, diskful replica preference, DRBD size rounding, heartbeat fencing interaction, retained volume names), and the as-built design guide's storage-target section (RAW_BLOCK_DEVICE mapping, pre-created devices, convert -n, block-disk XML finalization, 48-character resource-name constraint and the short cleanup marker).
Found during live validation on an Ubuntu 24.04 LINSTOR lab node: virt-v2v-in-place 2.4.0 does not know the -O (write updated output XML) option, which only exists from virt-v2v 2.5 on (EL9 ships 2.5.x, where the RBD flows were originally validated). Both the VMware CBT cutover finalization and the direct VDDK import finalization passed -O unconditionally, so otherwise fully capable hosts failed the in-place step at the very end of a migration. Nothing ever consumed the output XML - both wrappers created a temporary file for it and deleted it unread - so the option and the temporary files are removed rather than gated on a version probe. Verified live: virt-v2v-in-place 2.4.0 with the same libvirt XML converts a guest on a DRBD block device successfully without -O.
|
Accepted: Planned: RPM + DEB, KVM SystemVM. Status: Queued for worker G. Jobs ahead: 0. The packages previously published for |
|
Package building started on worker G. |
Packaging results:
Test packages are available at: |
|
@DaanHoogland @weizhouapache @shwstppr - please check the latest commits (upgrade paths from 4.23 to 4.24) if all looks good 🙏 |
|
@blueorangutan package |
|
@andrijapanicsb a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✖️ el8 ✖️ el9 ✖️ debian ✖️ suse15. SL-JID 19072 |
Co-authored-by: dahn <daan.hoogland@gmail.com>
|
@blueorangutan package |
|
@andrijapanicsb a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 19078 |
@andrijapanicsb IMO, schema upgrade changes are good for now but since we are dropping '4.' you may have to update the PR when #14041 is merged and #14033 or similar is added to main |
|
Copy that @shwstppr - thx 🙏 I'll be (re)doing a full functional cycle (33 or so tests) with the current packages I've built, to get that out of the way - later Marvin tests need to pass (and schema changes are just a matter of change, doesn't affect functional testing) |
|
This pull request has merge conflicts. Dear author, please fix the conflicts and sync your branch with the base branch. |
|
Hi @andrijapanicsb, the upgrade schema PR #14033 has been merged. Can you please rebase the latest main branch and fix the merge conflicts? |
|
doing it just now @nvazquez Pls review those last commits, and if all good pls triger packaging and testing. I will submit a functional testing report from the new packages (I will build packagess with my own bot) Thanks, |
|
@ACSHomeBot package A |
Packaging results:
Test packages are available at: |
|
@blueorangutan package |
|
@andrijapanicsb a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 19285 |
|
@nvazquez @DaanHoogland @shwstppr if you guys want to start tests pls |
|
Functional tests repeated/finished - all results (text and PDF) is a product of the latest functional test run. Smoke test required before merge. |
|
@blueorangutan test |
|
@DaanHoogland a [SL] Trillian-Jenkins test job (ol8 mgmt + kvm-ol8) has been kicked to run smoke tests |
|
[SF] Trillian test result (tid-17027)
|
|
Sounds fine to be merged @nvazquez @shwstppr @DaanHoogland @Pearl1594 (see my previous note on repeated functional tests passing 100%) |
Description
This PR makes Ceph/RBD and Linstor first-class targets for KVM VM onboarding and adds an operator-driven warm VMware→KVM migration path. It bundles the following (Ceph/RBD plus Linstor as block-storage destinations):
This PR targets Apache CloudStack
24.0.0and is aligned withmainat24.0.0-SNAPSHOT.1. VMware CBT → native RBD/qcow2 warm migration to KVM
An operator-driven, warm VMware-to-KVM migration built on VDDK and VMware Changed Block Tracking (CBT). It maintains a source-equivalent KVM-side replica kept current through repeated delta/sync cycles, then finalizes the guest with virt-v2v in-place at cutover — bounding downtime to the cutover window instead of a full cold copy.
qcow2) and native Ceph/RBD (raw image) primary storage.startVmwareCbtMigration,syncVmwareCbtMigration,cutoverVmwareCbtMigration,cancelVmwareCbtMigration,deleteVmwareCbtMigration,listVmwareCbtMigrations,checkVmwareCbtMigrationPrerequisites.VmwareCbtMigrationManagerImpl(+VmwareCbtMigrationServiceImpl, cutover policy), backed by new VOs/DAOs and a registered4.23.0.0→24.0.0database upgrade path.docs/vmware-cbt/(architecture + README) anddocs/vmware-cbt-migration.md.2. Direct VDDK VMware import into Ceph/RBD — the cold (one-shot) path
The cold counterpart to the warm CBT migration in (1): extends the existing
VDDK + virt-v2v VMware→KVM import — which previously landed only on NFS/
qcow2(direct, or via a staged file) — so the converted disk is written straight into an
RBD pool as a raw image, with in-place virt-v2v finalization and no intermediate
qcow2-on-NFS staging copy. (The warm path in (1) reuses this same full-disk copy for its
initial sync.) Adds host-capability detection for qemu-img RBD support, RBD qemu-copy,
virt-v2v in-place, and direct-RBD import — advertised via
ReadyCommandand reconciledby the agent manager.
3. Adoption of existing RBD (Ceph) and Linstor ROOT and DATA volumes
Extends the KVM unmanaged-import / manage-volume flow so existing RBD and Linstor
volumes can be adopted in place, without copying their data.
A ROOT volume is adopted with
importVm importsource=shared. Additional DATAvolumes are discovered with
listVolumesForImport, adopted withimportVolume,and attached with
attachVolume.For RBD, this adds RBD-aware format handling in
VolumeOrchestrator(RBD ⇒RAWinstead of the hardcoded
QCOW2) and the RBD branch in the libvirt volume-inspectionpath (
LibvirtCheckVolumeCommandWrapper), soCheckVolumeCommandsucceeds insteadof failing with "Disk not found or is invalid".
For Linstor (DRBD) primary storage, externally prepared ROOT and DATA volumes
(for example, landed by a migration/conversion tool) can be adopted without any
data copy. Linstor volumes are raw local block devices, so volume inspection runs
qemu-img against the
/dev/drbd/…device path (LibvirtCheckVolumeCommandWrapperfor ROOT,
LibvirtGetVolumesOnStorageCommandWrapperplus the volumeimport/unmanage gate for DATA), and
VolumeOrchestratorrecordsRAW.Because a host-local qemu-img file lock cannot see a DRBD resource that is
Primary/open on another node (unlike RBD's cluster-wide exclusive lock),
adoption additionally consults Linstor's cluster-wide
InUsestate — the newKVMStoragePool.getVolumeInUseNode()capability (default no-op), answered viathe existing
LinstorUtil.isResourceInUse— and refuses a volume attached to arunning VM anywhere in the cluster. Volumes are adopted under their existing
resource names (Linstor cannot rename; 48-character limit).
The existing filesystem/
qcow2adoption path is left unchanged, byconstruction rather than by accident: the supported-pool-type list is extended
additively; the raw-device inspection branch is guarded by an explicit
RBD/Linstor check that returns early, so filesystem pools still fall through to
the original
checkQcow2Filepath; the new cluster-wide in-use lookup is aKVMStoragePooldefault returningnulland is overridden only byLinstorStoragePool; and the format resolution is a new overload that delegatesto the pre-existing method for every pool type other than RBD/Linstor (so
qcow2pools still resolve toQCOW2).Live coverage includes RBD and Linstor ROOT adoption through
importVm, plusRBD and Linstor DATA-volume adoption through
importVolume. The adoptedvolumes retained their original backend paths, were attached to booted VMs,
and preserved their checksums. The existing qcow2/NFS ROOT adoption path was
also rechecked live: the file was adopted in place, the VM booted, and the
pre-adoption checksum matched inside the guest.
4. Linstor (DRBD) primary storage as a migration destination
Extends all three VMware→KVM paths above — staged import, direct VDDK import, and warm CBT migration — so the converted disks can also land on Linstor primary storage, not just Ceph/RBD. A generic
RAW_BLOCK_DEVICEtarget type covers "write RAW into a host-local block device provided by the storage adaptor", so the same code paths serve Linstor (and lay groundwork for other block backends).qemu-imgcannot create a DRBD device), copies withqemu-img convert -n— ornbdcopywhen the host has it — into the local/dev/drbd/…device, and finalizes withvirt-v2v-in-placefed a<disk type='block'>domain XML (no qemu-nbd bridge needed for a local device).qemu-img convert -n -S 0), avoiding a temp-file round-trip.-Oflag from thevirt-v2v-in-placeinvocation (fixes in-place finalization on virt-v2v < 2.5, for example Ubuntu 24.04) — which benefits the RBD path too.5. Data-plane efficiency and correctness for the agent-driven copies
These apply to the agent's own nbdkit/VDDK full-disk copies (cold direct import and CBT initial full sync); they do not touch the staged virt-v2v conversion path.
compression=<value>(newvddk.nbd.compressionagent property, defaultfastlz;none/zlib/fastlz/skipz). On datastores that do not expose block allocation to VDDK, the full nominal disk size otherwise crosses the network;fastlzcompresses both zero regions and real data on the ESXi side at low CPU cost (measured on a 30 GiB disk: 32.4 GB → 2.65 GB over the wire).nbdcopyfor RBD full copies — cold-direct-to-RBD and the CBT initial full sync to RBD copy withnbdcopyover a localhostqemu-nbdbridge (pre-create the raw image, serve it locally, copy NBD-to-NBD) rather than a single-streamqemu-img convert, falling back toqemu-img convertwhennbdcopyis unavailable. The Linstor block-device path usesnbdcopydirectly against the local device; CBT delta cycles use a range copier.--target-is-zero/--destination-is-zero) only when the backend guarantees a freshly created volume reads back as zeros, via a newKVMStoragePool.isVolumeZeroInitialized()capability (Linstor answers it from the provider kind — thin providers only). On backends that do not guarantee it (for example LVM-thick) the zeros are written, so no stale data from a previously deleted volume leaks into the unwritten regions.qemu-img's--target-is-zerosupport is also probed directly (newer qemu dropped it from--helpwhile still supporting it).6. Windows guest post-migration handling
For Windows guests, a first-boot script is injected via
virt-v2v --firstboot: on first boot it sets the SAN policy toOnlineAlland brings migrated data disks online and read-write, closing the common post-conversion gap where secondary disks come up Offline/Read-only under the default Windows SAN policy. It is best-effort and fail-safe — if it cannot run, the conversion still succeeds and the disks simply keep their default state. (Uses Storage cmdlets available on Windows Server 2012+.)Networking. After conversion the guest keeps its source MAC (with
forced=truesemantics per the import flow), so on a CloudStack-managed network the virtual router hands the guest exactly the IP CloudStack allocated for that NIC. How that IP is chosen is covered by the static-IP preservation in (8) below.7. Guest identity, firmware and console defaults derived from the source
Guest OS type and firmware (BIOS vs UEFI) are derived from the source VM's vCenter
configuration (
config.guestFullName/config.guestId/config.firmware/config.bootOptions) instead of relying on VMware Tools guest info. Tools is not running on apowered-off source — and block-storage destinations require the source to be powered off — so
previously every such import silently landed on the import dummy template's defaults: a generic
Linux OS type and BIOS firmware. For a UEFI source that produces a VM that cannot boot at all
(GPT/EFI disk under SeaBIOS), and for Windows guests it additionally means wrong clock semantics
(UTC instead of localtime), no hyperv enlightenments, and — on Server Core — a console that renders
nothing on the legacy cirrus video device. Imports set the guest OS type (nearest catalog match
for releases newer than the catalog, for example Windows Server 2025 → 2022), the
UEFIdetail(
SECUREwhen the source has secure boot enabled), theq35machine type for UEFI sources, and avgaconsole for Windows guests. Explicit caller-supplied values always take precedence. Theconversion fails fast with a clear message when virt-v2v reports that the host's
virtio-win driver set has no drivers for the guest's Windows release, instead of delivering an
unbootable VM. Related platform issue for the cirrus default affecting native deployments too:
#13806.
8. Static source IPv4 preservation
When the operator does not supply an explicit
nicipaddresslistentry for a NIC, the importkeeps the guest's own IPv4 address rather than allocating a random one. While the source
runs, per-NIC addresses with prefixes, the subnet's default gateway and the DNS servers are captured
from VMware Tools (
GuestNicInfo.ipConfig, with a fallback to the bare address list for olderTools). At import time each unspecified NIC keeps its captured address if it fits the target
network's CIDR, is not the gateway and is not already in use; otherwise — and for NICs with no
usable source data, for example DHCP guests whose lease belongs to the source network — the NIC falls back
to automatic allocation (the
"auto"marker, resolved by the network orchestrator to a freeaddress). An explicitly supplied
nicipaddresslistentry always wins. The result: a static Windowsguest arrives on KVM with the same address inside the guest and in CloudStack's allocation,
with no operator input and no in-guest rewriting.
9. Hardening from extended validation
consistent rejections, and no records stranded in a non-terminal state after a failure.
chosen, so concurrent disk bridges cannot race for the same port.
proceeding on incomplete information.
Types of changes
Feature/Enhancement Scale
How Has This Been Tested?
Unit and build validation
The relevant unit tests, Maven compile, Checkstyle and database upgrade tests
passed.
After this run,
mainmerged#14041, which changed the
development version to
24.0.0-SNAPSHOT, and#14033, which added the
official
4.23.0.0to24.0.0database upgrade path. Updating this branchproduced five content conflicts:
PendingReleaseNotes— kept both the VMware migration notes and the new24.0.0release section.AgentManagerImplandLibvirtComputingResource— kept the CBT hostcapabilities together with the new NVRAM snapshot and RBD encryption
capability reporting from
main.DatabaseUpgradeCheckerandDatabaseUpgradeCheckerTest— moved the CBTupgrade into the new
Upgrade42300to2400path. The CBT DDL now lives inschema-42300to2400.sql.These were integration-only resolutions. They did not change VMware migration
runtime behavior, and the relevant compile, Checkstyle and database upgrade
tests passed afterwards. No functional risk was introduced, so the full
end-to-end run does not need to be repeated on the latest PR commit.
End-to-end acceptance run
All 36 functional tests were run using management, common, usage, agent and
System VM packages built from:
3eaf6dad724e038f67cf2cc3e7b683bddb183ebcThe installed release was
4.24.0.0-2, from immutable package sourcepr13656-3eaf6dad724e-g2-el9-systemvm-kvm. Package provenance was checked onboth the management server and KVM conversion host before testing. No
uncommitted or unpublished runtime changes were included.
These functional results apply to that exact package build.
All CloudStack API/CLI requests were authenticated on port 8080. The
unauthenticated integration API was not used.
F00is one of the 36 tests. After the two Windows tests, one final cleanupand health check was run.
UI03was blocked because the project network was missing from the importwizard. The form was not submitted, so no resource was created. This is related
to the import-wizard network-scoping problem tracked in
#13780. The related UI
ownership work is tracked in
#13156. Project ownership
and isolation passed separately in
O03.Functional coverage
P00,P01N00,C00,L00N01,S01,S02N02,C01,L01N03,C02,L02N04C03R01-R05A01,A02,A03B01,B02,V01,V02O01,O02,O03F00RBD and Linstor ROOT adoption through
importVm importsource=sharedhadalready been live-validated, including adopt-and-boot. This run revalidated the
companion DATA-volume path through
importVolumeon RBD and Linstor (A02andA03). Direct and warm migration of ROOT + DATA disk sets was additionallycovered by
C01,L01,C02andL02; those cases exercise migration ratherthan adoption.
Guest boot was accepted only after guest-level evidence. Where applicable, the
run also verified disk ordering, exact storage placement, source/destination
checksums, network mapping and reachability, stop/start/reboot lifecycle,
source-snapshot cleanup and absence of temporary conversion data.
Windows Server 2019 coverage
N02passed a cold direct VDDK import to NFS. The imported UEFI/q35 guest usedthe accepted
EPYC-IBPBCPU model, reached the Windows Server 2019 Core loginscreen and exposed both Red Hat VirtIO SCSI disks as Online/Healthy through
QGA. Both VirtIO NIC mappings were preserved. The ROOT disk remained the boot
disk, the DATA disk remained the additional disk, and both checksums matched
the source VM. The import completed in 188 seconds and cleanup removed the VM,
volumes, exact NFS paths, conversion processes and source clone.
C02passed a warm CBT migration to native Ceph/RBD. Initial synchronization,two explicit delta cycles,
ReadyForCutover, verified graceful sourceshutdown, final delta, in-place conversion and
Completedwere all observed.The three cycles copied 62,455,808 changed bytes (59.56 MiB) in total. The
UEFI/q35 Windows Server 2019 Core target booted from its two finalized RBD
images. QGA reported both VirtIO SCSI disks Online/Healthy, and both VirtIO
NICs were up with the expected mappings. The ROOT disk remained the boot disk,
the DATA disk remained the additional disk, and both checksums matched the
source VM. Cleanup removed the source snapshot, VM, volumes, RBD images, CBT
rows, bridge/conversion processes and source clone.
UI tests
UI01- admin importUI02- account/domain importUI03- project importO03passedUI04- unauthorized-network negativepermission denied; no VM, volume or migration artifact was createdThe new run also captured complete Windows UI evidence for
N02andC02,including cold conversion, CBT initial sync, expanded replication details,
delta copying,
ReadyForCutover, the cutover confirmation, final delta,in-place conversion,
Completed, target details and the Windows Server Corelogin screen.
Representative warm CBT UI evidence
Ready for the operator-approved final cutover after two completed delta cycles:
Completed migration after the final delta synchronization and in-place conversion:
Final environment check
was
UpandEnabled.Up.Runningwith agentsUp; the Iso1 and Iso2 routers wererunning as reusable network fixtures.
worker, exact NFS path, RBD image, Linstor resource or dated VMware source
clone remained.
original values.
Full acceptance report
The PDF report contains the detailed results and representative N02/C02
screenshots:
Last updated: 20 September 2026 — includes the latest functional test run.
PR13656-acceptance-report.pdf