Skip to content

Commit 80ca3ac

Browse files
Allow encrypted volume migration for PowerFlex volumes (#7757)
1 parent cee7a71 commit 80ca3ac

File tree

2 files changed

+58
-5
lines changed

2 files changed

+58
-5
lines changed

server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2999,6 +2999,8 @@ public Volume migrateVolume(MigrateVolumeCmd cmd) {
29992999
throw new InvalidParameterValueException("Volume cannot be migrated, please remove all VM snapshots for VM to which this volume is attached");
30003000
}
30013001

3002+
StoragePoolVO srcStoragePoolVO = _storagePoolDao.findById(vol.getPoolId());
3003+
30023004
// OfflineVmwareMigration: extract this block as method and check if it is subject to regression
30033005
if (vm != null && State.Running.equals(vm.getState())) {
30043006
// Check if the VM is GPU enabled.
@@ -3020,16 +3022,15 @@ public Volume migrateVolume(MigrateVolumeCmd cmd) {
30203022
liveMigrateVolume = capabilities.isStorageMotionSupported();
30213023
}
30223024

3023-
StoragePoolVO storagePoolVO = _storagePoolDao.findById(vol.getPoolId());
3024-
if (liveMigrateVolume && HypervisorType.KVM.equals(host.getHypervisorType()) && !storagePoolVO.getPoolType().equals(Storage.StoragePoolType.PowerFlex)) {
3025+
if (liveMigrateVolume && HypervisorType.KVM.equals(host.getHypervisorType()) && !srcStoragePoolVO.getPoolType().equals(Storage.StoragePoolType.PowerFlex)) {
30253026
StoragePoolVO destinationStoragePoolVo = _storagePoolDao.findById(storagePoolId);
30263027

3027-
if (isSourceOrDestNotOnStorPool(storagePoolVO, destinationStoragePoolVo)) {
3028+
if (isSourceOrDestNotOnStorPool(srcStoragePoolVO, destinationStoragePoolVo)) {
30283029
throw new InvalidParameterValueException("KVM does not support volume live migration due to the limited possibility to refresh VM XML domain. " +
30293030
"Therefore, to live migrate a volume between storage pools, one must migrate the VM to a different host as well to force the VM XML domain update. " +
30303031
"Use 'migrateVirtualMachineWithVolumes' instead.");
30313032
}
3032-
srcAndDestOnStorPool = isSourceAndDestOnStorPool(storagePoolVO, destinationStoragePoolVo);
3033+
srcAndDestOnStorPool = isSourceAndDestOnStorPool(srcStoragePoolVO, destinationStoragePoolVo);
30333034
}
30343035
}
30353036

@@ -3043,7 +3044,7 @@ public Volume migrateVolume(MigrateVolumeCmd cmd) {
30433044
}
30443045
}
30453046

3046-
if (vol.getPassphraseId() != null && !srcAndDestOnStorPool) {
3047+
if (vol.getPassphraseId() != null && !srcAndDestOnStorPool && !srcStoragePoolVO.getPoolType().equals(Storage.StoragePoolType.PowerFlex)) {
30473048
throw new InvalidParameterValueException("Migration of encrypted volumes is unsupported");
30483049
}
30493050

server/src/test/java/com/cloud/storage/VolumeApiServiceImplTest.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.cloud.storage;
1818

1919
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.fail;
2021
import static org.mockito.Matchers.any;
2122
import static org.mockito.Matchers.anyLong;
2223
import static org.mockito.Matchers.anyObject;
@@ -40,8 +41,11 @@
4041
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
4142
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
4243
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
44+
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
4345
import org.apache.cloudstack.context.CallContext;
4446
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
47+
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
48+
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
4549
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
4650
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
4751
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
@@ -52,6 +56,7 @@
5256
import org.apache.cloudstack.framework.jobs.AsyncJobManager;
5357
import org.apache.cloudstack.framework.jobs.dao.AsyncJobJoinMapDao;
5458
import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
59+
import org.apache.cloudstack.snapshot.SnapshotHelper;
5560
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
5661
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
5762
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@@ -114,6 +119,7 @@
114119
import com.cloud.user.User;
115120
import com.cloud.user.UserVO;
116121
import com.cloud.user.dao.AccountDao;
122+
import com.cloud.utils.exception.CloudRuntimeException;
117123
import com.cloud.utils.db.TransactionLegacy;
118124
import com.cloud.utils.fsm.NoTransitionException;
119125
import com.cloud.vm.UserVmManager;
@@ -169,6 +175,8 @@ public class VolumeApiServiceImplTest {
169175
@Mock
170176
private CreateVolumeCmd createVol;
171177
@Mock
178+
private MigrateVolumeCmd migrateVolumeCmd;
179+
@Mock
172180
private UserVmManager userVmManager;
173181
@Mock
174182
private DataCenterDao _dcDao;
@@ -188,6 +196,10 @@ public class VolumeApiServiceImplTest {
188196
private ServiceOfferingDao serviceOfferingDao;
189197
@Mock
190198
private DiskOfferingDao _diskOfferingDao;
199+
@Mock
200+
private DataStoreManager dataStoreMgr;
201+
@Mock
202+
private SnapshotHelper snapshotHelper;
191203

192204
private DetachVolumeCmd detachCmd = new DetachVolumeCmd();
193205
private Class<?> _detachCmdClass = detachCmd.getClass();
@@ -218,6 +230,9 @@ public class VolumeApiServiceImplTest {
218230
@Mock
219231
private ProjectManager projectManagerMock;
220232

233+
@Mock
234+
private StorageManager storageMgr;
235+
221236
private long accountMockId = 456l;
222237
private long volumeMockId = 12313l;
223238
private long vmInstanceMockId = 1123l;
@@ -1579,4 +1594,41 @@ public void testIsSendCommandForVmVolumeAttachDetachKVMHost() {
15791594
Mockito.when(host.getHypervisorType()).thenReturn(HypervisorType.KVM);
15801595
Assert.assertFalse(volumeApiServiceImpl.isSendCommandForVmVolumeAttachDetach(host, Mockito.mock(StoragePoolVO.class)));
15811596
}
1597+
1598+
// Below test covers both allowing encrypted volume migration for PowerFlex storage and expect error on storagepool compatibility
1599+
@Test
1600+
public void testStoragePoolCompatibilityAndAllowEncryptedVolumeMigrationForPowerFlexStorage() {
1601+
try {
1602+
Mockito.when(migrateVolumeCmd.getVolumeId()).thenReturn(1L);
1603+
Mockito.when(migrateVolumeCmd.getStoragePoolId()).thenReturn(2L);
1604+
VolumeVO vol = Mockito.mock(VolumeVO.class);
1605+
Mockito.when(volumeDaoMock.findById(1L)).thenReturn(vol);
1606+
Mockito.when(volumeDaoMock.getHypervisorType(1L)).thenReturn(HypervisorType.KVM);
1607+
Mockito.when(vol.getState()).thenReturn(Volume.State.Ready);
1608+
Mockito.when(vol.getPoolId()).thenReturn(1L);
1609+
Mockito.when(vol.getInstanceId()).thenReturn(null);
1610+
Mockito.when(vol.getDiskOfferingId()).thenReturn(1L);
1611+
DiskOfferingVO diskOffering = Mockito.mock(DiskOfferingVO.class);
1612+
Mockito.when(_diskOfferingDao.findById(1L)).thenReturn(diskOffering);
1613+
1614+
StoragePoolVO srcStoragePoolVOMock = Mockito.mock(StoragePoolVO.class);
1615+
StoragePool destPool = Mockito.mock(StoragePool.class);
1616+
PrimaryDataStore dataStore = Mockito.mock(PrimaryDataStore.class);
1617+
1618+
Mockito.when(vol.getPassphraseId()).thenReturn(1L);
1619+
Mockito.when(primaryDataStoreDaoMock.findById(1L)).thenReturn(srcStoragePoolVOMock);
1620+
Mockito.when(srcStoragePoolVOMock.getPoolType()).thenReturn(Storage.StoragePoolType.PowerFlex);
1621+
Mockito.when(dataStoreMgr.getDataStore(2L, DataStoreRole.Primary)).thenReturn( dataStore);
1622+
Mockito.doNothing().when(snapshotHelper).checkKvmVolumeSnapshotsOnlyInPrimaryStorage(vol, HypervisorType.KVM);
1623+
Mockito.when(destPool.getUuid()).thenReturn("bd525970-3d2a-4230-880d-261892129ef3");
1624+
1625+
Mockito.when(storageMgr.storagePoolCompatibleWithVolumePool(destPool, vol)).thenReturn(false);
1626+
1627+
volumeApiServiceImpl.migrateVolume(migrateVolumeCmd);
1628+
} catch (InvalidParameterValueException e) {
1629+
fail("Unexpected InvalidParameterValueException was thrown");
1630+
} catch (CloudRuntimeException e) {
1631+
// test passed
1632+
}
1633+
}
15821634
}

0 commit comments

Comments
 (0)