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 c27240823b16..d74ed7dcd6cf 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 @@ protected void createStoragePoolMappingsForVolumes(VirtualMachineProfile profile 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 95362f44b138..9e54d07e9934 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 @@ -408,6 +408,9 @@ protected Answer copyVolumeBetweenPools(DataObject srcData, DataObject destData) answer = new Answer(cmd, false, errMsg); } else { answer = ep.sendMessage(cmd); + if (answer != null && answer.getResult()) { + setClvmLockHostIdIfApplicable(destData, ep); + } } return answer; } @@ -463,6 +466,7 @@ protected Answer copyVolumeBetweenPools(DataObject srcData, DataObject destData) imageStore.delete(objOnImageStore); return answer; } + setClvmLockHostIdIfApplicable(destData, ep); } catch (Exception e) { if (imageStore.exists(objOnImageStore)) { objOnImageStore.processEvent(Event.OperationFailed); @@ -486,6 +490,9 @@ protected Answer copyVolumeBetweenPools(DataObject srcData, DataObject destData) 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) { @@ -495,6 +502,17 @@ protected Answer copyVolumeBetweenPools(DataObject srcData, DataObject destData) } } + 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()) { @@ -613,6 +631,9 @@ protected Answer migrateVolumeToPool(DataObject srcData, DataObject destData) { 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 6fe4c2708c59..61ca1b7a2e3e 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 @@ -3096,6 +3096,12 @@ public boolean isLockTransferRequired(VolumeInfo volumeToAttach, StoragePoolType } 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 38af2a7550b3..8d355263a6c3 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 void testIsLockTransferRequired_NonCLVMPool() { } @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 4a93b1bce4a1..4f32762b2fb5 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 @@ -7022,7 +7022,7 @@ private static boolean isClvmVolume(DiskDef disk, VirtualMachineTO vmSpec) { 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/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 9174aaa38693..0d8b939822be 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 @@ -437,16 +437,10 @@ public void revertSnapshot(SnapshotInfo snapshot, SnapshotInfo snapshotOnPrimary 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); - } + ep = epSelector.select(volumeInfo); } if ( ep == null ){