CLVM: Fix volume mapping and disk path matching for storage migration (#13468)

This commit is contained in:
Pearl Dsilva 2026-07-10 08:32:36 -04:00 committed by GitHub
parent 4816e05938
commit 4d54125bb6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 76 additions and 15 deletions

View File

@ -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;
}
/**

View File

@ -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();

View File

@ -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;
}

View File

@ -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_NullPoolIds() {
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_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));

View File

@ -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();

View File

@ -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());
}

View File

@ -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 ){