Add managed storage pool constraints to MigrateWithVolume API method (#2761)

* Add managed storage pool constraints to MigrateWithVolume API method

* Apply mike's suggestions

* Apply Mike's suggestion in a second review

* Mike's suggestions

* Confused bit

* just executeManagedStorageChecks

* Created methods `executeManagedStorageChecksWhenTargetStoragePoolNotProvided` and `executeManagedStorageChecksWhenTargetStoragePoolProvided`

* improve "executeManagedStorageChecksWhenTargetStoragePoolNotProvided"

* Fix "findVolumesThatWereNotMappedByTheUser" method

* Applu Mike's suggestion to improve "createMappingVolumeAndStoragePool" method

* Unit tests to cover modified code
This commit is contained in:
Rafael Weingärtner 2018-09-10 20:09:26 -03:00 committed by GitHub
parent 82fc9f3016
commit f550d70305
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 539 additions and 56 deletions

View File

@ -2286,31 +2286,52 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
}
/**
* Create the mapping of volumes and storage pools. If the user did not enter a mapping on her/his own, we create one using {@link #getDefaultMappingOfVolumesAndStoragePoolForMigration(VirtualMachineProfile, Host)}.
* If the user provided a mapping, we use whatever the user has provided (check the method {@link #createMappingVolumeAndStoragePoolEnteredByUser(VirtualMachineProfile, Host, Map)}).
* We create the mapping of volumes and storage pool to migrate the VMs according to the information sent by the user.
* If the user did not enter a complete mapping, the volumes that were left behind will be auto mapped using {@link #createStoragePoolMappingsForVolumes(VirtualMachineProfile, Host, Map, List)}
*/
private Map<Volume, StoragePool> getPoolListForVolumesForMigration(VirtualMachineProfile profile, Host targetHost, Map<Long, Long> volumeToPool) {
if (MapUtils.isEmpty(volumeToPool)) {
return getDefaultMappingOfVolumesAndStoragePoolForMigration(profile, targetHost);
}
protected Map<Volume, StoragePool> createMappingVolumeAndStoragePool(VirtualMachineProfile profile, Host targetHost, Map<Long, Long> userDefinedMapOfVolumesAndStoragePools) {
Map<Volume, StoragePool> volumeToPoolObjectMap = buildMapUsingUserInformation(profile, targetHost, userDefinedMapOfVolumesAndStoragePools);
return createMappingVolumeAndStoragePoolEnteredByUser(profile, targetHost, volumeToPool);
List<Volume> volumesNotMapped = findVolumesThatWereNotMappedByTheUser(profile, volumeToPoolObjectMap);
createStoragePoolMappingsForVolumes(profile, targetHost, volumeToPoolObjectMap, volumesNotMapped);
return volumeToPoolObjectMap;
}
/**
* We create the mapping of volumes and storage pool to migrate the VMs according to the information sent by the user.
* Given the map of volume to target storage pool entered by the user, we check for other volumes that the VM might have and were not configured.
* This map can be then used by CloudStack to find new target storage pools according to the target host.
*/
private Map<Volume, StoragePool> createMappingVolumeAndStoragePoolEnteredByUser(VirtualMachineProfile profile, Host host, Map<Long, Long> volumeToPool) {
Map<Volume, StoragePool> volumeToPoolObjectMap = new HashMap<Volume, StoragePool>();
for(Long volumeId: volumeToPool.keySet()) {
protected List<Volume> findVolumesThatWereNotMappedByTheUser(VirtualMachineProfile profile, Map<Volume, StoragePool> volumeToStoragePoolObjectMap) {
List<VolumeVO> allVolumes = _volsDao.findUsableVolumesForInstance(profile.getId());
List<Volume> volumesNotMapped = new ArrayList<>();
for (Volume volume : allVolumes) {
if (!volumeToStoragePoolObjectMap.containsKey(volume)) {
volumesNotMapped.add(volume);
}
}
return volumesNotMapped;
}
/**
* Builds the map of storage pools and volumes with the information entered by the user. Before creating the an entry we validate if the migration is feasible checking if the migration is allowed and if the target host can access the defined target storage pool.
*/
protected Map<Volume, StoragePool> buildMapUsingUserInformation(VirtualMachineProfile profile, Host targetHost, Map<Long, Long> userDefinedVolumeToStoragePoolMap) {
Map<Volume, StoragePool> volumeToPoolObjectMap = new HashMap<>();
if (MapUtils.isEmpty(userDefinedVolumeToStoragePoolMap)) {
return volumeToPoolObjectMap;
}
for(Long volumeId: userDefinedVolumeToStoragePoolMap.keySet()) {
VolumeVO volume = _volsDao.findById(volumeId);
Long poolId = volumeToPool.get(volumeId);
Long poolId = userDefinedVolumeToStoragePoolMap.get(volumeId);
StoragePoolVO targetPool = _storagePoolDao.findById(poolId);
StoragePoolVO currentPool = _storagePoolDao.findById(volume.getPoolId());
if (_poolHostDao.findByPoolHost(targetPool.getId(), host.getId()) == null) {
throw new CloudRuntimeException(String.format("Cannot migrate the volume [%s] to the storage pool [%s] while migrating VM [%s] to target host [%s]. The host does not have access to the storage pool entered.", volume.getUuid(), targetPool.getUuid(), profile.getUuid(), host.getUuid()));
executeManagedStorageChecksWhenTargetStoragePoolProvided(currentPool, volume, targetPool);
if (_poolHostDao.findByPoolHost(targetPool.getId(), targetHost.getId()) == null) {
throw new CloudRuntimeException(
String.format("Cannot migrate the volume [%s] to the storage pool [%s] while migrating VM [%s] to target host [%s]. The host does not have access to the storage pool entered.",
volume.getUuid(), targetPool.getUuid(), profile.getUuid(), targetHost.getUuid()));
}
if (currentPool.getId() == targetPool.getId()) {
s_logger.info(String.format("The volume [%s] is already allocated in storage pool [%s].", volume.getUuid(), targetPool.getUuid()));
@ -2321,60 +2342,99 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
}
/**
* We create the default mapping of volumes and storage pools for the migration of the VM to the target host.
* If the current storage pool of one of the volumes is using local storage in the host, it then needs to be migrated to a local storage in the target host.
* Otherwise, we do not need to migrate, and the volume can be kept in its current storage pool.
* Executes the managed storage checks for the mapping<volume, storage pool> entered by the user. The checks execute by this method are the following.
* <ul>
* <li> If the current storage pool of the volume is not a managed storage, we do not need to validate anything here.
* <li> If the current storage pool is a managed storage and the target storage pool ID is different from the current one, we throw an exception.
* </ul>
*/
private Map<Volume, StoragePool> getDefaultMappingOfVolumesAndStoragePoolForMigration(VirtualMachineProfile profile, Host targetHost) {
Map<Volume, StoragePool> volumeToPoolObjectMap = new HashMap<Volume, StoragePool>();
List<VolumeVO> allVolumes = _volsDao.findUsableVolumesForInstance(profile.getId());
for (VolumeVO volume : allVolumes) {
protected void executeManagedStorageChecksWhenTargetStoragePoolProvided(StoragePoolVO currentPool, VolumeVO volume, StoragePoolVO targetPool) {
if (!currentPool.isManaged()) {
return;
}
if (currentPool.getId() == targetPool.getId()) {
return;
}
throw new CloudRuntimeException(String.format("Currently, a volume on managed storage can only be 'migrated' to itself " + "[volumeId=%s, currentStoragePoolId=%s, targetStoragePoolId=%s].",
volume.getUuid(), currentPool.getUuid(), targetPool.getUuid()));
}
/**
* For each one of the volumes we will map it to a storage pool that is available via the target host.
* An exception is thrown if we cannot find a storage pool that is accessible in the target host to migrate the volume to.
*/
protected void createStoragePoolMappingsForVolumes(VirtualMachineProfile profile, Host targetHost, Map<Volume, StoragePool> volumeToPoolObjectMap, List<Volume> allVolumes) {
for (Volume volume : allVolumes) {
StoragePoolVO currentPool = _storagePoolDao.findById(volume.getPoolId());
if (ScopeType.HOST.equals(currentPool.getScope())) {
createVolumeToStoragePoolMappingIfNeeded(profile, targetHost, volumeToPoolObjectMap, volume, currentPool);
executeManagedStorageChecksWhenTargetStoragePoolNotProvided(targetHost, currentPool, volume);
if (ScopeType.HOST.equals(currentPool.getScope()) || isStorageCrossClusterMigration(targetHost, currentPool)) {
createVolumeToStoragePoolMappingIfPossible(profile, targetHost, volumeToPoolObjectMap, volume, currentPool);
} else {
volumeToPoolObjectMap.put(volume, currentPool);
}
}
return volumeToPoolObjectMap;
}
/**
* Executes the managed storage checks for the volumes that the user has not entered a mapping of <volume, storage pool>. The following checks are performed.
* <ul>
* <li> If the current storage pool is not a managed storage, we do not need to proceed with this method;
* <li> We check if the target host has access to the current managed storage pool. If it does not have an exception will be thrown.
* </ul>
*/
protected void executeManagedStorageChecksWhenTargetStoragePoolNotProvided(Host targetHost, StoragePoolVO currentPool, Volume volume) {
if (!currentPool.isManaged()) {
return;
}
if (_poolHostDao.findByPoolHost(currentPool.getId(), targetHost.getId()) == null) {
throw new CloudRuntimeException(String.format("The target host does not have access to the volume's managed storage pool. [volumeId=%s, storageId=%s, targetHostId=%s].", volume.getUuid(),
currentPool.getUuid(), targetHost.getUuid()));
}
}
/**
* Return true if the VM migration is a cross cluster migration. To execute that, we check if the volume current storage pool cluster is different from the target host cluster.
*/
protected boolean isStorageCrossClusterMigration(Host targetHost, StoragePoolVO currentPool) {
return ScopeType.CLUSTER.equals(currentPool.getScope()) && currentPool.getClusterId() != targetHost.getClusterId();
}
/**
* We will add a mapping of volume to storage pool if needed. The conditions to add a mapping are the following:
* <ul>
* <li> The current storage pool where the volume is allocated can be accessed by the target host
* <li> If not storage pool is found to allocate the volume we throw an exception.
* <li> The candidate storage pool where the volume is to be allocated can be accessed by the target host
* <li> If no storage pool is found to allocate the volume we throw an exception.
* </ul>
*
* Side note: this method should only be called if the volume is on local storage or if we are executing a cross cluster migration.
*/
private void createVolumeToStoragePoolMappingIfNeeded(VirtualMachineProfile profile, Host targetHost, Map<Volume, StoragePool> volumeToPoolObjectMap, VolumeVO volume, StoragePoolVO currentPool) {
List<StoragePool> poolList = getCandidateStoragePoolsToMigrateLocalVolume(profile, targetHost, volume);
protected void createVolumeToStoragePoolMappingIfPossible(VirtualMachineProfile profile, Host targetHost, Map<Volume, StoragePool> volumeToPoolObjectMap, Volume volume,
StoragePoolVO currentPool) {
List<StoragePool> storagePoolList = getCandidateStoragePoolsToMigrateLocalVolume(profile, targetHost, volume);
Collections.shuffle(poolList);
boolean canTargetHostAccessVolumeStoragePool = false;
for (StoragePool storagePool : poolList) {
if (CollectionUtils.isEmpty(storagePoolList)) {
throw new CloudRuntimeException(String.format("There is not storage pools available at the target host [%s] to migrate volume [%s]", targetHost.getUuid(), volume.getUuid()));
}
Collections.shuffle(storagePoolList);
boolean canTargetHostAccessVolumeCurrentStoragePool = false;
for (StoragePool storagePool : storagePoolList) {
if (storagePool.getId() == currentPool.getId()) {
canTargetHostAccessVolumeStoragePool = true;
canTargetHostAccessVolumeCurrentStoragePool = true;
break;
}
}
if(!canTargetHostAccessVolumeStoragePool && CollectionUtils.isEmpty(poolList)) {
throw new CloudRuntimeException(String.format("There is not storage pools avaliable at the target host [%s] to migrate volume [%s]", targetHost.getUuid(), volume.getUuid()));
}
if (!canTargetHostAccessVolumeStoragePool) {
volumeToPoolObjectMap.put(volume, _storagePoolDao.findByUuid(poolList.get(0).getUuid()));
}
if (!canTargetHostAccessVolumeStoragePool && !volumeToPoolObjectMap.containsKey(volume)) {
throw new CloudRuntimeException(String.format("Cannot find a storage pool which is available for volume [%s] while migrating virtual machine [%s] to host [%s]", volume.getUuid(),
profile.getUuid(), targetHost.getUuid()));
if (!canTargetHostAccessVolumeCurrentStoragePool) {
volumeToPoolObjectMap.put(volume, _storagePoolDao.findByUuid(storagePoolList.get(0).getUuid()));
}
}
/**
* We use {@link StoragePoolAllocator} objects to find local storage pools connected to the targetHost where we would be able to allocate the given volume.
* We use {@link StoragePoolAllocator} objects to find storage pools connected to the targetHost where we would be able to allocate the given volume.
*/
private List<StoragePool> getCandidateStoragePoolsToMigrateLocalVolume(VirtualMachineProfile profile, Host targetHost, VolumeVO volume) {
protected List<StoragePool> getCandidateStoragePoolsToMigrateLocalVolume(VirtualMachineProfile profile, Host targetHost, Volume volume) {
List<StoragePool> poolList = new ArrayList<>();
DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
@ -2392,7 +2452,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
continue;
}
for (StoragePool pool : poolListFromAllocator) {
if (pool.isLocal()) {
if (pool.isLocal() || isStorageCrossClusterMigration(targetHost, volumeStoragePool)) {
poolList.add(pool);
}
}
@ -2487,7 +2547,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
// Create a map of which volume should go in which storage pool.
final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm);
final Map<Volume, StoragePool> volumeToPoolMap = getPoolListForVolumesForMigration(profile, destHost, volumeToPool);
final Map<Volume, StoragePool> volumeToPoolMap = createMappingVolumeAndStoragePool(profile, destHost, volumeToPool);
// If none of the volumes have to be migrated, fail the call. Administrator needs to make a call for migrating
// a vm and not migrating a vm with storage.
@ -3971,8 +4031,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {ClusterDeltaSyncInterval, StartRetry, VmDestroyForcestop, VmOpCancelInterval, VmOpCleanupInterval, VmOpCleanupWait,
VmOpLockStateRetry,
VmOpWaitInterval, ExecuteInSequence, VmJobCheckInterval, VmJobTimeout, VmJobStateReportInterval, VmConfigDriveLabel, VmConfigDriveOnPrimaryPool, HaVmRestartHostUp};
VmOpLockStateRetry,
VmOpWaitInterval, ExecuteInSequence, VmJobCheckInterval, VmJobTimeout, VmJobStateReportInterval, VmConfigDriveLabel, VmConfigDriveOnPrimaryPool, HaVmRestartHostUp};
}
public List<StoragePoolAllocator> getStoragePoolAllocators() {

View File

@ -21,16 +21,25 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
@ -38,12 +47,22 @@ import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.host.HostVO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.HypervisorGuru;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.ScopeType;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolHostVO;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.VirtualMachine.State;
@ -58,37 +77,76 @@ public class VirtualMachineManagerImplTest {
@Mock
private AgentManager agentManagerMock;
@Mock
private VMInstanceDao vmInstanceDao;
private VMInstanceDao vmInstanceDaoMock;
@Mock
private ServiceOfferingDao serviceOfferingDao;
private ServiceOfferingDao serviceOfferingDaoMock;
@Mock
private VolumeDao volumeDao;
private VolumeDao volumeDaoMock;
@Mock
private PrimaryDataStoreDao storagePoolDaoMock;
@Mock
private VMInstanceVO vmInstanceMock;
private long vmInstanceVoMockId = 1L;
@Mock
private ServiceOfferingVO serviceOfferingMock;
private long hostMockId = 1L;
@Mock
private HostVO hostMock;
@Mock
private VirtualMachineProfile virtualMachineProfileMock;
@Mock
private StoragePoolVO storagePoolVoMock;
private long storagePoolVoMockId = 11L;
private long storagePoolVoMockClusterId = 234L;
@Mock
private VolumeVO volumeVoMock;
private long volumeMockId = 1111L;
@Mock
private StoragePoolHostDao storagePoolHostDaoMock;
@Mock
private StoragePoolAllocator storagePoolAllocatorMock;
@Mock
private DiskOfferingDao diskOfferingDaoMock;
@Before
public void setup() {
virtualMachineManagerImpl.setHostAllocators(new ArrayList<>());
when(vmInstanceMock.getId()).thenReturn(1L);
when(vmInstanceMock.getId()).thenReturn(vmInstanceVoMockId);
when(vmInstanceMock.getServiceOfferingId()).thenReturn(2L);
when(vmInstanceMock.getInstanceName()).thenReturn("myVm");
when(vmInstanceMock.getHostId()).thenReturn(2L);
when(vmInstanceMock.getType()).thenReturn(VirtualMachine.Type.User);
when(hostMock.getId()).thenReturn(1L);
when(hostMock.getId()).thenReturn(hostMockId);
Mockito.doReturn(vmInstanceVoMockId).when(virtualMachineProfileMock).getId();
Mockito.doReturn(storagePoolVoMockId).when(storagePoolVoMock).getId();
Mockito.doReturn(storagePoolVoMockClusterId).when(storagePoolVoMock).getClusterId();
Mockito.doReturn(volumeMockId).when(volumeVoMock).getId();
Mockito.doReturn(storagePoolVoMockId).when(volumeVoMock).getPoolId();
Mockito.doReturn(volumeVoMock).when(volumeDaoMock).findById(volumeMockId);
Mockito.doReturn(storagePoolVoMock).when(storagePoolDaoMock).findById(storagePoolVoMockId);
ArrayList<StoragePoolAllocator> storagePoolAllocators = new ArrayList<>();
storagePoolAllocators.add(storagePoolAllocatorMock);
virtualMachineManagerImpl.setStoragePoolAllocators(storagePoolAllocators);
}
@Test(expected = CloudRuntimeException.class)
public void testScaleVM3() throws Exception {
when(vmInstanceMock.getHostId()).thenReturn(null);
when(vmInstanceDao.findById(anyLong())).thenReturn(vmInstanceMock);
when(vmInstanceDao.findByUuid(any(String.class))).thenReturn(vmInstanceMock);
when(vmInstanceDaoMock.findById(anyLong())).thenReturn(vmInstanceMock);
when(vmInstanceDaoMock.findByUuid(any(String.class))).thenReturn(vmInstanceMock);
DeploymentPlanner.ExcludeList excludeHostList = new DeploymentPlanner.ExcludeList();
virtualMachineManagerImpl.findHostAndMigrate(vmInstanceMock.getUuid(), 2l, excludeHostList);
}
@ -154,7 +212,7 @@ public class VirtualMachineManagerImplTest {
ServiceOfferingVO mockCurrentServiceOffering = mock(ServiceOfferingVO.class);
when(serviceOfferingDao.findByIdIncludingRemoved(anyLong(), anyLong())).thenReturn(mockCurrentServiceOffering);
when(serviceOfferingDaoMock.findByIdIncludingRemoved(anyLong(), anyLong())).thenReturn(mockCurrentServiceOffering);
when(mockCurrentServiceOffering.getUseLocalStorage()).thenReturn(true);
when(serviceOfferingMock.getUseLocalStorage()).thenReturn(true);
when(mockCurrentServiceOffering.getSystemUse()).thenReturn(true);
@ -164,4 +222,369 @@ public class VirtualMachineManagerImplTest {
virtualMachineManagerImpl.checkIfCanUpgrade(vmInstanceMock, serviceOfferingMock);
}
}
@Test
public void isStorageCrossClusterMigrationTestStorageTypeEqualsCluster() {
Mockito.doReturn(1L).when(hostMock).getClusterId();
Mockito.doReturn(2L).when(storagePoolVoMock).getClusterId();
Mockito.doReturn(ScopeType.CLUSTER).when(storagePoolVoMock).getScope();
boolean returnedValue = virtualMachineManagerImpl.isStorageCrossClusterMigration(hostMock, storagePoolVoMock);
Assert.assertTrue(returnedValue);
}
@Test
public void isStorageCrossClusterMigrationTestStorageSameCluster() {
Mockito.doReturn(1L).when(hostMock).getClusterId();
Mockito.doReturn(1L).when(storagePoolVoMock).getClusterId();
Mockito.doReturn(ScopeType.CLUSTER).when(storagePoolVoMock).getScope();
boolean returnedValue = virtualMachineManagerImpl.isStorageCrossClusterMigration(hostMock, storagePoolVoMock);
Assert.assertFalse(returnedValue);
}
@Test
public void isStorageCrossClusterMigrationTestStorageTypeEqualsZone() {
Mockito.doReturn(1L).when(hostMock).getClusterId();
Mockito.doReturn(2L).when(storagePoolVoMock).getClusterId();
Mockito.doReturn(ScopeType.ZONE).when(storagePoolVoMock).getScope();
boolean returnedValue = virtualMachineManagerImpl.isStorageCrossClusterMigration(hostMock, storagePoolVoMock);
Assert.assertFalse(returnedValue);
}
@Test
public void executeManagedStorageChecksWhenTargetStoragePoolProvidedTestCurrentStoragePoolNotManaged() {
Mockito.doReturn(false).when(storagePoolVoMock).isManaged();
virtualMachineManagerImpl.executeManagedStorageChecksWhenTargetStoragePoolProvided(storagePoolVoMock, volumeVoMock, Mockito.mock(StoragePoolVO.class));
Mockito.verify(storagePoolVoMock).isManaged();
Mockito.verify(storagePoolVoMock, Mockito.times(0)).getId();
}
@Test
public void executeManagedStorageChecksWhenTargetStoragePoolProvidedTestCurrentStoragePoolEqualsTargetPool() {
Mockito.doReturn(true).when(storagePoolVoMock).isManaged();
virtualMachineManagerImpl.executeManagedStorageChecksWhenTargetStoragePoolProvided(storagePoolVoMock, volumeVoMock, storagePoolVoMock);
Mockito.verify(storagePoolVoMock).isManaged();
Mockito.verify(storagePoolVoMock, Mockito.times(2)).getId();
}
@Test(expected = CloudRuntimeException.class)
public void executeManagedStorageChecksWhenTargetStoragePoolProvidedTestCurrentStoragePoolNotEqualsTargetPool() {
Mockito.doReturn(true).when(storagePoolVoMock).isManaged();
virtualMachineManagerImpl.executeManagedStorageChecksWhenTargetStoragePoolProvided(storagePoolVoMock, volumeVoMock, Mockito.mock(StoragePoolVO.class));
}
@Test
public void buildMapUsingUserInformationTestUserDefinedMigrationMapEmpty() {
HashMap<Long, Long> userDefinedVolumeToStoragePoolMap = Mockito.spy(new HashMap<>());
Map<Volume, StoragePool> volumeToPoolObjectMap = virtualMachineManagerImpl.buildMapUsingUserInformation(virtualMachineProfileMock, hostMock, userDefinedVolumeToStoragePoolMap);
Assert.assertTrue(volumeToPoolObjectMap.isEmpty());
Mockito.verify(userDefinedVolumeToStoragePoolMap, times(0)).keySet();
}
@Test(expected = CloudRuntimeException.class)
public void buildMapUsingUserInformationTestTargetHostDoesNotHaveAccessToPool() {
HashMap<Long, Long> userDefinedVolumeToStoragePoolMap = new HashMap<>();
userDefinedVolumeToStoragePoolMap.put(volumeMockId, storagePoolVoMockId);
Mockito.doNothing().when(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolProvided(Mockito.any(StoragePoolVO.class), Mockito.any(VolumeVO.class), Mockito.any(StoragePoolVO.class));
Mockito.doReturn(null).when(storagePoolHostDaoMock).findByPoolHost(storagePoolVoMockId, hostMockId);
virtualMachineManagerImpl.buildMapUsingUserInformation(virtualMachineProfileMock, hostMock, userDefinedVolumeToStoragePoolMap);
}
@Test
public void buildMapUsingUserInformationTestTargetHostHasAccessToPool() {
HashMap<Long, Long> userDefinedVolumeToStoragePoolMap = Mockito.spy(new HashMap<>());
userDefinedVolumeToStoragePoolMap.put(volumeMockId, storagePoolVoMockId);
Mockito.doNothing().when(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolProvided(Mockito.any(StoragePoolVO.class), Mockito.any(VolumeVO.class),
Mockito.any(StoragePoolVO.class));
Mockito.doReturn(Mockito.mock(StoragePoolHostVO.class)).when(storagePoolHostDaoMock).findByPoolHost(storagePoolVoMockId, hostMockId);
Map<Volume, StoragePool> volumeToPoolObjectMap = virtualMachineManagerImpl.buildMapUsingUserInformation(virtualMachineProfileMock, hostMock, userDefinedVolumeToStoragePoolMap);
Assert.assertFalse(volumeToPoolObjectMap.isEmpty());
Assert.assertEquals(storagePoolVoMock, volumeToPoolObjectMap.get(volumeVoMock));
Mockito.verify(userDefinedVolumeToStoragePoolMap, times(1)).keySet();
}
@Test
public void findVolumesThatWereNotMappedByTheUserTest() {
Map<Volume, StoragePool> volumeToStoragePoolObjectMap = Mockito.spy(new HashMap<>());
volumeToStoragePoolObjectMap.put(volumeVoMock, storagePoolVoMock);
Volume volumeVoMock2 = Mockito.mock(Volume.class);
List<Volume> volumesOfVm = new ArrayList<>();
volumesOfVm.add(volumeVoMock);
volumesOfVm.add(volumeVoMock2);
Mockito.doReturn(volumesOfVm).when(volumeDaoMock).findUsableVolumesForInstance(vmInstanceVoMockId);
List<Volume> volumesNotMapped = virtualMachineManagerImpl.findVolumesThatWereNotMappedByTheUser(virtualMachineProfileMock, volumeToStoragePoolObjectMap);
Assert.assertEquals(1, volumesNotMapped.size());
Assert.assertEquals(volumeVoMock2, volumesNotMapped.get(0));
}
@Test
public void executeManagedStorageChecksWhenTargetStoragePoolNotProvidedTestCurrentStoragePoolNotManaged() {
Mockito.doReturn(false).when(storagePoolVoMock).isManaged();
virtualMachineManagerImpl.executeManagedStorageChecksWhenTargetStoragePoolNotProvided(hostMock, storagePoolVoMock, volumeVoMock);
Mockito.verify(storagePoolVoMock).isManaged();
Mockito.verify(storagePoolHostDaoMock, Mockito.times(0)).findByPoolHost(Mockito.anyLong(), Mockito.anyLong());
}
@Test
public void executeManagedStorageChecksWhenTargetStoragePoolNotProvidedTestCurrentStoragePoolManagedIsConnectedToHost() {
Mockito.doReturn(true).when(storagePoolVoMock).isManaged();
Mockito.doReturn(Mockito.mock(StoragePoolHostVO.class)).when(storagePoolHostDaoMock).findByPoolHost(storagePoolVoMockId, hostMockId);
virtualMachineManagerImpl.executeManagedStorageChecksWhenTargetStoragePoolNotProvided(hostMock, storagePoolVoMock, volumeVoMock);
Mockito.verify(storagePoolVoMock).isManaged();
Mockito.verify(storagePoolHostDaoMock, Mockito.times(1)).findByPoolHost(storagePoolVoMockId, hostMockId);
}
@Test(expected = CloudRuntimeException.class)
public void executeManagedStorageChecksWhenTargetStoragePoolNotProvidedTestCurrentStoragePoolManagedIsNotConnectedToHost() {
Mockito.doReturn(true).when(storagePoolVoMock).isManaged();
Mockito.doReturn(null).when(storagePoolHostDaoMock).findByPoolHost(storagePoolVoMockId, hostMockId);
virtualMachineManagerImpl.executeManagedStorageChecksWhenTargetStoragePoolNotProvided(hostMock, storagePoolVoMock, volumeVoMock);
}
@Test
public void getCandidateStoragePoolsToMigrateLocalVolumeTestLocalVolume() {
Mockito.doReturn(Mockito.mock(DiskOfferingVO.class)).when(diskOfferingDaoMock).findById(Mockito.anyLong());
Mockito.doReturn(true).when(storagePoolVoMock).isLocal();
List<StoragePool> poolListMock = new ArrayList<>();
poolListMock.add(storagePoolVoMock);
Mockito.doReturn(poolListMock).when(storagePoolAllocatorMock).allocateToPool(Mockito.any(DiskProfile.class), Mockito.any(VirtualMachineProfile.class), Mockito.any(DeploymentPlan.class),
Mockito.any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL));
List<StoragePool> poolList = virtualMachineManagerImpl.getCandidateStoragePoolsToMigrateLocalVolume(virtualMachineProfileMock, hostMock, volumeVoMock);
Assert.assertEquals(1, poolList.size());
Assert.assertEquals(storagePoolVoMock, poolList.get(0));
}
@Test
public void getCandidateStoragePoolsToMigrateLocalVolumeTestCrossClusterMigration() {
Mockito.doReturn(Mockito.mock(DiskOfferingVO.class)).when(diskOfferingDaoMock).findById(Mockito.anyLong());
Mockito.doReturn(false).when(storagePoolVoMock).isLocal();
List<StoragePool> poolListMock = new ArrayList<>();
poolListMock.add(storagePoolVoMock);
Mockito.doReturn(poolListMock).when(storagePoolAllocatorMock).allocateToPool(Mockito.any(DiskProfile.class), Mockito.any(VirtualMachineProfile.class), Mockito.any(DeploymentPlan.class),
Mockito.any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL));
Mockito.doReturn(true).when(virtualMachineManagerImpl).isStorageCrossClusterMigration(hostMock, storagePoolVoMock);
List<StoragePool> poolList = virtualMachineManagerImpl.getCandidateStoragePoolsToMigrateLocalVolume(virtualMachineProfileMock, hostMock, volumeVoMock);
Assert.assertEquals(1, poolList.size());
Assert.assertEquals(storagePoolVoMock, poolList.get(0));
}
@Test
public void getCandidateStoragePoolsToMigrateLocalVolumeTestWithinClusterMigration() {
Mockito.doReturn(Mockito.mock(DiskOfferingVO.class)).when(diskOfferingDaoMock).findById(Mockito.anyLong());
Mockito.doReturn(false).when(storagePoolVoMock).isLocal();
List<StoragePool> poolListMock = new ArrayList<>();
poolListMock.add(storagePoolVoMock);
Mockito.doReturn(poolListMock).when(storagePoolAllocatorMock).allocateToPool(Mockito.any(DiskProfile.class), Mockito.any(VirtualMachineProfile.class), Mockito.any(DeploymentPlan.class),
Mockito.any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL));
Mockito.doReturn(false).when(virtualMachineManagerImpl).isStorageCrossClusterMigration(hostMock, storagePoolVoMock);
List<StoragePool> poolList = virtualMachineManagerImpl.getCandidateStoragePoolsToMigrateLocalVolume(virtualMachineProfileMock, hostMock, volumeVoMock);
Assert.assertTrue(poolList.isEmpty());
}
@Test
public void getCandidateStoragePoolsToMigrateLocalVolumeTestMoreThanOneAllocator() {
StoragePoolAllocator storagePoolAllocatorMock2 = Mockito.mock(StoragePoolAllocator.class);
StoragePoolAllocator storagePoolAllocatorMock3 = Mockito.mock(StoragePoolAllocator.class);
List<StoragePoolAllocator> storagePoolAllocatorsMock = new ArrayList<>();
storagePoolAllocatorsMock.add(storagePoolAllocatorMock);
storagePoolAllocatorsMock.add(storagePoolAllocatorMock2);
storagePoolAllocatorsMock.add(storagePoolAllocatorMock3);
virtualMachineManagerImpl.setStoragePoolAllocators(storagePoolAllocatorsMock);
Mockito.doReturn(Mockito.mock(DiskOfferingVO.class)).when(diskOfferingDaoMock).findById(Mockito.anyLong());
Mockito.doReturn(false).when(storagePoolVoMock).isLocal();
List<StoragePool> poolListMock = new ArrayList<>();
poolListMock.add(storagePoolVoMock);
Mockito.doReturn(poolListMock).when(storagePoolAllocatorMock).allocateToPool(Mockito.any(DiskProfile.class), Mockito.any(VirtualMachineProfile.class), Mockito.any(DeploymentPlan.class),
Mockito.any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL));
Mockito.doReturn(null).when(storagePoolAllocatorMock2).allocateToPool(Mockito.any(DiskProfile.class), Mockito.any(VirtualMachineProfile.class), Mockito.any(DeploymentPlan.class),
Mockito.any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL));
Mockito.doReturn(new ArrayList<>()).when(storagePoolAllocatorMock3).allocateToPool(Mockito.any(DiskProfile.class), Mockito.any(VirtualMachineProfile.class), Mockito.any(DeploymentPlan.class),
Mockito.any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL));
Mockito.doReturn(false).when(virtualMachineManagerImpl).isStorageCrossClusterMigration(hostMock, storagePoolVoMock);
List<StoragePool> poolList = virtualMachineManagerImpl.getCandidateStoragePoolsToMigrateLocalVolume(virtualMachineProfileMock, hostMock, volumeVoMock);
Assert.assertTrue(poolList.isEmpty());
Mockito.verify(storagePoolAllocatorMock).allocateToPool(Mockito.any(DiskProfile.class), Mockito.any(VirtualMachineProfile.class), Mockito.any(DeploymentPlan.class),
Mockito.any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL));
Mockito.verify(storagePoolAllocatorMock2).allocateToPool(Mockito.any(DiskProfile.class), Mockito.any(VirtualMachineProfile.class), Mockito.any(DeploymentPlan.class),
Mockito.any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL));
Mockito.verify(storagePoolAllocatorMock3).allocateToPool(Mockito.any(DiskProfile.class), Mockito.any(VirtualMachineProfile.class), Mockito.any(DeploymentPlan.class),
Mockito.any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL));
}
@Test(expected = CloudRuntimeException.class)
public void createVolumeToStoragePoolMappingIfPossibleTestNotStoragePoolsAvailable() {
Mockito.doReturn(null).when(virtualMachineManagerImpl).getCandidateStoragePoolsToMigrateLocalVolume(virtualMachineProfileMock, hostMock, volumeVoMock);
virtualMachineManagerImpl.createVolumeToStoragePoolMappingIfPossible(virtualMachineProfileMock, hostMock, new HashMap<>(), volumeVoMock, storagePoolVoMock);
}
@Test
public void createVolumeToStoragePoolMappingIfPossibleTestTargetHostAccessCurrentStoragePool() {
List<StoragePool> storagePoolList = new ArrayList<>();
storagePoolList.add(storagePoolVoMock);
Mockito.doReturn(storagePoolList).when(virtualMachineManagerImpl).getCandidateStoragePoolsToMigrateLocalVolume(virtualMachineProfileMock, hostMock, volumeVoMock);
HashMap<Volume, StoragePool> volumeToPoolObjectMap = new HashMap<>();
virtualMachineManagerImpl.createVolumeToStoragePoolMappingIfPossible(virtualMachineProfileMock, hostMock, volumeToPoolObjectMap, volumeVoMock, storagePoolVoMock);
Assert.assertTrue(volumeToPoolObjectMap.isEmpty());
}
@Test
public void createVolumeToStoragePoolMappingIfPossibleTestTargetHostDoesNotAccessCurrentStoragePool() {
StoragePoolVO storagePoolMockOther = Mockito.mock(StoragePoolVO.class);
String storagePoolMockOtherUuid = "storagePoolMockOtherUuid";
Mockito.doReturn(storagePoolMockOtherUuid).when(storagePoolMockOther).getUuid();
Mockito.doReturn(storagePoolMockOther).when(storagePoolDaoMock).findByUuid(storagePoolMockOtherUuid);
List<StoragePool> storagePoolList = new ArrayList<>();
storagePoolList.add(storagePoolMockOther);
Mockito.doReturn(storagePoolList).when(virtualMachineManagerImpl).getCandidateStoragePoolsToMigrateLocalVolume(virtualMachineProfileMock, hostMock, volumeVoMock);
HashMap<Volume, StoragePool> volumeToPoolObjectMap = new HashMap<>();
virtualMachineManagerImpl.createVolumeToStoragePoolMappingIfPossible(virtualMachineProfileMock, hostMock, volumeToPoolObjectMap, volumeVoMock, storagePoolVoMock);
Assert.assertFalse(volumeToPoolObjectMap.isEmpty());
Assert.assertEquals(storagePoolMockOther, volumeToPoolObjectMap.get(volumeVoMock));
}
@Test
public void createStoragePoolMappingsForVolumesTestLocalStoragevolume() {
ArrayList<Volume> allVolumes = new ArrayList<>();
allVolumes.add(volumeVoMock);
HashMap<Volume, StoragePool> volumeToPoolObjectMap = new HashMap<>();
Mockito.doReturn(ScopeType.HOST).when(storagePoolVoMock).getScope();
Mockito.doNothing().when(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolNotProvided(hostMock, storagePoolVoMock, volumeVoMock);
Mockito.doNothing().when(virtualMachineManagerImpl).createVolumeToStoragePoolMappingIfPossible(virtualMachineProfileMock, hostMock, volumeToPoolObjectMap, volumeVoMock,
storagePoolVoMock);
virtualMachineManagerImpl.createStoragePoolMappingsForVolumes(virtualMachineProfileMock, hostMock, volumeToPoolObjectMap, allVolumes);
Assert.assertTrue(volumeToPoolObjectMap.isEmpty());
Mockito.verify(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolNotProvided(hostMock, storagePoolVoMock, volumeVoMock);
Mockito.verify(virtualMachineManagerImpl).createVolumeToStoragePoolMappingIfPossible(virtualMachineProfileMock, hostMock, volumeToPoolObjectMap, volumeVoMock, storagePoolVoMock);
}
@Test
public void createStoragePoolMappingsForVolumesTestCrossCluterMigration() {
ArrayList<Volume> allVolumes = new ArrayList<>();
allVolumes.add(volumeVoMock);
HashMap<Volume, StoragePool> volumeToPoolObjectMap = new HashMap<>();
Mockito.doReturn(ScopeType.CLUSTER).when(storagePoolVoMock).getScope();
Mockito.doNothing().when(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolNotProvided(hostMock, storagePoolVoMock, volumeVoMock);
Mockito.doNothing().when(virtualMachineManagerImpl).createVolumeToStoragePoolMappingIfPossible(virtualMachineProfileMock, hostMock, volumeToPoolObjectMap, volumeVoMock, storagePoolVoMock);
Mockito.doReturn(true).when(virtualMachineManagerImpl).isStorageCrossClusterMigration(hostMock, storagePoolVoMock);
virtualMachineManagerImpl.createStoragePoolMappingsForVolumes(virtualMachineProfileMock, hostMock, volumeToPoolObjectMap, allVolumes);
Assert.assertTrue(volumeToPoolObjectMap.isEmpty());
Mockito.verify(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolNotProvided(hostMock, storagePoolVoMock, volumeVoMock);
Mockito.verify(virtualMachineManagerImpl).createVolumeToStoragePoolMappingIfPossible(virtualMachineProfileMock, hostMock, volumeToPoolObjectMap, volumeVoMock, storagePoolVoMock);
Mockito.verify(virtualMachineManagerImpl).isStorageCrossClusterMigration(hostMock, storagePoolVoMock);
}
@Test
public void createStoragePoolMappingsForVolumesTestNotCrossCluterMigrationWithClusterStorage() {
ArrayList<Volume> allVolumes = new ArrayList<>();
allVolumes.add(volumeVoMock);
HashMap<Volume, StoragePool> volumeToPoolObjectMap = new HashMap<>();
Mockito.doReturn(ScopeType.CLUSTER).when(storagePoolVoMock).getScope();
Mockito.doNothing().when(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolNotProvided(hostMock, storagePoolVoMock, volumeVoMock);
Mockito.doNothing().when(virtualMachineManagerImpl).createVolumeToStoragePoolMappingIfPossible(virtualMachineProfileMock, hostMock, volumeToPoolObjectMap, volumeVoMock, storagePoolVoMock);
Mockito.doReturn(false).when(virtualMachineManagerImpl).isStorageCrossClusterMigration(hostMock, storagePoolVoMock);
virtualMachineManagerImpl.createStoragePoolMappingsForVolumes(virtualMachineProfileMock, hostMock, volumeToPoolObjectMap, allVolumes);
Assert.assertFalse(volumeToPoolObjectMap.isEmpty());
Assert.assertEquals(storagePoolVoMock, volumeToPoolObjectMap.get(volumeVoMock));
Mockito.verify(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolNotProvided(hostMock, storagePoolVoMock, volumeVoMock);
Mockito.verify(virtualMachineManagerImpl).isStorageCrossClusterMigration(hostMock, storagePoolVoMock);
Mockito.verify(virtualMachineManagerImpl, Mockito.times(0)).createVolumeToStoragePoolMappingIfPossible(virtualMachineProfileMock, hostMock, volumeToPoolObjectMap, volumeVoMock,
storagePoolVoMock);
}
@Test
public void createMappingVolumeAndStoragePoolTest() {
Map<Volume, StoragePool> volumeToPoolObjectMap = new HashMap<>();
List<Volume> volumesNotMapped = new ArrayList<>();
Mockito.doReturn(volumeToPoolObjectMap).when(virtualMachineManagerImpl).buildMapUsingUserInformation(Mockito.eq(virtualMachineProfileMock), Mockito.eq(hostMock),
Mockito.anyMapOf(Long.class, Long.class));
Mockito.doReturn(volumesNotMapped).when(virtualMachineManagerImpl).findVolumesThatWereNotMappedByTheUser(virtualMachineProfileMock, volumeToPoolObjectMap);
Mockito.doNothing().when(virtualMachineManagerImpl).createStoragePoolMappingsForVolumes(virtualMachineProfileMock, hostMock, volumeToPoolObjectMap, volumesNotMapped);
Map<Volume, StoragePool> mappingVolumeAndStoragePool = virtualMachineManagerImpl.createMappingVolumeAndStoragePool(virtualMachineProfileMock, hostMock, new HashMap<>());
Assert.assertEquals(mappingVolumeAndStoragePool, volumeToPoolObjectMap);
InOrder inOrder = Mockito.inOrder(virtualMachineManagerImpl);
inOrder.verify(virtualMachineManagerImpl).buildMapUsingUserInformation(Mockito.eq(virtualMachineProfileMock), Mockito.eq(hostMock), Mockito.anyMapOf(Long.class, Long.class));
inOrder.verify(virtualMachineManagerImpl).findVolumesThatWereNotMappedByTheUser(virtualMachineProfileMock, volumeToPoolObjectMap);
inOrder.verify(virtualMachineManagerImpl).createStoragePoolMappingsForVolumes(virtualMachineProfileMock, hostMock, volumeToPoolObjectMap, volumesNotMapped);
}
}