You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mi...@apache.org on 2012/08/30 09:20:37 UTC

[1/2] git commit: Initial commit of vm snapshots feature for xenserver and vmware

Updated Branches:
  refs/heads/vm-snapshot [created] 33f690f1a


Initial commit of vm snapshots feature for xenserver and vmware


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

Branch: refs/heads/vm-snapshot
Commit: 33f690f1a0c2cb8bda2ea794abb8aac2c995f71b
Parents: cefc5cb
Author: Mice Xia <mi...@tcloudcomputing.com>
Authored: Thu Aug 30 15:02:30 2012 +0800
Committer: Mice Xia <mi...@tcloudcomputing.com>
Committed: Thu Aug 30 15:02:30 2012 +0800

----------------------------------------------------------------------
 api/src/com/cloud/agent/api/to/VolumeTO.java       |    4 +
 api/src/com/cloud/api/ApiConstants.java            |    6 +
 api/src/com/cloud/api/BaseCmd.java                 |    3 +
 api/src/com/cloud/api/ResponseGenerator.java       |    5 +
 api/src/com/cloud/event/EventTypes.java            |    5 +
 api/src/com/cloud/vm/VirtualMachine.java           |   20 +-
 client/tomcatconf/commands.properties.in           |    6 +
 .../vmware/manager/VmwareStorageManager.java       |    6 +
 .../vmware/manager/VmwareStorageManagerImpl.java   |  275 ++++++++++
 .../hypervisor/vmware/resource/VmwareResource.java |  104 ++++-
 .../xen/resource/CitrixResourceBase.java           |  406 +++++++++++++++
 scripts/vm/hypervisor/xenserver/vmopsSnapshot      |   28 +-
 server/src/com/cloud/api/ApiDBUtils.java           |   22 +-
 server/src/com/cloud/api/ApiResponseHelper.java    |   20 +
 server/src/com/cloud/configuration/Config.java     |    9 +-
 .../configuration/DefaultComponentLibrary.java     |    6 +
 .../storage/snapshot/SnapshotManagerImpl.java      |   13 +-
 server/src/com/cloud/vm/UserVmManagerImpl.java     |   49 ++-
 .../com/cloud/vm/VirtualMachineManagerImpl.java    |   33 ++-
 setup/db/create-schema.sql                         |   46 ++
 ui/index.jsp                                       |    1 +
 ui/scripts/instances.js                            |   71 +++-
 ui/scripts/ui/widgets/detailView.js                |   13 +-
 .../src/com/cloud/hypervisor/vmware/mo/HostMO.java |   18 +
 .../hypervisor/vmware/mo/VirtualMachineMO.java     |   20 +
 25 files changed, 1162 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/api/src/com/cloud/agent/api/to/VolumeTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/VolumeTO.java b/api/src/com/cloud/agent/api/to/VolumeTO.java
index ca0acb5..ef651b9 100644
--- a/api/src/com/cloud/agent/api/to/VolumeTO.java
+++ b/api/src/com/cloud/agent/api/to/VolumeTO.java
@@ -122,6 +122,10 @@ public class VolumeTO {
     public String getOsType() {
         return guestOsType;
     }
+    
+    public void setPath(String path){
+        this.path = path;
+    }
 
     @Override
     public String toString() {

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/api/src/com/cloud/api/ApiConstants.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java
index 425b9fb..1073b76 100755
--- a/api/src/com/cloud/api/ApiConstants.java
+++ b/api/src/com/cloud/api/ApiConstants.java
@@ -205,6 +205,7 @@ public class ApiConstants {
     public static final String VM_AVAILABLE = "vmavailable";
     public static final String VM_LIMIT = "vmlimit";
     public static final String VM_TOTAL = "vmtotal";
+    public static final String VM_ID = "vmid";
     public static final String VNET = "vnet";
     public static final String VOLUME_ID = "volumeid";
     public static final String ZONE_ID = "zoneid";
@@ -381,6 +382,11 @@ public class ApiConstants {
     public static final String NICIRA_NVP_DEVICE_ID = "nvpdeviceid";
     public static final String NICIRA_NVP_TRANSPORT_ZONE_UUID = "transportzoneuuid";
     public static final String NICIRA_NVP_DEVICE_NAME = "niciradevicename";
+    public static final String VM_SNAPSHOT_DESCRIPTION = "description";
+    public static final String VM_SNAPSHOT_DISPLAYNAME = "name";
+    public static final String VM_SNAPSHOT_ID = "vmsnapshotid";
+    public static final String VM_SNAPSHOT_DISK_IDS = "vmsnapshotdiskids";
+    public static final String VM_SNAPSHOT_MEMORY = "snapshotmemory";
     
 
     public enum HostDetails {

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/api/src/com/cloud/api/BaseCmd.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/api/BaseCmd.java b/api/src/com/cloud/api/BaseCmd.java
index 91c2035..b4acebf 100755
--- a/api/src/com/cloud/api/BaseCmd.java
+++ b/api/src/com/cloud/api/BaseCmd.java
@@ -67,6 +67,7 @@ import com.cloud.utils.Pair;
 import com.cloud.utils.component.ComponentLocator;
 import com.cloud.vm.BareMetalVmService;
 import com.cloud.vm.UserVmService;
+import com.cloud.vm.snapshot.VMSnapshotService;
 
 public abstract class BaseCmd {
     private static final Logger s_logger = Logger.getLogger(BaseCmd.class.getName());
@@ -138,6 +139,7 @@ public abstract class BaseCmd {
     public static VpcService _vpcService;
     public static NetworkACLService _networkACLService;
     public static Site2SiteVpnService _s2sVpnService;
+    public static VMSnapshotService _vmSnapshotService;
 
     static void setComponents(ResponseGenerator generator) {
         ComponentLocator locator = ComponentLocator.getLocator(ManagementService.Name);
@@ -168,6 +170,7 @@ public abstract class BaseCmd {
         _taggedResourceService = locator.getManager(TaggedResourceService.class);
         _vpcService = locator.getManager(VpcService.class);
         _networkACLService = locator.getManager(NetworkACLService.class);
+        _vmSnapshotService = locator.getManager(VMSnapshotService.class);
         _s2sVpnService = locator.getManager(Site2SiteVpnService.class);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/api/src/com/cloud/api/ResponseGenerator.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/api/ResponseGenerator.java b/api/src/com/cloud/api/ResponseGenerator.java
index 996a5fc..ccfd352 100755
--- a/api/src/com/cloud/api/ResponseGenerator.java
+++ b/api/src/com/cloud/api/ResponseGenerator.java
@@ -78,6 +78,7 @@ import com.cloud.api.response.TemplateResponse;
 import com.cloud.api.response.TrafficTypeResponse;
 import com.cloud.api.response.UserResponse;
 import com.cloud.api.response.UserVmResponse;
+import com.cloud.api.response.VMSnapshotResponse;
 import com.cloud.api.response.VirtualRouterProviderResponse;
 import com.cloud.api.response.VlanIpRangeResponse;
 import com.cloud.api.response.VolumeResponse;
@@ -143,6 +144,7 @@ import com.cloud.user.UserAccount;
 import com.cloud.uservm.UserVm;
 import com.cloud.vm.InstanceGroup;
 import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.snapshot.VMSnapshot;
 
 public interface ResponseGenerator {
     UserResponse createUserResponse(UserAccount user);
@@ -162,6 +164,7 @@ public interface ResponseGenerator {
     ConfigurationResponse createConfigurationResponse(Configuration cfg);
 
     SnapshotResponse createSnapshotResponse(Snapshot snapshot);
+    VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot);
 
     SnapshotPolicyResponse createSnapshotPolicyResponse(SnapshotPolicy policy);
 
@@ -298,6 +301,8 @@ public interface ResponseGenerator {
      */
     Long getIdentiyId(String tableName, String token);
 
+    VMSnapshot getVMSnapshotById(Long vmSnapshotId);
+
     /**
      * @param resourceTag
      * @param keyValueOnly TODO

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/api/src/com/cloud/event/EventTypes.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index e84a403..41ae97e 100755
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -290,5 +290,10 @@ public class EventTypes {
     // tag related events
     public static final String EVENT_TAGS_CREATE = "CREATE_TAGS";
     public static final String EVENT_TAGS_DELETE = "DELETE_TAGS";
+    
+	// vm snapshot events
+    public static final String EVENT_VM_SNAPSHOT_CREATE = "VMSNAPSHOT.CREATE";
+    public static final String EVENT_VM_SNAPSHOT_DELETE = "VMSNAPSHOT.DELETE";
+    public static final String EVENT_VM_SNAPSHOT_REVERT = "VMSNAPSHOT.REVERT";
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/api/src/com/cloud/vm/VirtualMachine.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java
index 1fa16c3..6647cb0 100755
--- a/api/src/com/cloud/vm/VirtualMachine.java
+++ b/api/src/com/cloud/vm/VirtualMachine.java
@@ -41,7 +41,8 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, S
         Migrating(true, "VM is being migrated.  host id holds to from host"),
         Error(false, "VM is in error"),
         Unknown(false, "VM state is unknown."),
-        Shutdowned(false, "VM is shutdowned from inside");
+        Shutdowned(false, "VM is shutdowned from inside"),
+        Reverting(true, "VM is reverting to snapshot");
 
         private final boolean _transitional;
         String _description;
@@ -109,6 +110,20 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, S
             s_fsm.addTransition(State.Expunging, VirtualMachine.Event.ExpungeOperation, State.Expunging);
             s_fsm.addTransition(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging);
             s_fsm.addTransition(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging);
+            
+            s_fsm.addTransition(State.Reverting, VirtualMachine.Event.OperationFailed, State.Stopped);
+            s_fsm.addTransition(State.Reverting, VirtualMachine.Event.OperationSucceeded, State.Running);
+            s_fsm.addTransition(State.Running, VirtualMachine.Event.RevertingRequested, State.Reverting);
+            s_fsm.addTransition(State.Stopped, VirtualMachine.Event.RevertingRequested, State.Reverting);
+            s_fsm.addTransition(State.Reverting, VirtualMachine.Event.AgentReportRunning, State.Running);
+            s_fsm.addTransition(State.Reverting, VirtualMachine.Event.AgentReportStopped, State.Stopped);
+        }
+        
+        public static boolean isVmReverted(State oldState, Event e, State newState) {
+            if (oldState == State.Reverting && newState == State.Running) {
+                return true;
+            }
+            return false;
         }
 
         public static boolean isVmStarted(State oldState, Event e, State newState) {
@@ -172,7 +187,8 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, S
         OperationFailedToError,
         OperationRetry,
         AgentReportShutdowned,
-        AgentReportMigrated
+        AgentReportMigrated,
+        RevertingRequested
     };
 
     public enum Type {

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index e233694..b61e5a3 100755
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -401,3 +401,9 @@ resetVpnConnection=com.cloud.api.commands.ResetVpnConnectionCmd;15
 listVpnCustomerGateways=com.cloud.api.commands.ListVpnCustomerGatewaysCmd;15
 listVpnGateways=com.cloud.api.commands.ListVpnGatewaysCmd;15
 listVpnConnections=com.cloud.api.commands.ListVpnConnectionsCmd;15
+
+### VM Snapshot commands
+listVMSnapshot=com.cloud.api.commands.ListVmSnapshotCmd;15
+createVMSnapshot=com.cloud.api.commands.CreateVMSnapshotCmd;15
+deleteVMSnapshot=com.cloud.api.commands.DeleteVMSnapshotCmd;15
+revertToSnapshot=com.cloud.api.commands.RevertToSnapshotCmd;15
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java
index b237291..15d2b56 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManager.java
@@ -16,7 +16,10 @@ import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.BackupSnapshotCommand;
 import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
 import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
+import com.cloud.agent.api.CreateVMSnapshotCommand;
 import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
+import com.cloud.agent.api.DeleteVMSnapshotCommand;
+import com.cloud.agent.api.RevertToSnapshotCommand;
 import com.cloud.agent.api.storage.CopyVolumeCommand;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
 
@@ -27,4 +30,7 @@ public interface VmwareStorageManager {
 	Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromSnapshotCommand cmd);
 	Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd);
 	Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd);
+	Answer execute(VmwareHostService hostService, CreateVMSnapshotCommand cmd);
+	Answer execute(VmwareHostService hostService, DeleteVMSnapshotCommand cmd);
+	Answer execute(VmwareHostService hostService, RevertToSnapshotCommand cmd);
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
index b525e13..170a12a 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
@@ -18,6 +18,7 @@ import java.io.FileOutputStream;
 import java.io.OutputStreamWriter;
 import java.rmi.RemoteException;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
@@ -28,20 +29,35 @@ import com.cloud.agent.api.BackupSnapshotAnswer;
 import com.cloud.agent.api.BackupSnapshotCommand;
 import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
 import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
+import com.cloud.agent.api.CreateVMSnapshotAnswer;
+import com.cloud.agent.api.CreateVMSnapshotCommand;
 import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
 import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
+import com.cloud.agent.api.CreateVolumeFromVMSnapshotAnswer;
+import com.cloud.agent.api.CreateVolumeFromVMSnapshotCommand;
+import com.cloud.agent.api.DeleteVMSnapshotAnswer;
+import com.cloud.agent.api.DeleteVMSnapshotCommand;
+import com.cloud.agent.api.RevertToSnapshotAnswer;
+import com.cloud.agent.api.RevertToSnapshotCommand;
 import com.cloud.agent.api.storage.CopyVolumeAnswer;
 import com.cloud.agent.api.storage.CopyVolumeCommand;
 import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
 import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.agent.api.to.VMSnapshotVolumeTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.hypervisor.vmware.mo.ClusterMO;
 import com.cloud.hypervisor.vmware.mo.CustomFieldConstants;
 import com.cloud.hypervisor.vmware.mo.DatacenterMO;
 import com.cloud.hypervisor.vmware.mo.DatastoreMO;
+import com.cloud.hypervisor.vmware.mo.HostMO;
 import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
+import com.cloud.hypervisor.vmware.mo.SnapshotDescriptor;
+import com.cloud.hypervisor.vmware.mo.SnapshotDescriptor.SnapshotInfo;
 import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
 import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
+import com.cloud.hypervisor.vmware.resource.VmwareResource;
 import com.cloud.hypervisor.vmware.util.VmwareContext;
 import com.cloud.hypervisor.vmware.util.VmwareHelper;
 import com.cloud.storage.JavaStorageLayer;
@@ -53,6 +69,8 @@ import com.cloud.utils.Pair;
 import com.cloud.utils.StringUtils;
 import com.cloud.utils.Ternary;
 import com.cloud.utils.script.Script;
+import com.cloud.vm.DiskProfile;
+import com.cloud.vm.VirtualMachine;
 import com.vmware.vim25.ManagedObjectReference;
 import com.vmware.vim25.VirtualDeviceConfigSpec;
 import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
@@ -877,4 +895,261 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
     private static String getSnapshotRelativeDirInSecStorage(long accountId, long volumeId) {
         return "snapshots/" + accountId + "/" + volumeId;
     }
+
+    @Override
+    public CreateVMSnapshotAnswer execute(VmwareHostService hostService, CreateVMSnapshotCommand cmd) {
+        List<VMSnapshotVolumeTO> listvsvTo = cmd.getSnapshotVolumeTos();
+        String vmName = cmd.getVmName();
+        String vmSnapshotName = cmd.getSnapshotName();
+        String vmSnapshotDesc = cmd.getSnapshotDesc();
+        boolean snapshotMemory = cmd.snapshotMemory();
+        VirtualMachineMO vmMo = null;
+        VmwareContext context = hostService.getServiceContext(cmd);
+        Map<String, String> mapSnapshotDisk = new HashMap<String, String>();
+        Map<String, String> mapNewDisk = new HashMap<String, String>();
+        String snapshotDiskFileName = "";
+        try {
+            VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+
+            vmMo = hyperHost.findVmOnHyperHost(vmName);
+            if (vmMo == null) {
+                String msg = "Unable to find owner VM for BackupSnapshotCommand on host "
+                        + hyperHost.getHyperHostName() + ", will try within datacenter";
+                if (s_logger.isDebugEnabled())
+                    s_logger.debug("Unable to find owner VM for BackupSnapshotCommand on host "
+                            + hyperHost.getHyperHostName() + ", will try within datacenter");
+                return new CreateVMSnapshotAnswer(cmd, false, msg);
+            } else {
+                if (!vmMo.createSnapshot(vmSnapshotName, vmSnapshotDesc, snapshotMemory, true)) {
+                    return new CreateVMSnapshotAnswer(cmd, false,
+                            "Unable to create snapshot due to esxi internal failed");
+                }
+                // find snapshot disk file path
+                SnapshotDescriptor descriptor = vmMo.getSnapshotDescriptor();
+                SnapshotInfo[] snapshotInfo = descriptor.getCurrentDiskChain();
+                VirtualDisk[] vdisks = vmMo.getAllDiskDevice();
+                for (int i = 0; i < vdisks.length; i++) {
+                    @SuppressWarnings("deprecation")
+                    List<Pair<String, ManagedObjectReference>> vmdkFiles = vmMo.getDiskDatastorePathChain(vdisks[i],
+                            false);
+                    for (Pair<String, ManagedObjectReference> fileItem : vmdkFiles) {
+                        String vmdkName = fileItem.first().split(" ")[1];
+                        if (vmdkName.endsWith(".vmdk")) {
+                            vmdkName = vmdkName.substring(0, vmdkName.length() - (".vmdk").length());
+                        }
+                        String[] s = vmdkName.split("-");
+                        mapNewDisk.put(s[0], vmdkName);
+                    }
+                }
+                // find vm disk file path (disk file name changed after taken
+                // snapshot
+                for (int i = 0; i < snapshotInfo.length; i++) {
+                    String name = snapshotInfo[i].getDisplayName();
+                    if (name.equals(vmSnapshotName)) {
+                        SnapshotDescriptor.DiskInfo[] disks = snapshotInfo[i].getDisks();
+                        for (SnapshotDescriptor.DiskInfo disk : disks) {
+                            HostMO hostMo = vmMo.getRunningHost();
+                            List<Pair<ManagedObjectReference, String>> datastoreMounts = hostMo
+                                    .getDatastoreMountsOnHost();
+                            String snapshotDiskFile = disk.getDiskFileName();
+                            if (snapshotDiskFile.startsWith("/")) {
+                                for (Pair<ManagedObjectReference, String> mount : datastoreMounts) {
+                                    if (snapshotDiskFile.startsWith(mount.second())) {
+                                        snapshotDiskFileName = snapshotDiskFile.substring(mount.second().length() + 1);
+                                    }
+                                }
+                            } else {
+                                snapshotDiskFileName = snapshotDiskFile;
+                            }
+                            if (snapshotDiskFileName.endsWith("vmdk")) {
+                                snapshotDiskFileName = snapshotDiskFileName.substring(0, snapshotDiskFileName.length()
+                                        - (".vmdk").length());
+                            }
+                            String[] s = snapshotDiskFileName.split("-");
+                            String key = s[0];
+                            mapSnapshotDisk.put(key, snapshotDiskFileName);
+                        }
+                    }
+                }
+                // update vmsnapshotVolumeTo using maps
+                for (VMSnapshotVolumeTO vsvTo : listvsvTo) {
+                    String parentUUID = vsvTo.getVolumePath();
+                    String[] s = parentUUID.split("-");
+                    String key = s[0];
+                    vsvTo.setSnapshotVolumePath(mapSnapshotDisk.get(key));
+                    vsvTo.setNewVolumePath(mapNewDisk.get(key));
+                }
+                return new CreateVMSnapshotAnswer(cmd, vmSnapshotName, listvsvTo);
+            }
+        } catch (Exception e) {
+            String msg = e.getMessage();
+            s_logger.error("failed to create snapshot for vm:" + vmName + " due to " + msg);
+            try {
+                if (vmMo.getSnapshotMor(vmSnapshotName) != null) {
+                    vmMo.removeSnapshot(vmSnapshotName, false);
+                }
+            } catch (Exception e1) {
+                e1.printStackTrace();
+            }
+            return new CreateVMSnapshotAnswer(cmd, false, e.getMessage());
+        }
+    }
+
+	@Override
+    public DeleteVMSnapshotAnswer execute(VmwareHostService hostService, DeleteVMSnapshotCommand cmd) {
+        List<VMSnapshotVolumeTO> listVolumeTo = cmd.getSnapshotVolumeTos();
+        VirtualMachineMO vmMo = null;
+        VmwareContext context = hostService.getServiceContext(cmd);
+        Map<String, String> mapNewDisk = new HashMap<String, String>();
+        String vmName = cmd.getVmName();
+        String vmSnapshotName = cmd.getSnapshotName();
+        try {
+            VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+
+            vmMo = hyperHost.findVmOnHyperHost(vmName);
+            if (vmMo == null) {
+                String msg = "Unable to find owner VM for BackupSnapshotCommand on host "
+                        + hyperHost.getHyperHostName() + ", will try within datacenter";
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.error(msg);
+                }
+                return new DeleteVMSnapshotAnswer(cmd, false, msg);
+            } else {
+                boolean result = false;
+                if (vmMo.getSnapshotMor(vmSnapshotName) == null) {
+                    result = true;
+                    s_logger.debug("can not find the snapshot " + vmSnapshotName + ", it is already removed");
+                } else {
+                    result = vmMo.removeSnapshot(vmSnapshotName, false);
+                    if (!result) {
+                        String msg = "delete vm snapshot " + vmSnapshotName + " due to excuted error in esxi";
+                        s_logger.error(msg);
+                        return new DeleteVMSnapshotAnswer(cmd, false, msg);
+                    }
+                }
+                s_logger.debug("snapshot: " + vmSnapshotName + " is removed");
+                // after removed snapshot, the volume path is changed for the
+                // vm, the db cloud.volume need to update
+                VirtualDisk[] vdisks = vmMo.getAllDiskDevice();
+                for (int i = 0; i < vdisks.length; i++) {
+                    @SuppressWarnings("deprecation")
+                    List<Pair<String, ManagedObjectReference>> vmdkFiles = vmMo.getDiskDatastorePathChain(vdisks[i],
+                            false);
+                    for (Pair<String, ManagedObjectReference> fileItem : vmdkFiles) {
+                        String vmdkName = fileItem.first().split(" ")[1];
+                        if (vmdkName.endsWith(".vmdk")) {
+                            vmdkName = vmdkName.substring(0, vmdkName.length() - (".vmdk").length());
+                        }
+                        String[] s = vmdkName.split("-");
+                        mapNewDisk.put(s[0], vmdkName);
+                    }
+                }
+                for (VMSnapshotVolumeTO volumeTo : listVolumeTo) {
+                    String key = null;
+                    String parentUUID = volumeTo.getVolumePath();
+                    String[] s = parentUUID.split("-");
+                    key = s[0];
+                    volumeTo.setNewVolumePath(mapNewDisk.get(key));
+                }
+                return new DeleteVMSnapshotAnswer(cmd, listVolumeTo);
+            }
+        } catch (Exception e) {
+            String msg = e.getMessage();
+            s_logger.error("failed to delete vm snapshot " + vmSnapshotName + " of vm " + vmName + " due to " + msg);
+            return new DeleteVMSnapshotAnswer(cmd, false, msg);
+        }
+    }
+
+	@Override
+    public RevertToSnapshotAnswer execute(VmwareHostService hostService, RevertToSnapshotCommand cmd) {
+        String snapshotName = cmd.getSnapshotName();
+        String vmName = cmd.getVmName();
+        Boolean snapshotMemory = cmd.memory();
+        List<VMSnapshotVolumeTO> listVolumeTo = cmd.getSnapshotVolumeTos();
+        VirtualMachine.State vmState = VirtualMachine.State.Running;
+        VirtualMachineMO vmMo = null;
+        VmwareContext context = hostService.getServiceContext(cmd);
+        Map<String, String> mapNewDisk = new HashMap<String, String>();
+        try {
+            VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+            HostMO hostMo = (HostMO) hyperHost;
+            vmMo = hyperHost.findVmOnHyperHost(vmName);
+            if (vmMo == null) {
+                String msg = "Unable to find owner VM for BackupSnapshotCommand on host "
+                        + hyperHost.getHyperHostName() + ", will try within datacenter";
+                s_logger.debug(msg);
+                return new RevertToSnapshotAnswer(cmd, false, msg);
+            } else {
+                boolean result = false;
+                if (snapshotName != null) {
+                    ManagedObjectReference morSnapshot = vmMo.getSnapshotMor(snapshotName);
+                    result = hostMo.revertToSnapshot(morSnapshot);
+                } else {
+                    return new RevertToSnapshotAnswer(cmd, false, "Unable to find the snapshot by name " + snapshotName);
+                }
+
+                if (result) {
+                    VirtualDisk[] vdisks = vmMo.getAllDiskDevice();
+                    for (int i = 0; i < vdisks.length; i++) {
+                        @SuppressWarnings("deprecation")
+                        List<Pair<String, ManagedObjectReference>> vmdkFiles = vmMo.getDiskDatastorePathChain(
+                                vdisks[i], false);
+                        for (Pair<String, ManagedObjectReference> fileItem : vmdkFiles) {
+                            String vmdkName = fileItem.first().split(" ")[1];
+                            if (vmdkName.endsWith(".vmdk")) {
+                                vmdkName = vmdkName.substring(0, vmdkName.length() - (".vmdk").length());
+                            }
+                            String[] s = vmdkName.split("-");
+                            mapNewDisk.put(s[0], vmdkName);
+                        }
+                    }
+                    String key = null;
+                    for (VMSnapshotVolumeTO volumeTo : listVolumeTo) {
+                        String parentUUID = volumeTo.getVolumePath();
+                        String[] s = parentUUID.split("-");
+                        key = s[0];
+                        volumeTo.setNewVolumePath(mapNewDisk.get(key));
+                    }
+                    if (!snapshotMemory) {
+                        vmState = VirtualMachine.State.Stopped;
+                    }
+                    return new RevertToSnapshotAnswer(cmd, listVolumeTo, vmState);
+                } else {
+                    return new RevertToSnapshotAnswer(cmd, false,
+                            "Error while reverting to snapshot due to execute in esxi");
+                }
+            }
+        } catch (Exception e) {
+            String msg = "revert vm " + vmName + " to snapshot " + snapshotName + " failed due to " + e.getMessage();
+            s_logger.error(msg);
+            return new RevertToSnapshotAnswer(cmd, false, msg);
+        }
+    }
+
+ 
+    private VirtualMachineMO createWorkingVM(DatastoreMO dsMo, VmwareHypervisorHost hyperHost) throws Exception {
+        String uniqueName = UUID.randomUUID().toString();
+        VirtualMachineMO workingVM = null;
+        VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec();
+        vmConfig.setName(uniqueName);
+        vmConfig.setMemoryMB((long) 4);
+        vmConfig.setNumCPUs(1);
+        vmConfig.setGuestId(VirtualMachineGuestOsIdentifier._otherGuest.toString());
+        VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo();
+        fileInfo.setVmPathName(String.format("[%s]", dsMo.getName()));
+        vmConfig.setFiles(fileInfo);
+
+        VirtualLsiLogicController scsiController = new VirtualLsiLogicController();
+        scsiController.setSharedBus(VirtualSCSISharing.noSharing);
+        scsiController.setBusNumber(0);
+        scsiController.setKey(1);
+        VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec();
+        scsiControllerSpec.setDevice(scsiController);
+        scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.add);
+
+        vmConfig.setDeviceChange(new VirtualDeviceConfigSpec[] { scsiControllerSpec });
+        hyperHost.createVm(vmConfig);
+        workingVM = hyperHost.findVmOnHyperHost(uniqueName);
+        return workingVM;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 93ce648..d0bcbc4 100755
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -26,9 +26,11 @@ import java.util.Comparator;
 import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
+import java.util.Set;
 import java.util.TimeZone;
 import java.util.UUID;
 
@@ -61,9 +63,13 @@ import com.cloud.agent.api.Command;
 import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
 import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
 import com.cloud.agent.api.CreateStoragePoolCommand;
+import com.cloud.agent.api.CreateVMSnapshotAnswer;
+import com.cloud.agent.api.CreateVMSnapshotCommand;
 import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
 import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
 import com.cloud.agent.api.DeleteStoragePoolCommand;
+import com.cloud.agent.api.DeleteVMSnapshotAnswer;
+import com.cloud.agent.api.DeleteVMSnapshotCommand;
 import com.cloud.agent.api.GetDomRVersionAnswer;
 import com.cloud.agent.api.GetDomRVersionCmd;
 import com.cloud.agent.api.GetHostStatsAnswer;
@@ -74,6 +80,8 @@ import com.cloud.agent.api.GetVmStatsAnswer;
 import com.cloud.agent.api.GetVmStatsCommand;
 import com.cloud.agent.api.GetVncPortAnswer;
 import com.cloud.agent.api.GetVncPortCommand;
+import com.cloud.agent.api.GetVolumesChangedAnswer;
+import com.cloud.agent.api.GetVolumesChangedCommand;
 import com.cloud.agent.api.HostStatsEntry;
 import com.cloud.agent.api.MaintainAnswer;
 import com.cloud.agent.api.MaintainCommand;
@@ -99,6 +107,8 @@ import com.cloud.agent.api.ReadyCommand;
 import com.cloud.agent.api.RebootAnswer;
 import com.cloud.agent.api.RebootCommand;
 import com.cloud.agent.api.RebootRouterCommand;
+import com.cloud.agent.api.RevertToSnapshotAnswer;
+import com.cloud.agent.api.RevertToSnapshotCommand;
 import com.cloud.agent.api.SetupAnswer;
 import com.cloud.agent.api.SetupCommand;
 import com.cloud.agent.api.SetupGuestNetworkAnswer;
@@ -134,8 +144,8 @@ import com.cloud.agent.api.routing.SetNetworkACLCommand;
 import com.cloud.agent.api.routing.SetPortForwardingRulesAnswer;
 import com.cloud.agent.api.routing.SetPortForwardingRulesCommand;
 import com.cloud.agent.api.routing.SetPortForwardingRulesVpcCommand;
-import com.cloud.agent.api.routing.SetSourceNatCommand;
 import com.cloud.agent.api.routing.SetSourceNatAnswer;
+import com.cloud.agent.api.routing.SetSourceNatCommand;
 import com.cloud.agent.api.routing.SetStaticNatRulesAnswer;
 import com.cloud.agent.api.routing.SetStaticNatRulesCommand;
 import com.cloud.agent.api.routing.VmDataCommand;
@@ -245,9 +255,6 @@ import com.vmware.vim25.VirtualMachineGuestOsIdentifier;
 import com.vmware.vim25.VirtualMachinePowerState;
 import com.vmware.vim25.VirtualMachineRuntimeInfo;
 import com.vmware.vim25.VirtualSCSISharing;
-import com.xensource.xenapi.Connection;
-import com.xensource.xenapi.VIF;
-import com.xensource.xenapi.VM;
 
 public class VmwareResource implements StoragePoolResource, ServerResource, VmwareHostService {
     private static final Logger s_logger = Logger.getLogger(VmwareResource.class);
@@ -440,7 +447,15 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                 answer = execute((SetSourceNatCommand) cmd);
             } else if (clz == SetNetworkACLCommand.class) {
                 answer = execute((SetNetworkACLCommand) cmd);
-            } else if (clz == SetPortForwardingRulesVpcCommand.class) {
+            } else if (cmd instanceof GetVolumesChangedCommand) {
+            	return execute((GetVolumesChangedCommand)cmd);
+            } else if (cmd instanceof CreateVMSnapshotCommand) {
+            	return execute((CreateVMSnapshotCommand)cmd);
+            } else if(cmd instanceof DeleteVMSnapshotCommand){
+            	return execute((DeleteVMSnapshotCommand)cmd);
+            } else if(cmd instanceof RevertToSnapshotCommand){
+            	return execute((RevertToSnapshotCommand)cmd);
+        	}else if (clz == SetPortForwardingRulesVpcCommand.class) {
                 answer = execute((SetPortForwardingRulesVpcCommand) cmd);
             } else {
                 answer = Answer.createUnsupportedCommandAnswer(cmd);
@@ -481,6 +496,50 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         return answer;
     }
     
+    private Answer execute(GetVolumesChangedCommand cmd) {
+        Map<String, Map<String, VolumeTO>> vmVolumesMap = cmd.getVmVolumesMap();// {vmName:{volumeName:volumeTo}}
+        Set<String> vmNames = vmVolumesMap.keySet();
+        List<VolumeTO> volumeToList = new ArrayList<VolumeTO>();
+        try {
+            VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext());
+            ClusterMO clusterMo = new ClusterMO(hyperHost.getContext(),
+                    ((HostMO) hyperHost).getParentMor());
+            for (String vmName : vmNames) {
+                Map<String, VolumeTO> volumeToMap = vmVolumesMap.get(vmName);
+                Collection<VolumeTO> volumeTos = volumeToMap.values();
+                VirtualMachineMO vmMo = clusterMo.findVmOnHyperHost(vmName);
+                if (vmMo == null) {
+                    s_logger.warn("vm " + vmName + " did not find");
+                }
+                VirtualDisk[] vdisks = vmMo.getAllDiskDevice();
+                for (int i = 0; i < vdisks.length; i++) {
+                    @SuppressWarnings("deprecation")
+                    List<Pair<String, ManagedObjectReference>> vmdkFiles = vmMo
+                            .getDiskDatastorePathChain(vdisks[i], false);
+                    vmMo.getConfigSummary().getNumVirtualDisks();
+                    for (Pair<String, ManagedObjectReference> fileItem : vmdkFiles) {
+                        String vmdkName = fileItem.first().split(" ")[1];
+                        vmdkName = vmdkName.substring(0, vmdkName.length() - 5);
+                        Iterator<VolumeTO> iter = volumeTos.iterator();
+                        while (iter.hasNext()) {
+                            VolumeTO volumeTo = iter.next();
+                            if (!volumeTo.getPath().equals(vmdkName)) {
+                                s_logger.warn("vm " + vmName + " has volume "
+                                        + volumeTo.getName() + " changed "
+                                        + volumeTo.getPath() + " -> "
+                                        + vmdkName);
+                                volumeTo.setPath(vmdkName);
+                                volumeToList.add(volumeTo);
+                            }
+                        }
+                    }
+                }
+            }
+            return new GetVolumesChangedAnswer(cmd, volumeToList);
+        } catch (Exception e) {
+            return new GetVolumesChangedAnswer(cmd, false, e.getMessage());
+        }
+    }
     protected Answer execute(CheckNetworkCommand cmd) {
         if (s_logger.isInfoEnabled()) {
             s_logger.info("Executing resource CheckNetworkCommand " + _gson.toJson(cmd));
@@ -3186,7 +3245,42 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         }
     }
 
+    protected Answer execute(CreateVMSnapshotCommand cmd) {
+        try {
+            VmwareContext context = getServiceContext();
+            VmwareManager mgr = context
+                    .getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
 
+            return mgr.getStorageManager().execute(this, cmd);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return new CreateVMSnapshotAnswer(cmd, false, "");
+        }
+    }
+    
+    protected Answer execute(DeleteVMSnapshotCommand cmd) {
+        try {
+            VmwareContext context = getServiceContext();
+            VmwareManager mgr = context
+                    .getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
+
+            return mgr.getStorageManager().execute(this, cmd);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return new DeleteVMSnapshotAnswer(cmd, false, "");
+        }
+    }
+    
+    protected Answer execute(RevertToSnapshotCommand cmd){
+    	try{
+    		VmwareContext context = getServiceContext();
+			VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
+			return mgr.getStorageManager().execute(this, cmd);
+    	}catch (Exception e){
+    		e.printStackTrace();
+    		return new RevertToSnapshotAnswer(cmd,false,"");
+    	}
+    }
     protected Answer execute(CreateVolumeFromSnapshotCommand cmd) {
         if (s_logger.isInfoEnabled()) {
             s_logger.info("Executing resource CreateVolumeFromSnapshotCommand: " + _gson.toJson(cmd));

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
index c88ae80..e3eacec 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
@@ -77,9 +77,15 @@ import com.cloud.agent.api.Command;
 import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
 import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
 import com.cloud.agent.api.CreateStoragePoolCommand;
+import com.cloud.agent.api.CreateVMSnapshotAnswer;
+import com.cloud.agent.api.CreateVMSnapshotCommand;
 import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
 import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
+import com.cloud.agent.api.CreateVolumeFromVMSnapshotAnswer;
+import com.cloud.agent.api.CreateVolumeFromVMSnapshotCommand;
 import com.cloud.agent.api.DeleteStoragePoolCommand;
+import com.cloud.agent.api.DeleteVMSnapshotAnswer;
+import com.cloud.agent.api.DeleteVMSnapshotCommand;
 import com.cloud.agent.api.GetDomRVersionAnswer;
 import com.cloud.agent.api.GetDomRVersionCmd;
 import com.cloud.agent.api.GetHostStatsAnswer;
@@ -90,6 +96,8 @@ import com.cloud.agent.api.GetVmStatsAnswer;
 import com.cloud.agent.api.GetVmStatsCommand;
 import com.cloud.agent.api.GetVncPortAnswer;
 import com.cloud.agent.api.GetVncPortCommand;
+import com.cloud.agent.api.GetVolumesChangedAnswer;
+import com.cloud.agent.api.GetVolumesChangedCommand;
 import com.cloud.agent.api.HostStatsEntry;
 import com.cloud.agent.api.MaintainAnswer;
 import com.cloud.agent.api.MaintainCommand;
@@ -116,6 +124,8 @@ import com.cloud.agent.api.ReadyCommand;
 import com.cloud.agent.api.RebootAnswer;
 import com.cloud.agent.api.RebootCommand;
 import com.cloud.agent.api.RebootRouterCommand;
+import com.cloud.agent.api.RevertToSnapshotAnswer;
+import com.cloud.agent.api.RevertToSnapshotCommand;
 import com.cloud.agent.api.SecurityGroupRuleAnswer;
 import com.cloud.agent.api.SecurityGroupRulesCmd;
 import com.cloud.agent.api.SetupAnswer;
@@ -178,6 +188,7 @@ import com.cloud.agent.api.to.PortForwardingRuleTO;
 import com.cloud.agent.api.to.StaticNatRuleTO;
 import com.cloud.agent.api.to.StorageFilerTO;
 import com.cloud.agent.api.to.SwiftTO;
+import com.cloud.agent.api.to.VMSnapshotVolumeTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.agent.api.to.VolumeTO;
 import com.cloud.exception.InternalErrorException;
@@ -238,6 +249,10 @@ import com.xensource.xenapi.Types;
 import com.xensource.xenapi.Types.BadServerResponse;
 import com.xensource.xenapi.Types.ConsoleProtocol;
 import com.xensource.xenapi.Types.IpConfigurationMode;
+import com.xensource.xenapi.Types.OperationNotAllowed;
+import com.xensource.xenapi.Types.SrFull;
+import com.xensource.xenapi.Types.VbdType;
+import com.xensource.xenapi.Types.VmBadPowerState;
 import com.xensource.xenapi.Types.VmPowerState;
 import com.xensource.xenapi.Types.XenAPIException;
 import com.xensource.xenapi.VBD;
@@ -553,11 +568,229 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             return execute((Site2SiteVpnCfgCommand) cmd);
         } else if (clazz == CheckS2SVpnConnectionsCommand.class) {
             return execute((CheckS2SVpnConnectionsCommand) cmd);
+        } else if (clazz == CreateVMSnapshotCommand.class) {
+            return execute((CreateVMSnapshotCommand)cmd);
+        } else if (clazz == DeleteVMSnapshotCommand.class) {
+            return execute((DeleteVMSnapshotCommand)cmd);
+        } else if (clazz == RevertToSnapshotCommand.class) {
+            return execute((RevertToSnapshotCommand)cmd);
+        } else if (clazz == CreateVolumeFromVMSnapshotCommand.class) {
+            return execute((CreateVolumeFromVMSnapshotCommand)cmd);
+        } else if (cmd instanceof GetVolumesChangedCommand) {
+            return execute((GetVolumesChangedCommand)cmd);
         } else {
             return Answer.createUnsupportedCommandAnswer(cmd);
         }
     }
 
+
+    private Answer execute(GetVolumesChangedCommand cmd) {
+        Map<String, Map<String, VolumeTO>> vmVolumesMap = cmd.getVmVolumesMap();// {vmName:{volumeName:volumeTo}}
+        Set<String> vmNames = vmVolumesMap.keySet();
+
+        Connection conn = getConnection();
+        List<VolumeTO> volumeToList = new ArrayList<VolumeTO>();
+
+        try {
+            Map<VM, VM.Record> vmRecords = VM.getAllRecords(conn);
+            Set<VM> vmSet = vmRecords.keySet();
+            for (VM vm : vmSet) {
+                String vmName = vm.getNameLabel(conn);
+                if (!vmNames.contains(vmName)) {
+                    continue;
+                }
+                Set<VBD> vbds = vmRecords.get(vm).VBDs;
+                Map<String, VolumeTO> volumeToMap = vmVolumesMap.get(vmName);
+                for (VBD vbd : vbds) {
+                    VBD.Record vbdr = vbd.getRecord(conn);
+                    if (vbdr.type == VbdType.DISK) {
+                        VDI vdi = vbdr.VDI;
+                        String deviceId = vbdr.userdevice;
+                        String vdiPath = vdi.getUuid(conn);
+                        VolumeTO volumeTo = volumeToMap.get(deviceId);
+                        String volumeName = volumeTo.getName();
+                        if (!volumeTo.getPath().equals(vdiPath)) {
+                            s_logger.warn("vm " + vmName + " has volume "
+                                    + volumeName + " changed "
+                                    + volumeTo.getPath() + " -> " + vdiPath);
+                            volumeTo.setPath(vdiPath);
+                            volumeToList.add(volumeTo);
+                        }
+                    }
+                }
+            }
+            return new GetVolumesChangedAnswer(cmd, volumeToList);
+        } catch (BadServerResponse e) {
+            return new GetVolumesChangedAnswer(cmd, false, e.getMessage());
+        } catch (XenAPIException e) {
+            return new GetVolumesChangedAnswer(cmd, false, e.getMessage());
+        } catch (XmlRpcException e) {
+            return new GetVolumesChangedAnswer(cmd, false, e.getMessage());
+        }
+    }
+
+    private Answer execute(CreateVolumeFromVMSnapshotCommand cmd) {
+        Connection conn = getConnection();
+        String vdiUUID = cmd.getPath();
+        String name = cmd.getName();
+        Boolean fullClone = cmd.getFullClone();
+        StorageFilerTO pool = cmd.getPool();
+        DiskProfile dskch = cmd.getDskch();
+
+        try {
+            VDI vdi = VDI.getByUuid(conn, vdiUUID);
+            VDI newVdi = null;
+            if (fullClone) {
+                newVdi = vdi.copy(conn, vdi.getSR(conn));
+            } else {
+                newVdi = vdi.createClone(conn, new HashMap<String, String>());
+            }
+            if (newVdi != null) {
+                newVdi.setNameLabel(conn, name);
+                VDI.Record vdir = newVdi.getRecord(conn);
+                VolumeTO vol = new VolumeTO(cmd.getVolumeId(), dskch.getType(),
+                        pool.getType(), pool.getUuid(), vdir.nameLabel,
+                        pool.getPath(), vdir.uuid, vdir.virtualSize, null);
+                return new CreateVolumeFromVMSnapshotAnswer(cmd, vol);
+            } else {
+                return new CreateVolumeFromVMSnapshotAnswer(cmd, false,
+                        "xenserver internal error");
+            }
+        } catch (BadServerResponse e) {
+            s_logger.error("create volume from vm snapshot failed due to "
+                    + e.getMessage());
+            return new CreateVolumeFromVMSnapshotAnswer(cmd, false,
+                    e.getMessage());
+        } catch (XenAPIException e) {
+            s_logger.error("create volume from vm snapshot failed due to "
+                    + e.getMessage());
+            return new CreateVolumeFromVMSnapshotAnswer(cmd, false,
+                    e.getMessage());
+        } catch (XmlRpcException e) {
+            s_logger.error("create volume from vm snapshot failed due to "
+                    + e.getMessage());
+            return new CreateVolumeFromVMSnapshotAnswer(cmd, false,
+                    e.getMessage());
+        }
+    }
+
+    private Answer execute(RevertToSnapshotCommand cmd) {
+        String vmName = cmd.getVmName();
+        List<VMSnapshotVolumeTO> listSnapshotVolumeTo = cmd
+                .getSnapshotVolumeTos();
+        Boolean snapshotMemory = cmd.memory();
+
+        Connection conn = getConnection();
+        Task task = null;
+        // List<VDI> oldVdiList = new ArrayList<VDI>();
+        // for (VMSnapshotVolumeTO snapshotVolumeTo : listSnapshotVolumeTo){
+        // String volumeUuid = snapshotVolumeTo.getVolumePath();
+        // try {
+        // oldVdiList.add(VDI.getByUuid(conn, volumeUuid));
+        // } catch (Types.UuidInvalid e){
+        // s_logger.warn("Unable to find vdi by uuid " + volumeUuid);
+        // } catch (Exception e){
+        // e.printStackTrace();
+        // }
+        // }
+        VirtualMachine.State vmState = VirtualMachine.State.Running;
+        boolean reverted = false;
+        VM vm = null;
+        try {
+
+            // remove vm from s_vms, for delta sync
+            s_vms.remove(_cluster, _name, vmName);
+            // check if snapshot contains memory
+            // if contains memory, check if snapshot vm exists
+            // else, check vm exists
+            VM vmSnapshot = VM.getByUuid(conn, cmd.getSnapshotUUID());
+            Set<VM> vms = VM.getByNameLabel(conn, vmName);
+            if (vms.size() == 0) {
+                vm = createWorkingVM(conn, vmName, "Other PV (64-bit)",
+                        listSnapshotVolumeTo);
+            } else if (vms.size() == 1) {
+                vm = getVM(conn, vmName);
+            } else {
+                String msg = "find more than 1 vm: " + vmName
+                        + " exists. error to revert";
+                s_logger.error(msg);
+                return new RevertToSnapshotAnswer(cmd, false, msg);
+            }
+            revertToSnapshot(conn, vmSnapshot, vmName, vm.getUuid(conn),
+                    snapshotMemory);
+            vm = getVM(conn, vmName);
+            Set<VBD> vbds = vm.getVBDs(conn);
+            Map<String, VDI> vdiMap = new HashMap<String, VDI>();
+            // get vdi:vbdr to a map
+            for (VBD vbd : vbds) {
+                VBD.Record vbdr = vbd.getRecord(conn);
+                if (vbdr.type == Types.VbdType.DISK) {
+                    VDI vdi = vbdr.VDI;
+                    vdiMap.put(vbdr.userdevice, vdi);
+                }
+            }
+
+            if (!snapshotMemory) {
+                vm.destroy(conn);
+                vmState = VirtualMachine.State.Stopped;
+            } else {
+                s_vms.put(_cluster, _name, vmName, State.Running);
+                vmState = VirtualMachine.State.Running;
+            }
+
+            for (VMSnapshotVolumeTO volumeTo : listSnapshotVolumeTo) {
+                Long deviceId = volumeTo.getDeviceId();
+                if (volumeTo.getDeviceId() != null) {
+                    VDI vdi = vdiMap.get(deviceId.toString());
+                    volumeTo.setNewVolumePath(vdi.getUuid(conn));
+                }
+            }
+
+            reverted = true;
+            return new RevertToSnapshotAnswer(cmd, listSnapshotVolumeTo,
+                    vmState);
+        } catch (XenAPIException e) {
+            reverted = false;
+            s_logger.error("revert vm " + vmName
+                    + " to snapshot failed due to " + e.getMessage());
+            return new RevertToSnapshotAnswer(cmd, false, e.getMessage());
+        } catch (Exception e) {
+            reverted = false;
+            s_logger.error("revert vm " + vmName
+                    + " to snapshot failed due to " + e.getMessage());
+            return new RevertToSnapshotAnswer(cmd, false, e.getMessage());
+        }
+    }
+
+    private void revertToSnapshot(Connection conn, VM vmSnapshot,
+            String vmName, String oldVmUuid, Boolean snapshotMemory)
+            throws XenAPIException, XmlRpcException {
+        // // revert
+        // Task task = vmSnapshot.revertAsync(conn);
+        // waitForTask(conn, task, 1000, 10 * 60 * 1000);
+        // checkForSuccess(conn, task);
+        // // finish revert to suspended
+        // // resume
+        // VM vm = getVM(conn, vmName);
+        // task = vm.resumeAsync(conn, false, true);
+        // waitForTask(conn, task, 1000, 10 * 60 * 1000);
+        // checkForSuccess(conn, task);
+        String results = callHostPluginAsync(conn, "vmopsSnapshot",
+                "revert_memory_snapshot", 10 * 60 * 1000, "snapshotUUID",
+                vmSnapshot.getUuid(conn), "vmName", vmName, "oldVmUuid",
+                oldVmUuid, "snapshotMemory", snapshotMemory.toString());
+        String errMsg = null;
+        if (results == null || results.isEmpty()) {
+            errMsg = "revert_memory_snapshot return null";
+        } else {
+            String[] tmp = results.split("#");
+            String status = tmp[0];
+            if (!status.equals("0")) {
+                errMsg = tmp[1];
+            }
+        }
+    }
+
     protected XsLocalNetwork getNativeNetworkForTraffic(Connection conn, TrafficType type, String name) throws XenAPIException, XmlRpcException {
         if (name != null) {
             if (s_logger.isDebugEnabled()) {
@@ -6100,6 +6333,179 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
 
     }
 
+    protected Answer execute(final CreateVMSnapshotCommand cmd) {
+        String vmName = cmd.getVmName();
+        String vmSnapshotName = cmd.getSnapshotName();
+        List<VMSnapshotVolumeTO> listVSVolumeTo = cmd.getSnapshotVolumeTos();
+        VirtualMachine.State vmState = cmd.getVmState();
+        String guestOSType = cmd.getGuestOSType();
+
+        boolean snapshotMemory = cmd.snapshotMemory();
+        long timeout = 600;
+
+        Connection conn = getConnection();
+        HashMap<String, VDI> snapshotVDIMap = new HashMap<String, VDI>();
+        VM vm = null;
+        VM vmSnapshot = null;
+        boolean success = false;
+
+        try {
+            if (vmState == VirtualMachine.State.Stopped) {
+                vm = createWorkingVM(conn, vmName, guestOSType, listVSVolumeTo);
+            } else {
+                vm = getVM(conn, vmName);
+            }
+
+            if (vm == null) {
+                return new CreateVMSnapshotAnswer(cmd, false,
+                        "Creating VM Snapshot Failed due to can not find vm: "
+                                + vmName);
+            }
+            Task task = null;
+            if (!snapshotMemory) {
+                task = vm.snapshotAsync(conn, vmSnapshotName);
+            } else {
+                task = vm.checkpointAsync(conn, vmSnapshotName);
+            }
+            waitForTask(conn, task, 1000, timeout * 1000);
+            checkForSuccess(conn, task);
+            String result = task.getResult(conn);
+            String ref = result.substring("<value>".length(), result.length()
+                    - "</value>".length());
+            vmSnapshot = Types.toVM(ref);
+            Set<VBD> snapshotVbds = vmSnapshot.getVBDs(conn);
+            for (VBD vbd : snapshotVbds) {
+                VBD.Record vbdr = vbd.getRecord(conn);
+                if (vbdr.type == VbdType.DISK) {
+                    VDI vdi = vbdr.VDI;
+                    snapshotVDIMap.put(vbdr.userdevice, vdi);
+                }
+            }
+            for (VMSnapshotVolumeTO vsVolumeTo : listVSVolumeTo) {
+                String key = vsVolumeTo.getDeviceId().toString();
+                String volumePath = vsVolumeTo.getVolumePath();
+                VDI vdi = snapshotVDIMap.get(key);
+                vsVolumeTo.setSnapshotVolumePath(vdi.getUuid(conn));
+                vsVolumeTo.setNewVolumePath(volumePath);
+            }
+            String snapshotUUID = vmSnapshot.getUuid(conn);
+            success = true;
+            return new CreateVMSnapshotAnswer(cmd, snapshotUUID, listVSVolumeTo);
+        } catch (Exception e) {
+            String msg = e.getMessage();
+            s_logger.error("Creating VM Snapshot Failed due to: " + msg);
+            return new CreateVMSnapshotAnswer(cmd, false, msg);
+        } finally {
+            try {
+                if (!success) {
+                    if (vmSnapshot != null) {
+                        s_logger.error("Delete exsisting VM Snapshot "
+                                + vmSnapshotName
+                                + " after making VolumeTO failed");
+                        Set<VBD> vbds = vmSnapshot.getVBDs(conn);
+                        for (VBD vbd : vbds) {
+                            VBD.Record vbdr = vbd.getRecord(conn);
+                            if (vbdr.type == VbdType.DISK) {
+                                VDI vdi = vbdr.VDI;
+                                vdi.destroy(conn);
+                            }
+                        }
+                        vmSnapshot.destroy(conn);
+                    }
+                }
+                if (vmState == VirtualMachine.State.Stopped) {
+                    if (vm != null) {
+                        vm.destroy(conn);
+                    }
+                }
+            } catch (Exception e2) {
+                s_logger.error("delete snapshot error due to "
+                        + e2.getMessage());
+            }
+        }
+    }
+    
+    private VM createWorkingVM(Connection conn, String vmName,
+            String guestOSType, List<VMSnapshotVolumeTO> snapshotVolumeTos)
+            throws BadServerResponse, VmBadPowerState, SrFull,
+            OperationNotAllowed, XenAPIException, XmlRpcException {
+        String guestOsTypeName = getGuestOsType(guestOSType, false);
+        if (guestOsTypeName == null) {
+            String msg = " Hypervisor " + this.getClass().getName()
+                    + " doesn't support guest OS type " + guestOSType
+                    + ". you can choose 'Other install media' to run it as HVM";
+            s_logger.warn(msg);
+            throw new CloudRuntimeException(msg);
+        }
+        VM template = getVM(conn, guestOsTypeName);
+        VM vm = template.createClone(conn, vmName);
+        vm.setIsATemplate(conn, false);
+        Map<VDI, VMSnapshotVolumeTO> vdiMap = new HashMap<VDI, VMSnapshotVolumeTO>();
+        for (VMSnapshotVolumeTO snapshotVolumeTo : snapshotVolumeTos) {
+            String vdiUuid = snapshotVolumeTo.getVolumePath();
+            try {
+                VDI vdi = VDI.getByUuid(conn, vdiUuid);
+                vdiMap.put(vdi, snapshotVolumeTo);
+            } catch (Types.UuidInvalid e) {
+                s_logger.warn("Unable to find vdi by uuid: " + vdiUuid
+                        + ", skip it");
+            }
+        }
+        for (VDI vdi : vdiMap.keySet()) {
+            VMSnapshotVolumeTO snapshotVolumeTo = vdiMap.get(vdi);
+            VBD.Record vbdr = new VBD.Record();
+            vbdr.VM = vm;
+            vbdr.VDI = vdi;
+            if (snapshotVolumeTo.getVolumeType() == Volume.Type.ROOT) {
+                vbdr.bootable = true;
+                vbdr.unpluggable = false;
+            } else {
+                vbdr.bootable = false;
+                vbdr.unpluggable = true;
+            }
+            vbdr.userdevice = snapshotVolumeTo.getDeviceId().toString();
+            vbdr.mode = Types.VbdMode.RW;
+            vbdr.type = Types.VbdType.DISK;
+            VBD.create(conn, vbdr);
+        }
+        return vm;
+    }
+
+    protected Answer execute(final DeleteVMSnapshotCommand cmd) {
+        String snapshotUUID = cmd.getSnapshotUUID();
+        Connection conn = getConnection();
+        List<VMSnapshotVolumeTO> snapshotVolumeToList = cmd
+                .getSnapshotVolumeTos();
+        try {
+            List<VDI> vdiList = new ArrayList<VDI>();
+            VM snapshot = VM.getByUuid(conn, snapshotUUID);
+            Set<VBD> vbds = snapshot.getVBDs(conn);
+            for (VBD vbd : vbds) {
+                if (vbd.getType(conn) == VbdType.DISK) {
+                    VDI vdi = vbd.getVDI(conn);
+                    vdiList.add(vdi);
+                }
+            }
+            snapshot.destroy(conn);
+            for (VDI vdi : vdiList) {
+                vdi.destroy(conn);
+            }
+            for (VMSnapshotVolumeTO snapshotVolume : snapshotVolumeToList) {
+                snapshotVolume.setNewVolumePath(snapshotVolume.getVolumePath());
+            }
+            return new DeleteVMSnapshotAnswer(cmd, snapshotVolumeToList);
+        } catch (Types.UuidInvalid e) {
+            s_logger.warn("No snapshot found by the uuid: " + snapshotUUID
+                    + ", snapshot not found or deleted");
+            return new DeleteVMSnapshotAnswer(cmd, true, "snapshot by uuid "
+                    + snapshotUUID + " not found, mark as removed");
+        } catch (Exception e) {
+            s_logger.warn("Catch Exception: " + e.getClass().toString()
+                    + " due to " + e.toString(), e);
+            return new DeleteVMSnapshotAnswer(cmd, false, e.getMessage());
+        }
+    }
+    
     protected Answer execute(final AttachIsoCommand cmd) {
         Connection conn = getConnection();
         boolean attach = cmd.isAttach();

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/scripts/vm/hypervisor/xenserver/vmopsSnapshot
----------------------------------------------------------------------
diff --git a/scripts/vm/hypervisor/xenserver/vmopsSnapshot b/scripts/vm/hypervisor/xenserver/vmopsSnapshot
index 80e21f8..3d383a2 100755
--- a/scripts/vm/hypervisor/xenserver/vmopsSnapshot
+++ b/scripts/vm/hypervisor/xenserver/vmopsSnapshot
@@ -556,6 +556,32 @@ def deleteSnapshotBackup(session, args):
 
     return "1"
    
+@echo
+def revert_memory_snapshot(session, args):
+    util.SMlog("Calling revert_memory_snapshot with " + str(args))
+    vmName = args['vmName']
+    snapshotUUID = args['snapshotUUID']
+    oldVmUuid = args['oldVmUuid']
+    snapshotMemory = args['snapshotMemory']
+    try:
+        cmd = '''xe vbd-list vm-uuid=%s | grep 'vdi-uuid' | grep -v 'not in database' | sed -e 's/vdi-uuid ( RO)://g' ''' % oldVmUuid
+        vdiUuids = os.popen(cmd).read().split()
+        cmd2 = '''xe vm-param-get param-name=power-state uuid=''' + oldVmUuid
+        if os.popen(cmd2).read().split()[0] != 'halted':
+            os.system("xe vm-shutdown force=true vm=" + vmName)
+        os.system("xe vm-destroy uuid=" + oldVmUuid)
+        os.system("xe snapshot-revert snapshot-uuid=" + snapshotUUID)
+        if snapshotMemory == 'true':
+            os.system("xe vm-resume vm=" + vmName)
+        for vdiUuid in vdiUuids:
+            os.system("xe vdi-destroy uuid=" + vdiUuid)
+    except OSError, (errno, strerror):
+        errMsg = "OSError while reverting vm " + vmName + " to snapshot " + snapshotUUID + " with errno: " + str(errno) + " and strerr: " + strerror
+        util.SMlog(errMsg)
+        raise xs_errors.XenError(errMsg)
+    return "0"
+
 if __name__ == "__main__":
-    XenAPIPlugin.dispatch({"getVhdParent":getVhdParent,  "create_secondary_storage_folder":create_secondary_storage_folder, "delete_secondary_storage_folder":delete_secondary_storage_folder, "post_create_private_template":post_create_private_template, "backupSnapshot": backupSnapshot, "deleteSnapshotBackup": deleteSnapshotBackup, "unmountSnapshotsDir": unmountSnapshotsDir})
+    XenAPIPlugin.dispatch({"getVhdParent":getVhdParent,  "create_secondary_storage_folder":create_secondary_storage_folder, "delete_secondary_storage_folder":delete_secondary_storage_folder, "post_create_private_template":post_create_private_template, "backupSnapshot": backupSnapshot, "deleteSnapshotBackup": deleteSnapshotBackup, "unmountSnapshotsDir": unmountSnapshotsDir, "revert_memory_snapshot":revert_memory_snapshot})
+    
 

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/server/src/com/cloud/api/ApiDBUtils.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java
index e1e8865..f7ab1e8 100755
--- a/server/src/com/cloud/api/ApiDBUtils.java
+++ b/server/src/com/cloud/api/ApiDBUtils.java
@@ -16,6 +16,7 @@
 // under the License.
 package com.cloud.api;
 
+import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
@@ -62,17 +63,17 @@ import com.cloud.network.NetworkManager;
 import com.cloud.network.NetworkProfile;
 import com.cloud.network.NetworkRuleConfigVO;
 import com.cloud.network.NetworkVO;
-import com.cloud.network.Site2SiteVpnGatewayVO;
-import com.cloud.network.Site2SiteCustomerGatewayVO;
 import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.Site2SiteCustomerGatewayVO;
+import com.cloud.network.Site2SiteVpnGatewayVO;
 import com.cloud.network.dao.FirewallRulesCidrsDao;
 import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.LoadBalancerDao;
 import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkDomainDao;
 import com.cloud.network.dao.NetworkRuleConfigDao;
-import com.cloud.network.dao.Site2SiteVpnGatewayDao;
 import com.cloud.network.dao.Site2SiteCustomerGatewayDao;
+import com.cloud.network.dao.Site2SiteVpnGatewayDao;
 import com.cloud.network.security.SecurityGroup;
 import com.cloud.network.security.SecurityGroupManager;
 import com.cloud.network.security.SecurityGroupVO;
@@ -149,6 +150,11 @@ import com.cloud.vm.dao.DomainRouterDao;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.UserVmData;
 import com.cloud.vm.dao.VMInstanceDao;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.VMSnapshotVolumeVO;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
+import com.cloud.vm.snapshot.dao.VMSnapshotVolumeDao;
 
 public class ApiDBUtils {
     private static ManagementServer _ms;
@@ -206,7 +212,8 @@ public class ApiDBUtils {
     private static HighAvailabilityManager _haMgr;
     private static VpcManager _vpcMgr;
     private static TaggedResourceService _taggedResourceService;
-
+    private static VMSnapshotDao _vmSnapshotDao;
+    private static VMSnapshotVolumeDao _vmSnapshotVolumeDao;
     static {
         _ms = (ManagementServer) ComponentLocator.getComponent(ManagementServer.Name);
          ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name);
@@ -790,7 +797,12 @@ public class ApiDBUtils {
     public static boolean canUseForDeploy(Network network) {
         return _networkMgr.canUseForDeploy(network);
     }
-    
+
+    public static VMSnapshot getVMSnapshotById(Long vmSnapshotId) {
+        VMSnapshot vmSnapshot = _vmSnapshotDao.findById(vmSnapshotId);
+        return vmSnapshot;
+    }
+
     public static String getUuid(String resourceId, TaggedResourceType resourceType) {
         return _taggedResourceService.getUuid(resourceId, resourceType);
     }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/server/src/com/cloud/api/ApiResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java
index 7334488..b1447d0 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -99,6 +99,7 @@ import com.cloud.api.response.TemplateResponse;
 import com.cloud.api.response.TrafficTypeResponse;
 import com.cloud.api.response.UserResponse;
 import com.cloud.api.response.UserVmResponse;
+import com.cloud.api.response.VMSnapshotResponse;
 import com.cloud.api.response.VirtualRouterProviderResponse;
 import com.cloud.api.response.VlanIpRangeResponse;
 import com.cloud.api.response.VolumeResponse;
@@ -219,6 +220,7 @@ import com.cloud.vm.VmStats;
 import com.cloud.vm.dao.UserVmData;
 import com.cloud.vm.dao.UserVmData.NicData;
 import com.cloud.vm.dao.UserVmData.SecurityGroupData;
+import com.cloud.vm.snapshot.VMSnapshot;
 
 public class ApiResponseHelper implements ResponseGenerator {
 
@@ -577,6 +579,19 @@ public class ApiResponseHelper implements ResponseGenerator {
     }
 
     @Override
+    public VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot) {
+        VMSnapshotResponse vmSnapshotResponse = new VMSnapshotResponse();
+        vmSnapshotResponse.setId(vmSnapshot.getId());
+        vmSnapshotResponse.setName(vmSnapshot.getName());
+        vmSnapshotResponse.setState(vmSnapshot.getState());
+        vmSnapshotResponse.setCreated(vmSnapshot.getCreated());
+        vmSnapshotResponse.setDescription(vmSnapshot.getDescription());
+        vmSnapshotResponse.setDisplayName(vmSnapshot.getDisplayName());
+        vmSnapshotResponse.setVmId(vmSnapshot.getvmId());
+        return vmSnapshotResponse;
+    }
+    
+    @Override
     public SnapshotPolicyResponse createSnapshotPolicyResponse(SnapshotPolicy policy) {
         SnapshotPolicyResponse policyResponse = new SnapshotPolicyResponse();
         policyResponse.setId(policy.getId());
@@ -3923,4 +3938,9 @@ public class ApiResponseHelper implements ResponseGenerator {
         response.setObjectName("vpnconnection");
         return response;
     }
+
+    @Override
+    public VMSnapshot getVMSnapshotById(Long vmSnapshotId) {
+        return ApiDBUtils.getVMSnapshotById(vmSnapshotId);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/server/src/com/cloud/configuration/Config.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java
index ebcd070..5335dcf 100755
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -33,6 +33,7 @@ import com.cloud.storage.secondary.SecondaryStorageVmManager;
 import com.cloud.storage.snapshot.SnapshotManager;
 import com.cloud.template.TemplateManager;
 import com.cloud.vm.UserVmManager;
+import com.cloud.vm.snapshot.VMSnapshotManager;
 
 public enum Config {
 	
@@ -350,8 +351,14 @@ public enum Config {
 	SecondaryStorageServiceOffering("Advanced", ManagementServer.class, Long.class, "secstorage.service.offering", null, "Service offering used by secondary storage; if NULL - system offering will be used", null),
 	HaTag("Advanced", ManagementServer.class, String.class, "ha.tag", null, "HA tag defining that the host marked with this tag can be used for HA purposes only", null),
 	VpcCleanupInterval("Advanced", ManagementServer.class, Integer.class, "vpc.cleanup.interval", "3600", "The interval (in seconds) between cleanup for Inactive VPCs", null),
-    VpcMaxNetworks("Advanced", ManagementServer.class, Integer.class, "vpc.max.networks", "3", "Maximum number of networks per vpc", null);
+    VpcMaxNetworks("Advanced", ManagementServer.class, Integer.class, "vpc.max.networks", "3", "Maximum number of networks per vpc", null),
 	
+	// VMSnapshots
+    VMSnapshotMax("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.max", "10", "Maximum vm snapshots for a vm", null),
+    VMSnapshotCreateWait("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.create.wait", "600", "In second, timeout for create vm snapshot", null),
+    VMSnapshotExpungeInterval("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.expunge.interval", "60", "The interval (in seconds) to wait before running the expunge thread.", null),
+    VMSnapshotExpungeWorkers("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.expunge.workers",  "1", "Number of workers performing expunge ", null);
+    
 	
 	private final String _category;
 	private final Class<?> _componentClass;

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/server/src/com/cloud/configuration/DefaultComponentLibrary.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java
index 4edd402..05aead9 100755
--- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java
+++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java
@@ -198,6 +198,9 @@ import com.cloud.vm.dao.UserVmDaoImpl;
 import com.cloud.vm.dao.UserVmDetailsDaoImpl;
 import com.cloud.vm.dao.VMInstanceDaoImpl;
 
+import com.cloud.vm.snapshot.VMSnapshotManagerImpl;
+import com.cloud.vm.snapshot.dao.VMSnapshotDaoImpl;
+import com.cloud.vm.snapshot.dao.VMSnapshotVolumeDaoImpl;
 
 public class DefaultComponentLibrary extends ComponentLibraryBase implements ComponentLibrary {
     protected void populateDaos() {
@@ -337,6 +340,8 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com
         addDao("Site2SiteVpnGatewayDao", Site2SiteVpnGatewayDaoImpl.class);
         addDao("Site2SiteCustomerGatewayDao", Site2SiteCustomerGatewayDaoImpl.class);
         addDao("Site2SiteVpnConnnectionDao", Site2SiteVpnConnectionDaoImpl.class);
+        addDao("VMSnapshotDao", VMSnapshotDaoImpl.class);
+        addDao("VMSnapshotVolumeDao", VMSnapshotVolumeDaoImpl.class);
     }
 
     @Override
@@ -395,6 +400,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com
         addManager("NetworkACLManager", NetworkACLManagerImpl.class);
         addManager("TaggedResourcesManager", TaggedResourceManagerImpl.class);
         addManager("Site2SiteVpnManager", Site2SiteVpnManagerImpl.class);
+        addManager("VMSnapshot Manager", VMSnapshotManagerImpl.class);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
index 8ae8ddc..9150318 100755
--- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
+++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
@@ -126,6 +126,9 @@ import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachine.State;
 import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
 
 @Local(value = { SnapshotManager.class, SnapshotService.class })
 public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Manager {
@@ -190,7 +193,8 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
     private VolumeDao _volumeDao;
     @Inject
     private ResourceTagDao _resourceTagDao;
-    
+    @Inject
+    protected VMSnapshotDao _vmSnapshotDao;
     String _name;
     private int _totalRetries;
     private int _pauseInterval;
@@ -427,6 +431,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
             }
 
             // if volume is attached to a vm in destroyed or expunging state; disallow
+            // if volume is attached to a vm in taking vm snapshot; disallow
             if (volume.getInstanceId() != null) {
                 UserVmVO userVm = _vmDao.findById(volume.getInstanceId());
                 if (userVm != null) {
@@ -440,6 +445,12 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
                         if(activeSnapshots.size() > 1)
                             throw new CloudRuntimeException("There is other active snapshot tasks on the instance to which the volume is attached, please try again later");
                     }
+                    List<VMSnapshotVO> activeVMSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(),
+                            VMSnapshot.Status.Creating);
+                    if (activeVMSnapshots.size() > 0) {
+                        throw new CloudRuntimeException(
+                                "There is other active vm snapshot tasks on the instance to which the volume is attached, please try again later");
+                    }			
                 }
             }
 

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/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 667b048..f76d4db 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -231,6 +231,11 @@ import com.cloud.vm.dao.NicDao;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.UserVmDetailsDao;
 import com.cloud.vm.dao.VMInstanceDao;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.VMSnapshotVolumeVO;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
+import com.cloud.vm.snapshot.dao.VMSnapshotVolumeDao;
 
 @Local(value = { UserVmManager.class, UserVmService.class })
 public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager {
@@ -358,7 +363,10 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
     PhysicalNetworkDao _physicalNetworkDao;
     @Inject
     VpcManager _vpcMgr;
-
+    @Inject
+    VMSnapshotDao _vmSnapshotDao;
+    @Inject
+    VMSnapshotVolumeDao _vmSnapshotVolumeDao;
     protected ScheduledExecutorService _executor = null;
     protected int _expungeInterval;
     protected int _expungeDelay;
@@ -590,6 +598,9 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
         //permission check
         _accountMgr.checkAccess(caller, null, true, volume, vm);
 
+        //check if vm has snapshot, if true: can't attache volume
+        boolean attach = true;
+        checkIsSnapshoted(vm, volumeId, attach);
         //Check if volume is stored on secondary Storage.
         boolean isVolumeOnSec = false;
         VolumeHostVO  volHostVO = _volumeHostDao.findByVolumeId(volume.getId());
@@ -793,8 +804,36 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
         }
     }
 
-    @Override
-    @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", async = true)
+    private void checkIsSnapshoted(UserVmVO vm, Long volumeId, boolean attach) {
+        // Check that if the volume has snapshot
+        Long vmId = vm.getId();
+        boolean snapshoted = false;
+        List<VMSnapshotVO> listSnapshot = _vmSnapshotDao.listByInstanceId(vmId,
+                VMSnapshot.Status.Created, VMSnapshot.Status.Creating);
+        if (!attach) {
+            for (VMSnapshotVO snapshot : listSnapshot) {
+                List<VMSnapshotVolumeVO> listSnapshotVolume = _vmSnapshotVolumeDao
+                        .findByVMSnapshot(snapshot.getId());
+                for (VMSnapshotVolumeVO svolume : listSnapshotVolume) {
+                    if (svolume.getSnapshotOf().equals(volumeId)) {
+                        snapshoted = true;
+                    }
+                }
+            }
+            if (snapshoted) {
+                throw new InvalidParameterValueException(
+                        "VM Snapshot relies on the volume, Please delete the snapshot first");
+            }
+        } else {
+            if (listSnapshot != null && listSnapshot.size() != 0) {
+                throw new InvalidParameterValueException(
+                        "The VM has snapshot, do not allowed to attach volume. Please delete the snapshot first.");
+            }
+        }
+    }
+
+	@Override
+    @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "event_detaching_volume1", async = true)
     public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) {
         Account caller = UserContext.current().getCaller();
         if ((cmmd.getId() == null && cmmd.getDeviceId() == null && cmmd.getVirtualMachineId() == null) || (cmmd.getId() != null && (cmmd.getDeviceId() != null || cmmd.getVirtualMachineId() != null))
@@ -848,6 +887,9 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
             throw new InvalidParameterValueException("Please specify a VM that is either running or stopped.");
         }
 
+        // Check that if the volume has snapshot
+        boolean attach = false;
+        checkIsSnapshoted(vm, volumeId, attach);
         AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor();
         if (asyncExecutor != null) {
             AsyncJobVO job = asyncExecutor.getJob();
@@ -1366,7 +1408,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
             }
 
             volume = _volsDao.findById(snapshot.getVolumeId());
-            VolumeVO snapshotVolume = _volsDao.findByIdIncludingRemoved(snapshot.getVolumeId());     
 
             //check permissions
             _accountMgr.checkAccess(caller, null, true, snapshot);

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/33f690f1/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
index 605ce57..1e687e7 100755
--- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -159,6 +159,9 @@ import com.cloud.vm.dao.NicDao;
 import com.cloud.vm.dao.SecondaryStorageVmDao;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
+import com.cloud.vm.snapshot.VMSnapshotManager;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
 
 @Local(value = VirtualMachineManager.class)
 public class VirtualMachineManagerImpl implements VirtualMachineManager, Listener {
@@ -227,6 +230,8 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
     protected HypervisorGuruManager _hvGuruMgr;
     @Inject
     protected NetworkDao _networkDao;
+    @Inject
+    protected VMSnapshotDao _vmSnapshotDao;
 
     @Inject(adapter = DeploymentPlanner.class)
     protected Adapters<DeploymentPlanner> _planners;
@@ -236,6 +241,9 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
 
     @Inject
     protected ResourceManager _resourceMgr;
+    
+    @Inject 
+    protected VMSnapshotManager _vmSnapshotMgr = null;
 
     Map<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>> _vmGurus = new HashMap<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>>();
     protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
@@ -1183,7 +1191,12 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
             s_logger.debug("Unable to stop " + vm);
             return false;
         }
-
+        
+        if (!_vmSnapshotMgr.deleteAllVMSnapshots(vm.getId())){
+            s_logger.debug("Unable to delete all snapshots for " + vm);
+            return false;
+        }
+        
         try {
             if (!stateTransitTo(vm, VirtualMachine.Event.DestroyRequested, vm.getHostId())) {
                 s_logger.debug("Unable to destroy the vm because it is not in the correct state: " + vm);
@@ -1748,8 +1761,9 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
             if (vm.isRemoved() || vm.getState() == State.Destroyed  || vm.getState() == State.Expunging) continue;
             AgentVmInfo info =  infos.remove(vm.getId());
             VMInstanceVO castedVm = null;
-            if ((info == null && (vm.getState() == State.Running || vm.getState() == State.Starting))  
-            		||  (info != null && (info.state == State.Running && vm.getState() == State.Starting))) 
+            if ((info == null && (vm.getState() == State.Running || vm.getState() == State.Starting || vm.getState() == State.Reverting))  
+            		||  (info != null && (info.state == State.Running && vm.getState() == State.Starting))
+					||  (info != null && (info.state == State.Running && vm.getState() == State.Reverting))) 
             {
             	s_logger.info("Found vm " + vm.getInstanceName() + " in inconsistent state. " + vm.getState() + " on CS while " +  (info == null ? "Stopped" : "Running") + " on agent");
                 info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped);
@@ -2259,6 +2273,12 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
 
         Long clusterId = agent.getClusterId();
         long agentId = agent.getId();
+
+        
+        if (agent.getType() == Host.Type.Routing){
+            _vmSnapshotMgr.syncVolumePath(agent.getId());
+        }
+        
         if (agent.getHypervisorType() == HypervisorType.XenServer) { // only for Xen
         	StartupRoutingCommand startup = (StartupRoutingCommand) cmd;
         	HashMap<String, Pair<String, State>> allStates = startup.getClusterVMStateChanges();
@@ -2375,6 +2395,13 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
         if (newServiceOffering == null) {
             throw new InvalidParameterValueException("Unable to find a service offering with id " + newServiceOfferingId);
         }
+		
+        // Check that the VM has snapshots
+        List<VMSnapshotVO> vmSnapshotList = _vmSnapshotDao.findByVm(vmInstance.getId());
+        if (vmSnapshotList.size() != 0){
+            s_logger.error("Unable to upgrade virtual machine " + vmInstance.toString() + " due to: vm has vm snapshots");
+            throw new InvalidParameterValueException("Unable to upgrade virtual machine " + vmInstance.toString() + " due to: vm has vm snapshots");
+        }
 
         // Check that the VM is stopped
         if (!vmInstance.getState().equals(State.Stopped)) {