diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index ca453ed0de1..7792afd2c63 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -569,7 +569,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac allocate(vmInstanceName, template, serviceOffering, new DiskOfferingInfo(diskOffering), new ArrayList<>(), networks, plan, hyperType, null, null); } - private VirtualMachineGuru getVmGuru(final VirtualMachine vm) { + VirtualMachineGuru getVmGuru(final VirtualMachine vm) { if(vm != null) { return _vmGurus.get(vm.getType()); } @@ -1443,6 +1443,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } if (canRetry) { try { + conditionallySetPodToDeployIn(vm); changeState(vm, Event.OperationFailed, null, work, Step.Done); } catch (final NoTransitionException e) { throw new ConcurrentOperationException(e.getMessage()); @@ -1460,6 +1461,24 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } } + /** + * Setting pod id to null can result in migration of Volumes across pods. This is not desirable for VMs which + * have a volume in Ready state (happens when a VM is shutdown and started again). + * So, we set it to null only when + * migration of VM across cluster is enabled + * Or, volumes are still in allocated state for that VM (happens when VM is Starting/deployed for the first time) + */ + private void conditionallySetPodToDeployIn(VMInstanceVO vm) { + if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(vm.getDataCenterId()) || areAllVolumesAllocated(vm.getId())) { + vm.setPodIdToDeployIn(null); + } + } + + boolean areAllVolumesAllocated(long vmId) { + final List vols = _volsDao.findByInstance(vmId); + return CollectionUtils.isEmpty(vols) || vols.stream().allMatch(v -> Volume.State.Allocated.equals(v.getState())); + } + private void logBootModeParameters(Map params) { if (params == null) { return; diff --git a/engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java b/engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java index 15a2f2c0ac1..20af10ed338 100644 --- a/engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java +++ b/engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java @@ -19,9 +19,12 @@ package com.cloud.vm; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyLong; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.when; @@ -35,6 +38,23 @@ import java.util.Map; import java.util.Random; import java.util.stream.Collectors; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; +import com.cloud.dc.Pod; +import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeploymentPlanningManager; +import com.cloud.hypervisor.HypervisorGuruManager; +import com.cloud.org.Cluster; +import com.cloud.template.VirtualMachineTemplate; +import com.cloud.user.Account; +import com.cloud.user.User; +import com.cloud.utils.Journal; +import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.fsm.StateMachine2; +import com.cloud.vm.dao.UserVmDetailsDao; +import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; @@ -49,7 +69,6 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.Spy; import org.mockito.stubbing.Answer; -import org.mockito.runners.MockitoJUnitRunner; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Command; @@ -88,13 +107,20 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.springframework.test.util.ReflectionTestUtils; -@RunWith(MockitoJUnitRunner.class) +@RunWith(PowerMockRunner.class) +@PrepareForTest(CallContext.class) +@PowerMockIgnore({"javax.xml.*", "org.w3c.dom.*", "org.apache.xerces.*", "org.xml.*"}) public class VirtualMachineManagerImplTest { @Spy @InjectMocks - private VirtualMachineManagerImpl virtualMachineManagerImpl; + private VirtualMachineManagerImpl virtualMachineManagerImpl = new VirtualMachineManagerImpl(); @Mock private AgentManager agentManagerMock; @Mock @@ -155,6 +181,20 @@ public class VirtualMachineManagerImplTest { private UserVmDao userVmDaoMock; @Mock private UserVmVO userVmMock; + @Mock + private EntityManager _entityMgr; + @Mock + private DeploymentPlanningManager _dpMgr; + @Mock + private HypervisorGuruManager _hvGuruMgr; + @Mock + private ClusterDetailsDao _clusterDetailsDao; + @Mock + private UserVmDetailsDao userVmDetailsDao; + @Mock + private ItWorkDao _workDao; + @Mock + protected StateMachine2 _stateMachine; @Before public void setup() { @@ -433,7 +473,7 @@ public class VirtualMachineManagerImplTest { HashMap 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.doNothing().when(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolProvided(any(StoragePoolVO.class), any(VolumeVO.class), any(StoragePoolVO.class)); Mockito.doReturn(null).when(storagePoolHostDaoMock).findByPoolHost(storagePoolVoMockId, hostMockId); virtualMachineManagerImpl.buildMapUsingUserInformation(virtualMachineProfileMock, hostMock, userDefinedVolumeToStoragePoolMap); @@ -445,8 +485,8 @@ public class VirtualMachineManagerImplTest { HashMap 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.doNothing().when(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolProvided(any(StoragePoolVO.class), any(VolumeVO.class), + any(StoragePoolVO.class)); Mockito.doReturn(Mockito.mock(StoragePoolHostVO.class)).when(storagePoolHostDaoMock).findByPoolHost(storagePoolVoMockId, hostMockId); Map volumeToPoolObjectMap = virtualMachineManagerImpl.buildMapUsingUserInformation(virtualMachineProfileMock, hostMock, userDefinedVolumeToStoragePoolMap); @@ -482,7 +522,7 @@ public class VirtualMachineManagerImplTest { virtualMachineManagerImpl.executeManagedStorageChecksWhenTargetStoragePoolNotProvided(hostMock, storagePoolVoMock, volumeVoMock); Mockito.verify(storagePoolVoMock).isManaged(); - Mockito.verify(storagePoolHostDaoMock, Mockito.times(0)).findByPoolHost(Mockito.anyLong(), Mockito.anyLong()); + Mockito.verify(storagePoolHostDaoMock, Mockito.times(0)).findByPoolHost(anyLong(), anyLong()); } @Test @@ -506,15 +546,15 @@ public class VirtualMachineManagerImplTest { @Test public void getCandidateStoragePoolsToMigrateLocalVolumeTestLocalVolume() { - Mockito.doReturn(Mockito.mock(DiskOfferingVO.class)).when(diskOfferingDaoMock).findById(Mockito.anyLong()); + Mockito.doReturn(Mockito.mock(DiskOfferingVO.class)).when(diskOfferingDaoMock).findById(anyLong()); Mockito.doReturn(true).when(storagePoolVoMock).isLocal(); List 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(poolListMock).when(storagePoolAllocatorMock).allocateToPool(any(DiskProfile.class), any(VirtualMachineProfile.class), any(DeploymentPlan.class), + any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL)); List poolList = virtualMachineManagerImpl.getCandidateStoragePoolsToMigrateLocalVolume(virtualMachineProfileMock, dataCenterDeploymentMock, volumeVoMock); @@ -524,15 +564,15 @@ public class VirtualMachineManagerImplTest { @Test public void getCandidateStoragePoolsToMigrateLocalVolumeTestCrossClusterMigration() { - Mockito.doReturn(Mockito.mock(DiskOfferingVO.class)).when(diskOfferingDaoMock).findById(Mockito.anyLong()); + Mockito.doReturn(Mockito.mock(DiskOfferingVO.class)).when(diskOfferingDaoMock).findById(anyLong()); Mockito.doReturn(false).when(storagePoolVoMock).isLocal(); List 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(poolListMock).when(storagePoolAllocatorMock).allocateToPool(any(DiskProfile.class), any(VirtualMachineProfile.class), any(DeploymentPlan.class), + any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL)); Mockito.doReturn(true).when(virtualMachineManagerImpl).isStorageCrossClusterMigration(clusterMockId, storagePoolVoMock); List poolList = virtualMachineManagerImpl.getCandidateStoragePoolsToMigrateLocalVolume(virtualMachineProfileMock, dataCenterDeploymentMock, volumeVoMock); @@ -543,15 +583,15 @@ public class VirtualMachineManagerImplTest { @Test public void getCandidateStoragePoolsToMigrateLocalVolumeTestWithinClusterMigration() { - Mockito.doReturn(Mockito.mock(DiskOfferingVO.class)).when(diskOfferingDaoMock).findById(Mockito.anyLong()); + Mockito.doReturn(Mockito.mock(DiskOfferingVO.class)).when(diskOfferingDaoMock).findById(anyLong()); Mockito.doReturn(false).when(storagePoolVoMock).isLocal(); List 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(poolListMock).when(storagePoolAllocatorMock).allocateToPool(any(DiskProfile.class), any(VirtualMachineProfile.class), any(DeploymentPlan.class), + any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL)); Mockito.doReturn(false).when(virtualMachineManagerImpl).isStorageCrossClusterMigration(clusterMockId, storagePoolVoMock); List poolList = virtualMachineManagerImpl.getCandidateStoragePoolsToMigrateLocalVolume(virtualMachineProfileMock, dataCenterDeploymentMock, volumeVoMock); @@ -571,33 +611,33 @@ public class VirtualMachineManagerImplTest { virtualMachineManagerImpl.setStoragePoolAllocators(storagePoolAllocatorsMock); - Mockito.doReturn(Mockito.mock(DiskOfferingVO.class)).when(diskOfferingDaoMock).findById(Mockito.anyLong()); + Mockito.doReturn(Mockito.mock(DiskOfferingVO.class)).when(diskOfferingDaoMock).findById(anyLong()); Mockito.doReturn(false).when(storagePoolVoMock).isLocal(); List 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(poolListMock).when(storagePoolAllocatorMock).allocateToPool(any(DiskProfile.class), any(VirtualMachineProfile.class), any(DeploymentPlan.class), + 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(null).when(storagePoolAllocatorMock2).allocateToPool(any(DiskProfile.class), any(VirtualMachineProfile.class), any(DeploymentPlan.class), + 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(new ArrayList<>()).when(storagePoolAllocatorMock3).allocateToPool(any(DiskProfile.class), any(VirtualMachineProfile.class), any(DeploymentPlan.class), + any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL)); Mockito.doReturn(false).when(virtualMachineManagerImpl).isStorageCrossClusterMigration(clusterMockId, storagePoolVoMock); List poolList = virtualMachineManagerImpl.getCandidateStoragePoolsToMigrateLocalVolume(virtualMachineProfileMock, dataCenterDeploymentMock, 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)); + Mockito.verify(storagePoolAllocatorMock).allocateToPool(any(DiskProfile.class), any(VirtualMachineProfile.class), any(DeploymentPlan.class), + any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL)); + Mockito.verify(storagePoolAllocatorMock2).allocateToPool(any(DiskProfile.class), any(VirtualMachineProfile.class), any(DeploymentPlan.class), + any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL)); + Mockito.verify(storagePoolAllocatorMock3).allocateToPool(any(DiskProfile.class), any(VirtualMachineProfile.class), any(DeploymentPlan.class), + any(ExcludeList.class), Mockito.eq(StoragePoolAllocator.RETURN_UPTO_ALL)); } @Test(expected = CloudRuntimeException.class) @@ -686,8 +726,8 @@ public class VirtualMachineManagerImplTest { HashMap volumeToPoolObjectMap = new HashMap<>(); Mockito.doReturn(ScopeType.CLUSTER).when(storagePoolVoMock).getScope(); - Mockito.doNothing().when(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolNotProvided(Mockito.any(), Mockito.any(), Mockito.any()); - Mockito.doReturn(false).when(virtualMachineManagerImpl).isStorageCrossClusterMigration(Mockito.anyLong(), Mockito.any()); + Mockito.doNothing().when(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolNotProvided(any(), any(), any()); + Mockito.doReturn(false).when(virtualMachineManagerImpl).isStorageCrossClusterMigration(anyLong(), any()); virtualMachineManagerImpl.createStoragePoolMappingsForVolumes(virtualMachineProfileMock, dataCenterDeploymentMock, volumeToPoolObjectMap, allVolumes); @@ -710,7 +750,7 @@ public class VirtualMachineManagerImplTest { Mockito.doReturn(volumesNotMapped).when(virtualMachineManagerImpl).findVolumesThatWereNotMappedByTheUser(virtualMachineProfileMock, volumeToPoolObjectMap); Mockito.doNothing().when(virtualMachineManagerImpl).createStoragePoolMappingsForVolumes(Mockito.eq(virtualMachineProfileMock), - Mockito.any(DataCenterDeployment.class), Mockito.eq(volumeToPoolObjectMap), Mockito.eq(volumesNotMapped)); + any(DataCenterDeployment.class), Mockito.eq(volumeToPoolObjectMap), Mockito.eq(volumesNotMapped)); Map mappingVolumeAndStoragePool = virtualMachineManagerImpl.createMappingVolumeAndStoragePool(virtualMachineProfileMock, hostMock, new HashMap<>()); @@ -720,7 +760,7 @@ public class VirtualMachineManagerImplTest { 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(Mockito.eq(virtualMachineProfileMock), - Mockito.any(DataCenterDeployment.class), Mockito.eq(volumeToPoolObjectMap), Mockito.eq(volumesNotMapped)); + any(DataCenterDeployment.class), Mockito.eq(volumeToPoolObjectMap), Mockito.eq(volumesNotMapped)); } @Test @@ -774,11 +814,11 @@ public class VirtualMachineManagerImplTest { private void prepareAndTestIsRootVolumeOnLocalStorage(ScopeType scope, boolean expected) { StoragePoolVO storagePoolVoMock = Mockito.mock(StoragePoolVO.class); - Mockito.doReturn(storagePoolVoMock).when(storagePoolDaoMock).findById(Mockito.anyLong()); + Mockito.doReturn(storagePoolVoMock).when(storagePoolDaoMock).findById(anyLong()); Mockito.doReturn(scope).when(storagePoolVoMock).getScope(); List mockedVolumes = new ArrayList<>(); mockedVolumes.add(volumeVoMock); - Mockito.doReturn(mockedVolumes).when(volumeDaoMock).findByInstanceAndType(Mockito.anyLong(), Mockito.any()); + Mockito.doReturn(mockedVolumes).when(volumeDaoMock).findByInstanceAndType(anyLong(), any()); boolean result = virtualMachineManagerImpl.isRootVolumeOnLocalStorage(0l); @@ -806,7 +846,7 @@ public class VirtualMachineManagerImplTest { } private void prepareAndRunCheckIfNewOfferingStorageScopeMatchesStoragePool(boolean isRootOnLocal, boolean isOfferingUsingLocal) { - Mockito.doReturn(isRootOnLocal).when(virtualMachineManagerImpl).isRootVolumeOnLocalStorage(Mockito.anyLong()); + Mockito.doReturn(isRootOnLocal).when(virtualMachineManagerImpl).isRootVolumeOnLocalStorage(anyLong()); Mockito.doReturn("vmInstanceMockedToString").when(vmInstanceMock).toString(); Mockito.doReturn(isOfferingUsingLocal).when(diskOfferingMock).isUseLocalStorage(); virtualMachineManagerImpl.checkIfNewOfferingStorageScopeMatchesStoragePool(vmInstanceMock, diskOfferingMock); @@ -895,4 +935,188 @@ public class VirtualMachineManagerImplTest { map.put(Mockito.mock(Volume.class), pool2); virtualMachineManagerImpl.checkAndAttemptMigrateVmAcrossCluster(vm, destinationClusterId, map); } + + @Test + public void testOrchestrateStartNonNullPodId() throws Exception { + VMInstanceVO vmInstance = new VMInstanceVO(); + ReflectionTestUtils.setField(vmInstance, "id", 1L); + ReflectionTestUtils.setField(vmInstance, "uuid", "vm-uuid"); + ReflectionTestUtils.setField(vmInstance, "serviceOfferingId", 2L); + ReflectionTestUtils.setField(vmInstance, "instanceName", "myVm"); + ReflectionTestUtils.setField(vmInstance, "hostId", 2L); + ReflectionTestUtils.setField(vmInstance, "type", VirtualMachine.Type.User); + ReflectionTestUtils.setField(vmInstance, "dataCenterId", 1L); + ReflectionTestUtils.setField(vmInstance, "hypervisorType", HypervisorType.KVM); + + VirtualMachineGuru vmGuru = mock(VirtualMachineGuru.class); + + User user = mock(User.class); + + Account account = mock(Account.class); + + ReservationContext ctx = mock(ReservationContext.class); + + ItWorkVO work = mock(ItWorkVO.class); + + ServiceOfferingVO serviceOffering = mock(ServiceOfferingVO.class); + + VirtualMachineTemplate template = mock(VirtualMachineTemplate.class); + when(template.isDeployAsIs()).thenReturn(false); + + DataCenterDeployment plan = mock(DataCenterDeployment.class); + when(plan.getDataCenterId()).thenReturn(1L); + when(plan.getPodId()).thenReturn(1L); + + Map params = new HashMap<>(); + + DeploymentPlanner planner = mock(DeploymentPlanner.class); + + when(vmInstanceDaoMock.findByUuid("vm-uuid")).thenReturn(vmInstance); + + doReturn(vmGuru).when(virtualMachineManagerImpl).getVmGuru(vmInstance); + + Ternary start = new Ternary<>(vmInstance, ctx, work); + Mockito.doReturn(start).when(virtualMachineManagerImpl).changeToStartState(vmGuru, vmInstance, user, account); + + when(ctx.getJournal()).thenReturn(Mockito.mock(Journal.class)); + + when(serviceOfferingDaoMock.findById(vmInstance.getId(), vmInstance.getServiceOfferingId())).thenReturn(serviceOffering); + + when(_entityMgr.findByIdIncludingRemoved(VirtualMachineTemplate.class, vmInstance.getTemplateId())).thenReturn(template); + + Host destHost = mock(Host.class); + Pod destPod = mock(Pod.class); + DeployDestination dest = mock(DeployDestination.class); + when(dest.getHost()).thenReturn(destHost); + when(dest.getPod()).thenReturn(destPod); + when(dest.getCluster()).thenReturn(mock(Cluster.class)); + when(destHost.getId()).thenReturn(1L); + when(destPod.getId()).thenReturn(2L); + when(_dpMgr.planDeployment(any(VirtualMachineProfileImpl.class), any(DataCenterDeployment.class), any(ExcludeList.class), any(DeploymentPlanner.class))).thenReturn(dest); + + doNothing().when(virtualMachineManagerImpl).checkIfTemplateNeededForCreatingVmVolumes(vmInstance); + + when(_workDao.updateStep(any(), any())).thenReturn(true); + when(_stateMachine.transitTo(vmInstance, VirtualMachine.Event.OperationRetry, new Pair(vmInstance.getHostId(), 1L), vmInstanceDaoMock)).thenThrow(new CloudRuntimeException("Error while transitioning")); + when(_stateMachine.transitTo(vmInstance, VirtualMachine.Event.OperationFailed, new Pair(vmInstance.getHostId(), null), vmInstanceDaoMock)).thenReturn(true); + + + Cluster cluster = mock(Cluster.class); + when(dest.getCluster()).thenReturn(cluster); + ClusterDetailsVO cluster_detail_cpu = mock(ClusterDetailsVO.class); + ClusterDetailsVO cluster_detail_ram = mock(ClusterDetailsVO.class); + when(cluster.getId()).thenReturn(1L); + when(_clusterDetailsDao.findDetail(1L, VmDetailConstants.CPU_OVER_COMMIT_RATIO)).thenReturn(cluster_detail_cpu); + when(_clusterDetailsDao.findDetail(1L, VmDetailConstants.MEMORY_OVER_COMMIT_RATIO)).thenReturn(cluster_detail_ram); + when(userVmDetailsDao.findDetail(anyLong(), Mockito.anyString())).thenReturn(null); + when(cluster_detail_cpu.getValue()).thenReturn("1.0"); + when(cluster_detail_ram.getValue()).thenReturn("1.0"); + doReturn(false).when(virtualMachineManagerImpl).areAllVolumesAllocated(Mockito.anyLong()); + + CallContext callContext = mock(CallContext.class); + Mockito.when(callContext.getCallingAccount()).thenReturn(account); + Mockito.when(callContext.getCallingUser()).thenReturn(user); + PowerMockito.mockStatic(CallContext.class); + PowerMockito.when(CallContext.current()).thenReturn(callContext); + + try { + virtualMachineManagerImpl.orchestrateStart("vm-uuid", params, plan, planner); + } catch (CloudRuntimeException e) { + assertEquals(e.getMessage(), "Error while transitioning"); + } + + assertEquals(vmInstance.getPodIdToDeployIn(), (Long) destPod.getId()); + } + + @Test + public void testOrchestrateStartNullPodId() throws Exception { + VMInstanceVO vmInstance = new VMInstanceVO(); + ReflectionTestUtils.setField(vmInstance, "id", 1L); + ReflectionTestUtils.setField(vmInstance, "uuid", "vm-uuid"); + ReflectionTestUtils.setField(vmInstance, "serviceOfferingId", 2L); + ReflectionTestUtils.setField(vmInstance, "instanceName", "myVm"); + ReflectionTestUtils.setField(vmInstance, "hostId", 2L); + ReflectionTestUtils.setField(vmInstance, "type", VirtualMachine.Type.User); + ReflectionTestUtils.setField(vmInstance, "dataCenterId", 1L); + ReflectionTestUtils.setField(vmInstance, "hypervisorType", HypervisorType.KVM); + + VirtualMachineGuru vmGuru = mock(VirtualMachineGuru.class); + + User user = mock(User.class); + + Account account = mock(Account.class); + + ReservationContext ctx = mock(ReservationContext.class); + + ItWorkVO work = mock(ItWorkVO.class); + + ServiceOfferingVO serviceOffering = mock(ServiceOfferingVO.class); + + VirtualMachineTemplate template = mock(VirtualMachineTemplate.class); + when(template.isDeployAsIs()).thenReturn(false); + + DataCenterDeployment plan = mock(DataCenterDeployment.class); + when(plan.getDataCenterId()).thenReturn(1L); + when(plan.getPodId()).thenReturn(1L); + + Map params = new HashMap<>(); + + DeploymentPlanner planner = mock(DeploymentPlanner.class); + + when(vmInstanceDaoMock.findByUuid("vm-uuid")).thenReturn(vmInstance); + + doReturn(vmGuru).when(virtualMachineManagerImpl).getVmGuru(vmInstance); + + Ternary start = new Ternary<>(vmInstance, ctx, work); + Mockito.doReturn(start).when(virtualMachineManagerImpl).changeToStartState(vmGuru, vmInstance, user, account); + + when(ctx.getJournal()).thenReturn(Mockito.mock(Journal.class)); + + when(serviceOfferingDaoMock.findById(vmInstance.getId(), vmInstance.getServiceOfferingId())).thenReturn(serviceOffering); + + when(_entityMgr.findByIdIncludingRemoved(VirtualMachineTemplate.class, vmInstance.getTemplateId())).thenReturn(template); + + Host destHost = mock(Host.class); + Pod destPod = mock(Pod.class); + DeployDestination dest = mock(DeployDestination.class); + when(dest.getHost()).thenReturn(destHost); + when(dest.getPod()).thenReturn(destPod); + when(dest.getCluster()).thenReturn(mock(Cluster.class)); + when(destHost.getId()).thenReturn(1L); + when(destPod.getId()).thenReturn(2L); + when(_dpMgr.planDeployment(any(VirtualMachineProfileImpl.class), any(DataCenterDeployment.class), any(ExcludeList.class), any(DeploymentPlanner.class))).thenReturn(dest); + + doNothing().when(virtualMachineManagerImpl).checkIfTemplateNeededForCreatingVmVolumes(vmInstance); + + when(_workDao.updateStep(any(), any())).thenReturn(true); + when(_stateMachine.transitTo(vmInstance, VirtualMachine.Event.OperationRetry, new Pair(vmInstance.getHostId(), 1L), vmInstanceDaoMock)).thenThrow(new CloudRuntimeException("Error while transitioning")); + when(_stateMachine.transitTo(vmInstance, VirtualMachine.Event.OperationFailed, new Pair(vmInstance.getHostId(), null), vmInstanceDaoMock)).thenReturn(true); + + + Cluster cluster = mock(Cluster.class); + when(dest.getCluster()).thenReturn(cluster); + ClusterDetailsVO cluster_detail_cpu = mock(ClusterDetailsVO.class); + ClusterDetailsVO cluster_detail_ram = mock(ClusterDetailsVO.class); + when(cluster.getId()).thenReturn(1L); + when(_clusterDetailsDao.findDetail(1L, VmDetailConstants.CPU_OVER_COMMIT_RATIO)).thenReturn(cluster_detail_cpu); + when(_clusterDetailsDao.findDetail(1L, VmDetailConstants.MEMORY_OVER_COMMIT_RATIO)).thenReturn(cluster_detail_ram); + when(userVmDetailsDao.findDetail(anyLong(), Mockito.anyString())).thenReturn(null); + when(cluster_detail_cpu.getValue()).thenReturn("1.0"); + when(cluster_detail_ram.getValue()).thenReturn("1.0"); + doReturn(true).when(virtualMachineManagerImpl).areAllVolumesAllocated(Mockito.anyLong()); + + CallContext callContext = mock(CallContext.class); + Mockito.when(callContext.getCallingAccount()).thenReturn(account); + Mockito.when(callContext.getCallingUser()).thenReturn(user); + PowerMockito.mockStatic(CallContext.class); + PowerMockito.when(CallContext.current()).thenReturn(callContext); + + try { + virtualMachineManagerImpl.orchestrateStart("vm-uuid", params, plan, planner); + } catch (CloudRuntimeException e) { + assertEquals(e.getMessage(), "Error while transitioning"); + } + + assertNull(vmInstance.getPodIdToDeployIn()); + } }