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:
Harikrishna Patnala 2013-05-24 16:38:55 +05:30 committed by Koushik Das
parent 23baacba62
commit a34e577d1b
3 changed files with 74 additions and 16 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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 {