This is an automated email from the ASF dual-hosted git repository. dahn pushed a commit to branch revert-10267-fix-volattach-uploaded in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 56e173b8f16df5dc1d33a7aa4774c4b5c5212251 Author: dahn <daan.hoogl...@gmail.com> AuthorDate: Tue Feb 4 11:02:58 2025 +0100 Revert "server: fix attach uploaded volume (#10267)" This reverts commit 1c84ce4e23e3fd243022c6c533fc14c10439c6f3. --- .../com/cloud/storage/VolumeApiServiceImpl.java | 123 ++++------ .../cloud/storage/VolumeApiServiceImplTest.java | 249 --------------------- 2 files changed, 42 insertions(+), 330 deletions(-) diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index 68546f185b7..7f867eb01a9 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -133,9 +133,7 @@ import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.Pod; -import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; -import com.cloud.dc.dao.HostPodDao; import com.cloud.domain.Domain; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; @@ -155,7 +153,6 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorCapabilitiesVO; import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.offering.DiskOffering; -import com.cloud.org.Cluster; import com.cloud.org.Grouping; import com.cloud.projects.Project; import com.cloud.projects.ProjectManager; @@ -326,8 +323,6 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic @Inject private VmWorkJobDao _workJobDao; @Inject - ClusterDao clusterDao; - @Inject private ClusterDetailsDao _clusterDetailsDao; @Inject private StorageManager storageMgr; @@ -351,8 +346,6 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic protected ProjectManager projectManager; @Inject protected StoragePoolDetailsDao storagePoolDetailsDao; - @Inject - HostPodDao podDao; protected Gson _gson; @@ -2387,10 +2380,17 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic return attachVolumeToVM(command.getVirtualMachineId(), command.getId(), command.getDeviceId()); } - protected VolumeVO getVmExistingVolumeForVolumeAttach(UserVmVO vm, VolumeInfo volumeToAttach) { + private Volume orchestrateAttachVolumeToVM(Long vmId, Long volumeId, Long deviceId) { + VolumeInfo volumeToAttach = volFactory.getVolume(volumeId); + + if (volumeToAttach.isAttachedVM()) { + throw new CloudRuntimeException("This volume is already attached to a VM."); + } + + UserVmVO vm = _userVmDao.findById(vmId); VolumeVO existingVolumeOfVm = null; VMTemplateVO template = _templateDao.findById(vm.getTemplateId()); - List<VolumeVO> rootVolumesOfVm = _volsDao.findByInstanceAndType(vm.getId(), Volume.Type.ROOT); + List<VolumeVO> rootVolumesOfVm = _volsDao.findByInstanceAndType(vmId, Volume.Type.ROOT); if (rootVolumesOfVm.size() > 1 && template != null && !template.isDeployAsIs()) { throw new CloudRuntimeException("The VM " + vm.getHostName() + " has more than one ROOT volume and is in an invalid state."); } else { @@ -2398,7 +2398,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic existingVolumeOfVm = rootVolumesOfVm.get(0); } else { // locate data volume of the vm - List<VolumeVO> diskVolumesOfVm = _volsDao.findByInstanceAndType(vm.getId(), Volume.Type.DATADISK); + List<VolumeVO> diskVolumesOfVm = _volsDao.findByInstanceAndType(vmId, Volume.Type.DATADISK); for (VolumeVO diskVolume : diskVolumesOfVm) { if (diskVolume.getState() != Volume.State.Allocated) { existingVolumeOfVm = diskVolume; @@ -2407,89 +2407,45 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic } } } - if (existingVolumeOfVm == null) { - if (s_logger.isTraceEnabled()) { - s_logger.trace(String.format("No existing volume found for VM (%s/%s) to attach volume %s/%s", + if (s_logger.isTraceEnabled()) { + String msg = "attaching volume %s/%s to a VM (%s/%s) with an existing volume %s/%s on primary storage %s"; + if (existingVolumeOfVm != null) { + s_logger.trace(String.format(msg, + volumeToAttach.getName(), volumeToAttach.getUuid(), vm.getName(), vm.getUuid(), - volumeToAttach.getName(), volumeToAttach.getUuid())); + existingVolumeOfVm.getName(), existingVolumeOfVm.getUuid(), + existingVolumeOfVm.getPoolId())); } - return null; } - if (s_logger.isTraceEnabled()) { - String msg = "attaching volume %s/%s to a VM (%s/%s) with an existing volume %s/%s on primary storage %s"; - s_logger.trace(String.format(msg, - volumeToAttach.getName(), volumeToAttach.getUuid(), - vm.getName(), vm.getUuid(), - existingVolumeOfVm.getName(), existingVolumeOfVm.getUuid(), - existingVolumeOfVm.getPoolId())); - } - return existingVolumeOfVm; - } - - protected StoragePool getPoolForAllocatedOrUploadedVolumeForAttach(final VolumeInfo volumeToAttach, final UserVmVO vm) { - DataCenter zone = _dcDao.findById(vm.getDataCenterId()); - Pair<Long, Long> clusterHostId = virtualMachineManager.findClusterAndHostIdForVm(vm, false); - long podId = vm.getPodIdToDeployIn(); - if (clusterHostId.first() != null) { - Cluster cluster = clusterDao.findById(clusterHostId.first()); - podId = cluster.getPodId(); - } - Pod pod = podDao.findById(podId); - DiskOfferingVO offering = _diskOfferingDao.findById(volumeToAttach.getDiskOfferingId()); - DiskProfile diskProfile = new DiskProfile(volumeToAttach.getId(), volumeToAttach.getVolumeType(), - volumeToAttach.getName(), volumeToAttach.getId(), volumeToAttach.getSize(), offering.getTagsArray(), - offering.isUseLocalStorage(), offering.isRecreatable(), - volumeToAttach.getTemplateId()); - diskProfile.setHyperType(vm.getHypervisorType()); - StoragePool pool = _volumeMgr.findStoragePool(diskProfile, zone, pod, clusterHostId.first(), - clusterHostId.second(), vm, Collections.emptySet()); - if (pool == null) { - throw new CloudRuntimeException(String.format("Failed to find a primary storage for volume in state: %s", volumeToAttach.getState())); - } - return pool; - } - - protected VolumeInfo createVolumeOnPrimaryForAttachIfNeeded(final VolumeInfo volumeToAttach, final UserVmVO vm, VolumeVO existingVolumeOfVm) { + + HypervisorType rootDiskHyperType = vm.getHypervisorType(); + HypervisorType volumeToAttachHyperType = _volsDao.getHypervisorType(volumeToAttach.getId()); + VolumeInfo newVolumeOnPrimaryStorage = volumeToAttach; - boolean volumeOnSecondary = volumeToAttach.getState() == Volume.State.Uploaded; - if (!Arrays.asList(Volume.State.Allocated, Volume.State.Uploaded).contains(volumeToAttach.getState())) { - return newVolumeOnPrimaryStorage; - } + //don't create volume on primary storage if its being attached to the vm which Root's volume hasn't been created yet - StoragePool destPrimaryStorage = null; + StoragePoolVO destPrimaryStorage = null; if (existingVolumeOfVm != null && !existingVolumeOfVm.getState().equals(Volume.State.Allocated)) { destPrimaryStorage = _storagePoolDao.findById(existingVolumeOfVm.getPoolId()); if (s_logger.isTraceEnabled() && destPrimaryStorage != null) { s_logger.trace(String.format("decided on target storage: %s/%s", destPrimaryStorage.getName(), destPrimaryStorage.getUuid())); } } - if (destPrimaryStorage == null) { - destPrimaryStorage = getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); - } - try { - if (volumeOnSecondary && Storage.StoragePoolType.PowerFlex.equals(destPrimaryStorage.getPoolType())) { - throw new InvalidParameterValueException("Cannot attach uploaded volume, this operation is unsupported on storage pool type " + destPrimaryStorage.getPoolType()); - } - newVolumeOnPrimaryStorage = _volumeMgr.createVolumeOnPrimaryStorage(vm, volumeToAttach, - vm.getHypervisorType(), destPrimaryStorage); - } catch (NoTransitionException e) { - s_logger.debug("Failed to create volume on primary storage", e); - throw new CloudRuntimeException("Failed to create volume on primary storage", e); - } - return newVolumeOnPrimaryStorage; - } - private Volume orchestrateAttachVolumeToVM(Long vmId, Long volumeId, Long deviceId) { - VolumeInfo volumeToAttach = volFactory.getVolume(volumeId); + boolean volumeOnSecondary = volumeToAttach.getState() == Volume.State.Uploaded; - if (volumeToAttach.isAttachedVM()) { - throw new CloudRuntimeException("This volume is already attached to a VM."); + if (destPrimaryStorage != null && (volumeToAttach.getState() == Volume.State.Allocated || volumeOnSecondary)) { + try { + if (volumeOnSecondary && destPrimaryStorage.getPoolType() == Storage.StoragePoolType.PowerFlex) { + throw new InvalidParameterValueException("Cannot attach uploaded volume, this operation is unsupported on storage pool type " + destPrimaryStorage.getPoolType()); + } + newVolumeOnPrimaryStorage = _volumeMgr.createVolumeOnPrimaryStorage(vm, volumeToAttach, rootDiskHyperType, destPrimaryStorage); + } catch (NoTransitionException e) { + s_logger.debug("Failed to create volume on primary storage", e); + throw new CloudRuntimeException("Failed to create volume on primary storage", e); + } } - UserVmVO vm = _userVmDao.findById(vmId); - VolumeVO existingVolumeOfVm = getVmExistingVolumeForVolumeAttach(vm, volumeToAttach); - VolumeInfo newVolumeOnPrimaryStorage = createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, existingVolumeOfVm); - // reload the volume from db newVolumeOnPrimaryStorage = volFactory.getVolume(newVolumeOnPrimaryStorage.getId()); boolean moveVolumeNeeded = needMoveVolume(existingVolumeOfVm, newVolumeOnPrimaryStorage); @@ -2507,17 +2463,19 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic StoragePoolVO vmRootVolumePool = _storagePoolDao.findById(existingVolumeOfVm.getPoolId()); try { - HypervisorType volumeToAttachHyperType = _volsDao.getHypervisorType(volumeToAttach.getId()); newVolumeOnPrimaryStorage = _volumeMgr.moveVolume(newVolumeOnPrimaryStorage, vmRootVolumePool.getDataCenterId(), vmRootVolumePool.getPodId(), vmRootVolumePool.getClusterId(), volumeToAttachHyperType); - } catch (ConcurrentOperationException | StorageUnavailableException e) { + } catch (ConcurrentOperationException e) { + s_logger.debug("move volume failed", e); + throw new CloudRuntimeException("move volume failed", e); + } catch (StorageUnavailableException e) { s_logger.debug("move volume failed", e); throw new CloudRuntimeException("move volume failed", e); } } VolumeVO newVol = _volsDao.findById(newVolumeOnPrimaryStorage.getId()); // Getting the fresh vm object in case of volume migration to check the current state of VM - if (moveVolumeNeeded) { + if (moveVolumeNeeded || volumeOnSecondary) { vm = _userVmDao.findById(vmId); if (vm == null) { throw new InvalidParameterValueException("VM not found."); @@ -2701,6 +2659,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic if (!_volsDao.findByInstanceAndDeviceId(vm.getId(), 0).isEmpty()) { throw new InvalidParameterValueException("Vm already has root volume attached to it"); } + if (volumeToAttach.getState() == Volume.State.Uploaded) { + throw new InvalidParameterValueException("No support for Root volume attach in state " + Volume.State.Uploaded); + } } } diff --git a/server/src/test/java/com/cloud/storage/VolumeApiServiceImplTest.java b/server/src/test/java/com/cloud/storage/VolumeApiServiceImplTest.java index 3e6f9ec63f9..a0f89956df5 100644 --- a/server/src/test/java/com/cloud/storage/VolumeApiServiceImplTest.java +++ b/server/src/test/java/com/cloud/storage/VolumeApiServiceImplTest.java @@ -45,7 +45,6 @@ import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd; import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; @@ -87,12 +86,8 @@ import org.springframework.test.util.ReflectionTestUtils; import com.cloud.api.query.dao.ServiceOfferingJoinDao; import com.cloud.configuration.Resource; import com.cloud.configuration.Resource.ResourceType; -import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenterVO; -import com.cloud.dc.HostPodVO; -import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; -import com.cloud.dc.dao.HostPodDao; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; import com.cloud.exception.InvalidParameterValueException; @@ -127,12 +122,10 @@ import com.cloud.utils.Pair; import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; -import com.cloud.vm.DiskProfile; import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; -import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.snapshot.VMSnapshotVO; @@ -206,15 +199,6 @@ public class VolumeApiServiceImplTest { private DataStoreManager dataStoreMgr; @Mock private SnapshotHelper snapshotHelper; - @Mock - VirtualMachineManager virtualMachineManager; - @Mock - HostPodDao podDao; - @Mock - ClusterDao clusterDao; - @Mock - VolumeOrchestrationService volumeOrchestrationService; - private DetachVolumeCmd detachCmd = new DetachVolumeCmd(); private Class<?> _detachCmdClass = detachCmd.getClass(); @@ -1836,237 +1820,4 @@ public class VolumeApiServiceImplTest { volumeApiServiceImpl.validationsForCheckVolumeOperation(volume); } - - private UserVmVO getMockedVm() { - UserVmVO vm = Mockito.mock(UserVmVO.class); - Mockito.when(vm.getId()).thenReturn(1L); - Mockito.when(vm.getTemplateId()).thenReturn(10L); - Mockito.when(vm.getHostName()).thenReturn("test-vm"); - return vm; - } - - private VMTemplateVO getMockedTemplate() { - VMTemplateVO template = Mockito.mock(VMTemplateVO.class); - Mockito.when(template.isDeployAsIs()).thenReturn(false); - return template; - } - - @Test(expected = CloudRuntimeException.class) - public void testGetVmExistingVolumeForVolumeAttach_MultipleRootVolumes_ThrowsException() { - UserVmVO vm = getMockedVm(); - VMTemplateVO template = getMockedTemplate(); - when(templateDao.findById(10L)).thenReturn(template); - when(volumeDaoMock.findByInstanceAndType(1L, Volume.Type.ROOT)) - .thenReturn(Arrays.asList(Mockito.mock(VolumeVO.class), Mockito.mock(VolumeVO.class))); - volumeApiServiceImpl.getVmExistingVolumeForVolumeAttach(vm, Mockito.mock(VolumeInfo.class)); - } - - @Test - public void testGetVmExistingVolumeForVolumeAttach_SingleRootVolume() { - UserVmVO vm = getMockedVm(); - VMTemplateVO template = getMockedTemplate(); - VolumeVO rootVolume = Mockito.mock(VolumeVO.class); - Mockito.when(rootVolume.getId()).thenReturn(20L); - Mockito.when(templateDao.findById(10L)).thenReturn(template); - Mockito.when(volumeDaoMock.findByInstanceAndType(1L, Volume.Type.ROOT)) - .thenReturn(Collections.singletonList(rootVolume)); - VolumeVO result = volumeApiServiceImpl.getVmExistingVolumeForVolumeAttach(vm, Mockito.mock(VolumeInfo.class)); - Assert.assertNotNull(result); - Assert.assertEquals(20L, result.getId()); - } - - private VolumeVO getMockedDataVolume() { - VolumeVO volume = Mockito.mock(VolumeVO.class); - Mockito.when(volume.getId()).thenReturn(30L); - Mockito.when(volume.getState()).thenReturn(Volume.State.Ready); - return volume; - } - - @Test - public void testGetVmExistingVolumeForVolumeAttach_NoRootVolume_DataDiskAvailable() { - UserVmVO vm = getMockedVm(); - VMTemplateVO template = getMockedTemplate(); - VolumeVO dataDisk = getMockedDataVolume(); - List<VolumeVO> rootVolumes = Collections.emptyList(); - List<VolumeVO> dataVolumes = Collections.singletonList(dataDisk); - Mockito.when(templateDao.findById(10L)).thenReturn(template); - Mockito.when(volumeDaoMock.findByInstanceAndType(1L, Volume.Type.ROOT)).thenReturn(rootVolumes); - Mockito.when(volumeDaoMock.findByInstanceAndType(1L, Volume.Type.DATADISK)).thenReturn(dataVolumes); - VolumeVO result = volumeApiServiceImpl.getVmExistingVolumeForVolumeAttach(vm, Mockito.mock(VolumeInfo.class)); - Assert.assertNotNull(result); - Assert.assertEquals(30L, result.getId()); - } - - @Test - public void testGetVmExistingVolumeForVolumeAttach_NoVolumesAtAll() { - UserVmVO vm = getMockedVm(); - VMTemplateVO template = getMockedTemplate(); - Mockito.when(templateDao.findById(10L)).thenReturn(template); - Mockito.when(volumeDaoMock.findByInstanceAndType(1L, Volume.Type.ROOT)).thenReturn(Collections.emptyList()); - Mockito.when(volumeDaoMock.findByInstanceAndType(1L, Volume.Type.DATADISK)).thenReturn(Collections.emptyList()); - VolumeVO result = volumeApiServiceImpl.getVmExistingVolumeForVolumeAttach(vm, Mockito.mock(VolumeInfo.class)); - Assert.assertNull(result); - } - - private void mockDiskOffering() { - DiskOfferingVO offering = Mockito.mock(DiskOfferingVO.class); - Mockito.when(_diskOfferingDao.findById(1L)).thenReturn(offering); - Mockito.when(offering.isUseLocalStorage()).thenReturn(true); - Mockito.when(offering.isRecreatable()).thenReturn(false); - } - - private DataCenterVO mockZone() { - DataCenterVO zone = Mockito.mock(DataCenterVO.class); - Mockito.when(_dcDao.findById(1L)).thenReturn(zone); - return zone; - } - - @Test - public void testGetPoolForAllocatedOrUploadedVolumeForAttach_Success() { - VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class); - UserVmVO vm = Mockito.mock(UserVmVO.class); - ClusterVO cluster = Mockito.mock(ClusterVO.class); - HostPodVO pod = Mockito.mock(HostPodVO.class); - DataCenterVO zone = mockZone(); - mockDiskOffering(); - StoragePool pool = Mockito.mock(StoragePool.class); - when(vm.getDataCenterId()).thenReturn(1L); - when(virtualMachineManager.findClusterAndHostIdForVm(vm, false)).thenReturn(new Pair<>(1L, 2L)); - when(clusterDao.findById(1L)).thenReturn(cluster); - when(cluster.getPodId()).thenReturn(1L); - when(podDao.findById(1L)).thenReturn(pod); - when(volumeToAttach.getDiskOfferingId()).thenReturn(1L); - when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(1L), eq(2L), eq(vm), eq(Collections.emptySet()))) - .thenReturn(pool); - StoragePool result = volumeApiServiceImpl.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); - Assert.assertNotNull(result); - Assert.assertEquals(pool, result); - } - - @Test(expected = CloudRuntimeException.class) - public void testGetPoolForAllocatedOrUploadedVolumeForAttach_NoPoolFound_ThrowsException() { - VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class); - UserVmVO vm = Mockito.mock(UserVmVO.class); - DataCenterVO zone = mockZone(); - Pair<Long, Long> clusterHostId = new Pair<>(1L, 2L); - ClusterVO cluster = Mockito.mock(ClusterVO.class); - HostPodVO pod = Mockito.mock(HostPodVO.class); - mockDiskOffering(); - when(vm.getDataCenterId()).thenReturn(1L); - when(clusterDao.findById(1L)).thenReturn(cluster); - when(virtualMachineManager.findClusterAndHostIdForVm(vm, false)).thenReturn(clusterHostId); - when(podDao.findById(anyLong())).thenReturn(pod); - when(volumeToAttach.getDiskOfferingId()).thenReturn(1L); - when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(1L), eq(2L), eq(vm), eq(Collections.emptySet()))) - .thenReturn(null); - volumeApiServiceImpl.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); - } - - @Test - public void testGetPoolForAllocatedOrUploadedVolumeForAttach_NoCluster() { - VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class); - UserVmVO vm = Mockito.mock(UserVmVO.class); - DataCenterVO zone = mockZone(); - HostPodVO pod = Mockito.mock(HostPodVO.class); - mockDiskOffering(); - StoragePool pool = Mockito.mock(StoragePool.class); - when(vm.getDataCenterId()).thenReturn(1L); - when(vm.getPodIdToDeployIn()).thenReturn(2L); - when(virtualMachineManager.findClusterAndHostIdForVm(vm, false)).thenReturn(new Pair<>(null, 2L)); - when(podDao.findById(2L)).thenReturn(pod); - when(volumeToAttach.getDiskOfferingId()).thenReturn(1L); - when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(null), eq(2L), eq(vm), eq(Collections.emptySet()))) - .thenReturn(pool); - StoragePool result = volumeApiServiceImpl.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); - Assert.assertNotNull(result); - Assert.assertEquals(pool, result); - } - - - @Test - public void testCreateVolumeOnSecondaryForAttachIfNeeded_VolumeNotAllocatedOrUploaded() { - VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class); - Mockito.when(volumeToAttach.getState()).thenReturn(Volume.State.Ready); - VolumeInfo result = volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded( - volumeToAttach, Mockito.mock(UserVmVO.class), null); - Assert.assertSame(volumeToAttach, result); - Mockito.verifyNoInteractions(primaryDataStoreDaoMock, volumeOrchestrationService); - } - - @Test - public void testCreateVolumeOnSecondaryForAttachIfNeeded_ExistingVolumeDeterminesStoragePool() { - VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class); - Mockito.when(volumeToAttach.getState()).thenReturn(Volume.State.Uploaded); - UserVmVO vm = Mockito.mock(UserVmVO.class); - VolumeVO existingVolume = Mockito.mock(VolumeVO.class); - Mockito.when(existingVolume.getState()).thenReturn(Volume.State.Ready); - when(existingVolume.getPoolId()).thenReturn(1L); - StoragePoolVO destPrimaryStorage = Mockito.mock(StoragePoolVO.class); - Mockito.when(destPrimaryStorage.getPoolType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem); - Mockito.when(primaryDataStoreDaoMock.findById(1L)).thenReturn(destPrimaryStorage); - VolumeInfo newVolumeOnPrimaryStorage = Mockito.mock(VolumeInfo.class); - try { - Mockito.when(volumeOrchestrationService.createVolumeOnPrimaryStorage(vm, volumeToAttach, vm.getHypervisorType(), destPrimaryStorage)) - .thenReturn(newVolumeOnPrimaryStorage); - } catch (NoTransitionException nte) { - Assert.fail(nte.getMessage()); - } - VolumeInfo result = volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, existingVolume); - Assert.assertSame(newVolumeOnPrimaryStorage, result); - Mockito.verify(primaryDataStoreDaoMock).findById(1L); - } - - @Test - public void testCreateVolumeOnPrimaryForAttachIfNeeded_UsesGetPoolForAttach() { - VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class); - Mockito.when(volumeToAttach.getState()).thenReturn(Volume.State.Allocated); - UserVmVO vm = Mockito.mock(UserVmVO.class); - StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class); - Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl) - .getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); - VolumeInfo newVolumeOnPrimaryStorage = Mockito.mock(VolumeInfo.class); - try { - Mockito.when(volumeOrchestrationService.createVolumeOnPrimaryStorage( - vm, volumeToAttach, vm.getHypervisorType(), destPrimaryStorage)) - .thenReturn(newVolumeOnPrimaryStorage); - } catch (NoTransitionException nte) { - Assert.fail(nte.getMessage()); - } - VolumeInfo result = volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null); - Assert.assertSame(newVolumeOnPrimaryStorage, result); - verify(volumeApiServiceImpl).getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); - } - - @Test(expected = InvalidParameterValueException.class) - public void testCreateVolumeOnPrimaryForAttachIfNeeded_UnsupportedPoolType_ThrowsException() { - VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class); - when(volumeToAttach.getState()).thenReturn(Volume.State.Uploaded); - UserVmVO vm = Mockito.mock(UserVmVO.class); - StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class); - when(destPrimaryStorage.getPoolType()).thenReturn(Storage.StoragePoolType.PowerFlex); - Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl) - .getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); - volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null); - } - - @Test - public void testCreateVolumeOnSecondaryForAttachIfNeeded_CreateVolumeFails_ThrowsException() { - VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class); - Mockito.when(volumeToAttach.getState()).thenReturn(Volume.State.Uploaded); - UserVmVO vm = Mockito.mock(UserVmVO.class); - StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class); - Mockito.when(destPrimaryStorage.getPoolType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem); - Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl) - .getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); - try { - Mockito.when(volumeOrchestrationService.createVolumeOnPrimaryStorage(vm, volumeToAttach, vm.getHypervisorType(), destPrimaryStorage)) - .thenThrow(new NoTransitionException("Mocked exception")); - } catch (NoTransitionException nte) { - Assert.fail(nte.getMessage()); - } - CloudRuntimeException exception = Assert.assertThrows(CloudRuntimeException.class, () -> - volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null) - ); - Assert.assertTrue(exception.getMessage().contains("Failed to create volume on primary storage")); - } }