From 01aa259effc5fe3095af6884ab763595ae9f41c5 Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Thu, 19 Mar 2026 16:09:20 -0400 Subject: [PATCH] add support to migrate to and from clvm to nfs --- .../endpoint/DefaultEndPointSelector.java | 5 +- .../wrapper/LibvirtMigrateCommandWrapper.java | 8 +- .../kvm/storage/LibvirtStorageAdaptor.java | 121 ++++++++---------- 3 files changed, 62 insertions(+), 72 deletions(-) diff --git a/engine/storage/src/main/java/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java b/engine/storage/src/main/java/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java index 8393ec6fe63..fc2f263ee85 100644 --- a/engine/storage/src/main/java/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java +++ b/engine/storage/src/main/java/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java @@ -33,7 +33,6 @@ import javax.inject.Inject; import com.cloud.dc.DedicatedResourceVO; import com.cloud.dc.dao.DedicatedResourceDao; import com.cloud.storage.ClvmLockManager; -import com.cloud.storage.Storage; import com.cloud.storage.VolumeDetailVO; import com.cloud.storage.dao.VolumeDetailsDao; import com.cloud.user.Account; @@ -423,9 +422,7 @@ public class DefaultEndPointSelector implements EndPointSelector { // Check if this is a CLVM pool StoragePoolVO pool = _storagePoolDao.findById(store.getId()); - if (pool == null || - (pool.getPoolType() != Storage.StoragePoolType.CLVM || - pool.getPoolType() != Storage.StoragePoolType.CLVM_NG)) { + if (pool == null || !ClvmLockManager.isClvmPoolType(pool.getPoolType())) { return null; } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java index 922a13807d0..5783a71c4bd 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java @@ -827,7 +827,13 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper {}", sourceFormat, destFormat); - } - - return performCopy(disk, name, destPool, timeout, srcPool, sourceFormat, - sourcePath, newDisk, destPath, destFormat, formatConversion); - - } finally { - if (isSourceClvm && shouldDeactivateSource) { - try { - logger.info("Deactivating source CLVM volume {} after copy", sourcePath); - LibvirtComputingResource.deactivateClvmVolume(sourcePath); - } catch (Exception e) { - logger.warn("Failed to deactivate source CLVM volume {}: {}", sourcePath, e.getMessage()); - } - } - if (isDestClvm && clvmLockVolume != null) { - try { - logger.info("Claiming exclusive lock on destination CLVM volume {} after copy", clvmLockVolume); - LibvirtComputingResource.activateClvmVolumeExclusive(clvmLockVolume); - } catch (Exception e) { - logger.warn("Failed to claim exclusive lock on destination CLVM volume {}: {}", clvmLockVolume, e.getMessage()); - } + newDisk = destPool.createPhysicalDisk(name, Storage.ProvisioningType.THIN, disk.getVirtualSize(), null); } + } else { + newDisk = new KVMPhysicalDisk(destPool.getSourceDir() + "/" + name, name, destPool); + newDisk.setFormat(PhysicalDiskFormat.RAW); + newDisk.setSize(disk.getVirtualSize()); + newDisk.setVirtualSize(disk.getSize()); } - } - private KVMPhysicalDisk performCopy(KVMPhysicalDisk disk, String name, KVMStoragePool destPool, int timeout, - KVMStoragePool srcPool, PhysicalDiskFormat sourceFormat, String sourcePath, - KVMPhysicalDisk newDisk, String destPath, PhysicalDiskFormat destFormat, - boolean formatConversion) { + String destPath = newDisk.getPath(); + PhysicalDiskFormat destFormat = newDisk.getFormat(); QemuImg qemu; @@ -2376,8 +2326,8 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { } } else { /** - We let Qemu-Img do the work here. Although we could work with librbd and have that do the cloning - it doesn't benefit us. It's better to keep the current code in place which works + We let Qemu-Img do the work here. Although we could work with librbd and have that do the cloning + it doesn't benefit us. It's better to keep the current code in place which works */ srcFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(srcPool, sourcePath)); srcFile.setFormat(sourceFormat); @@ -2786,4 +2736,41 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { lvremove.add(lvPath); lvremove.execute(); } + + /** + * Creates a raw LV volume for CLVM pools using direct LVM commands. + * This bypasses libvirt since CLVM pools are kept inactive in libvirt. + * + * @param volumeName the name of the volume to create + * @param size the size of the volume in bytes + * @param pool the CLVM storage pool + * @return the created KVMPhysicalDisk + */ + private KVMPhysicalDisk createClvmVolume(String volumeName, long size, KVMStoragePool pool) { + String vgName = getVgName(pool.getLocalPath()); + String volumePath = "/dev/" + vgName + "/" + volumeName; + int timeout = 30000; // 30 seconds timeout for LV creation + + logger.info("Creating CLVM volume {} in VG {} with size {} bytes", volumeName, vgName, size); + + Script lvcreate = new Script("lvcreate", Duration.millis(timeout), logger); + lvcreate.add("-n", volumeName); + lvcreate.add("-L", size + "B"); + lvcreate.add(vgName); + + String result = lvcreate.execute(); + if (result != null) { + throw new CloudRuntimeException("Failed to create CLVM volume: " + result); + } + + logger.info("Successfully created CLVM volume {} at {} with size {}", volumeName, volumePath, toHumanReadableSize(size)); + + long actualSize = getClvmVolumeSize(volumePath); + KVMPhysicalDisk disk = new KVMPhysicalDisk(volumePath, volumeName, pool); + disk.setFormat(PhysicalDiskFormat.RAW); + disk.setSize(actualSize); + disk.setVirtualSize(actualSize); + + return disk; + } }