Skip to content

Commit 572ffeb

Browse files
committed
migrate clvm volumes as full clone and allow migration from clvm to nfs
1 parent 4c34200 commit 572ffeb

File tree

2 files changed

+44
-4
lines changed

2 files changed

+44
-4
lines changed

engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageDataMotionStrategy.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ protected void logInCaseOfTemplateCopyFailure(Answer copyCommandAnswer, Template
285285
}
286286

287287
protected Boolean supportStoragePoolType(StoragePoolType storagePoolType) {
288-
return super.supportStoragePoolType(storagePoolType, StoragePoolType.Filesystem);
288+
return super.supportStoragePoolType(storagePoolType, StoragePoolType.Filesystem,
289+
StoragePoolType.CLVM, StoragePoolType.CLVM_NG);
289290
}
290291
}

engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
import com.cloud.agent.api.MigrateCommand.MigrateDiskInfo;
8888
import com.cloud.agent.api.ModifyTargetsAnswer;
8989
import com.cloud.agent.api.ModifyTargetsCommand;
90+
import com.cloud.agent.api.PreMigrationCommand;
9091
import com.cloud.agent.api.PrepareForMigrationCommand;
9192
import com.cloud.agent.api.storage.CopyVolumeAnswer;
9293
import com.cloud.agent.api.storage.CopyVolumeCommand;
@@ -2096,7 +2097,7 @@ public void copyAsync(Map<VolumeInfo, DataStore> volumeDataStoreMap, VirtualMach
20962097

20972098
MigrateCommand.MigrateDiskInfo migrateDiskInfo;
20982099

2099-
boolean isNonManagedToNfs = supportStoragePoolType(sourceStoragePool.getPoolType(), StoragePoolType.Filesystem) && destStoragePool.getPoolType() == StoragePoolType.NetworkFilesystem && !managedStorageDestination;
2100+
boolean isNonManagedToNfs = supportStoragePoolType(sourceStoragePool.getPoolType(), StoragePoolType.Filesystem, StoragePoolType.CLVM, StoragePoolType.CLVM_NG) && destStoragePool.getPoolType() == StoragePoolType.NetworkFilesystem && !managedStorageDestination;
21002101
if (isNonManagedToNfs) {
21012102
migrateDiskInfo = new MigrateCommand.MigrateDiskInfo(srcVolumeInfo.getPath(),
21022103
MigrateCommand.MigrateDiskInfo.DiskType.FILE,
@@ -2116,6 +2117,8 @@ public void copyAsync(Map<VolumeInfo, DataStore> volumeDataStoreMap, VirtualMach
21162117
srcVolumeInfoToDestVolumeInfo.put(srcVolumeInfo, destVolumeInfo);
21172118
}
21182119

2120+
prepareDisksForMigrationForClvm(vmTO, volumeDataStoreMap, srcHost);
2121+
21192122
PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(vmTO);
21202123
Answer pfma;
21212124

@@ -2211,19 +2214,55 @@ public void copyAsync(Map<VolumeInfo, DataStore> volumeDataStoreMap, VirtualMach
22112214
}
22122215
}
22132216

2217+
private void prepareDisksForMigrationForClvm(VirtualMachineTO vmTO, Map<VolumeInfo, DataStore> volumeDataStoreMap, Host srcHost) {
2218+
// For CLVM/CLVM_NG source pools, convert volumes from exclusive to shared mode
2219+
// on the source host BEFORE PrepareForMigrationCommand on the destination.
2220+
boolean hasClvmSource = volumeDataStoreMap.keySet().stream()
2221+
.map(v -> _storagePoolDao.findById(v.getPoolId()))
2222+
.anyMatch(p -> p != null && (p.getPoolType() == StoragePoolType.CLVM || p.getPoolType() == StoragePoolType.CLVM_NG));
2223+
2224+
if (hasClvmSource) {
2225+
logger.info("CLVM/CLVM_NG source pool detected for VM [{}], sending PreMigrationCommand to source host [{}] to convert volumes to shared mode.", vmTO.getName(), srcHost.getId());
2226+
PreMigrationCommand preMigCmd = new PreMigrationCommand(vmTO, vmTO.getName());
2227+
try {
2228+
Answer preMigAnswer = agentManager.send(srcHost.getId(), preMigCmd);
2229+
if (preMigAnswer == null || !preMigAnswer.getResult()) {
2230+
String details = preMigAnswer != null ? preMigAnswer.getDetails() : "null answer returned";
2231+
logger.warn("PreMigrationCommand failed for CLVM/CLVM_NG VM [{}] on source host [{}]: {}. Migration will continue but may fail if volumes are exclusively locked.", vmTO.getName(), srcHost.getId(), details);
2232+
} else {
2233+
logger.info("Successfully converted CLVM/CLVM_NG volumes to shared mode on source host [{}] for VM [{}].", srcHost.getId(), vmTO.getName());
2234+
}
2235+
} catch (Exception e) {
2236+
logger.warn("Failed to send PreMigrationCommand to source host [{}] for VM [{}]: {}. Migration will continue but may fail if volumes are exclusively locked.", srcHost.getId(), vmTO.getName(), e.getMessage());
2237+
}
2238+
}
2239+
}
2240+
22142241
private MigrationOptions.Type decideMigrationTypeAndCopyTemplateIfNeeded(Host destHost, VMInstanceVO vmInstance, VolumeInfo srcVolumeInfo, StoragePoolVO sourceStoragePool, StoragePoolVO destStoragePool, DataStore destDataStore) {
22152242
VMTemplateVO vmTemplate = _vmTemplateDao.findById(vmInstance.getTemplateId());
22162243
String srcVolumeBackingFile = getVolumeBackingFile(srcVolumeInfo);
2244+
2245+
// Check if source is CLVM/CLVM_NG (block device storage)
2246+
// LinkedClone (VIR_MIGRATE_NON_SHARED_INC) only works for file → file migrations
2247+
// For block device sources, use FullClone (VIR_MIGRATE_NON_SHARED_DISK)
2248+
boolean sourceIsBlockDevice = sourceStoragePool.getPoolType() == StoragePoolType.CLVM ||
2249+
sourceStoragePool.getPoolType() == StoragePoolType.CLVM_NG;
2250+
22172251
if (StringUtils.isNotBlank(srcVolumeBackingFile) && supportStoragePoolType(destStoragePool.getPoolType(), StoragePoolType.Filesystem) &&
2252+
!sourceIsBlockDevice &&
22182253
srcVolumeInfo.getTemplateId() != null &&
22192254
Objects.nonNull(vmTemplate) &&
22202255
!Arrays.asList(KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME, VM_IMPORT_DEFAULT_TEMPLATE_NAME).contains(vmTemplate.getName())) {
22212256
logger.debug(String.format("Copying template [%s] of volume [%s] from source storage pool [%s] to target storage pool [%s].", srcVolumeInfo.getTemplateId(), srcVolumeInfo.getId(), sourceStoragePool.getId(), destStoragePool.getId()));
22222257
copyTemplateToTargetFilesystemStorageIfNeeded(srcVolumeInfo, sourceStoragePool, destDataStore, destStoragePool, destHost);
22232258
return MigrationOptions.Type.LinkedClone;
22242259
}
2225-
logger.debug(String.format("Skipping copy template from source storage pool [%s] to target storage pool [%s] before migration due to volume [%s] does not have a " +
2226-
"template or we are doing full clone migration.", sourceStoragePool.getId(), destStoragePool.getId(), srcVolumeInfo.getId()));
2260+
2261+
if (sourceIsBlockDevice) {
2262+
logger.debug(String.format("Source storage pool [%s] is block device (CLVM/CLVM_NG). Using FullClone migration for volume [%s] to target storage pool [%s]. Template copy skipped as entire volume will be copied.", sourceStoragePool.getId(), srcVolumeInfo.getId(), destStoragePool.getId()));
2263+
} else {
2264+
logger.debug(String.format("Skipping copy template from source storage pool [%s] to target storage pool [%s] before migration due to volume [%s] does not have a template or we are doing full clone migration.", sourceStoragePool.getId(), destStoragePool.getId(), srcVolumeInfo.getId()));
2265+
}
22272266
return MigrationOptions.Type.FullClone;
22282267
}
22292268

0 commit comments

Comments
 (0)