This is an automated email from the ASF dual-hosted git repository.
weizhouapache pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push:
new 4d54125bb62 CLVM: Fix volume mapping and disk path matching for
storage migration (#13468)
4d54125bb62 is described below
commit 4d54125bb62de999cba3b3b05622a391fc564985
Author: Pearl Dsilva <[email protected]>
AuthorDate: Fri Jul 10 08:32:36 2026 -0400
CLVM: Fix volume mapping and disk path matching for storage migration
(#13468)
---
.../com/cloud/vm/VirtualMachineManagerImpl.java | 3 +-
.../storage/motion/AncientDataMotionStrategy.java | 21 ++++++++++++
.../storage/volume/VolumeServiceImpl.java | 6 ++++
.../storage/volume/VolumeServiceImplClvmTest.java | 39 ++++++++++++++++++++--
.../kvm/resource/LibvirtComputingResource.java | 2 +-
.../kvm/storage/KVMStorageProcessor.java | 6 +++-
.../CloudStackPrimaryDataStoreDriverImpl.java | 14 +++-----
7 files changed, 76 insertions(+), 15 deletions(-)
diff --git
a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
index a232bdd05da..d5f7937a463 100755
---
a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
+++
b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -3543,7 +3543,8 @@ public class VirtualMachineManagerImpl extends
ManagerBase implements VirtualMac
protected boolean shouldMapVolume(VirtualMachineProfile profile,
StoragePoolVO currentPool) {
boolean isManaged = currentPool.isManaged();
boolean isNotKvm = HypervisorType.KVM != profile.getHypervisorType();
- return isNotKvm || isManaged;
+ boolean isClvm =
ClvmPoolManager.isClvmPoolType(currentPool.getPoolType());
+ return isNotKvm || isManaged || isClvm;
}
/**
diff --git
a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
index dd54dd58005..bbf775de27a 100644
---
a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
+++
b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
@@ -445,6 +445,9 @@ public class AncientDataMotionStrategy implements
DataMotionStrategy {
answer = new Answer(cmd, false, errMsg);
} else {
answer = ep.sendMessage(cmd);
+ if (answer != null && answer.getResult()) {
+ setClvmLockHostIdIfApplicable(destData, ep);
+ }
}
return answer;
}
@@ -500,6 +503,7 @@ public class AncientDataMotionStrategy implements
DataMotionStrategy {
imageStore.delete(objOnImageStore);
return answer;
}
+ setClvmLockHostIdIfApplicable(destData, ep);
} catch (Exception e) {
if (imageStore.exists(objOnImageStore)) {
objOnImageStore.processEvent(Event.OperationFailed);
@@ -523,6 +527,9 @@ public class AncientDataMotionStrategy implements
DataMotionStrategy {
answer = new Answer(cmd, false, errMsg);
} else {
answer = ep.sendMessage(cmd);
+ if (answer != null && answer.getResult()) {
+ setClvmLockHostIdIfApplicable(destData, ep);
+ }
}
// delete volume on cache store
if (cacheData != null) {
@@ -532,6 +539,17 @@ public class AncientDataMotionStrategy implements
DataMotionStrategy {
}
}
+ private void setClvmLockHostIdIfApplicable(DataObject destData, EndPoint
ep) {
+ if (ep == null || !(destData instanceof VolumeInfo)) {
+ return;
+ }
+ VolumeInfo destVolume = (VolumeInfo) destData;
+ if (ClvmPoolManager.isClvmPoolType(destVolume.getStoragePoolType())) {
+ clvmPoolManager.setClvmLockHostId(destVolume.getId(), ep.getId());
+ logger.debug("Set CLVM lock host {} for migrated volume {}",
ep.getId(), destVolume.getUuid());
+ }
+ }
+
private boolean canBypassSecondaryStorage(DataObject srcData, DataObject
destData) {
if (srcData instanceof VolumeInfo) {
if (((VolumeInfo)srcData).isDirectDownload()) {
@@ -650,6 +668,9 @@ public class AncientDataMotionStrategy implements
DataMotionStrategy {
if (destPool.getPoolType() == StoragePoolType.CLVM) {
volumeVo.setFormat(ImageFormat.RAW);
}
+ if (ClvmPoolManager.isClvmPoolType(destPool.getPoolType())) {
+ clvmPoolManager.setClvmLockHostId(volume.getId(), ep.getId());
+ }
// For SMB, pool credentials are also stored in the uri query
string. We trim the query string
// part here to make sure the credentials do not get stored in
the db unencrypted.
String folder = destPool.getPath();
diff --git
a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
index 8a0f93fe5fc..f8d9cab56f7 100644
---
a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
+++
b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
@@ -3118,6 +3118,12 @@ public class VolumeServiceImpl implements VolumeService {
}
if (volumePoolId == null || !volumePoolId.equals(vmPoolId)) {
+ Long volumeLockHostId = findVolumeLockHost(volumeToAttach);
+ if (volumeLockHostId != null && vmHostId != null &&
!volumeLockHostId.equals(vmHostId)) {
+ logger.info("CLVM cross-pool lock transfer required: Volume {}
on pool {} lock is on host {} but VM is on host {}",
+ volumeToAttach.getUuid(), volumePoolId,
volumeLockHostId, vmHostId);
+ return true;
+ }
return false;
}
diff --git
a/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceImplClvmTest.java
b/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceImplClvmTest.java
index 38af2a7550b..8d355263a6c 100644
---
a/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceImplClvmTest.java
+++
b/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceImplClvmTest.java
@@ -167,14 +167,49 @@ public class VolumeServiceImplClvmTest {
}
@Test
- public void testIsLockTransferRequired_DifferentPools() {
+ public void
testIsLockTransferRequired_DifferentPools_LockOnDifferentHost() {
+
when(volumeService.findVolumeLockHost(volumeInfoMock)).thenReturn(HOST_ID_2);
+
+ assertTrue(volumeService.isLockTransferRequired(
+ volumeInfoMock, StoragePoolType.CLVM, StoragePoolType.CLVM,
+ POOL_ID_1, POOL_ID_2, HOST_ID_1));
+ }
+
+ @Test
+ public void testIsLockTransferRequired_DifferentPools_LockOnSameHost() {
+
when(volumeService.findVolumeLockHost(volumeInfoMock)).thenReturn(HOST_ID_1);
+
+ assertFalse(volumeService.isLockTransferRequired(
+ volumeInfoMock, StoragePoolType.CLVM, StoragePoolType.CLVM,
+ POOL_ID_1, POOL_ID_2, HOST_ID_1));
+ }
+
+ @Test
+ public void testIsLockTransferRequired_DifferentPools_NoLockHost() {
+
when(volumeService.findVolumeLockHost(volumeInfoMock)).thenReturn(null);
+
assertFalse(volumeService.isLockTransferRequired(
volumeInfoMock, StoragePoolType.CLVM, StoragePoolType.CLVM,
POOL_ID_1, POOL_ID_2, HOST_ID_1));
}
@Test
- public void testIsLockTransferRequired_NullPoolIds() {
+ public void testIsLockTransferRequired_NullPoolIds_LockOnDifferentHost() {
+
when(volumeService.findVolumeLockHost(volumeInfoMock)).thenReturn(HOST_ID_2);
+
+ assertTrue(volumeService.isLockTransferRequired(
+ volumeInfoMock, StoragePoolType.CLVM, StoragePoolType.CLVM,
+ null, POOL_ID_1, HOST_ID_1));
+
+ assertTrue(volumeService.isLockTransferRequired(
+ volumeInfoMock, StoragePoolType.CLVM, StoragePoolType.CLVM,
+ POOL_ID_1, null, HOST_ID_1));
+ }
+
+ @Test
+ public void testIsLockTransferRequired_NullPoolIds_NoLockHost() {
+
when(volumeService.findVolumeLockHost(volumeInfoMock)).thenReturn(null);
+
assertFalse(volumeService.isLockTransferRequired(
volumeInfoMock, StoragePoolType.CLVM, StoragePoolType.CLVM,
null, POOL_ID_1, HOST_ID_1));
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 41716881fa4..acc4a878dea 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -7038,7 +7038,7 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
continue;
}
VolumeObjectTO volumeTO = (VolumeObjectTO)
diskTO.getData();
- if (!diskPath.equals(volumeTO.getPath()) &&
!diskPath.equals(diskTO.getPath())) {
+ if
(!diskPath.substring(diskPath.lastIndexOf(File.separator) +
1).equals(volumeTO.getPath())) {
continue;
}
DataStoreTO dataStore = volumeTO.getDataStore();
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
index 009e1decee2..0f5c2f0913b 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
@@ -570,7 +570,11 @@ public class KVMStorageProcessor implements
StorageProcessor {
final VolumeObjectTO newVol = new VolumeObjectTO();
newVol.setPath(vol.getName());
- newVol.setSize(volume.getSize());
+ if (StoragePoolType.CLVM_NG.equals(primaryStore.getPoolType()) &&
vol != null && vol.getVirtualSize() > 0) {
+ newVol.setSize(vol.getVirtualSize());
+ } else {
+ newVol.setSize(volume.getSize());
+ }
if (vol.getQemuEncryptFormat() != null) {
newVol.setEncryptFormat(vol.getQemuEncryptFormat().toString());
}
diff --git
a/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
b/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
index 3e9fa8a5438..a12836cdb96 100644
---
a/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
+++
b/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
@@ -436,17 +436,11 @@ public class CloudStackPrimaryDataStoreDriverImpl
implements PrimaryDataStoreDri
CommandResult result = new CommandResult();
try {
EndPoint ep = null;
- VolumeInfo volumeInfo =
volFactory.getVolume(snapshot.getVolumeId(), DataStoreRole.Primary);
-
- StoragePoolVO storagePool =
primaryStoreDao.findById(volumeInfo.getPoolId());
- if (storagePool != null && storagePool.getPoolType() ==
StoragePoolType.CLVM) {
- ep = epSelector.select(volumeInfo);
+ if (snapshotOnPrimaryStore != null) {
+ ep = epSelector.select(snapshotOnPrimaryStore);
} else {
- if (snapshotOnPrimaryStore != null) {
- ep = epSelector.select(snapshotOnPrimaryStore);
- } else {
- ep = epSelector.select(volumeInfo);
- }
+ VolumeInfo volumeInfo =
volFactory.getVolume(snapshot.getVolumeId(), DataStoreRole.Primary);
+ ep = epSelector.select(volumeInfo);
}
if ( ep == null ){