Skip to content

Commit 01aa259

Browse files
committed
add support to migrate to and from clvm to nfs
1 parent c0cf895 commit 01aa259

File tree

3 files changed

+62
-72
lines changed

3 files changed

+62
-72
lines changed

engine/storage/src/main/java/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import com.cloud.dc.DedicatedResourceVO;
3434
import com.cloud.dc.dao.DedicatedResourceDao;
3535
import com.cloud.storage.ClvmLockManager;
36-
import com.cloud.storage.Storage;
3736
import com.cloud.storage.VolumeDetailVO;
3837
import com.cloud.storage.dao.VolumeDetailsDao;
3938
import com.cloud.user.Account;
@@ -423,9 +422,7 @@ private EndPoint selectClvmEndpointIfApplicable(VolumeInfo volume, String operat
423422

424423
// Check if this is a CLVM pool
425424
StoragePoolVO pool = _storagePoolDao.findById(store.getId());
426-
if (pool == null ||
427-
(pool.getPoolType() != Storage.StoragePoolType.CLVM ||
428-
pool.getPoolType() != Storage.StoragePoolType.CLVM_NG)) {
425+
if (pool == null || !ClvmLockManager.isClvmPoolType(pool.getPoolType())) {
429426
return null;
430427
}
431428

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,13 @@ protected String replaceStorage(String xmlDesc, Map<String, MigrateCommand.Migra
827827
for (int z = 0; z < diskChildNodes.getLength(); z++) {
828828
Node diskChildNode = diskChildNodes.item(z);
829829

830-
if (migrateStorageManaged && "driver".equals(diskChildNode.getNodeName())) {
830+
// Update driver type for managed storage OR when migrating to CLVM
831+
// CLVM uses RAW format requiring XML driver type update
832+
// Note: CLVM_NG uses QCOW2-on-block, so no format change needed (already QCOW2)
833+
boolean shouldUpdateDriverType = migrateStorageManaged ||
834+
(migrateDiskInfo.getDestPoolType() == Storage.StoragePoolType.CLVM);
835+
836+
if (shouldUpdateDriverType && "driver".equals(diskChildNode.getNodeName())) {
831837
Node driverNode = diskChildNode;
832838

833839
NamedNodeMap driverNodeAttributes = driverNode.getAttributes();

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java

Lines changed: 54 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,8 @@ public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool,
14071407
createPhysicalDiskByQemuImg(name, pool, PhysicalDiskFormat.RAW, provisioningType, size, passphrase);
14081408
} else if (StoragePoolType.CLVM_NG.equals(poolType)) {
14091409
return createClvmNgDiskWithBacking(name, 0, size, null, pool, provisioningType);
1410+
} else if (StoragePoolType.CLVM.equals(poolType)) {
1411+
return createClvmVolume(name, size, pool);
14101412
} else if (StoragePoolType.NetworkFilesystem.equals(poolType) || StoragePoolType.Filesystem.equals(poolType)) {
14111413
switch (format) {
14121414
case QCOW2:
@@ -2207,75 +2209,23 @@ to support snapshots(backuped) as qcow2 files. */
22072209
disk.getFormat() : PhysicalDiskFormat.RAW;
22082210
String sourcePath = disk.getPath();
22092211

2210-
boolean isSourceClvm = srcPool.getType() == StoragePoolType.CLVM || srcPool.getType() == StoragePoolType.CLVM_NG;
2211-
boolean isDestClvm = destPool.getType() == StoragePoolType.CLVM || destPool.getType() == StoragePoolType.CLVM_NG;
2212-
2213-
String clvmLockVolume = null;
2214-
boolean shouldDeactivateSource = false;
2215-
2216-
try {
2217-
if (isSourceClvm) {
2218-
logger.info("Activating source CLVM volume {} in shared mode for copy", sourcePath);
2219-
LibvirtComputingResource.setClvmVolumeToSharedMode(sourcePath);
2220-
shouldDeactivateSource = !isDestClvm;
2221-
}
2222-
2223-
KVMPhysicalDisk newDisk;
2224-
logger.debug("copyPhysicalDisk: disk size:{}, virtualsize:{} format:{}", toHumanReadableSize(disk.getSize()), toHumanReadableSize(disk.getVirtualSize()), disk.getFormat());
2225-
if (destPool.getType() != StoragePoolType.RBD) {
2226-
if (disk.getFormat() == PhysicalDiskFormat.TAR) {
2227-
newDisk = destPool.createPhysicalDisk(name, PhysicalDiskFormat.DIR, Storage.ProvisioningType.THIN, disk.getVirtualSize(), null);
2228-
} else {
2229-
newDisk = destPool.createPhysicalDisk(name, Storage.ProvisioningType.THIN, disk.getVirtualSize(), null);
2230-
}
2212+
KVMPhysicalDisk newDisk;
2213+
logger.debug("copyPhysicalDisk: disk size:{}, virtualsize:{} format:{}", toHumanReadableSize(disk.getSize()), toHumanReadableSize(disk.getVirtualSize()), disk.getFormat());
2214+
if (destPool.getType() != StoragePoolType.RBD) {
2215+
if (disk.getFormat() == PhysicalDiskFormat.TAR) {
2216+
newDisk = destPool.createPhysicalDisk(name, PhysicalDiskFormat.DIR, Storage.ProvisioningType.THIN, disk.getVirtualSize(), null);
22312217
} else {
2232-
newDisk = new KVMPhysicalDisk(destPool.getSourceDir() + "/" + name, name, destPool);
2233-
newDisk.setFormat(PhysicalDiskFormat.RAW);
2234-
newDisk.setSize(disk.getVirtualSize());
2235-
newDisk.setVirtualSize(disk.getSize());
2236-
}
2237-
2238-
String destPath = newDisk.getPath();
2239-
PhysicalDiskFormat destFormat = newDisk.getFormat();
2240-
2241-
if (isDestClvm) {
2242-
logger.info("Activating destination CLVM volume {} in shared mode for copy", destPath);
2243-
LibvirtComputingResource.setClvmVolumeToSharedMode(destPath);
2244-
clvmLockVolume = destPath;
2245-
}
2246-
2247-
boolean formatConversion = sourceFormat != destFormat;
2248-
if (formatConversion) {
2249-
logger.info("Format conversion required: {} -> {}", sourceFormat, destFormat);
2250-
}
2251-
2252-
return performCopy(disk, name, destPool, timeout, srcPool, sourceFormat,
2253-
sourcePath, newDisk, destPath, destFormat, formatConversion);
2254-
2255-
} finally {
2256-
if (isSourceClvm && shouldDeactivateSource) {
2257-
try {
2258-
logger.info("Deactivating source CLVM volume {} after copy", sourcePath);
2259-
LibvirtComputingResource.deactivateClvmVolume(sourcePath);
2260-
} catch (Exception e) {
2261-
logger.warn("Failed to deactivate source CLVM volume {}: {}", sourcePath, e.getMessage());
2262-
}
2263-
}
2264-
if (isDestClvm && clvmLockVolume != null) {
2265-
try {
2266-
logger.info("Claiming exclusive lock on destination CLVM volume {} after copy", clvmLockVolume);
2267-
LibvirtComputingResource.activateClvmVolumeExclusive(clvmLockVolume);
2268-
} catch (Exception e) {
2269-
logger.warn("Failed to claim exclusive lock on destination CLVM volume {}: {}", clvmLockVolume, e.getMessage());
2270-
}
2218+
newDisk = destPool.createPhysicalDisk(name, Storage.ProvisioningType.THIN, disk.getVirtualSize(), null);
22712219
}
2220+
} else {
2221+
newDisk = new KVMPhysicalDisk(destPool.getSourceDir() + "/" + name, name, destPool);
2222+
newDisk.setFormat(PhysicalDiskFormat.RAW);
2223+
newDisk.setSize(disk.getVirtualSize());
2224+
newDisk.setVirtualSize(disk.getSize());
22722225
}
2273-
}
22742226

2275-
private KVMPhysicalDisk performCopy(KVMPhysicalDisk disk, String name, KVMStoragePool destPool, int timeout,
2276-
KVMStoragePool srcPool, PhysicalDiskFormat sourceFormat, String sourcePath,
2277-
KVMPhysicalDisk newDisk, String destPath, PhysicalDiskFormat destFormat,
2278-
boolean formatConversion) {
2227+
String destPath = newDisk.getPath();
2228+
PhysicalDiskFormat destFormat = newDisk.getFormat();
22792229

22802230
QemuImg qemu;
22812231

@@ -2376,8 +2326,8 @@ private KVMPhysicalDisk performCopy(KVMPhysicalDisk disk, String name, KVMStorag
23762326
}
23772327
} else {
23782328
/**
2379-
We let Qemu-Img do the work here. Although we could work with librbd and have that do the cloning
2380-
it doesn't benefit us. It's better to keep the current code in place which works
2329+
We let Qemu-Img do the work here. Although we could work with librbd and have that do the cloning
2330+
it doesn't benefit us. It's better to keep the current code in place which works
23812331
*/
23822332
srcFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(srcPool, sourcePath));
23832333
srcFile.setFormat(sourceFormat);
@@ -2786,4 +2736,41 @@ private void removeLvOnFailure(String lvPath, int timeout) {
27862736
lvremove.add(lvPath);
27872737
lvremove.execute();
27882738
}
2739+
2740+
/**
2741+
* Creates a raw LV volume for CLVM pools using direct LVM commands.
2742+
* This bypasses libvirt since CLVM pools are kept inactive in libvirt.
2743+
*
2744+
* @param volumeName the name of the volume to create
2745+
* @param size the size of the volume in bytes
2746+
* @param pool the CLVM storage pool
2747+
* @return the created KVMPhysicalDisk
2748+
*/
2749+
private KVMPhysicalDisk createClvmVolume(String volumeName, long size, KVMStoragePool pool) {
2750+
String vgName = getVgName(pool.getLocalPath());
2751+
String volumePath = "/dev/" + vgName + "/" + volumeName;
2752+
int timeout = 30000; // 30 seconds timeout for LV creation
2753+
2754+
logger.info("Creating CLVM volume {} in VG {} with size {} bytes", volumeName, vgName, size);
2755+
2756+
Script lvcreate = new Script("lvcreate", Duration.millis(timeout), logger);
2757+
lvcreate.add("-n", volumeName);
2758+
lvcreate.add("-L", size + "B");
2759+
lvcreate.add(vgName);
2760+
2761+
String result = lvcreate.execute();
2762+
if (result != null) {
2763+
throw new CloudRuntimeException("Failed to create CLVM volume: " + result);
2764+
}
2765+
2766+
logger.info("Successfully created CLVM volume {} at {} with size {}", volumeName, volumePath, toHumanReadableSize(size));
2767+
2768+
long actualSize = getClvmVolumeSize(volumePath);
2769+
KVMPhysicalDisk disk = new KVMPhysicalDisk(volumePath, volumeName, pool);
2770+
disk.setFormat(PhysicalDiskFormat.RAW);
2771+
disk.setSize(actualSize);
2772+
disk.setVirtualSize(actualSize);
2773+
2774+
return disk;
2775+
}
27892776
}

0 commit comments

Comments
 (0)