mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CLOUDSTACK-1453: support restore for VM created from ISO
This is to support restore a vm to a new/currently_attached ISO. In the restorevm API we have an optional parameter templateId to restore the vm to the new template/ISO ID.
This commit is contained in:
parent
23baacba62
commit
a34e577d1b
@ -35,7 +35,7 @@ import com.cloud.user.Account;
|
||||
import com.cloud.user.UserContext;
|
||||
import com.cloud.uservm.UserVm;
|
||||
|
||||
@APICommand(name = "restoreVirtualMachine", description="Restore a VM to original template or new template", responseObject=UserVmResponse.class, since="3.0.0")
|
||||
@APICommand(name = "restoreVirtualMachine", description="Restore a VM to original template/ISO or new template/ISO", responseObject=UserVmResponse.class, since="3.0.0")
|
||||
public class RestoreVMCmd extends BaseAsyncCmd {
|
||||
public static final Logger s_logger = Logger.getLogger(RestoreVMCmd.class);
|
||||
private static final String s_name = "restorevmresponse";
|
||||
@ -44,9 +44,10 @@ public class RestoreVMCmd extends BaseAsyncCmd {
|
||||
required=true, description="Virtual Machine ID")
|
||||
private Long vmId;
|
||||
|
||||
@Parameter(name=ApiConstants.TEMPLATE_ID, type=CommandType.UUID, entityType = TemplateResponse.class, description="an optional template Id to restore vm from the new template")
|
||||
@Parameter(name=ApiConstants.TEMPLATE_ID, type=CommandType.UUID, entityType = TemplateResponse.class, description="an optional template Id to restore vm from the new template. This can be an ISO id in case of restore vm deployed using ISO")
|
||||
private Long templateId;
|
||||
|
||||
|
||||
@Override
|
||||
public String getEventType() {
|
||||
return EventTypes.EVENT_VM_RESTORE;
|
||||
|
||||
@ -4237,6 +4237,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
|
||||
|
||||
long vmId = cmd.getVmId();
|
||||
Long newTemplateId = cmd.getTemplateId();
|
||||
|
||||
UserVmVO vm = _vmDao.findById(vmId);
|
||||
if (vm == null) {
|
||||
InvalidParameterValueException ex = new InvalidParameterValueException("Cannot find VM with ID " + vmId);
|
||||
@ -4292,21 +4293,35 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
|
||||
|
||||
VolumeVO root = rootVols.get(0);
|
||||
Long templateId = root.getTemplateId();
|
||||
boolean isISO = false;
|
||||
if(templateId == null) {
|
||||
InvalidParameterValueException ex = new InvalidParameterValueException("Currently there is no support to reset a vm that is deployed using ISO " + vm.getUuid());
|
||||
ex.addProxyObject(vm, vmId, "vmId");
|
||||
throw ex;
|
||||
// Assuming that for a vm deployed using ISO, template ID is set to NULL
|
||||
isISO = true;
|
||||
templateId = vm.getIsoId();
|
||||
}
|
||||
|
||||
VMTemplateVO template = null;
|
||||
//newTemplateId can be either template or ISO id. In the following snippet based on the vm deployment (from template or ISO) it is handled accordingly
|
||||
if(newTemplateId != null) {
|
||||
template = _templateDao.findById(newTemplateId);
|
||||
_accountMgr.checkAccess(caller, null, true, template);
|
||||
if (isISO) {
|
||||
if (!template.getFormat().equals(ImageFormat.ISO)) {
|
||||
throw new InvalidParameterValueException("Invalid ISO id provided to restore the VM ");
|
||||
}
|
||||
} else {
|
||||
if (template.getFormat().equals(ImageFormat.ISO)) {
|
||||
throw new InvalidParameterValueException("Invalid template id provided to restore the VM ");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isISO && templateId == null) {
|
||||
throw new CloudRuntimeException("Cannot restore the VM since there is no ISO attached to VM");
|
||||
}
|
||||
template = _templateDao.findById(templateId);
|
||||
if (template == null) {
|
||||
InvalidParameterValueException ex = new InvalidParameterValueException(
|
||||
"Cannot find template for specified volumeid and vmId");
|
||||
"Cannot find template/ISO for specified volumeid and vmId");
|
||||
ex.addProxyObject(vm, vmId, "vmId");
|
||||
ex.addProxyObject(root, root.getId(), "volumeId");
|
||||
throw ex;
|
||||
@ -4325,13 +4340,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
|
||||
}
|
||||
}
|
||||
|
||||
/* If new template is provided allocate a new volume from new template otherwise allocate new volume from original template */
|
||||
/* If new template/ISO is provided allocate a new volume from new template/ISO otherwise allocate new volume from original template/ISO */
|
||||
VolumeVO newVol = null;
|
||||
if (newTemplateId != null) {
|
||||
if (isISO) {
|
||||
newVol = volumeMgr.allocateDuplicateVolume(root, null);
|
||||
vm.setIsoId(newTemplateId);
|
||||
vm.setGuestOSId(template.getGuestOSId());
|
||||
vm.setTemplateId(newTemplateId);
|
||||
_vmDao.update(vmId, vm);
|
||||
} else {
|
||||
newVol = volumeMgr.allocateDuplicateVolume(root, newTemplateId);
|
||||
vm.setGuestOSId(template.getGuestOSId());
|
||||
vm.setTemplateId(newTemplateId);
|
||||
_vmDao.update(vmId, vm);
|
||||
}
|
||||
} else {
|
||||
newVol = volumeMgr.allocateDuplicateVolume(root, null);
|
||||
}
|
||||
|
||||
@ -24,10 +24,8 @@ import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
@ -64,6 +62,7 @@ import com.cloud.storage.VolumeManager;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.VMTemplateDao;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountManager;
|
||||
import com.cloud.user.AccountService;
|
||||
@ -200,6 +199,7 @@ public class UserVmManagerTest {
|
||||
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(_itMgr.stop(_vmMock, _userMock, _account)).thenReturn(true);
|
||||
@ -220,6 +220,40 @@ public class UserVmManagerTest {
|
||||
|
||||
}
|
||||
|
||||
// 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(_itMgr.stop(_vmMock, _userMock, _account)).thenReturn(true);
|
||||
when(_storageMgr.allocateDuplicateVolume(_volumeMock, null)).thenReturn(_volumeMock);
|
||||
doNothing().when(_vmMock).setIsoId(14L);
|
||||
when(_templateMock.getGuestOSId()).thenReturn(5L);
|
||||
doNothing().when(_vmMock).setGuestOSId(anyLong());
|
||||
doNothing().when(_vmMock).setTemplateId(3L);
|
||||
when(_vmDao.update(314L, _vmMock)).thenReturn(true);
|
||||
when(_itMgr.start(_vmMock, null, _userMock, _account)).thenReturn(_vmMock);
|
||||
when(_storageMgr.allocateDuplicateVolume(_volumeMock, null)).thenReturn(_volumeMock);
|
||||
doNothing().when(_volsDao).attachVolume(anyLong(), anyLong(), anyLong());
|
||||
when(_volumeMock.getId()).thenReturn(3L);
|
||||
doNothing().when(_volsDao).detachVolume(anyLong());
|
||||
|
||||
when(_templateMock.getUuid()).thenReturn("b1a3626e-72e0-4697-8c7c-a110940cc55d");
|
||||
|
||||
_userVmMgr.restoreVMInternal(_account, _vmMock, 14L);
|
||||
|
||||
verify(_vmMock, times(1)).setIsoId(14L);
|
||||
|
||||
}
|
||||
// Test scaleVm on incompatible HV.
|
||||
@Test(expected=InvalidParameterValueException.class)
|
||||
public void testScaleVMF1() throws Exception {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user