Merge remote-tracking branch 'origin/4.14'

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Rohit Yadav 2020-08-05 23:59:16 +05:30
commit 562a7db8df
6 changed files with 148 additions and 196 deletions

View File

@ -490,6 +490,8 @@ public interface UserVmService {
UserVm restoreVM(RestoreVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException;
UserVm restoreVirtualMachine(Account caller, long vmId, Long newTemplateId) throws InsufficientCapacityException, ResourceUnavailableException;
UserVm upgradeVirtualMachine(ScaleVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException,
VirtualMachineMigrationException;

View File

@ -43,6 +43,7 @@ import com.cloud.offering.ServiceOffering;
import com.cloud.storage.StoragePool;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account;
import com.cloud.uservm.UserVm;
import com.cloud.utils.component.Manager;
import com.cloud.utils.fsm.NoTransitionException;
@ -234,4 +235,6 @@ public interface VirtualMachineManager extends Manager {
* - Keep the VM as it is on the hypervisor
*/
boolean unmanage(String vmUuid);
UserVm restoreVirtualMachine(long vmId, Long newTemplateId) throws ResourceUnavailableException, InsufficientCapacityException;
}

View File

@ -201,6 +201,7 @@ import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account;
import com.cloud.user.ResourceLimitService;
import com.cloud.user.User;
import com.cloud.uservm.UserVm;
import com.cloud.utils.DateUtil;
import com.cloud.utils.Journal;
import com.cloud.utils.Pair;
@ -5629,4 +5630,107 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
_resourceLimitMgr.decrementResourceCount(accountId, ResourceType.memory, memory);
}
@Override
public UserVm restoreVirtualMachine(final long vmId, final Long newTemplateId) throws ResourceUnavailableException, InsufficientCapacityException {
final AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) {
VmWorkJobVO placeHolder = null;
placeHolder = createPlaceHolderWork(vmId);
try {
return orchestrateRestoreVirtualMachine(vmId, newTemplateId);
} finally {
if (placeHolder != null) {
_workJobDao.expunge(placeHolder.getId());
}
}
} else {
final Outcome<VirtualMachine> outcome = restoreVirtualMachineThroughJobQueue(vmId, newTemplateId);
try {
outcome.get();
} catch (final InterruptedException e) {
throw new RuntimeException("Operation is interrupted", e);
} catch (final java.util.concurrent.ExecutionException e) {
throw new RuntimeException("Execution exception", e);
}
final Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob());
if (jobResult != null) {
if (jobResult instanceof ResourceUnavailableException) {
throw (ResourceUnavailableException)jobResult;
} else if (jobResult instanceof ConcurrentOperationException) {
throw (ConcurrentOperationException)jobResult;
} else if (jobResult instanceof RuntimeException) {
throw (RuntimeException)jobResult;
} else if (jobResult instanceof Throwable) {
throw new RuntimeException("Unexpected exception", (Throwable)jobResult);
} else if (jobResult instanceof HashMap) {
HashMap<Long, String> passwordMap = (HashMap<Long, String>)jobResult;
UserVmVO userVm = _userVmDao.findById(vmId);
userVm.setPassword(passwordMap.get(vmId));
return userVm;
}
}
throw new RuntimeException("Unexpected job execution result");
}
}
private UserVm orchestrateRestoreVirtualMachine(final long vmId, final Long newTemplateId) throws ResourceUnavailableException, InsufficientCapacityException {
s_logger.debug("Restoring vm " + vmId + " with new templateId " + newTemplateId);
final CallContext context = CallContext.current();
final Account account = context.getCallingAccount();
return _userVmService.restoreVirtualMachine(account, vmId, newTemplateId);
}
public Outcome<VirtualMachine> restoreVirtualMachineThroughJobQueue(final long vmId, final Long newTemplateId) {
final CallContext context = CallContext.current();
final User user = context.getCallingUser();
final Account account = context.getCallingAccount();
final List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
VirtualMachine.Type.Instance, vmId,
VmWorkRestore.class.getName());
VmWorkJobVO workJob = null;
if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
assert pendingWorkJobs.size() == 1;
workJob = pendingWorkJobs.get(0);
} else {
workJob = new VmWorkJobVO(context.getContextId());
workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER);
workJob.setCmd(VmWorkRestore.class.getName());
workJob.setAccountId(account.getId());
workJob.setUserId(user.getId());
workJob.setVmType(VirtualMachine.Type.Instance);
workJob.setVmInstanceId(vmId);
workJob.setRelated(AsyncJobExecutionContext.getOriginJobId());
final VmWorkRestore workInfo = new VmWorkRestore(user.getId(), account.getId(), vmId,
VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, newTemplateId);
workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
_jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vmId);
}
AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(workJob.getId());
return new VmJobVirtualMachineOutcome(workJob, vmId);
}
@ReflectionUse
private Pair<JobInfo.Status, String> orchestrateRestoreVirtualMachine(final VmWorkRestore work) throws Exception {
final VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId());
if (vm == null) {
s_logger.info("Unable to find vm " + work.getVmId());
}
assert vm != null;
UserVm uservm = orchestrateRestoreVirtualMachine(vm.getId(), work.getTemplateId());
HashMap<Long, String> passwordMap = new HashMap<Long, String>();
passwordMap.put(uservm.getId(), uservm.getPassword());
return new Pair<JobInfo.Status, String>(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(passwordMap));
}
}

View File

@ -0,0 +1,33 @@
// 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;
public class VmWorkRestore extends VmWork {
private static final long serialVersionUID = 195901782359759635L;
private Long templateId;
public VmWorkRestore(long userId, long accountId, long vmId, String handlerName, Long templateId) {
super(userId, accountId, vmId, handlerName);
this.templateId = templateId;
}
public Long getTemplateId() {
return templateId;
}
}

View File

@ -6614,11 +6614,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
public UserVm restoreVMInternal(Account caller, UserVmVO vm, Long newTemplateId) throws InsufficientCapacityException, ResourceUnavailableException {
return _itMgr.restoreVirtualMachine(vm.getId(), newTemplateId);
}
@Override
public UserVm restoreVirtualMachine(final Account caller, final long vmId, final Long newTemplateId) throws InsufficientCapacityException, ResourceUnavailableException {
Long userId = caller.getId();
Account owner = _accountDao.findById(vm.getAccountId());
_userDao.findById(userId);
long vmId = vm.getId();
UserVmVO vm = _vmDao.findById(vmId);
Account owner = _accountDao.findById(vm.getAccountId());
boolean needRestart = false;
// Input validation

View File

@ -50,7 +50,6 @@ import java.util.UUID;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
@ -60,7 +59,6 @@ import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationSe
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.junit.Assert;
@ -82,12 +80,8 @@ import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.deploy.DeployDestination;
import com.cloud.event.dao.UsageEventDao;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.IpAddressManager;
@ -106,9 +100,7 @@ import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.Storage;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VolumeDao;
@ -232,9 +224,7 @@ public class UserVmManagerTest {
@Before
public void setup() {
doReturn(3L).when(_account).getId();
doReturn(8L).when(_vmMock).getAccountId();
when(_accountDao.findById(anyLong())).thenReturn(_accountMock);
lenient().when(_userDao.findById(anyLong())).thenReturn(_userMock);
lenient().doReturn(Account.State.enabled).when(_account).getState();
lenient().when(_vmMock.getId()).thenReturn(314L);
@ -242,8 +232,6 @@ public class UserVmManagerTest {
lenient().when(_vmInstance.getServiceOfferingId()).thenReturn(2L);
List<VMSnapshotVO> mockList = new ArrayList<>();
when(_vmSnapshotDao.findByVm(anyLong())).thenReturn(mockList);
when(_templateStoreDao.findByTemplateZoneReady(anyLong(), anyLong())).thenReturn(_templateDataStoreMock);
}
@ -294,188 +282,6 @@ public class UserVmManagerTest {
_userVmMgr.validateRootDiskResize(hypervisorType, rootDiskSize, templateVO, vm, customParameters);
}
// Test restoreVm when VM state not in running/stopped case
@Test(expected = CloudRuntimeException.class)
public void testRestoreVMF1() throws ResourceAllocationException, InsufficientCapacityException, ResourceUnavailableException {
lenient().when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
lenient().when(_templateDao.findById(anyLong())).thenReturn(_templateMock);
doReturn(VirtualMachine.State.Error).when(_vmMock).getState();
Account account = new AccountVO("testaccount", 1L, "networkdomain", (short)0, "uuid");
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
CallContext.register(user, account);
try {
_userVmMgr.restoreVMInternal(_account, _vmMock, null);
} finally {
CallContext.unregister();
}
}
// Test restoreVm when VM is in stopped state
@Test
public void testRestoreVMF2() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException {
doReturn(VirtualMachine.State.Stopped).when(_vmMock).getState();
lenient().when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
when(_volsDao.findByInstanceAndType(314L, Volume.Type.ROOT)).thenReturn(_rootVols);
doReturn(false).when(_rootVols).isEmpty();
when(_rootVols.get(eq(0))).thenReturn(_volumeMock);
doReturn(3L).when(_volumeMock).getTemplateId();
when(_templateDao.findById(anyLong())).thenReturn(_templateMock);
when(_storageMgr.allocateDuplicateVolume(_volumeMock, null)).thenReturn(_volumeMock);
doNothing().when(_volsDao).attachVolume(anyLong(), anyLong(), anyLong());
when(_volumeMock.getId()).thenReturn(3L);
doNothing().when(_volsDao).detachVolume(anyLong());
lenient().when(_templateMock.getUuid()).thenReturn("e0552266-7060-11e2-bbaa-d55f5db67735");
Account account = new AccountVO("testaccount", 1L, "networkdomain", (short)0, "uuid");
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
StoragePoolVO storagePool = new StoragePoolVO();
storagePool.setManaged(false);
when(_storagePoolDao.findById(anyLong())).thenReturn(storagePool);
CallContext.register(user, account);
try {
_userVmMgr.restoreVMInternal(_account, _vmMock, null);
} finally {
CallContext.unregister();
}
}
// Test restoreVM when VM is in running state
@Test
public void testRestoreVMF3() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException {
doReturn(VirtualMachine.State.Running).when(_vmMock).getState();
when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
when(_volsDao.findByInstanceAndType(314L, Volume.Type.ROOT)).thenReturn(_rootVols);
doReturn(false).when(_rootVols).isEmpty();
when(_rootVols.get(eq(0))).thenReturn(_volumeMock);
doReturn(3L).when(_volumeMock).getTemplateId();
when(_templateDao.findById(anyLong())).thenReturn(_templateMock);
when(_storageMgr.allocateDuplicateVolume(_volumeMock, null)).thenReturn(_volumeMock);
doNothing().when(_volsDao).attachVolume(anyLong(), anyLong(), anyLong());
when(_volumeMock.getId()).thenReturn(3L);
doNothing().when(_volsDao).detachVolume(anyLong());
lenient().when(_templateMock.getUuid()).thenReturn("e0552266-7060-11e2-bbaa-d55f5db67735");
Account account = new AccountVO("testaccount", 1L, "networkdomain", (short)0, "uuid");
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
StoragePoolVO storagePool = new StoragePoolVO();
storagePool.setManaged(false);
when(_storagePoolDao.findById(anyLong())).thenReturn(storagePool);
CallContext.register(user, account);
try {
_userVmMgr.restoreVMInternal(_account, _vmMock, null);
} finally {
CallContext.unregister();
}
}
// Test restoreVM on providing new template Id, when VM is in running state
@Test
public void testRestoreVMF4() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException {
doReturn(VirtualMachine.State.Running).when(_vmMock).getState();
when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
when(_volsDao.findByInstanceAndType(314L, Volume.Type.ROOT)).thenReturn(_rootVols);
doReturn(false).when(_rootVols).isEmpty();
when(_rootVols.get(eq(0))).thenReturn(_volumeMock);
doReturn(3L).when(_volumeMock).getTemplateId();
doReturn(ImageFormat.VHD).when(_templateMock).getFormat();
when(_templateDao.findById(anyLong())).thenReturn(_templateMock);
doNothing().when(_accountMgr).checkAccess(_account, null, true, _templateMock);
when(_storageMgr.allocateDuplicateVolume(_volumeMock, 14L)).thenReturn(_volumeMock);
when(_templateMock.getGuestOSId()).thenReturn(5L);
doNothing().when(_vmMock).setGuestOSId(anyLong());
lenient().doNothing().when(_vmMock).setTemplateId(3L);
when(_vmDao.update(314L, _vmMock)).thenReturn(true);
lenient().when(_storageMgr.allocateDuplicateVolume(_volumeMock, null)).thenReturn(_volumeMock);
doNothing().when(_volsDao).attachVolume(anyLong(), anyLong(), anyLong());
when(_volumeMock.getId()).thenReturn(3L);
doNothing().when(_volsDao).detachVolume(anyLong());
List<VMSnapshotVO> mockList = new ArrayList<>();
when(_vmSnapshotDao.findByVm(anyLong())).thenReturn(mockList);
lenient().when(_templateMock.getUuid()).thenReturn("b1a3626e-72e0-4697-8c7c-a110940cc55d");
Account account = new AccountVO("testaccount", 1L, "networkdomain", (short)0, "uuid");
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
StoragePoolVO storagePool = new StoragePoolVO();
storagePool.setManaged(false);
when(_storagePoolDao.findById(anyLong())).thenReturn(storagePool);
CallContext.register(user, account);
try {
_userVmMgr.restoreVMInternal(_account, _vmMock, 14L);
} finally {
CallContext.unregister();
}
verify(_vmMock, times(0)).setIsoId(Mockito.anyLong());
}
// Test restoreVM on providing new ISO Id, when VM(deployed using ISO) is in running state
@Test
public void testRestoreVMF5() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException {
doReturn(VirtualMachine.State.Running).when(_vmMock).getState();
when(_vmDao.findById(anyLong())).thenReturn(_vmMock);
when(_volsDao.findByInstanceAndType(314L, Volume.Type.ROOT)).thenReturn(_rootVols);
doReturn(false).when(_rootVols).isEmpty();
when(_rootVols.get(eq(0))).thenReturn(_volumeMock);
doReturn(null).when(_volumeMock).getTemplateId();
doReturn(3L).when(_vmMock).getIsoId();
doReturn(ImageFormat.ISO).when(_templateMock).getFormat();
when(_templateDao.findById(anyLong())).thenReturn(_templateMock);
doNothing().when(_accountMgr).checkAccess(_account, null, true, _templateMock);
when(_storageMgr.allocateDuplicateVolume(_volumeMock, null)).thenReturn(_volumeMock);
doNothing().when(_vmMock).setIsoId(14L);
when(_templateMock.getGuestOSId()).thenReturn(5L);
doNothing().when(_vmMock).setGuestOSId(anyLong());
lenient().doNothing().when(_vmMock).setTemplateId(3L);
when(_vmDao.update(314L, _vmMock)).thenReturn(true);
when(_storageMgr.allocateDuplicateVolume(_volumeMock, null)).thenReturn(_volumeMock);
doNothing().when(_volsDao).attachVolume(anyLong(), anyLong(), anyLong());
when(_volumeMock.getId()).thenReturn(3L);
doNothing().when(_volsDao).detachVolume(anyLong());
List<VMSnapshotVO> mockList = new ArrayList<>();
when(_vmSnapshotDao.findByVm(anyLong())).thenReturn(mockList);
lenient().when(_templateMock.getUuid()).thenReturn("b1a3626e-72e0-4697-8c7c-a110940cc55d");
Account account = new AccountVO("testaccount", 1L, "networkdomain", (short)0, "uuid");
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
StoragePoolVO storagePool = new StoragePoolVO();
storagePool.setManaged(false);
when(_storagePoolDao.findById(anyLong())).thenReturn(storagePool);
CallContext.register(user, account);
try {
_userVmMgr.restoreVMInternal(_account, _vmMock, 14L);
} finally {
CallContext.unregister();
}
verify(_vmMock, times(1)).setIsoId(14L);
}
// Test scaleVm on incompatible HV.
@Test(expected = InvalidParameterValueException.class)
public void testScaleVMF1() throws Exception {