Skip to content

Commit 81bb667

Browse files
committed
add support for new gen clvm with template (qcow2) backing
1 parent d51123d commit 81bb667

File tree

17 files changed

+491
-69
lines changed

17 files changed

+491
-69
lines changed

api/src/main/java/com/cloud/storage/Storage.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ public static enum StoragePoolType {
170170
ISO(false, false, EncryptionSupport.Unsupported), // for iso image
171171
LVM(false, false, EncryptionSupport.Unsupported), // XenServer local LVM SR
172172
CLVM(true, false, EncryptionSupport.Unsupported),
173+
CLVM_NG(true, false, EncryptionSupport.Hypervisor),
173174
RBD(true, true, EncryptionSupport.Unsupported), // http://libvirt.org/storage.html#StorageBackendRBD
174175
SharedMountPoint(true, true, EncryptionSupport.Hypervisor),
175176
VMFS(true, true, EncryptionSupport.Unsupported), // VMware VMFS storage

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3382,7 +3382,7 @@ private void updateClvmLockHostForVmVolumes(long vmId, long destHostId) {
33823382

33833383
for (VolumeVO volume : volumes) {
33843384
StoragePoolVO pool = _storagePoolDao.findById(volume.getPoolId());
3385-
if (pool != null && pool.getPoolType() == Storage.StoragePoolType.CLVM) {
3385+
if (pool != null && ClvmLockManager.isClvmPoolType(pool.getPoolType())) {
33863386
clvmLockManager.setClvmLockHostId(volume.getId(), destHostId);
33873387
}
33883388
}

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ public VolumeInfo createVolume(VolumeInfo volumeInfo, VirtualMachine vm, Virtual
754754

755755
// For CLVM pools, set the lock host hint so volume is created on the correct host
756756
// This avoids the need for shared mode activation and improves performance
757-
if (pool.getPoolType() == Storage.StoragePoolType.CLVM && hostId != null) {
757+
if (ClvmLockManager.isClvmPoolType(pool.getPoolType()) && hostId != null) {
758758
logger.info("CLVM pool detected. Setting lock host {} for volume {} to route creation to correct host",
759759
hostId, volumeInfo.getUuid());
760760
volumeInfo.setDestinationHostId(hostId);
@@ -818,7 +818,7 @@ private void updateClvmLockHostAfterMigration(Volume migratedVolume, StoragePool
818818
}
819819

820820
StoragePoolVO pool = _storagePoolDao.findById(destPool.getId());
821-
if (pool == null || pool.getPoolType() != Storage.StoragePoolType.CLVM) {
821+
if (pool == null || pool.getPoolType() != Storage.StoragePoolType.CLVM || pool.getPoolType() != Storage.StoragePoolType.CLVM_NG) {
822822
return;
823823
}
824824

@@ -860,7 +860,7 @@ private Long getClvmLockHostFromVmVolumes(Long vmId) {
860860
}
861861

862862
StoragePoolVO pool = _storagePoolDao.findById(volume.getPoolId());
863-
if (pool != null && pool.getPoolType() == Storage.StoragePoolType.CLVM) {
863+
if (pool != null && ClvmLockManager.isClvmPoolType(pool.getPoolType())) {
864864
Long lockHostId = clvmLockManager.getClvmLockHostId(volume.getId(), volume.getUuid());
865865
if (lockHostId != null) {
866866
logger.debug("Found CLVM lock host {} from existing volume {} of VM {}",
@@ -884,7 +884,7 @@ private void transferClvmLocksForVmStart(List<VolumeVO> volumes, Long destHostId
884884
}
885885

886886
StoragePoolVO pool = _storagePoolDao.findById(volume.getPoolId());
887-
if (pool == null || pool.getPoolType() != Storage.StoragePoolType.CLVM) {
887+
if (pool == null || pool.getPoolType() != Storage.StoragePoolType.CLVM || pool.getPoolType() != Storage.StoragePoolType.CLVM_NG) {
888888
continue;
889889
}
890890

@@ -1324,8 +1324,8 @@ public VolumeInfo createVolumeOnPrimaryStorage(VirtualMachine vm, VolumeInfo vol
13241324
Long clusterId = storagePool.getClusterId();
13251325
logger.trace("storage-pool {}/{} is associated with cluster {}",storagePool.getName(), storagePool.getUuid(), clusterId);
13261326
Long hostId = vm.getHostId();
1327-
if (hostId == null && (storagePool.isLocal() || storagePool.getPoolType() == Storage.StoragePoolType.CLVM)) {
1328-
if (storagePool.getPoolType() == Storage.StoragePoolType.CLVM) {
1327+
if (hostId == null && (storagePool.isLocal() || ClvmLockManager.isClvmPoolType(storagePool.getPoolType()))) {
1328+
if (ClvmLockManager.isClvmPoolType(storagePool.getPoolType())) {
13291329
hostId = getClvmLockHostFromVmVolumes(vm.getId());
13301330
if (hostId != null) {
13311331
logger.debug("Using CLVM lock host {} from VM {}'s existing volumes for new volume creation",
@@ -1998,7 +1998,7 @@ private Pair<VolumeVO, DataStore> recreateVolume(VolumeVO vol, VirtualMachinePro
19981998
// For CLVM pools, set the destination host hint so volume is created on the correct host
19991999
// This avoids the need for shared mode activation and improves performance
20002000
StoragePoolVO poolVO = _storagePoolDao.findById(destPool.getId());
2001-
if (poolVO != null && poolVO.getPoolType() == Storage.StoragePoolType.CLVM) {
2001+
if (poolVO != null && ClvmLockManager.isClvmPoolType(poolVO.getPoolType())) {
20022002
Long hostId = vm.getVirtualMachine().getHostId();
20032003
if (hostId != null) {
20042004
volume.setDestinationHostId(hostId);

engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/DefaultSnapshotStrategy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ protected boolean isSnapshotStoredOnSecondaryForCLVMVolume(Snapshot snapshot, Vo
710710
}
711711

712712
StoragePool pool = (StoragePool) dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary);
713-
if (pool == null || pool.getPoolType() != StoragePoolType.CLVM) {
713+
if (pool == null || pool.getPoolType() != StoragePoolType.CLVM || pool.getPoolType() != StoragePoolType.CLVM_NG) {
714714
return false;
715715
}
716716

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
import com.cloud.dc.DedicatedResourceVO;
3434
import com.cloud.dc.dao.DedicatedResourceDao;
35+
import com.cloud.storage.ClvmLockManager;
3536
import com.cloud.storage.Storage;
3637
import com.cloud.storage.VolumeDetailVO;
3738
import com.cloud.storage.dao.VolumeDetailsDao;
@@ -273,8 +274,6 @@ public EndPoint select(DataObject srcData, DataObject destData) {
273274

274275
@Override
275276
public EndPoint select(DataObject srcData, DataObject destData, boolean volumeEncryptionSupportRequired) {
276-
// FOR CLVM: Check if destination is a volume with destinationHostId hint
277-
// This ensures template-to-volume copy is routed to the correct host for optimal lock placement
278277
if (destData instanceof VolumeInfo) {
279278
EndPoint clvmEndpoint = selectClvmEndpointIfApplicable((VolumeInfo) destData, "template-to-volume copy");
280279
if (clvmEndpoint != null) {
@@ -424,7 +423,9 @@ private EndPoint selectClvmEndpointIfApplicable(VolumeInfo volume, String operat
424423

425424
// Check if this is a CLVM pool
426425
StoragePoolVO pool = _storagePoolDao.findById(store.getId());
427-
if (pool == null || pool.getPoolType() != Storage.StoragePoolType.CLVM) {
426+
if (pool == null ||
427+
(pool.getPoolType() != Storage.StoragePoolType.CLVM ||
428+
pool.getPoolType() != Storage.StoragePoolType.CLVM_NG)) {
428429
return null;
429430
}
430431

@@ -450,7 +451,6 @@ private EndPoint selectClvmEndpointIfApplicable(VolumeInfo volume, String operat
450451
public EndPoint select(DataObject object, boolean encryptionSupportRequired) {
451452
DataStore store = object.getDataStore();
452453

453-
// For CLVM volumes with destination host hint, route to that specific host
454454
// This ensures volumes are created on the correct host with exclusive locks
455455
if (object instanceof VolumeInfo && store.getRole() == DataStoreRole.Primary) {
456456
VolumeInfo volInfo = (VolumeInfo) object;
@@ -467,6 +467,7 @@ public EndPoint select(DataObject object, boolean encryptionSupportRequired) {
467467
throw new CloudRuntimeException(String.format("Storage role %s doesn't support encryption", store.getRole()));
468468
}
469469

470+
470471
@Override
471472
public EndPoint select(DataObject object) {
472473
DataStore store = object.getDataStore();
@@ -475,7 +476,7 @@ public EndPoint select(DataObject object) {
475476
if (object instanceof VolumeInfo && store.getRole() == DataStoreRole.Primary) {
476477
VolumeInfo volume = (VolumeInfo) object;
477478
StoragePoolVO pool = _storagePoolDao.findById(store.getId());
478-
if (pool != null && pool.getPoolType() == Storage.StoragePoolType.CLVM) {
479+
if (pool != null && ClvmLockManager.isClvmPoolType(pool.getPoolType())) {
479480
Long lockHostId = getClvmLockHostId(volume);
480481
if (lockHostId != null) {
481482
logger.debug("Routing CLVM volume {} operation to lock holder host {}",
@@ -589,7 +590,7 @@ public EndPoint select(DataObject object, StorageAction action, boolean encrypti
589590
DataStore store = volume.getDataStore();
590591
if (store.getRole() == DataStoreRole.Primary) {
591592
StoragePoolVO pool = _storagePoolDao.findById(store.getId());
592-
if (pool != null && pool.getPoolType() == Storage.StoragePoolType.CLVM) {
593+
if (pool != null && ClvmLockManager.isClvmPoolType(pool.getPoolType())) {
593594
Long lockHostId = getClvmLockHostId(volume);
594595
if (lockHostId != null) {
595596
logger.info("Routing CLVM volume {} deletion to lock holder host {}",

engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import com.cloud.network.dao.NetworkVO;
3838
import com.cloud.offerings.NetworkOfferingVO;
3939
import com.cloud.offerings.dao.NetworkOfferingDao;
40+
import com.cloud.storage.ClvmLockManager;
4041
import com.cloud.storage.DataStoreRole;
4142
import com.cloud.storage.Storage;
4243
import com.cloud.storage.StorageManager;
@@ -144,7 +145,7 @@ public boolean hostConnect(long hostId, long poolId) throws StorageConflictExcep
144145
// Propagate CLVM secure zero-fill setting to the host
145146
// Note: This is done during host connection (agent start, MS restart, host reconnection)
146147
// so the setting is non-dynamic. Changes require host reconnection to take effect.
147-
if (pool.getPoolType() == Storage.StoragePoolType.CLVM) {
148+
if (ClvmLockManager.isClvmPoolType(pool.getPoolType())) {
148149
Boolean clvmSecureZeroFill = VolumeApiServiceImpl.CLVMSecureZeroFill.valueIn(poolId);
149150
if (clvmSecureZeroFill != null) {
150151
detailsMap.put("clvmsecurezerofill", String.valueOf(clvmSecureZeroFill));

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

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2484,7 +2484,8 @@ public String getResizeScriptType(final KVMStoragePool pool, final KVMPhysicalDi
24842484
} else if ((poolType == StoragePoolType.NetworkFilesystem
24852485
|| poolType == StoragePoolType.SharedMountPoint
24862486
|| poolType == StoragePoolType.Filesystem
2487-
|| poolType == StoragePoolType.Gluster)
2487+
|| poolType == StoragePoolType.Gluster
2488+
|| poolType == StoragePoolType.CLVM_NG)
24882489
&& volFormat == PhysicalDiskFormat.QCOW2 ) {
24892490
return "QCOW2";
24902491
} else if (poolType == StoragePoolType.Linstor) {
@@ -3680,13 +3681,19 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {
36803681
final String glusterVolume = pool.getSourceDir().replace("/", "");
36813682
disk.defNetworkBasedDisk(glusterVolume + path.replace(mountpoint, ""), pool.getSourceHost(), pool.getSourcePort(), null,
36823683
null, devId, diskBusType, DiskProtocol.GLUSTER, DiskDef.DiskFmtType.QCOW2);
3683-
} else if (pool.getType() == StoragePoolType.CLVM || physicalDisk.getFormat() == PhysicalDiskFormat.RAW) {
3684+
} else if (pool.getType() == StoragePoolType.CLVM || pool.getType() == StoragePoolType.CLVM_NG || physicalDisk.getFormat() == PhysicalDiskFormat.RAW) {
3685+
// CLVM and CLVM_NG use block devices (/dev/vgname/volume)
36843686
if (volume.getType() == Volume.Type.DATADISK && !(isWindowsTemplate && isUefiEnabled)) {
36853687
disk.defBlockBasedDisk(physicalDisk.getPath(), devId, diskBusTypeData);
3686-
}
3687-
else {
3688+
} else {
36883689
disk.defBlockBasedDisk(physicalDisk.getPath(), devId, diskBusType);
36893690
}
3691+
3692+
// CLVM_NG uses QCOW2 format on block devices, override the default RAW format
3693+
if (pool.getType() == StoragePoolType.CLVM_NG) {
3694+
disk.setDiskFormatType(DiskDef.DiskFmtType.QCOW2);
3695+
}
3696+
36903697
if (pool.getType() == StoragePoolType.Linstor && isQemuDiscardBugFree(diskBusType)) {
36913698
disk.setDiscard(DiscardType.UNMAP);
36923699
}
@@ -6566,21 +6573,7 @@ public static void modifyClvmVolumesStateForMigration(List<DiskDef> disks, Libvi
65666573
if (isClvmVolume(disk, resource, vmSpec)) {
65676574
String volumePath = disk.getDiskPath();
65686575
try {
6569-
LOGGER.info("[CLVM Migration] {} for volume [{}]",
6570-
state.getLogMessage(), volumePath);
6571-
6572-
Script cmd = new Script("lvchange", Duration.standardSeconds(300), LOGGER);
6573-
cmd.add(state.getLvchangeFlag());
6574-
cmd.add(volumePath);
6575-
6576-
String result = cmd.execute();
6577-
if (result != null) {
6578-
LOGGER.error("[CLVM Migration] Failed to set volume [{}] to {} state. Command result: {}",
6579-
volumePath, state.getDescription(), result);
6580-
} else {
6581-
LOGGER.info("[CLVM Migration] Successfully set volume [{}] to {} state.",
6582-
volumePath, state.getDescription());
6583-
}
6576+
modifyClvmVolumeState(volumePath, state.getLvchangeFlag(), state.getDescription(), state.getLogMessage());
65846577
} catch (Exception e) {
65856578
LOGGER.error("[CLVM Migration] Exception while setting volume [{}] to {} state: {}",
65866579
volumePath, state.getDescription(), e.getMessage(), e);
@@ -6589,6 +6582,53 @@ public static void modifyClvmVolumesStateForMigration(List<DiskDef> disks, Libvi
65896582
}
65906583
}
65916584

6585+
private static void modifyClvmVolumeState(String volumePath, String lvchangeFlag,
6586+
String stateDescription, String logMessage) {
6587+
try {
6588+
LOGGER.info("[CLVM Migration] {} for volume [{}]", logMessage, volumePath);
6589+
6590+
Script cmd = new Script("lvchange", Duration.standardSeconds(300), LOGGER);
6591+
cmd.add(lvchangeFlag);
6592+
cmd.add(volumePath);
6593+
6594+
String result = cmd.execute();
6595+
if (result != null) {
6596+
String errorMsg = String.format(
6597+
"[CLVM Migration] Failed to set volume [%s] to %s state. Command result: %s",
6598+
volumePath, stateDescription, result);
6599+
LOGGER.error(errorMsg);
6600+
throw new CloudRuntimeException(errorMsg);
6601+
} else {
6602+
LOGGER.info("[CLVM Migration] Successfully set volume [{}] to {} state.",
6603+
volumePath, stateDescription);
6604+
}
6605+
} catch (CloudRuntimeException e) {
6606+
throw e;
6607+
} catch (Exception e) {
6608+
String errorMsg = String.format(
6609+
"[CLVM Migration] Exception while setting volume [%s] to %s state: %s",
6610+
volumePath, stateDescription, e.getMessage());
6611+
LOGGER.error(errorMsg, e);
6612+
throw new CloudRuntimeException(errorMsg, e);
6613+
}
6614+
}
6615+
6616+
public static void activateClvmVolumeExclusive(String volumePath) {
6617+
modifyClvmVolumeState(volumePath, ClvmVolumeState.EXCLUSIVE.getLvchangeFlag(),
6618+
ClvmVolumeState.EXCLUSIVE.getDescription(),
6619+
"Activating CLVM volume in exclusive mode for copy");
6620+
}
6621+
6622+
public static void deactivateClvmVolume(String volumePath) {
6623+
try {
6624+
modifyClvmVolumeState(volumePath, ClvmVolumeState.DEACTIVATE.getLvchangeFlag(),
6625+
ClvmVolumeState.DEACTIVATE.getDescription(),
6626+
"Deactivating CLVM volume after copy");
6627+
} catch (Exception e) {
6628+
LOGGER.warn("Failed to deactivate CLVM volume {}: {}", volumePath, e.getMessage());
6629+
}
6630+
}
6631+
65926632
/**
65936633
* Determines if a disk is on a CLVM storage pool by checking the actual pool type from VirtualMachineTO.
65946634
* This is the most reliable method as it uses CloudStack's own storage pool information.
@@ -6613,8 +6653,9 @@ private static boolean isClvmVolume(DiskDef disk, LibvirtComputingResource resou
66136653
DataStoreTO dataStore = volumeTO.getDataStore();
66146654
if (dataStore instanceof PrimaryDataStoreTO) {
66156655
PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO) dataStore;
6616-
boolean isClvm = StoragePoolType.CLVM == primaryStore.getPoolType();
6617-
LOGGER.debug("Disk {} identified as CLVM={} via VirtualMachineTO pool type: {}",
6656+
boolean isClvm = StoragePoolType.CLVM == primaryStore.getPoolType() ||
6657+
StoragePoolType.CLVM_NG == primaryStore.getPoolType();
6658+
LOGGER.debug("Disk {} identified as CLVM/CLVM_NG={} via VirtualMachineTO pool type: {}",
66186659
diskPath, isClvm, primaryStore.getPoolType());
66196660
return isClvm;
66206661
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ public Answer execute(final ResizeVolumeCommand command, final LibvirtComputingR
113113
logger.debug("Resizing volume: " + path + ", from: " + toHumanReadableSize(currentSize) + ", to: " + toHumanReadableSize(newSize) + ", type: " + type + ", name: " + vmInstanceName + ", shrinkOk: " + shrinkOk);
114114

115115
/* libvirt doesn't support resizing (C)LVM devices, and corrupts QCOW2 in some scenarios, so we have to do these via qemu-img */
116-
if (pool.getType() != StoragePoolType.CLVM && pool.getType() != StoragePoolType.Linstor && pool.getType() != StoragePoolType.PowerFlex
116+
if (pool.getType() != StoragePoolType.CLVM && pool.getType() != StoragePoolType.CLVM_NG
117+
&& pool.getType() != StoragePoolType.Linstor && pool.getType() != StoragePoolType.PowerFlex
117118
&& vol.getFormat() != PhysicalDiskFormat.QCOW2) {
118119
logger.debug("Volume " + path + " can be resized by libvirt. Asking libvirt to resize the volume.");
119120
try {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public Answer execute(final RevertSnapshotCommand command, final LibvirtComputin
117117
secondaryStoragePool = storagePoolMgr.getStoragePoolByURI(snapshotImageStore.getUrl());
118118
}
119119

120-
if (primaryPool.getType() == StoragePoolType.CLVM) {
120+
if (primaryPool.getType() == StoragePoolType.CLVM || primaryPool.getType() == StoragePoolType.CLVM_NG) {
121121
Script cmd = new Script(libvirtComputingResource.manageSnapshotPath(), libvirtComputingResource.getCmdsTimeout(), logger);
122122
cmd.add("-v", getFullPathAccordingToStorage(secondaryStoragePool, snapshotRelPath));
123123
cmd.add("-n", snapshotDisk.getName());

0 commit comments

Comments
 (0)