| // Licensed to the Apache Software Foundation (ASF) under one | |
| // or more contributor license agreements. See the NOTICE file | |
| // distributed with this work for additional information | |
| // regarding copyright ownership. The ASF licenses this file | |
| // to you under the Apache License, Version 2.0 (the | |
| // "License"); you may not use this file except in compliance | |
| // with the License. You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, | |
| // software distributed under the License is distributed on an | |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| // KIND, either express or implied. See the License for the | |
| // specific language governing permissions and limitations | |
| // under the License. | |
| package com.cloud.vm; | |
| import com.cloud.agent.AgentManager; | |
| import com.cloud.agent.api.Answer; | |
| import com.cloud.agent.api.ScaleVmAnswer; | |
| import com.cloud.agent.api.ScaleVmCommand; | |
| import com.cloud.capacity.CapacityManager; | |
| import com.cloud.configuration.ConfigurationManager; | |
| import com.cloud.configuration.dao.ConfigurationDao; | |
| import com.cloud.deploy.DeployDestination; | |
| import com.cloud.host.HostVO; | |
| import com.cloud.host.dao.HostDao; | |
| import com.cloud.service.ServiceOfferingVO; | |
| import com.cloud.storage.VMTemplateVO; | |
| import com.cloud.storage.VolumeManager; | |
| import com.cloud.storage.VolumeVO; | |
| import com.cloud.agent.api.PrepareForMigrationAnswer; | |
| import com.cloud.agent.api.PrepareForMigrationCommand; | |
| import com.cloud.agent.api.MigrateWithStorageAnswer; | |
| import com.cloud.agent.api.MigrateWithStorageCommand; | |
| import com.cloud.agent.api.MigrateWithStorageReceiveAnswer; | |
| import com.cloud.agent.api.MigrateWithStorageReceiveCommand; | |
| import com.cloud.agent.api.MigrateWithStorageSendAnswer; | |
| import com.cloud.agent.api.MigrateWithStorageSendCommand; | |
| import com.cloud.agent.api.MigrateWithStorageCompleteAnswer; | |
| import com.cloud.agent.api.MigrateWithStorageCompleteCommand; | |
| import com.cloud.agent.api.CheckVirtualMachineAnswer; | |
| import com.cloud.agent.api.CheckVirtualMachineCommand; | |
| import com.cloud.capacity.CapacityManager; | |
| import com.cloud.configuration.ConfigurationManager; | |
| import com.cloud.configuration.dao.ConfigurationDao; | |
| import com.cloud.dc.dao.ClusterDao; | |
| import com.cloud.dc.dao.DataCenterDao; | |
| import com.cloud.dc.dao.HostPodDao; | |
| import com.cloud.exception.ConcurrentOperationException; | |
| import com.cloud.exception.ManagementServerException; | |
| import com.cloud.exception.ResourceUnavailableException; | |
| import com.cloud.exception.VirtualMachineMigrationException; | |
| import com.cloud.exception.OperationTimedoutException; | |
| import com.cloud.host.HostVO; | |
| import com.cloud.host.dao.HostDao; | |
| import com.cloud.hypervisor.HypervisorGuru; | |
| import com.cloud.hypervisor.HypervisorGuruManager; | |
| import com.cloud.hypervisor.Hypervisor.HypervisorType; | |
| import com.cloud.network.NetworkManager; | |
| import com.cloud.storage.DiskOfferingVO; | |
| import com.cloud.storage.StoragePoolHostVO; | |
| import com.cloud.storage.VolumeManager; | |
| import com.cloud.storage.VolumeVO; | |
| import com.cloud.storage.dao.DiskOfferingDao; | |
| import com.cloud.storage.dao.StoragePoolHostDao; | |
| import com.cloud.storage.dao.VMTemplateDao; | |
| import com.cloud.storage.dao.VolumeDao; | |
| import com.cloud.user.*; | |
| import com.cloud.user.dao.AccountDao; | |
| import com.cloud.user.dao.UserDao; | |
| import com.cloud.utils.exception.CloudRuntimeException; | |
| import com.cloud.vm.dao.UserVmDao; | |
| import com.cloud.vm.dao.VMInstanceDao; | |
| import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; | |
| import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; | |
| import com.cloud.utils.Pair; | |
| import com.cloud.utils.exception.CloudRuntimeException; | |
| import com.cloud.vm.dao.UserVmDao; | |
| import com.cloud.vm.dao.VMInstanceDao; | |
| import com.cloud.vm.snapshot.VMSnapshotManager; | |
| import com.cloud.vm.VirtualMachine.Event; | |
| import com.cloud.vm.VirtualMachine.State; | |
| import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; | |
| import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; | |
| import org.junit.Test; | |
| import org.junit.Before; | |
| import org.mockito.Mock; | |
| import org.mockito.MockitoAnnotations; | |
| import org.mockito.Spy; | |
| import static org.mockito.Matchers.anyLong; | |
| import static org.mockito.Mockito.*; | |
| import java.lang.reflect.Field; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.HashMap; | |
| import java.util.Iterator; | |
| public class VirtualMachineManagerImplTest { | |
| @Spy VirtualMachineManagerImpl _vmMgr = new VirtualMachineManagerImpl(); | |
| @Mock | |
| VolumeManager _storageMgr; | |
| @Mock | |
| Account _account; | |
| @Mock | |
| AccountManager _accountMgr; | |
| @Mock | |
| ConfigurationManager _configMgr; | |
| @Mock | |
| CapacityManager _capacityMgr; | |
| @Mock | |
| AgentManager _agentMgr; | |
| @Mock | |
| AccountDao _accountDao; | |
| @Mock | |
| ConfigurationDao _configDao; | |
| @Mock | |
| HostDao _hostDao; | |
| @Mock | |
| UserDao _userDao; | |
| @Mock | |
| UserVmDao _vmDao; | |
| @Mock | |
| ItWorkDao _workDao; | |
| @Mock | |
| VMInstanceDao _vmInstanceDao; | |
| @Mock | |
| VMTemplateDao _templateDao; | |
| @Mock | |
| VolumeDao _volsDao; | |
| @Mock | |
| RestoreVMCmd _restoreVMCmd; | |
| @Mock | |
| AccountVO _accountMock; | |
| @Mock | |
| UserVO _userMock; | |
| @Mock | |
| UserVmVO _vmMock; | |
| @Mock | |
| VMInstanceVO _vmInstance; | |
| @Mock | |
| HostVO _host; | |
| @Mock | |
| VMTemplateVO _templateMock; | |
| @Mock | |
| VolumeVO _volumeMock; | |
| @Mock | |
| List<VolumeVO> _rootVols; | |
| @Mock | |
| ItWorkVO _work; | |
| @Mock ClusterDao _clusterDao; | |
| @Mock HostPodDao _podDao; | |
| @Mock DataCenterDao _dcDao; | |
| @Mock DiskOfferingDao _diskOfferingDao; | |
| @Mock PrimaryDataStoreDao _storagePoolDao; | |
| @Mock StoragePoolHostDao _poolHostDao; | |
| @Mock NetworkManager _networkMgr; | |
| @Mock HypervisorGuruManager _hvGuruMgr; | |
| @Mock VMSnapshotManager _vmSnapshotMgr; | |
| // Mock objects for vm migration with storage test. | |
| @Mock DiskOfferingVO _diskOfferingMock; | |
| @Mock StoragePoolVO _srcStoragePoolMock; | |
| @Mock StoragePoolVO _destStoragePoolMock; | |
| @Mock HostVO _srcHostMock; | |
| @Mock HostVO _destHostMock; | |
| @Mock Map<VolumeVO, StoragePoolVO> _volumeToPoolMock; | |
| @Before | |
| public void setup(){ | |
| MockitoAnnotations.initMocks(this); | |
| _vmMgr._templateDao = _templateDao; | |
| _vmMgr._volsDao = _volsDao; | |
| _vmMgr.volumeMgr = _storageMgr; | |
| _vmMgr._accountDao = _accountDao; | |
| _vmMgr._userDao = _userDao; | |
| _vmMgr._accountMgr = _accountMgr; | |
| _vmMgr._configMgr = _configMgr; | |
| _vmMgr._capacityMgr = _capacityMgr; | |
| _vmMgr._hostDao = _hostDao; | |
| _vmMgr._nodeId = 1L; | |
| _vmMgr._workDao = _workDao; | |
| _vmMgr._agentMgr = _agentMgr; | |
| _vmMgr._podDao = _podDao; | |
| _vmMgr._clusterDao = _clusterDao; | |
| _vmMgr._dcDao = _dcDao; | |
| _vmMgr._diskOfferingDao = _diskOfferingDao; | |
| _vmMgr._storagePoolDao = _storagePoolDao; | |
| _vmMgr._poolHostDao= _poolHostDao; | |
| _vmMgr._networkMgr = _networkMgr; | |
| _vmMgr._hvGuruMgr = _hvGuruMgr; | |
| _vmMgr._vmSnapshotMgr = _vmSnapshotMgr; | |
| _vmMgr._vmDao = _vmInstanceDao; | |
| when(_vmMock.getId()).thenReturn(314l); | |
| when(_vmInstance.getId()).thenReturn(1L); | |
| when(_vmInstance.getServiceOfferingId()).thenReturn(2L); | |
| when(_vmInstance.getInstanceName()).thenReturn("myVm"); | |
| when(_vmInstance.getHostId()).thenReturn(2L); | |
| when(_vmInstance.getType()).thenReturn(VirtualMachine.Type.User); | |
| when(_host.getId()).thenReturn(1L); | |
| when(_hostDao.findById(anyLong())).thenReturn(null); | |
| when(_configMgr.getServiceOffering(anyLong())).thenReturn(getSvcoffering(512)); | |
| when(_workDao.persist(_work)).thenReturn(_work); | |
| when(_workDao.update("1", _work)).thenReturn(true); | |
| when(_work.getId()).thenReturn("1"); | |
| doNothing().when(_work).setStep(ItWorkVO.Step.Done); | |
| //doNothing().when(_volsDao).detachVolume(anyLong()); | |
| //when(_work.setStep(ItWorkVO.Step.Done)).thenReturn("1"); | |
| } | |
| @Test(expected=CloudRuntimeException.class) | |
| public void testScaleVM1() throws Exception { | |
| DeployDestination dest = new DeployDestination(null, null, null, _host); | |
| long l = 1L; | |
| when(_vmInstanceDao.findById(anyLong())).thenReturn(_vmInstance); | |
| _vmMgr.migrateForScale(_vmInstance, l, dest, l); | |
| } | |
| @Test (expected=CloudRuntimeException.class) | |
| public void testScaleVM2() throws Exception { | |
| DeployDestination dest = new DeployDestination(null, null, null, _host); | |
| long l = 1L; | |
| when(_vmInstanceDao.findById(anyLong())).thenReturn(_vmInstance); | |
| ServiceOfferingVO newServiceOffering = getSvcoffering(512); | |
| ScaleVmCommand reconfigureCmd = new ScaleVmCommand("myVmName", newServiceOffering.getCpu(), | |
| newServiceOffering.getSpeed(), newServiceOffering.getRamSize(), newServiceOffering.getRamSize(), newServiceOffering.getLimitCpuUse()); | |
| Answer answer = new ScaleVmAnswer(reconfigureCmd, true, "details"); | |
| when(_agentMgr.send(2l, reconfigureCmd)).thenReturn(null); | |
| _vmMgr.reConfigureVm(_vmInstance, getSvcoffering(256), false); | |
| } | |
| @Test (expected=CloudRuntimeException.class) | |
| public void testScaleVM3() throws Exception { | |
| /*VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm); | |
| Long srcHostId = vm.getHostId(); | |
| Long oldSvcOfferingId = vm.getServiceOfferingId(); | |
| if (srcHostId == null) { | |
| throw new CloudRuntimeException("Unable to scale the vm because it doesn't have a host id"); | |
| }*/ | |
| when(_vmInstance.getHostId()).thenReturn(null); | |
| when(_vmInstanceDao.findById(anyLong())).thenReturn(_vmInstance); | |
| _vmMgr.findHostAndMigrate(VirtualMachine.Type.User, _vmInstance, 2l); | |
| } | |
| private ServiceOfferingVO getSvcoffering(int ramSize){ | |
| long id = 4L; | |
| String name = "name"; | |
| String displayText = "displayText"; | |
| int cpu = 1; | |
| //int ramSize = 256; | |
| int speed = 128; | |
| boolean ha = false; | |
| boolean useLocalStorage = false; | |
| ServiceOfferingVO serviceOffering = new ServiceOfferingVO(name, cpu, ramSize, speed, null, null, ha, displayText, useLocalStorage, false, null, false, null, false); | |
| return serviceOffering; | |
| } | |
| private void initializeMockConfigForMigratingVmWithVolumes() throws OperationTimedoutException, | |
| ResourceUnavailableException { | |
| // Mock the source and destination hosts. | |
| when(_srcHostMock.getId()).thenReturn(5L); | |
| when(_destHostMock.getId()).thenReturn(6L); | |
| when(_hostDao.findById(5L)).thenReturn(_srcHostMock); | |
| when(_hostDao.findById(6L)).thenReturn(_destHostMock); | |
| // Mock the vm being migrated. | |
| when(_vmMock.getId()).thenReturn(1L); | |
| when(_vmMock.getHypervisorType()).thenReturn(HypervisorType.XenServer); | |
| when(_vmMock.getState()).thenReturn(State.Running).thenReturn(State.Running).thenReturn(State.Migrating) | |
| .thenReturn(State.Migrating); | |
| when(_vmMock.getHostId()).thenReturn(5L); | |
| when(_vmInstance.getId()).thenReturn(1L); | |
| when(_vmInstance.getServiceOfferingId()).thenReturn(2L); | |
| when(_vmInstance.getInstanceName()).thenReturn("myVm"); | |
| when(_vmInstance.getHostId()).thenReturn(5L); | |
| when(_vmInstance.getType()).thenReturn(VirtualMachine.Type.User); | |
| when(_vmInstance.getState()).thenReturn(State.Running).thenReturn(State.Running).thenReturn(State.Migrating) | |
| .thenReturn(State.Migrating); | |
| // Mock the work item. | |
| when(_workDao.persist(any(ItWorkVO.class))).thenReturn(_work); | |
| when(_workDao.update("1", _work)).thenReturn(true); | |
| when(_work.getId()).thenReturn("1"); | |
| doNothing().when(_work).setStep(ItWorkVO.Step.Done); | |
| // Mock the vm guru and the user vm object that gets returned. | |
| _vmMgr._vmGurus = new HashMap<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>>(); | |
| UserVmManagerImpl userVmManager = mock(UserVmManagerImpl.class); | |
| _vmMgr.registerGuru(VirtualMachine.Type.User, userVmManager); | |
| when(userVmManager.findById(anyLong())).thenReturn(_vmMock); | |
| // Mock the iteration over all the volumes of an instance. | |
| Iterator<VolumeVO> volumeIterator = mock(Iterator.class); | |
| when(_volsDao.findUsableVolumesForInstance(anyLong())).thenReturn(_rootVols); | |
| when(_rootVols.iterator()).thenReturn(volumeIterator); | |
| when(volumeIterator.hasNext()).thenReturn(true, false); | |
| when(volumeIterator.next()).thenReturn(_volumeMock); | |
| // Mock the disk offering and pool objects for a volume. | |
| when(_volumeMock.getDiskOfferingId()).thenReturn(5L); | |
| when(_volumeMock.getPoolId()).thenReturn(200L); | |
| when(_diskOfferingDao.findById(anyLong())).thenReturn(_diskOfferingMock); | |
| when(_storagePoolDao.findById(anyLong())).thenReturn(_srcStoragePoolMock); | |
| // Mock the volume to pool mapping. | |
| when(_volumeToPoolMock.get(_volumeMock)).thenReturn(_destStoragePoolMock); | |
| when(_destStoragePoolMock.getId()).thenReturn(201L); | |
| when(_srcStoragePoolMock.getId()).thenReturn(200L); | |
| when(_destStoragePoolMock.isLocal()).thenReturn(false); | |
| when(_diskOfferingMock.getUseLocalStorage()).thenReturn(false); | |
| when(_poolHostDao.findByPoolHost(anyLong(), anyLong())).thenReturn(mock(StoragePoolHostVO.class)); | |
| // Mock hypervisor guru. | |
| HypervisorGuru guruMock = mock(HypervisorGuru.class); | |
| when(_hvGuruMgr.getGuru(HypervisorType.XenServer)).thenReturn(guruMock); | |
| when(_srcHostMock.getClusterId()).thenReturn(3L); | |
| when(_destHostMock.getClusterId()).thenReturn(3L); | |
| // Mock the commands and answers to the agent. | |
| PrepareForMigrationAnswer prepAnswerMock = mock(PrepareForMigrationAnswer.class); | |
| when(prepAnswerMock.getResult()).thenReturn(true); | |
| when(_agentMgr.send(anyLong(), isA(PrepareForMigrationCommand.class))).thenReturn(prepAnswerMock); | |
| MigrateWithStorageAnswer migAnswerMock = mock(MigrateWithStorageAnswer.class); | |
| when(migAnswerMock.getResult()).thenReturn(true); | |
| when(_agentMgr.send(anyLong(), isA(MigrateWithStorageCommand.class))).thenReturn(migAnswerMock); | |
| MigrateWithStorageReceiveAnswer migRecAnswerMock = mock(MigrateWithStorageReceiveAnswer.class); | |
| when(migRecAnswerMock.getResult()).thenReturn(true); | |
| when(_agentMgr.send(anyLong(), isA(MigrateWithStorageReceiveCommand.class))).thenReturn(migRecAnswerMock); | |
| MigrateWithStorageSendAnswer migSendAnswerMock = mock(MigrateWithStorageSendAnswer.class); | |
| when(migSendAnswerMock.getResult()).thenReturn(true); | |
| when(_agentMgr.send(anyLong(), isA(MigrateWithStorageSendCommand.class))).thenReturn(migSendAnswerMock); | |
| MigrateWithStorageCompleteAnswer migCompleteAnswerMock = mock(MigrateWithStorageCompleteAnswer.class); | |
| when(migCompleteAnswerMock.getResult()).thenReturn(true); | |
| when(_agentMgr.send(anyLong(), isA(MigrateWithStorageCompleteCommand.class))).thenReturn(migCompleteAnswerMock); | |
| CheckVirtualMachineAnswer checkVmAnswerMock = mock(CheckVirtualMachineAnswer.class); | |
| when(checkVmAnswerMock.getResult()).thenReturn(true); | |
| when(checkVmAnswerMock.getState()).thenReturn(State.Running); | |
| when(_agentMgr.send(anyLong(), isA(CheckVirtualMachineCommand.class))).thenReturn(checkVmAnswerMock); | |
| // Mock the state transitions of vm. | |
| Pair<Long, Long> opaqueMock = new Pair<Long, Long> (_vmMock.getHostId(), _destHostMock.getId()); | |
| when(_vmSnapshotMgr.hasActiveVMSnapshotTasks(anyLong())).thenReturn(false); | |
| when(_vmInstanceDao.updateState(State.Running, Event.MigrationRequested, State.Migrating, _vmMock, opaqueMock)) | |
| .thenReturn(true); | |
| when(_vmInstanceDao.updateState(State.Migrating, Event.OperationSucceeded, State.Running, _vmMock, opaqueMock)) | |
| .thenReturn(true); | |
| } | |
| // Check migration of a vm with its volumes within a cluster. | |
| @Test | |
| public void testMigrateWithVolumeWithinCluster() throws ResourceUnavailableException, ConcurrentOperationException, | |
| ManagementServerException, VirtualMachineMigrationException, OperationTimedoutException { | |
| initializeMockConfigForMigratingVmWithVolumes(); | |
| when(_srcHostMock.getClusterId()).thenReturn(3L); | |
| when(_destHostMock.getClusterId()).thenReturn(3L); | |
| _vmMgr.migrateWithStorage(_vmInstance, _srcHostMock.getId(), _destHostMock.getId(), _volumeToPoolMock); | |
| } | |
| // Check migration of a vm with its volumes across a cluster. | |
| @Test | |
| public void testMigrateWithVolumeAcrossCluster() throws ResourceUnavailableException, ConcurrentOperationException, | |
| ManagementServerException, VirtualMachineMigrationException, OperationTimedoutException { | |
| initializeMockConfigForMigratingVmWithVolumes(); | |
| when(_srcHostMock.getClusterId()).thenReturn(3L); | |
| when(_destHostMock.getClusterId()).thenReturn(4L); | |
| _vmMgr.migrateWithStorage(_vmInstance, _srcHostMock.getId(), _destHostMock.getId(), _volumeToPoolMock); | |
| } | |
| // Check migration of a vm fails when src and destination pool are not of same type; that is, one is shared and | |
| // other is local. | |
| @Test(expected=CloudRuntimeException.class) | |
| public void testMigrateWithVolumeFail1() throws ResourceUnavailableException, ConcurrentOperationException, | |
| ManagementServerException, VirtualMachineMigrationException, OperationTimedoutException { | |
| initializeMockConfigForMigratingVmWithVolumes(); | |
| when(_srcHostMock.getClusterId()).thenReturn(3L); | |
| when(_destHostMock.getClusterId()).thenReturn(3L); | |
| when(_destStoragePoolMock.isLocal()).thenReturn(true); | |
| when(_diskOfferingMock.getUseLocalStorage()).thenReturn(false); | |
| _vmMgr.migrateWithStorage(_vmInstance, _srcHostMock.getId(), _destHostMock.getId(), _volumeToPoolMock); | |
| } | |
| // Check migration of a vm fails when vm is not in Running state. | |
| @Test(expected=ConcurrentOperationException.class) | |
| public void testMigrateWithVolumeFail2() throws ResourceUnavailableException, ConcurrentOperationException, | |
| ManagementServerException, VirtualMachineMigrationException, OperationTimedoutException { | |
| initializeMockConfigForMigratingVmWithVolumes(); | |
| when(_srcHostMock.getClusterId()).thenReturn(3L); | |
| when(_destHostMock.getClusterId()).thenReturn(3L); | |
| when(_vmMock.getState()).thenReturn(State.Stopped); | |
| _vmMgr.migrateWithStorage(_vmInstance, _srcHostMock.getId(), _destHostMock.getId(), _volumeToPoolMock); | |
| } | |
| } |