migrate clvm volumes as full clone and allow migration from clvm to nfs

This commit is contained in:
Pearl Dsilva 2026-03-16 16:34:33 -04:00
parent 4c34200b7a
commit 572ffeb4bd
2 changed files with 44 additions and 4 deletions

View File

@ -285,6 +285,7 @@ public class KvmNonManagedStorageDataMotionStrategy extends StorageSystemDataMot
}
protected Boolean supportStoragePoolType(StoragePoolType storagePoolType) {
return super.supportStoragePoolType(storagePoolType, StoragePoolType.Filesystem);
return super.supportStoragePoolType(storagePoolType, StoragePoolType.Filesystem,
StoragePoolType.CLVM, StoragePoolType.CLVM_NG);
}
}

View File

@ -87,6 +87,7 @@ import com.cloud.agent.api.MigrateCommand;
import com.cloud.agent.api.MigrateCommand.MigrateDiskInfo;
import com.cloud.agent.api.ModifyTargetsAnswer;
import com.cloud.agent.api.ModifyTargetsCommand;
import com.cloud.agent.api.PreMigrationCommand;
import com.cloud.agent.api.PrepareForMigrationCommand;
import com.cloud.agent.api.storage.CopyVolumeAnswer;
import com.cloud.agent.api.storage.CopyVolumeCommand;
@ -2096,7 +2097,7 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
MigrateCommand.MigrateDiskInfo migrateDiskInfo;
boolean isNonManagedToNfs = supportStoragePoolType(sourceStoragePool.getPoolType(), StoragePoolType.Filesystem) && destStoragePool.getPoolType() == StoragePoolType.NetworkFilesystem && !managedStorageDestination;
boolean isNonManagedToNfs = supportStoragePoolType(sourceStoragePool.getPoolType(), StoragePoolType.Filesystem, StoragePoolType.CLVM, StoragePoolType.CLVM_NG) && destStoragePool.getPoolType() == StoragePoolType.NetworkFilesystem && !managedStorageDestination;
if (isNonManagedToNfs) {
migrateDiskInfo = new MigrateCommand.MigrateDiskInfo(srcVolumeInfo.getPath(),
MigrateCommand.MigrateDiskInfo.DiskType.FILE,
@ -2116,6 +2117,8 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
srcVolumeInfoToDestVolumeInfo.put(srcVolumeInfo, destVolumeInfo);
}
prepareDisksForMigrationForClvm(vmTO, volumeDataStoreMap, srcHost);
PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(vmTO);
Answer pfma;
@ -2211,10 +2214,42 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
}
}
private void prepareDisksForMigrationForClvm(VirtualMachineTO vmTO, Map<VolumeInfo, DataStore> volumeDataStoreMap, Host srcHost) {
// For CLVM/CLVM_NG source pools, convert volumes from exclusive to shared mode
// on the source host BEFORE PrepareForMigrationCommand on the destination.
boolean hasClvmSource = volumeDataStoreMap.keySet().stream()
.map(v -> _storagePoolDao.findById(v.getPoolId()))
.anyMatch(p -> p != null && (p.getPoolType() == StoragePoolType.CLVM || p.getPoolType() == StoragePoolType.CLVM_NG));
if (hasClvmSource) {
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());
PreMigrationCommand preMigCmd = new PreMigrationCommand(vmTO, vmTO.getName());
try {
Answer preMigAnswer = agentManager.send(srcHost.getId(), preMigCmd);
if (preMigAnswer == null || !preMigAnswer.getResult()) {
String details = preMigAnswer != null ? preMigAnswer.getDetails() : "null answer returned";
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);
} else {
logger.info("Successfully converted CLVM/CLVM_NG volumes to shared mode on source host [{}] for VM [{}].", srcHost.getId(), vmTO.getName());
}
} catch (Exception e) {
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());
}
}
}
private MigrationOptions.Type decideMigrationTypeAndCopyTemplateIfNeeded(Host destHost, VMInstanceVO vmInstance, VolumeInfo srcVolumeInfo, StoragePoolVO sourceStoragePool, StoragePoolVO destStoragePool, DataStore destDataStore) {
VMTemplateVO vmTemplate = _vmTemplateDao.findById(vmInstance.getTemplateId());
String srcVolumeBackingFile = getVolumeBackingFile(srcVolumeInfo);
// Check if source is CLVM/CLVM_NG (block device storage)
// LinkedClone (VIR_MIGRATE_NON_SHARED_INC) only works for file file migrations
// For block device sources, use FullClone (VIR_MIGRATE_NON_SHARED_DISK)
boolean sourceIsBlockDevice = sourceStoragePool.getPoolType() == StoragePoolType.CLVM ||
sourceStoragePool.getPoolType() == StoragePoolType.CLVM_NG;
if (StringUtils.isNotBlank(srcVolumeBackingFile) && supportStoragePoolType(destStoragePool.getPoolType(), StoragePoolType.Filesystem) &&
!sourceIsBlockDevice &&
srcVolumeInfo.getTemplateId() != null &&
Objects.nonNull(vmTemplate) &&
!Arrays.asList(KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME, VM_IMPORT_DEFAULT_TEMPLATE_NAME).contains(vmTemplate.getName())) {
@ -2222,8 +2257,12 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
copyTemplateToTargetFilesystemStorageIfNeeded(srcVolumeInfo, sourceStoragePool, destDataStore, destStoragePool, destHost);
return MigrationOptions.Type.LinkedClone;
}
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()));
if (sourceIsBlockDevice) {
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()));
} else {
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()));
}
return MigrationOptions.Type.FullClone;
}