Commit ab78f7b
committed
linstor: add LinstorDataMotionStrategy for live migration
Add a new DataMotionStrategy implementation that enables VM live migration
when the destination storage pool is Linstor (DRBD). Without this strategy,
CloudStack's storage migration framework had no code path to handle live
migrations *to* Linstor pools, leaving three scenarios broken:
- Linstor -> Linstor: blocked (no strategy claimed it)
- SMP -> Linstor: DEFECT (KvmNonManagedDMS claimed it but generated
wrong DiskType=FILE/DriverType=QCOW2 and an invalid
device path using the resource group name instead of
a DRBD block device path)
- StorPool -> Linstor: blocked (no strategy claimed it)
How strategy selection works:
CloudStack iterates all DataMotionStrategy beans and picks the one
returning the highest StrategyPriority from canHandle(). The existing
strategies return:
- StorPoolDMS: HIGHEST only when ALL dest pools are StorPool
- KvmNonManagedDMS: HYPERVISOR only for {NFS, SMP, Filesystem}
- StorageSystemDMS: only for managed (isManaged=true) pools
- AncientDMS: DEFAULT (fallback, copies via secondary storage)
LinstorDataMotionStrategy returns HIGHEST when ALL destination pools are
Linstor, giving it priority over KvmNonManagedDMS (HYPERVISOR=2) and
AncientDMS (DEFAULT=1), while not conflicting with StorPoolDMS.
canHandle semantics:
Offline (DataObject, DataObject):
Always returns CANT_HANDLE. Offline volume copies continue to use
existing paths (AncientDMS or driver canCopy). A native Linstor
offline copy (e.g. DRBD clone) can be added in a future commit.
Live (Map<VolumeInfo,DataStore>, Host, Host):
Returns HIGHEST when ALL destination DataStores are Linstor pools.
The source pools can be anything (Linstor, StorPool, SMP, NFS, ...),
enabling cross-storage live migration *to* Linstor.
Live migration flow (copyAsync with volumeMap):
For each volume in the migration set:
1. Create a destination VolumeVO record in the database
(duplicateVolumeOnAnotherStorage).
2. If cross-storage (src is not Linstor, or different Linstor controller):
create a new DRBD resource via the Linstor REST API
(resourceGroupSpawn on the destination pool's resource group).
3. Ensure the resource is available on the destination KVM host
(resourceMakeAvailableOnNode). For same-controller Linstor->Linstor,
DRBD already has the data replicated so this is a lightweight diskless
attach or no-op.
4. Set DRBD allow-two-primaries so both source and destination hosts can
have the device open read-write simultaneously during migration.
Uses ResourceDefinition-level properties when both nodes are diskless
(DRBD client topology), or ResourceConnection-level properties when
nodes are hyperconverged (have local disks).
5. Build MigrateDiskInfo with DiskType=BLOCK, DriverType=RAW, Source=DEV,
and destPath=/dev/drbd/by-res/<rscName>/0. This tells libvirt's
replaceStorage() to modify the VM's disk XML for block-copy migration.
6. Send PrepareForMigrationCommand to destination host, then
MigrateCommand (with migrateStorageManaged=true) to source host.
Libvirt performs the actual block copy using VIR_MIGRATE_NON_SHARED_DISK.
Post-migration success:
- Remove allow-two-primaries from all resources
- Swap volume UUIDs between source and destination (updateUuid)
- Destroy and expunge source volumes
- Update snapshot references to point to new volume IDs
Post-migration failure:
- Remove allow-two-primaries
- Delete destination Linstor resources unconditionally (not just diskless)
- Delete resource definitions if no resources remain
- Expunge destination volumes (DB records)
- Rollback PrepareForMigration on destination host
Error handling:
- On early failure (before MigrateCommand), handlePostMigration(false)
is called from the catch block to ensure Linstor resources are cleaned
up and not left orphaned.
- viewResources API errors are logged as warnings and creation is
attempted regardless (rather than silently assuming resource absence).
- applyAuxProps errors are logged but non-fatal.
Spring context:
Register the LinstorDataMotionStrategy bean in
spring-storage-volume-linstor-context.xml so StorageStrategyFactoryImpl
discovers it via auto-wiring.
Files:
- NEW: plugins/storage/volume/linstor/src/main/java/org/apache/
cloudstack/storage/motion/LinstorDataMotionStrategy.java
- MOD: plugins/storage/volume/linstor/src/main/resources/META-INF/
cloudstack/storage-volume-linstor/
spring-storage-volume-linstor-context.xml1 parent 13a4950 commit ab78f7b
File tree
2 files changed
+582
-0
lines changed- plugins/storage/volume/linstor/src/main
- java/org/apache/cloudstack/storage/motion
- resources/META-INF/cloudstack/storage-volume-linstor
2 files changed
+582
-0
lines changed
0 commit comments