mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
server: fix pod retrieval during volume attach (#10324)
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
parent
802bf5fce7
commit
a627ab67c2
@ -133,7 +133,9 @@ 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;
|
||||
@ -153,6 +155,7 @@ 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;
|
||||
@ -323,6 +326,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
@Inject
|
||||
private VmWorkJobDao _workJobDao;
|
||||
@Inject
|
||||
ClusterDao clusterDao;
|
||||
@Inject
|
||||
private ClusterDetailsDao _clusterDetailsDao;
|
||||
@Inject
|
||||
private StorageManager storageMgr;
|
||||
@ -346,6 +351,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
protected ProjectManager projectManager;
|
||||
@Inject
|
||||
protected StoragePoolDetailsDao storagePoolDetailsDao;
|
||||
@Inject
|
||||
HostPodDao podDao;
|
||||
|
||||
|
||||
protected Gson _gson;
|
||||
@ -2380,17 +2387,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
||||
return attachVolumeToVM(command.getVirtualMachineId(), command.getId(), command.getDeviceId());
|
||||
}
|
||||
|
||||
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);
|
||||
protected VolumeVO getVmExistingVolumeForVolumeAttach(UserVmVO vm, VolumeInfo volumeToAttach) {
|
||||
VolumeVO existingVolumeOfVm = null;
|
||||
VMTemplateVO template = _templateDao.findById(vm.getTemplateId());
|
||||
List<VolumeVO> rootVolumesOfVm = _volsDao.findByInstanceAndType(vmId, Volume.Type.ROOT);
|
||||
List<VolumeVO> rootVolumesOfVm = _volsDao.findByInstanceAndType(vm.getId(), 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(vmId, Volume.Type.DATADISK);
|
||||
List<VolumeVO> diskVolumesOfVm = _volsDao.findByInstanceAndType(vm.getId(), Volume.Type.DATADISK);
|
||||
for (VolumeVO diskVolume : diskVolumesOfVm) {
|
||||
if (diskVolume.getState() != Volume.State.Allocated) {
|
||||
existingVolumeOfVm = diskVolume;
|
||||
@ -2407,44 +2407,90 @@ 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",
|
||||
vm.getName(), vm.getUuid(),
|
||||
volumeToAttach.getName(), volumeToAttach.getUuid()));
|
||||
}
|
||||
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";
|
||||
if (existingVolumeOfVm != null) {
|
||||
s_logger.trace(String.format(msg,
|
||||
volumeToAttach.getName(), volumeToAttach.getUuid(),
|
||||
vm.getName(), vm.getUuid(),
|
||||
existingVolumeOfVm.getName(), existingVolumeOfVm.getUuid(),
|
||||
existingVolumeOfVm.getPoolId()));
|
||||
}
|
||||
s_logger.trace(String.format(msg,
|
||||
volumeToAttach.getName(), volumeToAttach.getUuid(),
|
||||
vm.getName(), vm.getUuid(),
|
||||
existingVolumeOfVm.getName(), existingVolumeOfVm.getUuid(),
|
||||
existingVolumeOfVm.getPoolId()));
|
||||
}
|
||||
return existingVolumeOfVm;
|
||||
}
|
||||
|
||||
HypervisorType rootDiskHyperType = vm.getHypervisorType();
|
||||
HypervisorType volumeToAttachHyperType = _volsDao.getHypervisorType(volumeToAttach.getId());
|
||||
protected StoragePool getSuitablePoolForAllocatedOrUploadedVolumeForAttach(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());
|
||||
return _volumeMgr.findStoragePool(diskProfile, zone, pod, clusterHostId.first(),
|
||||
clusterHostId.second(), vm, Collections.emptySet());
|
||||
}
|
||||
|
||||
protected VolumeInfo createVolumeOnPrimaryForAttachIfNeeded(final VolumeInfo volumeToAttach, final UserVmVO vm, VolumeVO existingVolumeOfVm) {
|
||||
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
|
||||
StoragePoolVO destPrimaryStorage = null;
|
||||
StoragePool 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()));
|
||||
}
|
||||
}
|
||||
|
||||
boolean volumeOnSecondary = volumeToAttach.getState() == Volume.State.Uploaded;
|
||||
|
||||
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());
|
||||
if (destPrimaryStorage == null) {
|
||||
destPrimaryStorage = getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
|
||||
if (destPrimaryStorage == null) {
|
||||
if (Volume.State.Allocated.equals(volumeToAttach.getState()) && State.Stopped.equals(vm.getState())) {
|
||||
return newVolumeOnPrimaryStorage;
|
||||
}
|
||||
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);
|
||||
throw new CloudRuntimeException(String.format("Failed to find a primary storage for volume in state: %s", volumeToAttach.getState()));
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
if (volumeToAttach.isAttachedVM()) {
|
||||
throw new CloudRuntimeException("This volume is already attached to a VM.");
|
||||
}
|
||||
|
||||
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());
|
||||
@ -2463,19 +2509,17 @@ 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 e) {
|
||||
s_logger.debug("move volume failed", e);
|
||||
throw new CloudRuntimeException("move volume failed", e);
|
||||
} catch (StorageUnavailableException e) {
|
||||
} catch (ConcurrentOperationException | 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 || volumeOnSecondary) {
|
||||
if (moveVolumeNeeded) {
|
||||
vm = _userVmDao.findById(vmId);
|
||||
if (vm == null) {
|
||||
throw new InvalidParameterValueException("VM not found.");
|
||||
@ -2659,9 +2703,6 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -45,6 +45,7 @@ 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;
|
||||
@ -86,8 +87,12 @@ 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;
|
||||
@ -122,10 +127,12 @@ 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;
|
||||
@ -199,6 +206,15 @@ 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();
|
||||
@ -1820,4 +1836,268 @@ 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.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
|
||||
Assert.assertNotNull(result);
|
||||
Assert.assertEquals(pool, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPoolForAllocatedOrUploadedVolumeForAttach_NoSuitablePoolFound_ReturnsNull() {
|
||||
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);
|
||||
Assert.assertNull(volumeApiServiceImpl.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSuitablePoolForAllocatedOrUploadedVolumeForAttach_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.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(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)
|
||||
.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(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).getSuitablePoolForAllocatedOrUploadedVolumeForAttach(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)
|
||||
.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(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)
|
||||
.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(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"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateVolumeOnSecondaryForAttachIfNeeded_NoSuitablePool_ThrowsException() {
|
||||
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
|
||||
Mockito.when(volumeToAttach.getState()).thenReturn(Volume.State.Uploaded);
|
||||
UserVmVO vm = Mockito.mock(UserVmVO.class);
|
||||
Mockito.doReturn(null).when(volumeApiServiceImpl)
|
||||
.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
|
||||
CloudRuntimeException exception = Assert.assertThrows(CloudRuntimeException.class, () ->
|
||||
volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null)
|
||||
);
|
||||
Assert.assertTrue(exception.getMessage().startsWith("Failed to find a primary storage for volume"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateVolumeOnSecondaryForAttachIfNeeded_NoSuitablePool_ReturnSameVolumeInfo() {
|
||||
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
|
||||
Mockito.when(volumeToAttach.getState()).thenReturn(Volume.State.Allocated);
|
||||
UserVmVO vm = Mockito.mock(UserVmVO.class);
|
||||
Mockito.when(vm.getState()).thenReturn(State.Stopped);
|
||||
Mockito.doReturn(null).when(volumeApiServiceImpl)
|
||||
.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
|
||||
VolumeInfo result = volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null);
|
||||
Assert.assertSame(volumeToAttach, result);
|
||||
try {
|
||||
Mockito.verify(volumeOrchestrationService, Mockito.never()).createVolumeOnPrimaryStorage(Mockito.any(),
|
||||
Mockito.any(), Mockito.any(), Mockito.any());
|
||||
} catch (NoTransitionException e) {
|
||||
Assert.fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user