You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ap...@apache.org on 2013/02/21 10:30:29 UTC

git commit: refs/heads/master - CLOUDSTACK-745: Reset a VM on reboot. On every reboot of VM, the root disk state is reset. This is for the VMs created using service offering where an optional parameter isvolatile is set true.

Updated Branches:
  refs/heads/master f7b600b43 -> 7a3f072a5


CLOUDSTACK-745: Reset a VM on reboot. On every reboot of VM, the root disk state is reset. This is for the VMs created using service offering where an optional parameter isvolatile is set true.

Signed-off-by: Abhinandan Prateek <ap...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/7a3f072a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/7a3f072a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/7a3f072a

Branch: refs/heads/master
Commit: 7a3f072a50f533c652721f613ba60f1ef78c44b9
Parents: f7b600b
Author: Harikrishna Patnala <ha...@citrix.com>
Authored: Thu Feb 21 14:59:35 2013 +0530
Committer: Abhinandan Prateek <ap...@apache.org>
Committed: Thu Feb 21 14:59:35 2013 +0530

----------------------------------------------------------------------
 api/src/com/cloud/offering/ServiceOffering.java    |    5 +
 .../org/apache/cloudstack/api/ApiConstants.java    |    1 +
 .../admin/offering/CreateServiceOfferingCmd.java   |   11 +-
 .../cloud/configuration/ConfigurationManager.java  |    3 +-
 .../configuration/ConfigurationManagerImpl.java    |   14 +-
 .../com/cloud/migration/ServiceOffering21VO.java   |    5 +
 .../src/com/cloud/service/ServiceOfferingVO.java   |   30 ++-
 server/src/com/cloud/vm/UserVmManagerImpl.java     |   42 +++-
 server/test/com/cloud/vm/UserVmManagerTest.java    |  148 +++++++++++++++
 .../cloud/vpc/MockConfigurationManagerImpl.java    |    2 +-
 setup/db/db/schema-410to420.sql                    |    5 +-
 11 files changed, 231 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/7a3f072a/api/src/com/cloud/offering/ServiceOffering.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/offering/ServiceOffering.java b/api/src/com/cloud/offering/ServiceOffering.java
index 4d71589..d6c215f 100755
--- a/api/src/com/cloud/offering/ServiceOffering.java
+++ b/api/src/com/cloud/offering/ServiceOffering.java
@@ -78,6 +78,11 @@ public interface ServiceOffering extends InfrastructureEntity, InternalIdentity,
     boolean getLimitCpuUse();
 
     /**
+     * @return Does this service plan support Volatile VM that is, discard VM's root disk and create a new one on reboot?
+     */
+    boolean getVolatileVm();
+
+    /**
      * @return the rate in megabits per sec to which a VM's network interface is throttled to
      */
     Integer getRateMbps();

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/7a3f072a/api/src/org/apache/cloudstack/api/ApiConstants.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index cd7d700..35a11dd 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -218,6 +218,7 @@ public class ApiConstants {
     public static final String VM_LIMIT = "vmlimit";
     public static final String VM_TOTAL = "vmtotal";
     public static final String VNET = "vnet";
+    public static final String IS_VOLATILE = "isvolatile";
     public static final String VOLUME_ID = "volumeid";
     public static final String ZONE_ID = "zoneid";
     public static final String ZONE_NAME = "zonename";

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/7a3f072a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java
index ee1e1b2..e915c48 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java
@@ -59,6 +59,9 @@ public class CreateServiceOfferingCmd extends BaseCmd {
     @Parameter(name=ApiConstants.LIMIT_CPU_USE, type=CommandType.BOOLEAN, description="restrict the CPU usage to committed service offering")
     private Boolean limitCpuUse;
 
+    @Parameter(name=ApiConstants.IS_VOLATILE, type=CommandType.BOOLEAN, description="true if the virtual machine needs to be volatile so that on every reboot of VM, original root disk is dettached then destroyed and a fresh root disk is created and attached to VM")
+    private Boolean isVolatile;
+
     @Parameter(name=ApiConstants.STORAGE_TYPE, type=CommandType.STRING, description="the storage type of the service offering. Values are local and shared.")
     private String storageType;
 
@@ -106,11 +109,15 @@ public class CreateServiceOfferingCmd extends BaseCmd {
     }
 
     public Boolean getOfferHa() {
-        return offerHa;
+        return offerHa == null ? false : offerHa;
     }
 
     public Boolean GetLimitCpuUse() {
-        return limitCpuUse;
+        return limitCpuUse == null ? false : limitCpuUse;
+    }
+
+    public Boolean getVolatileVm() {
+        return isVolatile == null ? false : isVolatile;
     }
 
     public String getStorageType() {

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/7a3f072a/server/src/com/cloud/configuration/ConfigurationManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java
index 5c1b0d5..7193928 100644
--- a/server/src/com/cloud/configuration/ConfigurationManager.java
+++ b/server/src/com/cloud/configuration/ConfigurationManager.java
@@ -72,6 +72,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager {
      * @param localStorageRequired
      * @param offerHA
      * @param domainId
+     * @param volatileVm
      * @param hostTag
      * @param networkRate
      *            TODO
@@ -80,7 +81,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager {
      * @return ID
      */
     ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vm_typeType, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired,
-            boolean offerHA, boolean limitResourceUse, String tags, Long domainId, String hostTag, Integer networkRate);
+            boolean offerHA, boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate);
 
     /**
      * Creates a new disk offering

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/7a3f072a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
index b886bed..cf3a908 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -1777,14 +1777,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
         }
 
         Boolean offerHA = cmd.getOfferHa();
-        if (offerHA == null) {
-            offerHA = false;
-        }
-
         Boolean limitCpuUse = cmd.GetLimitCpuUse();
-        if (limitCpuUse == null) {
-            limitCpuUse = false;
-        }
+        Boolean volatileVm = cmd.getVolatileVm();
 
         String vmTypeString = cmd.getSystemVmType();
         VirtualMachine.Type vmType = null;
@@ -1811,15 +1805,15 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
         }
 
         return createServiceOffering(userId, cmd.getIsSystem(), vmType, cmd.getServiceOfferingName(), cpuNumber.intValue(), memory.intValue(), cpuSpeed.intValue(), cmd.getDisplayText(),
-                localStorageRequired, offerHA, limitCpuUse, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), cmd.getNetworkRate());
+                localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(), cmd.getNetworkRate());
     }
 
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_SERVICE_OFFERING_CREATE, eventDescription = "creating service offering")
     public ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, VirtualMachine.Type vm_type, String name, int cpu, int ramSize, int speed, String displayText,
-            boolean localStorageRequired, boolean offerHA, boolean limitResourceUse, String tags, Long domainId, String hostTag, Integer networkRate) {
+            boolean localStorageRequired, boolean offerHA, boolean limitResourceUse, boolean volatileVm,  String tags, Long domainId, String hostTag, Integer networkRate) {
         tags = cleanupTags(tags);
-        ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, limitResourceUse, displayText, localStorageRequired, false, tags, isSystem, vm_type,
+        ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, limitResourceUse, volatileVm, displayText, localStorageRequired, false, tags, isSystem, vm_type,
                 domainId, hostTag);
 
         if ((offering = _serviceOfferingDao.persist(offering)) != null) {

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/7a3f072a/server/src/com/cloud/migration/ServiceOffering21VO.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/migration/ServiceOffering21VO.java b/server/src/com/cloud/migration/ServiceOffering21VO.java
index fdec30e..d07be64 100644
--- a/server/src/com/cloud/migration/ServiceOffering21VO.java
+++ b/server/src/com/cloud/migration/ServiceOffering21VO.java
@@ -169,5 +169,10 @@ public class ServiceOffering21VO extends DiskOffering21VO implements ServiceOffe
         return null;
     }
 
+    @Override
+    public boolean getVolatileVm() {
+        return false;
+    }
+
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/7a3f072a/server/src/com/cloud/service/ServiceOfferingVO.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/service/ServiceOfferingVO.java b/server/src/com/cloud/service/ServiceOfferingVO.java
index c199a86..7be939c 100755
--- a/server/src/com/cloud/service/ServiceOfferingVO.java
+++ b/server/src/com/cloud/service/ServiceOfferingVO.java
@@ -53,6 +53,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
     @Column(name="limit_cpu_use")
     private boolean limitCpuUse;    
     
+    @Column(name="is_volatile")
+    private boolean volatileVm;
+
     @Column(name="host_tag")
     private String hostTag;
 
@@ -78,11 +81,12 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
         this.multicastRateMbps = multicastRateMbps;
         this.offerHA = offerHA;
         this.limitCpuUse = false; 
+        this.volatileVm = false;
         this.default_use = defaultUse;
         this.vm_type = vm_type == null ? null : vm_type.toString().toLowerCase();
     }
 
-    public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId) {
+    public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse, boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId) {
         super(name, displayText, false, tags, recreatable, useLocalStorage, systemUse, true, domainId);
         this.cpu = cpu;
         this.ramSize = ramSize;
@@ -91,11 +95,12 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
         this.multicastRateMbps = multicastRateMbps;
         this.offerHA = offerHA;
         this.limitCpuUse = limitCpuUse;  
+        this.volatileVm = volatileVm;
         this.vm_type = vm_type == null ? null : vm_type.toString().toLowerCase();
     }
 
-    public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitResourceUse, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId, String hostTag) {
-        this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, displayText, useLocalStorage, recreatable, tags, systemUse, vm_type, domainId);
+    public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId, String hostTag) {
+        this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, displayText, useLocalStorage, recreatable, tags, systemUse, vm_type, domainId);
         this.hostTag = hostTag;
     }    
 
@@ -189,13 +194,18 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering
 	public String getSystemVmType(){
 	    return vm_type;
 	}
+
+	public void setSortKey(int key) {
+		sortKey = key;
+	}
+
+	public int getSortKey() {
+		return sortKey;
+	}
 	
-    public void setSortKey(int key) {
-    	sortKey = key;
-    }
-    
-    public int getSortKey() {
-    	return sortKey;
+    @Override
+    public boolean getVolatileVm() {
+        return volatileVm;
     }
-	
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/7a3f072a/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index df97609..ea25c66 100644
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -2672,6 +2672,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
 
         _accountMgr.checkAccess(caller, null, true, vmInstance);
 
+        // If the VM is Volatile in nature, on reboot discard the VM's root disk and create a new root disk for it: by calling restoreVM
+        long serviceOfferingId = vmInstance.getServiceOfferingId();
+        ServiceOfferingVO offering = _serviceOfferingDao.findById(serviceOfferingId);
+        if(offering.getVolatileVm()){
+            return restoreVMInternal(caller, vmInstance);
+        }
+
         return rebootVirtualMachine(UserContext.current().getCallerUserId(),
                 vmId);
     }
@@ -4789,19 +4796,27 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
         // Input validation
         Account caller = UserContext.current().getCaller();
         Long userId = UserContext.current().getCallerUserId();
-        UserVO user = _userDao.findById(userId);
-        boolean needRestart = false;
 
         long vmId = cmd.getVmId();
         UserVmVO vm = _vmDao.findById(vmId);
         if (vm == null) {
-            InvalidParameterValueException ex = new InvalidParameterValueException(
-                    "Cann not find VM with ID " + vmId);
+            InvalidParameterValueException ex = new InvalidParameterValueException("Cannot find VM with ID " + vmId);
             ex.addProxyObject(vm, vmId, "vmId");
             throw ex;
         }
 
+        return restoreVMInternal(caller, vm);
+    }
+
+    public UserVm restoreVMInternal(Account caller, UserVmVO vm){
+
+        Long userId = caller.getId();
         Account owner = _accountDao.findById(vm.getAccountId());
+        UserVO user = _userDao.findById(userId);
+        long vmId = vm.getId();
+        boolean needRestart = false;
+
+        // Input validation
         if (owner == null) {
             throw new InvalidParameterValueException("The owner of " + vm
                     + " does not exist: " + vm.getAccountId());
@@ -4816,7 +4831,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
                 && vm.getState() != VirtualMachine.State.Stopped) {
             throw new CloudRuntimeException(
                     "Vm "
-                            + vmId
+                            + vm.getUuid()
                             + " currently in "
                             + vm.getState()
                             + " state, restore vm can only execute when VM in Running or Stopped");
@@ -4829,13 +4844,19 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
         List<VolumeVO> rootVols = _volsDao.findByInstance(vmId);
         if (rootVols.isEmpty()) {
             InvalidParameterValueException ex = new InvalidParameterValueException(
-                    "Can not find root volume for VM " + vmId);
+                    "Can not find root volume for VM " + vm.getUuid());
             ex.addProxyObject(vm, vmId, "vmId");
             throw ex;
         }
 
         VolumeVO root = rootVols.get(0);
-        long templateId = root.getTemplateId();
+        Long templateId = root.getTemplateId();
+        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;
+        }
+
         VMTemplateVO template = _templateDao.findById(templateId);
         if (template == null) {
             InvalidParameterValueException ex = new InvalidParameterValueException(
@@ -4849,7 +4870,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
             try {
                 _itMgr.stop(vm, user, caller);
             } catch (ResourceUnavailableException e) {
-                s_logger.debug("Stop vm " + vmId + " failed", e);
+                s_logger.debug("Stop vm " + vm.getUuid() + " failed", e);
                 CloudRuntimeException ex = new CloudRuntimeException(
                         "Stop vm failed for specified vmId");
                 ex.addProxyObject(vm, vmId, "vmId");
@@ -4874,7 +4895,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
             try {
                 _itMgr.start(vm, null, user, caller);
             } catch (Exception e) {
-                s_logger.debug("Unable to start VM " + vmId, e);
+                s_logger.debug("Unable to start VM " + vm.getUuid(), e);
                 CloudRuntimeException ex = new CloudRuntimeException(
                         "Unable to start VM with specified id" + e.getMessage());
                 ex.addProxyObject(vm, vmId, "vmId");
@@ -4882,9 +4903,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
             }
         }
 
-        s_logger.debug("Restore VM " + vmId + " with template "
+        s_logger.debug("Restore VM " + vm.getUuid() + " with template "
                 + root.getTemplateId() + " successfully");
         return vm;
+
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/7a3f072a/server/test/com/cloud/vm/UserVmManagerTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vm/UserVmManagerTest.java b/server/test/com/cloud/vm/UserVmManagerTest.java
new file mode 100755
index 0000000..46069ed
--- /dev/null
+++ b/server/test/com/cloud/vm/UserVmManagerTest.java
@@ -0,0 +1,148 @@
+// 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 java.util.List;
+
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
+import org.apache.log4j.Logger;
+import org.junit.Test;
+import org.junit.Before;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.storage.StorageManager;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.AccountVO;
+import com.cloud.user.UserVO;
+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 static org.mockito.Mockito.*;
+
+public class UserVmManagerTest {
+
+    @Spy UserVmManagerImpl _userVmMgr = new UserVmManagerImpl();
+    @Mock VirtualMachineManager _itMgr;
+    @Mock StorageManager _storageMgr;
+    @Mock Account account;
+    @Mock AccountManager _accountMgr;
+    @Mock AccountDao _accountDao;
+    @Mock UserDao _userDao;
+    @Mock UserVmDao _vmDao;
+    @Mock VMTemplateDao _templateDao;
+    @Mock VolumeDao _volsDao;
+    @Mock RestoreVMCmd restoreVMCmd;
+    @Mock AccountVO accountMock;
+    @Mock UserVO userMock;
+    @Mock UserVmVO vmMock;
+    @Mock VMTemplateVO templateMock;
+    @Mock VolumeVO volumeMock;
+    @Mock List<VolumeVO> rootVols;
+    @Before
+    public void setup(){
+        MockitoAnnotations.initMocks(this);
+
+        _userVmMgr._vmDao = _vmDao;
+        _userVmMgr._templateDao = _templateDao;
+        _userVmMgr._volsDao = _volsDao;
+        _userVmMgr._itMgr = _itMgr;
+        _userVmMgr._storageMgr = _storageMgr;
+        _userVmMgr._accountDao = _accountDao;
+        _userVmMgr._userDao = _userDao;
+
+        doReturn(3L).when(account).getId();
+        doReturn(8L).when(vmMock).getAccountId();
+        when(_accountDao.findById(anyLong())).thenReturn(accountMock);
+        when(_userDao.findById(anyLong())).thenReturn(userMock);
+        doReturn(Account.State.enabled).when(account).getState();
+        when(vmMock.getId()).thenReturn(314L);
+
+    }
+
+    // VM state not in running/stopped case
+    @Test(expected=CloudRuntimeException.class)
+    public void testRestoreVMF1() throws ResourceAllocationException {
+
+        when(_vmDao.findById(anyLong())).thenReturn(vmMock);
+        when(_templateDao.findById(anyLong())).thenReturn(templateMock);
+        doReturn(VirtualMachine.State.Error).when(vmMock).getState();
+        _userVmMgr.restoreVMInternal(account, vmMock);
+    }
+
+    // when VM is in stopped state
+    @Test
+    public void testRestoreVMF2()  throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException,
+    ConcurrentOperationException, ResourceAllocationException {
+
+        doReturn(VirtualMachine.State.Stopped).when(vmMock).getState();
+        when(_vmDao.findById(anyLong())).thenReturn(vmMock);
+        when(_volsDao.findByInstance(anyLong())).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());
+        when(_storageMgr.destroyVolume(volumeMock)).thenReturn(true);
+
+        _userVmMgr.restoreVMInternal(account, vmMock);
+
+    }
+
+    // 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.findByInstance(anyLong())).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(_itMgr.stop(vmMock, userMock, account)).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(_storageMgr.destroyVolume(volumeMock)).thenReturn(true);
+
+        _userVmMgr.restoreVMInternal(account, vmMock);
+
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/7a3f072a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
index 180138a..e93b2a1 100644
--- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
@@ -433,7 +433,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu
      */
     @Override
     public ServiceOfferingVO createServiceOffering(long userId, boolean isSystem, Type vm_typeType, String name, int cpu, int ramSize, int speed, String displayText, boolean localStorageRequired, boolean offerHA,
-            boolean limitResourceUse, String tags, Long domainId, String hostTag, Integer networkRate) {
+            boolean limitResourceUse, boolean volatileVm, String tags, Long domainId, String hostTag, Integer networkRate) {
         // TODO Auto-generated method stub
         return null;
     }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/7a3f072a/setup/db/db/schema-410to420.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql
index 65add75..0335f2a 100644
--- a/setup/db/db/schema-410to420.sql
+++ b/setup/db/db/schema-410to420.sql
@@ -23,4 +23,7 @@ ALTER TABLE `cloud`.`hypervisor_capabilities` ADD COLUMN `max_hosts_per_cluster`
 UPDATE `cloud`.`hypervisor_capabilities` SET `max_hosts_per_cluster`=32 WHERE `hypervisor_type`='VMware';
 INSERT IGNORE INTO `cloud`.`hypervisor_capabilities`(hypervisor_type, hypervisor_version, max_guests_limit, security_group_enabled, max_hosts_per_cluster) VALUES ('VMware', '5.1', 128, 0, 32);
 DELETE FROM `cloud`.`configuration` where name='vmware.percluster.host.max';
-INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'AgentManager', 'xen.nics.max', '7', 'Maximum allowed nics for Vms created on Xen');
\ No newline at end of file
+INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'AgentManager', 'xen.nics.max', '7', 'Maximum allowed nics for Vms created on Xen');
+
+
+ALTER TABLE `cloud`.`service_offering` ADD COLUMN `is_volatile` tinyint(1) unsigned NOT NULL DEFAULT 0  COMMENT 'true if the vm needs to be volatile, i.e., on every reboot of vm from API root disk is discarded and creates a new root disk';