incubator-cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From edi...@apache.org
Subject [15/50] [abbrv] CLOUDSTACK-684 support vm snapshot
Date Thu, 14 Feb 2013 01:11:27 GMT
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/api/src/org/apache/cloudstack/api/response/VMSnapshotResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/VMSnapshotResponse.java b/api/src/org/apache/cloudstack/api/response/VMSnapshotResponse.java
new file mode 100644
index 0000000..3b30ab6
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/response/VMSnapshotResponse.java
@@ -0,0 +1,220 @@
+// 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 org.apache.cloudstack.api.response;
+
+import java.util.Date;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.EntityReference;
+
+import com.cloud.serializer.Param;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.google.gson.annotations.SerializedName;
+
+@EntityReference(value=VMSnapshot.class)
+public class VMSnapshotResponse extends BaseResponse implements ControlledEntityResponse{
+
+    @SerializedName(ApiConstants.ID)
+    @Param(description = "the ID of the vm snapshot")
+    private String id;
+
+    @SerializedName(ApiConstants.NAME)
+    @Param(description = "the name of the vm snapshot")
+    private String name;
+
+    @SerializedName(ApiConstants.STATE)
+    @Param(description = "the state of the vm snapshot")
+    private VMSnapshot.State state;
+
+    @SerializedName(ApiConstants.DESCRIPTION)
+    @Param(description = "the description of the vm snapshot")
+    private String description;
+
+    @SerializedName(ApiConstants.DISPLAY_NAME)
+    @Param(description = "the display name of the vm snapshot")
+    private String displayName;
+
+    @SerializedName(ApiConstants.ZONE_ID)
+    @Param(description = "the Zone ID of the vm snapshot")
+    private String zoneId;
+
+    @SerializedName(ApiConstants.VIRTUAL_MACHINE_ID)
+    @Param(description = "the vm ID of the vm snapshot")
+    private String virtualMachineid;
+
+    @SerializedName("parent")
+    @Param(description = "the parent ID of the vm snapshot")
+    private String parent; 
+    
+    @SerializedName("parentName")
+    @Param(description = "the parent displayName of the vm snapshot")
+    private String parentName; 
+    
+    @SerializedName("current")
+    @Param(description = "indiates if this is current snapshot")
+    private Boolean current; 
+    
+    @SerializedName("type")
+    @Param(description = "VM Snapshot type")
+    private String type; 
+    
+    @SerializedName(ApiConstants.CREATED)
+    @Param(description = "the create date of the vm snapshot")
+    private Date created;
+    
+    @SerializedName(ApiConstants.ACCOUNT)
+    @Param(description = "the account associated with the disk volume")
+    private String accountName;
+
+    @SerializedName(ApiConstants.PROJECT_ID) @Param(description="the project id of the vpn")
+    private String projectId;
+
+    @SerializedName(ApiConstants.PROJECT) @Param(description="the project name of the vpn")
+    private String projectName;
+
+    @SerializedName(ApiConstants.DOMAIN_ID)
+    @Param(description = "the ID of the domain associated with the disk volume")
+    private String domainId;
+    
+    @SerializedName(ApiConstants.DOMAIN)
+    @Param(description = "the domain associated with the disk volume")
+    private String domainName;
+
+    @Override
+    public String getObjectId() {
+        return getId();
+    }
+
+    public Date getCreated() {
+        return created;
+    }
+
+    public void setCreated(Date created) {
+        this.created = created;
+    }
+
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    public void setDisplayName(String displayName) {
+        this.displayName = displayName;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getZoneId() {
+        return zoneId;
+    }
+
+    public void setZoneId(String zoneId) {
+        this.zoneId = zoneId;
+    }
+
+    public String getVirtualMachineid() {
+        return virtualMachineid;
+    }
+
+    public void setVirtualMachineid(String virtualMachineid) {
+        this.virtualMachineid = virtualMachineid;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setState(VMSnapshot.State state) {
+        this.state = state;
+    }
+
+    public VMSnapshot.State getState() {
+        return state;
+    }
+
+    public Boolean getCurrent() {
+        return current;
+    }
+
+    public void setCurrent(Boolean current) {
+        this.current = current;
+    }
+    
+    public void setParentName(String parentName) {
+        this.parentName = parentName;
+    }
+
+    public String getParentName() {
+        return parentName;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    @Override
+    public void setAccountName(String accountName) {
+        this.accountName = accountName;
+        
+    }
+
+    @Override
+    public void setProjectId(String projectId) {
+        this.projectId = projectId;
+        
+    }
+
+    @Override
+    public void setProjectName(String projectName) {
+        this.projectName = projectName;
+        
+    }
+
+    @Override
+    public void setDomainId(String domainId) {
+        this.domainId = domainId;
+    }
+
+    @Override
+    public void setDomainName(String domainName) {
+        this.domainName = domainName;
+        
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/client/WEB-INF/classes/resources/messages.properties
----------------------------------------------------------------------
diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties
index 9c4fcb3..11b1ca1 100644
--- a/client/WEB-INF/classes/resources/messages.properties
+++ b/client/WEB-INF/classes/resources/messages.properties
@@ -1410,6 +1410,20 @@ label.zone.step.4.title=Step 4: <strong>Add an IP range</strong>
 label.zone.wide=Zone-Wide
 label.zone=Zone
 
+#VM snapshot label
+label.vmsnapshot=VM Snapshots
+label.vmsnapshot.type=Type
+label.vmsnapshot.parentname=Parent
+label.vmsnapshot.current=isCurrent
+label.vmsnapshot.memory=Snapshot memory
+message.action.vmsnapshot.delete=Please confirm that you want to delete this VM snapshot.
+label.action.vmsnapshot.delete=Delete VM snapshot
+label.action.vmsnapshot.revert=Revert to VM snapshot
+message.action.vmsnapshot.revert=Revert VM snapshot
+label.action.vmsnapshot.create=Take VM Snapshot
+
+
+
 #Messages
 message.acquire.public.ip=Please select a zone from which you want to acquire your new IP from.
 message.action.cancel.maintenance.mode=Please confirm that you want to cancel this maintenance.

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index d70649b..e1d0fb2 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -537,3 +537,9 @@ addRegion=1
 updateRegion=1
 removeRegion=1
 listRegions=15
+
+### VM Snapshot commands
+listVMSnapshot=15
+createVMSnapshot=15
+deleteVMSnapshot=15
+revertToSnapshot=15

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/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 f27e026..a2e517d 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
@@ -20,15 +20,21 @@ 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.RevertToVMSnapshotCommand;
 import com.cloud.agent.api.storage.CopyVolumeCommand;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
 
 public interface VmwareStorageManager {
     Answer execute(VmwareHostService hostService, PrimaryStorageDownloadCommand cmd);
-	Answer execute(VmwareHostService hostService, BackupSnapshotCommand cmd);
-	Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromVolumeCommand cmd);
-	Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromSnapshotCommand cmd);
-	Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd);
-	Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd);
+    Answer execute(VmwareHostService hostService, BackupSnapshotCommand cmd);
+    Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromVolumeCommand cmd);
+    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, RevertToVMSnapshotCommand cmd);
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/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 8650274..c7b7cd3 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
@@ -22,6 +22,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;
 
@@ -32,18 +33,27 @@ 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.DeleteVMSnapshotAnswer;
+import com.cloud.agent.api.DeleteVMSnapshotCommand;
+import com.cloud.agent.api.RevertToVMSnapshotAnswer;
+import com.cloud.agent.api.RevertToVMSnapshotCommand;
 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.VolumeTO;
 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.TaskMO;
 import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
 import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
 import com.cloud.hypervisor.vmware.util.VmwareContext;
@@ -57,7 +67,11 @@ 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.VirtualMachine;
+import com.cloud.vm.snapshot.VMSnapshot;
 import com.vmware.vim25.ManagedObjectReference;
+import com.vmware.vim25.TaskEvent;
+import com.vmware.vim25.TaskInfo;
 import com.vmware.vim25.VirtualDeviceConfigSpec;
 import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
 import com.vmware.vim25.VirtualDisk;
@@ -222,8 +236,12 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
                 }
 				
 			} finally {
-                if(vmMo != null)
-                    vmMo.removeAllSnapshots();
+                if(vmMo != null){
+                    ManagedObjectReference snapshotMor = vmMo.getSnapshotMor(snapshotUuid);
+                    if (snapshotMor != null){
+                        vmMo.removeSnapshot(snapshotUuid, false);
+                    }
+                }
 			    
 				try {
 		            if (workerVm != null) {
@@ -377,47 +395,47 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
 	}
     
     @Override
-	public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd) {
+    public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd) {
 
-		String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
-		Long accountId = cmd.getAccountId();
-		Long volumeId = cmd.getVolumeId();
-        String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
-		String backedUpSnapshotUuid = cmd.getSnapshotUuid();
+            String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
+            Long accountId = cmd.getAccountId();
+            Long volumeId = cmd.getVolumeId();
+            String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
+            String backedUpSnapshotUuid = cmd.getSnapshotUuid();
 
-		String details = null;
-		boolean success = false;
-		String newVolumeName = UUID.randomUUID().toString().replaceAll("-", "");
+            String details = null;
+            boolean success = false;
+            String newVolumeName = UUID.randomUUID().toString().replaceAll("-", "");
 
-		VmwareContext context = hostService.getServiceContext(cmd);
-		try {
-			VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
-			
-			ManagedObjectReference morPrimaryDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStorageNameLabel);
-			if (morPrimaryDs == null) {
-				String msg = "Unable to find datastore: " + primaryStorageNameLabel;
-				s_logger.error(msg);
-				throw new Exception(msg);
-			}
+            VmwareContext context = hostService.getServiceContext(cmd);
+            try {
+                    VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+                    ManagedObjectReference morPrimaryDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost,
+                            primaryStorageNameLabel);
+                    if (morPrimaryDs == null) {
+                        String msg = "Unable to find datastore: " + primaryStorageNameLabel;
+                        s_logger.error(msg);
+                        throw new Exception(msg);
+                    }
 
-			DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs);
-			details = createVolumeFromSnapshot(hyperHost, primaryDsMo,
-					newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid);
-			if (details == null) {
-				success = true;
-			}
-		} catch (Throwable e) {
-			if (e instanceof RemoteException) {
-				hostService.invalidateServiceContext(context);
-			}
+                    DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs);
+                    details = createVolumeFromSnapshot(hyperHost, primaryDsMo,
+                            newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid);
+                    if (details == null) {
+                        success = true;
+                    }
+            } catch (Throwable e) {
+                if (e instanceof RemoteException) {
+                    hostService.invalidateServiceContext(context);
+                }
+                
+                s_logger.error("Unexpecpted exception ", e);
+                details = "CreateVolumeFromSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e);
+            }
 
-			s_logger.error("Unexpecpted exception ", e);
-			details = "CreateVolumeFromSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e);
-		}
+            return new CreateVolumeFromSnapshotAnswer(cmd, success, details, newVolumeName);
+    }
 
-		return new CreateVolumeFromSnapshotAnswer(cmd, success, details, newVolumeName);
-	}
-	
     // templateName: name in secondary storage
     // templateUuid: will be used at hypervisor layer
     private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl,
@@ -881,4 +899,244 @@ 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<VolumeTO> volumeTOs = cmd.getVolumeTOs();
+        String vmName = cmd.getVmName();
+        String vmSnapshotName = cmd.getTarget().getSnapshotName();
+        String vmSnapshotDesc = cmd.getTarget().getDescription();
+        boolean snapshotMemory = cmd.getTarget().getType() == VMSnapshot.Type.DiskAndMemory;
+        VirtualMachineMO vmMo = null;
+        VmwareContext context = hostService.getServiceContext(cmd);
+        Map<String, String> mapNewDisk = new HashMap<String, String>();
+        try {
+            VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+            
+            // wait if there are already VM snapshot task running
+            ManagedObjectReference taskmgr = context.getServiceContent().getTaskManager();
+            ManagedObjectReference[] tasks =  (ManagedObjectReference[]) context.getServiceUtil().getDynamicProperty(taskmgr, "recentTask");
+            for (ManagedObjectReference taskMor : tasks) {
+                TaskInfo info = (TaskInfo) (context.getServiceUtil().getDynamicProperty(taskMor, "info"));
+                if(info.getEntityName().equals(cmd.getVmName()) && info.getName().equalsIgnoreCase("CreateSnapshot_Task")){
+                    s_logger.debug("There is already a VM snapshot task running, wait for it");
+                    context.getServiceUtil().waitForTask(taskMor);
+                }
+            }
+            
+            vmMo = hyperHost.findVmOnHyperHost(vmName);
+            if(vmMo == null)
+                vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
+            if (vmMo == null) {
+                String msg = "Unable to find VM for CreateVMSnapshotCommand";
+                s_logger.debug(msg);
+                return new CreateVMSnapshotAnswer(cmd, false, msg);
+            } else {
+                if (vmMo.getSnapshotMor(vmSnapshotName) != null){
+                    s_logger.debug("VM snapshot " + vmSnapshotName + " already exists");
+                }else if (!vmMo.createSnapshot(vmSnapshotName, vmSnapshotDesc, snapshotMemory, true)) {
+                    return new CreateVMSnapshotAnswer(cmd, false,
+                            "Unable to create snapshot due to esxi internal failed");
+                }
+                // find VM disk file path after creating snapshot
+                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);
+                    }
+                }
+                
+                // update volume path using maps
+                for (VolumeTO volumeTO : volumeTOs) {
+                    String parentUUID = volumeTO.getPath();
+                    String[] s = parentUUID.split("-");
+                    String key = s[0];
+                    volumeTO.setPath(mapNewDisk.get(key));
+                }
+                return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), volumeTOs);
+            }
+        } 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) {
+            }
+            return new CreateVMSnapshotAnswer(cmd, false, e.getMessage());
+        }
+    }
+
+	@Override
+    public DeleteVMSnapshotAnswer execute(VmwareHostService hostService, DeleteVMSnapshotCommand cmd) {
+        List<VolumeTO> listVolumeTo = cmd.getVolumeTOs();
+        VirtualMachineMO vmMo = null;
+        VmwareContext context = hostService.getServiceContext(cmd);
+        Map<String, String> mapNewDisk = new HashMap<String, String>();
+        String vmName = cmd.getVmName();
+        String vmSnapshotName = cmd.getTarget().getSnapshotName();
+        try {
+            VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+            vmMo = hyperHost.findVmOnHyperHost(vmName);
+            if(vmMo == null)
+                vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
+            if (vmMo == null) {
+                String msg = "Unable to find VM for RevertToVMSnapshotCommand";
+                s_logger.debug(msg);
+                return new DeleteVMSnapshotAnswer(cmd, false, msg);
+            } else {
+                if (vmMo.getSnapshotMor(vmSnapshotName) == null) {
+                    s_logger.debug("can not find the snapshot " + vmSnapshotName + ", assume it is already removed");
+                } else {
+                    if (!vmMo.removeSnapshot(vmSnapshotName, false)) {
+                        String msg = "delete vm snapshot " + vmSnapshotName + " due to error occured in vmware";
+                        s_logger.error(msg);
+                        return new DeleteVMSnapshotAnswer(cmd, false, msg);
+                    }
+                }
+                s_logger.debug("snapshot: " + vmSnapshotName + " is removed");
+                // after removed snapshot, the volumes' paths have been changed for the VM, needs to report new paths to manager 
+                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 (VolumeTO volumeTo : listVolumeTo) {
+                    String key = null;
+                    String parentUUID = volumeTo.getPath();
+                    String[] s = parentUUID.split("-");
+                    key = s[0];
+                    volumeTo.setPath(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 RevertToVMSnapshotAnswer execute(VmwareHostService hostService, RevertToVMSnapshotCommand cmd) {
+        String snapshotName = cmd.getTarget().getSnapshotName();
+        String vmName = cmd.getVmName();
+        Boolean snapshotMemory = cmd.getTarget().getType() == VMSnapshot.Type.DiskAndMemory;
+        List<VolumeTO> listVolumeTo = cmd.getVolumeTOs();
+        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);
+            
+            // wait if there are already VM revert task running
+            ManagedObjectReference taskmgr = context.getServiceContent().getTaskManager();
+            ManagedObjectReference[] tasks =  (ManagedObjectReference[]) context.getServiceUtil().getDynamicProperty(taskmgr, "recentTask");
+            for (ManagedObjectReference taskMor : tasks) {
+                TaskInfo info = (TaskInfo) (context.getServiceUtil().getDynamicProperty(taskMor, "info"));
+                if(info.getEntityName().equals(cmd.getVmName()) && info.getName().equalsIgnoreCase("RevertToSnapshot_Task")){
+                    s_logger.debug("There is already a VM snapshot task running, wait for it");
+                    context.getServiceUtil().waitForTask(taskMor);
+                }
+            }
+            
+            HostMO hostMo = (HostMO) hyperHost;
+            vmMo = hyperHost.findVmOnHyperHost(vmName);
+            if(vmMo == null)
+                vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
+            if (vmMo == null) {
+                String msg = "Unable to find VM for RevertToVMSnapshotCommand";
+                s_logger.debug(msg);
+                return new RevertToVMSnapshotAnswer(cmd, false, msg);
+            } else {
+                boolean result = false;
+                if (snapshotName != null) {
+                    ManagedObjectReference morSnapshot = vmMo.getSnapshotMor(snapshotName);
+                    result = hostMo.revertToSnapshot(morSnapshot);
+                } else {
+                    return new RevertToVMSnapshotAnswer(cmd, false, "Unable to find the snapshot by name " + snapshotName);
+                }
+
+                if (result) {
+                    VirtualDisk[] vdisks = vmMo.getAllDiskDevice();
+                    // build a map<volumeName, vmdk>
+                    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 (VolumeTO volumeTo : listVolumeTo) {
+                        String parentUUID = volumeTo.getPath();
+                        String[] s = parentUUID.split("-");
+                        key = s[0];
+                        volumeTo.setPath(mapNewDisk.get(key));
+                    }
+                    if (!snapshotMemory) {
+                        vmState = VirtualMachine.State.Stopped;
+                    }
+                    return new RevertToVMSnapshotAnswer(cmd, listVolumeTo, vmState);
+                } else {
+                    return new RevertToVMSnapshotAnswer(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 RevertToVMSnapshotAnswer(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/9a12756a/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 841a535..5cac253 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
@@ -65,9 +65,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;
@@ -103,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.RevertToVMSnapshotAnswer;
+import com.cloud.agent.api.RevertToVMSnapshotCommand;
 import com.cloud.agent.api.SetupAnswer;
 import com.cloud.agent.api.SetupCommand;
 import com.cloud.agent.api.SetupGuestNetworkAnswer;
@@ -445,7 +451,13 @@ 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 CreateVMSnapshotCommand) {
+            	return execute((CreateVMSnapshotCommand)cmd);
+            } else if(cmd instanceof DeleteVMSnapshotCommand){
+            	return execute((DeleteVMSnapshotCommand)cmd);
+            } else if(cmd instanceof RevertToVMSnapshotCommand){
+            	return execute((RevertToVMSnapshotCommand)cmd);
+        	}else if (clz == SetPortForwardingRulesVpcCommand.class) {
                 answer = execute((SetPortForwardingRulesVpcCommand) cmd);
             } else if (clz == Site2SiteVpnCfgCommand.class) {
                 answer = execute((Site2SiteVpnCfgCommand) cmd);
@@ -2799,7 +2811,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                         // before we stop VM, remove all possible snapshots on the VM to let
                         // disk chain be collapsed
                         s_logger.info("Remove all snapshot before stopping VM " + cmd.getVmName());
-                        vmMo.removeAllSnapshots();
                         if (vmMo.safePowerOff(_shutdown_waitMs)) {
                             state = State.Stopped;
                             return new StopAnswer(cmd, "Stop VM " + cmd.getVmName() + " Succeed", 0, true);
@@ -3351,7 +3362,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(RevertToVMSnapshotCommand 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 RevertToVMSnapshotAnswer(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/9a12756a/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 b3cb54f..22f4ba9 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
@@ -90,9 +90,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;
@@ -129,6 +133,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.RevertToVMSnapshotAnswer;
+import com.cloud.agent.api.RevertToVMSnapshotCommand;
 import com.cloud.agent.api.SecurityGroupRuleAnswer;
 import com.cloud.agent.api.SecurityGroupRulesCmd;
 import com.cloud.agent.api.SetupAnswer;
@@ -237,6 +243,7 @@ import com.cloud.utils.net.NetUtils;
 import com.cloud.vm.DiskProfile;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.snapshot.VMSnapshot;
 import com.trilead.ssh2.SCPClient;
 import com.xensource.xenapi.Bond;
 import com.xensource.xenapi.Connection;
@@ -256,6 +263,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;
@@ -579,11 +590,109 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             return execute((CheckS2SVpnConnectionsCommand) cmd);
         } else if (cmd instanceof StorageSubSystemCommand) {
             return this.storageResource.handleStorageCommands((StorageSubSystemCommand)cmd);
+        } else if (clazz == CreateVMSnapshotCommand.class) {
+            return execute((CreateVMSnapshotCommand)cmd);
+        } else if (clazz == DeleteVMSnapshotCommand.class) {
+            return execute((DeleteVMSnapshotCommand)cmd);
+        } else if (clazz == RevertToVMSnapshotCommand.class) {
+            return execute((RevertToVMSnapshotCommand)cmd);
         } else {
             return Answer.createUnsupportedCommandAnswer(cmd);
         }
     }
 
+
+
+    private Answer execute(RevertToVMSnapshotCommand cmd) {
+        String vmName = cmd.getVmName();
+        List<VolumeTO> listVolumeTo = cmd.getVolumeTOs();
+        VMSnapshot.Type vmSnapshotType = cmd.getTarget().getType();
+        Boolean snapshotMemory = vmSnapshotType == VMSnapshot.Type.DiskAndMemory;
+        Connection conn = getConnection();
+        VirtualMachine.State vmState = null;
+        VM vm = null;
+        try {
+
+            // remove vm from s_vms, for delta sync
+            s_vms.remove(_cluster, _name, vmName);
+
+            Set<VM> vmSnapshots = VM.getByNameLabel(conn, cmd.getTarget().getSnapshotName());
+            if(vmSnapshots.size() == 0)
+                return new RevertToVMSnapshotAnswer(cmd, false, "Cannot find vmSnapshot with name: " + cmd.getTarget().getSnapshotName());
+            
+            VM vmSnapshot = vmSnapshots.iterator().next();
+            
+            // find target VM or creating a work VM
+            try {
+                vm = getVM(conn, vmName);
+            } catch (Exception e) {
+                vm = createWorkingVM(conn, vmName, cmd.getGuestOSType(), listVolumeTo);
+            }
+
+            if (vm == null) {
+                return new RevertToVMSnapshotAnswer(cmd, false,
+                        "Revert to VM Snapshot Failed due to can not find vm: " + vmName);
+            }
+            
+            // call plugin to execute revert
+            revertToSnapshot(conn, vmSnapshot, vmName, vm.getUuid(conn), snapshotMemory, _host.uuid);
+            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;
+            }
+
+            // after revert, VM's volumes path have been changed, need to report to manager
+            for (VolumeTO volumeTo : listVolumeTo) {
+                Long deviceId = volumeTo.getDeviceId();
+                VDI vdi = vdiMap.get(deviceId.toString());
+                volumeTo.setPath(vdi.getUuid(conn));
+            }
+
+            return new RevertToVMSnapshotAnswer(cmd, listVolumeTo,vmState);
+        } catch (Exception e) {
+            s_logger.error("revert vm " + vmName
+                    + " to snapshot " + cmd.getTarget().getSnapshotName() + " failed due to " + e.getMessage());
+            return new RevertToVMSnapshotAnswer(cmd, false, e.getMessage());
+        } 
+    }
+
+    private String revertToSnapshot(Connection conn, VM vmSnapshot,
+            String vmName, String oldVmUuid, Boolean snapshotMemory, String hostUUID)
+            throws XenAPIException, XmlRpcException {
+ 
+        String results = callHostPluginAsync(conn, "vmopsSnapshot",
+                "revert_memory_snapshot", 10 * 60 * 1000, "snapshotUUID",
+                vmSnapshot.getUuid(conn), "vmName", vmName, "oldVmUuid",
+                oldVmUuid, "snapshotMemory", snapshotMemory.toString(), "hostUUID", hostUUID);
+        String errMsg = null;
+        if (results == null || results.isEmpty()) {
+            errMsg = "revert_memory_snapshot return null";
+        } else {
+            if (results.equals("0")) {
+                return results;
+            } else {
+                errMsg = "revert_memory_snapshot exception";
+            }
+        }
+        s_logger.warn(errMsg);
+        throw new CloudRuntimeException(errMsg);
+    }
+
     protected XsLocalNetwork getNativeNetworkForTraffic(Connection conn, TrafficType type, String name) throws XenAPIException, XmlRpcException {
         if (name != null) {
             if (s_logger.isDebugEnabled()) {
@@ -6167,6 +6276,199 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
 
     }
 
+    protected Answer execute(final CreateVMSnapshotCommand cmd) {
+        String vmName = cmd.getVmName();
+        String vmSnapshotName = cmd.getTarget().getSnapshotName();
+        List<VolumeTO> listVolumeTo = cmd.getVolumeTOs();
+        VirtualMachine.State vmState = cmd.getVmState();
+        String guestOSType = cmd.getGuestOSType();
+
+        boolean snapshotMemory = cmd.getTarget().getType() == VMSnapshot.Type.DiskAndMemory;
+        long timeout = 600;
+
+        Connection conn = getConnection();
+        VM vm = null;
+        VM vmSnapshot = null;
+        boolean success = false;
+
+        try {
+            // check if VM snapshot already exists
+            Set<VM> vmSnapshots = VM.getByNameLabel(conn, cmd.getTarget().getSnapshotName());
+            if(vmSnapshots.size() > 0)
+                return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), cmd.getVolumeTOs());
+            
+            // check if there is already a task for this VM snapshot
+            Task task = null;
+            Set<Task> tasks = Task.getByNameLabel(conn, "Async.VM.snapshot");
+            tasks.addAll(Task.getByNameLabel(conn, "Async.VM.checkpoint"));
+            for (Task taskItem : tasks) {
+                if(taskItem.getOtherConfig(conn).containsKey("CS_VM_SNAPSHOT_KEY")){
+                    String vmSnapshotTaskName = taskItem.getOtherConfig(conn).get("CS_VM_SNAPSHOT_KEY");
+                    if(vmSnapshotTaskName != null && vmSnapshotTaskName.equals(cmd.getTarget().getSnapshotName())){
+                        task = taskItem;
+                    }
+                }
+            }
+            
+            // create a new task if there is no existing task for this VM snapshot
+            if(task == null){
+                try {
+                    vm = getVM(conn, vmName);
+                } catch (Exception e) {
+                    if (!snapshotMemory) {
+                        vm = createWorkingVM(conn, vmName, guestOSType, listVolumeTo);
+                    }
+                }
+    
+                if (vm == null) {
+                    return new CreateVMSnapshotAnswer(cmd, false,
+                            "Creating VM Snapshot Failed due to can not find vm: "
+                                    + vmName);
+                }
+                
+                // call Xenserver API
+                if (!snapshotMemory) {
+                    task = vm.snapshotAsync(conn, vmSnapshotName);
+                } else {
+                    Set<VBD> vbds = vm.getVBDs(conn);
+                    Pool pool = Pool.getByUuid(conn, _host.pool);
+                    for (VBD vbd: vbds){
+                        VBD.Record vbdr = vbd.getRecord(conn);
+                        if (vbdr.userdevice.equals("0")){
+                            VDI vdi = vbdr.VDI;
+                            SR sr = vdi.getSR(conn);
+                            // store memory image on the same SR with ROOT volume
+                            pool.setSuspendImageSR(conn, sr);
+                        }
+                    }
+                    task = vm.checkpointAsync(conn, vmSnapshotName);
+                }
+                task.addToOtherConfig(conn, "CS_VM_SNAPSHOT_KEY", vmSnapshotName);
+            }
+            
+            waitForTask(conn, task, 1000, timeout * 1000);
+            checkForSuccess(conn, task);
+            String result = task.getResult(conn);
+            
+            // extract VM snapshot ref from result 
+            String ref = result.substring("<value>".length(), result.length() - "</value>".length());
+            vmSnapshot = Types.toVM(ref);
+            
+            success = true;
+            return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), cmd.getVolumeTOs());
+        } catch (Exception e) {
+            String msg = e.getMessage();
+            s_logger.error("Creating VM Snapshot " + cmd.getTarget().getSnapshotName() + " failed due to: " + msg);
+            return new CreateVMSnapshotAnswer(cmd, false, msg);
+        } finally {
+            try {
+                if (!success) {
+                    if (vmSnapshot != null) {
+                        s_logger.debug("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<VolumeTO> listVolumeTo)
+            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, VolumeTO> vdiMap = new HashMap<VDI, VolumeTO>();
+        for (VolumeTO volume : listVolumeTo) {
+            String vdiUuid = volume.getPath();
+            try {
+                VDI vdi = VDI.getByUuid(conn, vdiUuid);
+                vdiMap.put(vdi, volume);
+            } catch (Types.UuidInvalid e) {
+                s_logger.warn("Unable to find vdi by uuid: " + vdiUuid
+                        + ", skip it");
+            }
+        }
+        for (VDI vdi : vdiMap.keySet()) {
+            VolumeTO volumeTO = vdiMap.get(vdi);
+            VBD.Record vbdr = new VBD.Record();
+            vbdr.VM = vm;
+            vbdr.VDI = vdi;
+            if (volumeTO.getType() == Volume.Type.ROOT) {
+                vbdr.bootable = true;
+                vbdr.unpluggable = false;
+            } else {
+                vbdr.bootable = false;
+                vbdr.unpluggable = true;
+            }
+            vbdr.userdevice = new Long(volumeTO.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 snapshotName = cmd.getTarget().getSnapshotName();
+        Connection conn = getConnection();
+                
+        try {
+            List<VDI> vdiList = new ArrayList<VDI>();
+            Set<VM> snapshots = VM.getByNameLabel(conn, snapshotName);
+            if(snapshots.size() == 0){
+                s_logger.warn("VM snapshot with name " + snapshotName + " does not exist, assume it is already deleted");
+                return new DeleteVMSnapshotAnswer(cmd, cmd.getVolumeTOs());
+            }
+            VM snapshot = snapshots.iterator().next();
+            Set<VBD> vbds = snapshot.getVBDs(conn);
+            for (VBD vbd : vbds) {
+                if (vbd.getType(conn) == VbdType.DISK) {
+                    VDI vdi = vbd.getVDI(conn);
+                    vdiList.add(vdi);
+                }
+            }
+            if(cmd.getTarget().getType() == VMSnapshot.Type.DiskAndMemory)
+                vdiList.add(snapshot.getSuspendVDI(conn));
+            snapshot.destroy(conn);
+            for (VDI vdi : vdiList) {
+                vdi.destroy(conn);
+            }
+            return new DeleteVMSnapshotAnswer(cmd, cmd.getVolumeTOs());
+        } 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/9a12756a/scripts/vm/hypervisor/xenserver/vmopsSnapshot
----------------------------------------------------------------------
diff --git a/scripts/vm/hypervisor/xenserver/vmopsSnapshot b/scripts/vm/hypervisor/xenserver/vmopsSnapshot
index 39fe31c..6fb1b18 100755
--- a/scripts/vm/hypervisor/xenserver/vmopsSnapshot
+++ b/scripts/vm/hypervisor/xenserver/vmopsSnapshot
@@ -556,6 +556,33 @@ 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']
+    hostUUID = args['hostUUID']
+    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 + " on=" + hostUUID)
+        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/9a12756a/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 83132c6..e6b1bf1 100755
--- a/server/src/com/cloud/api/ApiDBUtils.java
+++ b/server/src/com/cloud/api/ApiDBUtils.java
@@ -209,6 +209,8 @@ import com.cloud.vm.dao.DomainRouterDao;
 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.dao.VMSnapshotDao;
 
 @Component
 public class ApiDBUtils {
@@ -309,6 +311,7 @@ public class ApiDBUtils {
     static SnapshotPolicyDao _snapshotPolicyDao;
     static AsyncJobDao _asyncJobDao;
     static HostDetailsDao _hostDetailsDao;
+    static VMSnapshotDao _vmSnapshotDao;
 
     @Inject private ManagementServer ms;
     @Inject public AsyncJobManager asyncMgr;
@@ -407,7 +410,7 @@ public class ApiDBUtils {
     @Inject private SnapshotPolicyDao snapshotPolicyDao;
     @Inject private AsyncJobDao asyncJobDao;
     @Inject private HostDetailsDao hostDetailsDao;
-
+    @Inject private VMSnapshotDao vmSnapshotDao;
     @PostConstruct
     void init() {
         _ms = ms;
@@ -505,7 +508,7 @@ public class ApiDBUtils {
         _snapshotPolicyDao = snapshotPolicyDao;
         _asyncJobDao = asyncJobDao;
         _hostDetailsDao = hostDetailsDao;
-
+        _vmSnapshotDao = vmSnapshotDao;
         // Note: stats collector should already have been initialized by this time, otherwise a null instance is returned
         _statsCollector = StatsCollector.getInstance();
     }
@@ -1054,6 +1057,11 @@ public class ApiDBUtils {
         return _networkModel.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/9a12756a/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 8c97615..a94e935 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -93,7 +93,6 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse;
 import org.apache.cloudstack.api.response.VpcResponse;
 import org.apache.cloudstack.api.response.VpnUsersResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
-
 import org.apache.cloudstack.api.response.S3Response;
 import org.springframework.stereotype.Component;
 
@@ -195,6 +194,13 @@ import org.apache.cloudstack.region.Region;
 import org.apache.cloudstack.usage.Usage;
 import org.apache.cloudstack.usage.UsageService;
 import org.apache.cloudstack.usage.UsageTypes;
+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;                                                                                            
+import org.apache.cloudstack.api.ResponseGenerator;                                                                                 
+import org.apache.cloudstack.api.response.VMSnapshotResponse;
 import org.apache.log4j.Logger;
 
 import java.text.DecimalFormat;
@@ -359,6 +365,25 @@ public class ApiResponseHelper implements ResponseGenerator {
     }
 
     @Override
+    public VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot) {
+        VMSnapshotResponse vmSnapshotResponse = new VMSnapshotResponse();
+        vmSnapshotResponse.setId(vmSnapshot.getUuid());
+        vmSnapshotResponse.setName(vmSnapshot.getName());
+        vmSnapshotResponse.setState(vmSnapshot.getState());
+        vmSnapshotResponse.setCreated(vmSnapshot.getCreated());
+        vmSnapshotResponse.setDescription(vmSnapshot.getDescription());
+        vmSnapshotResponse.setDisplayName(vmSnapshot.getDisplayName());
+        UserVm vm = ApiDBUtils.findUserVmById(vmSnapshot.getVmId());        
+        if(vm!=null)
+            vmSnapshotResponse.setVirtualMachineid(vm.getUuid());
+        if(vmSnapshot.getParent() != null)
+            vmSnapshotResponse.setParentName(ApiDBUtils.getVMSnapshotById(vmSnapshot.getParent()).getDisplayName());
+        vmSnapshotResponse.setCurrent(vmSnapshot.getCurrent());
+        vmSnapshotResponse.setType(vmSnapshot.getType().toString());
+        return vmSnapshotResponse;
+    }
+    
+    @Override
     public SnapshotPolicyResponse createSnapshotPolicyResponse(SnapshotPolicy policy) {
         SnapshotPolicyResponse policyResponse = new SnapshotPolicyResponse();
         policyResponse.setId(policy.getUuid());
@@ -3093,7 +3118,6 @@ public class ApiResponseHelper implements ResponseGenerator {
         response.setObjectName("vpnconnection");
         return response;
     }
-    
     @Override
     public GuestOSResponse createGuestOSResponse(GuestOS guestOS) {
         GuestOSResponse response = new GuestOSResponse();
@@ -3133,7 +3157,6 @@ public class ApiResponseHelper implements ResponseGenerator {
     }
 
 
-
 	@Override
 	public UsageRecordResponse createUsageResponse(Usage usageRecord) {
 		UsageRecordResponse usageRecResponse = new UsageRecordResponse();

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/server/src/com/cloud/capacity/CapacityManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java
index d7b7053..4787c7b 100755
--- a/server/src/com/cloud/capacity/CapacityManagerImpl.java
+++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java
@@ -62,9 +62,11 @@ import com.cloud.storage.VMTemplateHostVO;
 import com.cloud.storage.VMTemplateStoragePoolVO;
 import com.cloud.storage.VMTemplateSwiftVO;
 import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.VMTemplatePoolDao;
 import com.cloud.storage.dao.VolumeDao;
 import com.cloud.storage.swift.SwiftManager;
+import com.cloud.uservm.UserVm;
 import com.cloud.utils.DateUtil;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
@@ -78,7 +80,11 @@ import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachine.Event;
 import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
 
 @Component
 @Local(value = CapacityManager.class)
@@ -110,7 +116,11 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
     ConfigurationManager _configMgr;   
     @Inject
     HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
-
+    @Inject
+    protected VMSnapshotDao _vmSnapshotDao;
+    @Inject
+    protected UserVmDao _userVMDao;
+    
     private int _vmCapacityReleaseInterval;
     private ScheduledExecutorService _executor;
     private boolean _stopped;
@@ -437,12 +447,43 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
 
     }
     
+    private long getVMSnapshotAllocatedCapacity(StoragePoolVO pool){
+        List<VolumeVO> volumes = _volumeDao.findByPoolId(pool.getId());
+        long totalSize = 0;
+        for (VolumeVO volume : volumes) {
+            if(volume.getInstanceId() == null)
+                continue;
+            Long vmId = volume.getInstanceId();
+            UserVm vm = _userVMDao.findById(vmId);
+            if(vm == null)
+                continue;
+            ServiceOffering offering = _offeringsDao.findById(vm.getServiceOfferingId());
+            List<VMSnapshotVO> vmSnapshots =  _vmSnapshotDao.findByVm(vmId);
+            long pathCount = 0;
+            long memorySnapshotSize = 0;
+            for (VMSnapshotVO vmSnapshotVO : vmSnapshots) {
+                if(_vmSnapshotDao.listByParent(vmSnapshotVO.getId()).size() == 0)
+                    pathCount++;
+                if(vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory)
+                    memorySnapshotSize += (offering.getRamSize() * 1024 * 1024);
+            }
+            if(pathCount <= 1)
+                totalSize = totalSize + memorySnapshotSize;
+            else
+                totalSize = totalSize + volume.getSize() * (pathCount - 1) + memorySnapshotSize;
+        }
+        return totalSize;
+    }
+    
     @Override
     public long getAllocatedPoolCapacity(StoragePoolVO pool, VMTemplateVO templateForVmCreation){
       
         // Get size for all the volumes
         Pair<Long, Long> sizes = _volumeDao.getCountAndTotalByPool(pool.getId());
         long totalAllocatedSize = sizes.second() + sizes.first() * _extraBytesPerVolume;
+        
+        // Get size for VM Snapshots 
+        totalAllocatedSize = totalAllocatedSize + getVMSnapshotAllocatedCapacity(pool);
 
         // Iterate through all templates on this storage pool
         boolean tmpinstalled = false;

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/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 b1a1308..26499bc 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 {
 
@@ -371,8 +372,16 @@ public enum Config {
 
     ApiLimitInterval("Advanced", ManagementServer.class, Integer.class, "api.throttling.interval", "1", "Time interval (in seconds) to reset API count", null),
     ApiLimitMax("Advanced", ManagementServer.class, Integer.class, "api.throttling.max", "25", "Max allowed number of APIs within fixed interval", null),
-    ApiLimitCacheSize("Advanced", ManagementServer.class, Integer.class, "api.throttling.cachesize", "50000", "Account based API count cache size", null);
-
+    ApiLimitCacheSize("Advanced", ManagementServer.class, Integer.class, "api.throttling.cachesize", "50000", "Account based API count cache size", 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;
 	private final Class<?> _type;

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index 0943bfc..d381206 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -99,6 +99,10 @@ import org.apache.cloudstack.api.command.user.tag.*;
 import org.apache.cloudstack.api.command.user.template.*;
 import org.apache.cloudstack.api.command.user.vm.*;
 import org.apache.cloudstack.api.command.user.vmgroup.*;
+import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd;
+import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd;
+import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd;
+import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToSnapshotCmd;
 import org.apache.cloudstack.api.command.user.volume.*;
 import org.apache.cloudstack.api.command.user.vpc.*;
 import org.apache.cloudstack.api.command.user.vpn.*;
@@ -2143,6 +2147,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         cmdList.add(ResetVpnConnectionCmd.class);
         cmdList.add(UpdateVpnCustomerGatewayCmd.class);
         cmdList.add(ListZonesByCmd.class);
+        cmdList.add(ListVMSnapshotCmd.class);
+        cmdList.add(CreateVMSnapshotCmd.class);
+        cmdList.add(RevertToSnapshotCmd.class);
+        cmdList.add(DeleteVMSnapshotCmd.class);
         return cmdList;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/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 c7beff0..e06da75 100755
--- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
+++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
@@ -104,6 +104,9 @@ import org.apache.log4j.Logger;
 import javax.ejb.Local;
 import javax.naming.ConfigurationException;
 import java.util.*;
+import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
 
 @Component
 @Local(value = { SnapshotManager.class, SnapshotService.class })
@@ -167,7 +170,9 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
     private ResourceTagDao _resourceTagDao;
     @Inject
     private ConfigurationDao _configDao;
-    
+    @Inject 
+    private VMSnapshotDao _vmSnapshotDao;
+    String _name;
     private int _totalRetries;
     private int _pauseInterval;
     private int _deltaSnapshotMax;
@@ -395,6 +400,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
             }
 
             // 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) {
@@ -408,6 +414,12 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
                         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.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging);
+                    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/9a12756a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
index e44343d..06756b6 100644
--- a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
+++ b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java
@@ -73,6 +73,7 @@ import com.cloud.utils.db.Transaction;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.uuididentity.dao.IdentityDao;
 import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
 
 
 @Component
@@ -121,6 +122,8 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso
     VpcDao _vpcDao;
     @Inject
     StaticRouteDao _staticRouteDao;
+    @Inject
+    VMSnapshotDao _vmSnapshotDao;
 
     @Override
     public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
@@ -139,6 +142,7 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso
         _daoMap.put(TaggedResourceType.Vpc, _vpcDao);
         _daoMap.put(TaggedResourceType.NetworkACL, _firewallDao);
         _daoMap.put(TaggedResourceType.StaticRoute, _staticRouteDao);
+        _daoMap.put(TaggedResourceType.VMSnapshot, _vmSnapshotDao);
 
         return true;
     }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/9a12756a/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 d5c66de..19887ff 100644
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -249,12 +249,37 @@ import com.cloud.utils.exception.ExecutionException;
 import com.cloud.utils.fsm.NoTransitionException;
 import com.cloud.utils.net.NetUtils;
 import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.dao.*;
+import org.apache.cloudstack.acl.ControlledEntity.ACLType;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
+import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
+import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd;
+import org.apache.cloudstack.api.command.user.vm.*;
+import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
+import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
+import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
+import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+import java.util.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 import com.cloud.vm.dao.InstanceGroupDao;
 import com.cloud.vm.dao.InstanceGroupVMMapDao;
 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.VMSnapshotManager;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
 
 @Local(value = { UserVmManager.class, UserVmService.class })
 public class UserVmManagerImpl extends ManagerBase implements UserVmManager, UserVmService {
@@ -392,7 +417,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
     protected GuestOSCategoryDao _guestOSCategoryDao;
     @Inject
     UsageEventDao _usageEventDao;
-
+    @Inject
+    protected VMSnapshotDao _vmSnapshotDao;
+    @Inject 
+    protected VMSnapshotManager _vmSnapshotMgr;
+    
     protected ScheduledExecutorService _executor = null;
     protected int _expungeInterval;
     protected int _expungeDelay;
@@ -813,7 +842,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
         // permission check
         _accountMgr.checkAccess(caller, null, true, volume, vm);
 
-        // Check if volume is stored on secondary Storage.
+        //check if vm has snapshot, if true: can't attache volume
+        boolean attach = true;
+        checkVMSnapshots(vm, volumeId, attach);
+
+        // Check if volume is stored on secondary Storage.  
+        //Check if volume is stored on secondary Storage.
         boolean isVolumeOnSec = false;
         VolumeHostVO  volHostVO = _volumeHostDao.findByVolumeId(volume.getId());
         if (volHostVO != null) {
@@ -1106,8 +1140,19 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
         }
     }
 
+    private void checkVMSnapshots(UserVmVO vm, Long volumeId, boolean attach) {
+        // Check that if vm has any VM snapshot
+        Long vmId = vm.getId();
+        List<VMSnapshotVO> listSnapshot = _vmSnapshotDao.listByInstanceId(vmId,
+                VMSnapshot.State.Ready, VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging);
+        if (listSnapshot != null && listSnapshot.size() != 0) {
+            throw new InvalidParameterValueException(
+                        "The VM has VM snapshots, do not allowed to attach volume. Please delete the VM snapshots first.");
+        }
+    }
+
     @Override
-    @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume",  async = true)
+    @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
@@ -1167,8 +1212,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
                     "Please specify a VM that is either running or stopped.");
         }
 
-        AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor
-                .getCurrentExecutor();
+        // Check that if the volume has snapshot
+        boolean attach = false;
+        checkVMSnapshots(vm, volumeId, attach);
+        AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor();
         if (asyncExecutor != null) {
             AsyncJobVO job = asyncExecutor.getJob();
 
@@ -1314,12 +1361,25 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
             throw new InvalidParameterValueException(
                     "unable to find a virtual machine with id " + vmId);
         }
-
+        
         _accountMgr.checkAccess(caller, null, true, vmInstance);
 
         // Check that the specified service offering ID is valid
         _itMgr.checkIfCanUpgrade(vmInstance, svcOffId);
 
+        // remove diskAndMemory VM snapshots
+        List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
+        for (VMSnapshotVO vmSnapshotVO : vmSnapshots) {
+            if(vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory){
+                if(!_vmSnapshotMgr.deleteAllVMSnapshots(vmId, VMSnapshot.Type.DiskAndMemory)){
+                    String errMsg = "Failed to remove VM snapshot during upgrading, snapshot id " + vmSnapshotVO.getId();
+                    s_logger.debug(errMsg);
+                    throw new CloudRuntimeException(errMsg);
+                }
+                    
+            }
+        }
+        
         _itMgr.upgradeVmDb(vmId, svcOffId);
 
         return _vmDao.findById(vmInstance.getId());
@@ -1997,8 +2057,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
             }
 
             volume = _volsDao.findById(snapshot.getVolumeId());
-            VolumeVO snapshotVolume = _volsDao
-                    .findByIdIncludingRemoved(snapshot.getVolumeId());
 
             // check permissions
             _accountMgr.checkAccess(caller, null, true, snapshot);


Mime
View raw message