This document describes the implemented Apache CloudStack architecture for warm VMware-to-KVM migration based on VMware Changed Block Tracking (CBT). Detailed API, database, configuration, and operational information is in README.md. KVM host preparation is documented in ../vmware-cbt-migration.md.
The KVM-side replica remains byte-compatible with the VMware source disk until the final CBT cycle has completed. Raw VMware CBT ranges are never applied to a disk after guest conversion has changed its layout.
The migration therefore has two distinct phases:
virt-v2v locally against the current KVM-side replica.This avoids a second full VMware read during cutover. CloudStack does not power off the source VM; shutdown remains an explicit operator action.
The API commands are:
checkVmwareCbtMigrationPrerequisitesstartVmwareCbtMigrationlistVmwareCbtMigrationssyncVmwareCbtMigrationcutoverVmwareCbtMigrationcancelVmwareCbtMigrationdeleteVmwareCbtMigrationVmwareCbtMigrationManagerImpl owns migration orchestration, host and storage validation, state transitions, cutover policy, agent command dispatch, import, and cleanup. VmwareCbtMigrationServiceImpl performs VMware inventory, snapshot, power-state, CBT enablement, and changed-area operations.
VmwareCbtStorageTarget classifies the selected primary storage and determines the target representation and finalization constraints.
The feature persists its state in three CloudStack tables:
cloud.vmware_cbt_migration: one row per migration session.cloud.vmware_cbt_migration_disk: source and target metadata for each disk, including the current per-disk VMware changeId.cloud.vmware_cbt_migration_cycle: metrics and status for each delta cycle.The schema and configuration entries are delivered through the standard 4.23.0.0-to-24.0.0 database upgrade path:
engine/schema/src/main/resources/META-INF/db/schema-42300to2400.sqlengine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade42300to2400.javaThe management server sends these commands to the selected conversion host:
VmwareCbtPrepareCommand: create or resolve target disks and perform the initial VDDK full copy.VmwareCbtSyncCommand: read and apply VMware CBT ranges.VmwareCbtCutoverCommand: finalize the current replica with virt-v2v.VmwareCbtCleanupCommand: terminate migration-owned processes and remove migration-owned temporary artifacts.VmwareCbtRbdProbeCommand: actively validate RBD create/write/read/delete access for the selected pool.The corresponding KVM wrappers are LibvirtVmwareCbtPrepareCommandWrapper, LibvirtVmwareCbtSyncCommandWrapper, LibvirtVmwareCbtCutoverCommandWrapper, LibvirtVmwareCbtCleanupCommandWrapper, and LibvirtVmwareCbtRbdProbeCommandWrapper.
The workflow is integrated into Import/Export Instances. The UI starts async operations through the API and uses listVmwareCbtMigrations as the detailed source for migration, disk, and cycle state.
VMware source VM | | preflight and source discovery v baseline VMware snapshot | | nbdkit-vddk full logical disk read v source-equivalent replica on KVM primary storage | | repeated VMware snapshots + QueryChangedDiskAreas | changed ranges copied through VDDK and patched in place v ReadyForCutover | | operator powers off the VMware VM | final CBT delta | local virt-v2v finalization v CloudStack KVM import
Preflight resolves the source, destination cluster, conversion host, and primary storage. It validates source CBT state, source disks, snapshots, storage support, host block-copy and in-place-finalization capabilities, RBD or LINSTOR access where applicable, Windows conversion dependencies, and optional compute-offering sizing.
The selected conversion host reports capability through host details. The principal gates are:
host.vddk.blockcopy.supporthost.vddk.blockcopy.inplace.finalization.supporthost.vddk.blockcopy.rbd.supportvddk.lib.dirhost.vddk.versionvirt-v2v version detailsStart creates the migration and disk records, enables CBT when required, creates a baseline VMware snapshot, prepares destination targets, and dispatches VmwareCbtPrepareCommand.
The KVM agent exposes each snapshot disk with nbdkit-vddk. It uses qemu-img convert for the general copy path and can use nbdcopy as an optional accelerator for supported pre-created or NBD-bridged targets. The result remains source-equivalent; virt-v2v is not run during initial sync.
After a successful copy, CloudStack records the baseline per-disk changeId and removes the baseline snapshot when possible.
Each synchronization cycle:
QueryChangedDiskAreas from the previous per-disk changeId.nbdkit-vddk on the KVM host.qemu-io.changeId.VmwareCbtMigrationCutoverPolicy evaluates the configured minimum, maximum, and quiet-cycle thresholds and moves the migration to ReadyForCutover when the policy boundary is reached.
Cutover is accepted only when the source VM is powered off. CloudStack runs one final CBT cycle, then finalizes the current KVM-side replica with one of these paths:
virt-v2v-in-place;virt-v2v --in-place; orvirt-v2v -o local for QCOW2 file targets only, when the explicit non-in-place fallback configuration is enabled.After finalization, CloudStack imports the disks through the shared external KVM import path. A successful import sets the migration to Completed. If finalization succeeds but import fails, the migration remains ReadyForImport and a retry repeats only the import stage.
| Primary storage | Replica | Initial copy | Delta writes | Finalization |
|---|---|---|---|---|
| NFS, filesystem, shared mount | QCOW2 file | qemu-img | qemu-io -f qcow2 | In-place preferred; explicitly gated local fallback supported |
| Ceph/RBD | Raw RBD image | Direct qemu RBD path or nbdcopy through a local NBD bridge | qemu-io -f raw | In-place only |
| LINSTOR | Pre-created raw DRBD block device | nbdcopy when available, otherwise qemu-img | qemu-io -f raw | In-place only |
For filesystem targets, temporary replicas are stored under a migration-owned cloudstack-cbt/<migration-uuid>/ directory. RBD and LINSTOR resources use CloudStack-owned migration markers. Cleanup is restricted to these owned paths and resource names.
Migration states:
Created -> InitialSync -> Replicating -> ReadyForCutover -> CuttingOver -> ReadyForImport -> Completed
Failed and Cancelled are terminal states. ReadyForImport is deliberately retryable.
Disk states are Created, Prepared, Syncing, Ready, and Failed. Cycle states are Created, QueryingChangedAreas, CopyingChangedBlocks, Completed, and Failed.
Sync and cutover commands are serialized by migration ID. Cancellation sends a best-effort agent cleanup command before marking a non-terminal migration as cancelled. Failed and cancelled migrations can delete their migration-owned temporary replicas when cleanup is requested.
Deleting a completed migration is record-only. It removes CBT bookkeeping but does not delete the imported VM, its CloudStack volumes, or finalized primary storage artifacts.
VMware snapshots are removed after initial and delta attempts when possible. Snapshot identifiers and cleanup errors remain visible in migration state so operators can identify VMware-side cleanup work.
Existing registered vCenter credentials are resolved from CloudStack‘s VMware datacenter record. External-source credentials are accepted by sensitive API commands and the password is stored through CloudStack’s encrypted DAO field handling until the migration no longer needs it.
On the KVM host, the password is written to a temporary owner-only file and passed to nbdkit with password=+<file>. It is not placed directly in the process command line. Returned errors are sanitized before persistence.
virtio-win driver bundle on that host.