You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ed...@apache.org on 2013/04/30 04:38:13 UTC

[4/5] git commit: updated refs/heads/object_store to 99dcb23

refactor snapshot


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

Branch: refs/heads/object_store
Commit: 2f689171e0e989982b3391944eee49acf98f98e1
Parents: 37cbe88
Author: Edison Su <su...@gmail.com>
Authored: Mon Apr 29 18:50:46 2013 -0700
Committer: Edison Su <su...@gmail.com>
Committed: Mon Apr 29 18:51:14 2013 -0700

----------------------------------------------------------------------
 api/src/com/cloud/storage/Snapshot.java            |    5 +
 api/src/com/cloud/storage/VolumeApiService.java    |    5 +-
 .../command/user/snapshot/CreateSnapshotCmd.java   |   20 +-
 .../subsystem/api/storage/SnapshotStrategy.java    |    7 +-
 .../subsystem/api/storage/StorageCacheManager.java |    7 +
 .../engine/subsystem/api/storage/VolumeInfo.java   |    1 +
 .../cloudstack/storage/command/CopyCommand.java    |   16 +-
 .../cloudstack/storage/to/SnapshotObjectTO.java    |   70 +++-
 .../cloudstack/storage/to/VolumeObjectTO.java      |   10 +
 .../cache/manager/StorageCacheManagerImpl.java     |   14 +
 .../storage/motion/AncientDataMotionStrategy.java  |  376 ++++-----------
 .../storage/snapshot/SnapshotObject.java           |    8 +
 .../storage/snapshot/SnapshotServiceImpl.java      |    2 +-
 .../snapshot/SnapshotStateMachineManagerImpl.java  |    6 +
 .../storage/snapshot/SnapshotStrategyBase.java     |    4 +-
 .../snapshot/XenserverSnapshotStrategy.java        |  132 +++---
 .../datastore/ObjectInDataStoreManagerImpl.java    |   28 +-
 .../storage/image/db/SnapshotDataStoreDaoImpl.java |    6 +
 .../storage/snapshot/SnapshotEntityImpl.java       |    6 -
 .../cloudstack/storage/volume/VolumeObject.java    |   17 +
 .../storage/volume/VolumeServiceImpl.java          |   11 +-
 .../xen/resource/CitrixResourceBase.java           |    2 +-
 .../xen/resource/XenServerStorageResource.java     |  397 ++++++++++++++-
 .../CloudStackPrimaryDataStoreDriverImpl.java      |   26 +-
 .../com/cloud/storage/CreateSnapshotPayload.java   |   20 +
 .../src/com/cloud/storage/VolumeManagerImpl.java   |   32 +-
 .../src/com/cloud/storage/dao/SnapshotDaoImpl.java |    4 +-
 .../cloud/storage/snapshot/SnapshotManager.java    |    4 -
 .../storage/snapshot/SnapshotManagerImpl.java      |  151 ++++---
 .../com/cloud/template/TemplateManagerImpl.java    |    2 +-
 30 files changed, 889 insertions(+), 500 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/api/src/com/cloud/storage/Snapshot.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/storage/Snapshot.java b/api/src/com/cloud/storage/Snapshot.java
index 0d58a14..27a2fe4 100644
--- a/api/src/com/cloud/storage/Snapshot.java
+++ b/api/src/com/cloud/storage/Snapshot.java
@@ -60,6 +60,9 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity,
         CreatedOnPrimary,
         BackingUp,
         BackedUp,
+        Copying,
+        Destroying,
+        Destroyed,//it's a state, user can't see the snapshot from ui, while the snapshot may still exist on the storage
         Error;
 
         public String toString() {
@@ -76,6 +79,8 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity,
         OperationNotPerformed,
         BackupToSecondary,
         BackedupToSecondary,
+        DestroyRequested,
+        CopyingRequested,
         OperationSucceeded,
         OperationFailed
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/api/src/com/cloud/storage/VolumeApiService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/storage/VolumeApiService.java b/api/src/com/cloud/storage/VolumeApiService.java
index 2f5364f..462ff64 100644
--- a/api/src/com/cloud/storage/VolumeApiService.java
+++ b/api/src/com/cloud/storage/VolumeApiService.java
@@ -80,6 +80,9 @@ public interface VolumeApiService {
 
     Volume detachVolumeFromVM(DetachVolumeCmd cmmd);
 
-	Snapshot takeSnapshot(Long volumeId, Long policyId)
+	Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account)
 			throws ResourceAllocationException;
+	
+	Snapshot allocSnapshot(Long volumeId, Long policyId)
+            throws ResourceAllocationException;
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java
index 95d7659..25cdedd 100644
--- a/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java
@@ -152,7 +152,7 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd {
 
     @Override
     public void create() throws ResourceAllocationException {
-        Snapshot snapshot = _snapshotService.allocSnapshot(getVolumeId(), getPolicyId());
+        Snapshot snapshot = this._volumeService.allocSnapshot(getVolumeId(), getPolicyId());
         if (snapshot != null) {
             this.setEntityId(snapshot.getId());
             this.setEntityUuid(snapshot.getUuid());
@@ -164,14 +164,20 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd {
     @Override
     public void execute() {
         UserContext.current().setEventDetails("Volume Id: "+getVolumeId());
-        Snapshot snapshot = _snapshotService.createSnapshot(getVolumeId(), getPolicyId(), getEntityId(), _accountService.getAccount(getEntityOwnerId()));
-        if (snapshot != null) {
-            SnapshotResponse response = _responseGenerator.createSnapshotResponse(snapshot);
-            response.setResponseName(getCommandName());
-            this.setResponseObject(response);
-        } else {
+        Snapshot snapshot;
+        try {
+            snapshot = _volumeService.takeSnapshot(this.getVolumeId(), this.getPolicyId(), this.getEntityId(), _accountService.getAccount(getEntityOwnerId()));
+            if (snapshot != null) {
+                SnapshotResponse response = _responseGenerator.createSnapshotResponse(snapshot);
+                response.setResponseName(getCommandName());
+                this.setResponseObject(response);
+            } else {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create snapshot due to an internal error creating snapshot for volume " + volumeId);
+            }
+        } catch (Exception e) {
             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create snapshot due to an internal error creating snapshot for volume " + volumeId);
         }
+        
     }
 
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java
index a642b5e..6b90c31 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java
@@ -3,9 +3,14 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
 import com.cloud.storage.Snapshot;
 
 
+
 public interface SnapshotStrategy {
 	public SnapshotInfo takeSnapshot(SnapshotInfo snapshot);
 	public SnapshotInfo backupSnapshot(SnapshotInfo snapshot);
 	public boolean deleteSnapshot(Long snapshotId);
-	public boolean canHandle(Snapshot snapshot);
+    /**
+     * @param snapshot
+     * @return
+     */
+    boolean canHandle(Snapshot snapshot);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java
index 70332c7..0aa30d3 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java
@@ -22,4 +22,11 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
 public interface StorageCacheManager {
     public DataStore getCacheStorage(Scope scope);
     public DataObject createCacheObject(DataObject data, Scope scope);
+    /** only create cache object in db
+     * @param data
+     * @param scope
+     * @return
+     */
+    DataObject getCacheObject(DataObject data, Scope scope);
+    DataObject deleteCacheObject(DataObject data);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
index 349325a..7165f37 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
@@ -27,4 +27,5 @@ public interface VolumeInfo extends DataObject, Volume {
 	public Object getpayload();
 	public HypervisorType getHypervisorType();
 	public Long getLastPoolId();
+	public String getAttachedVmName();
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java b/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java
index 5fe1cbe..5bceb03 100644
--- a/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java
+++ b/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java
@@ -23,12 +23,12 @@ import com.cloud.agent.api.Command;
 public class CopyCommand extends Command implements StorageSubSystemCommand {
     private DataTO srcTO;
     private DataTO destTO;
+    private DataTO cacheTO;
 
-
-    public CopyCommand(DataTO srcUri, DataTO destUri, int timeout) {
+    public CopyCommand(DataTO srcData, DataTO destData, int timeout) {
         super();
-        this.srcTO = srcUri;
-        this.destTO = destUri;
+        this.srcTO = srcData;
+        this.destTO = destData;
         this.setWait(timeout);
     }
     
@@ -45,4 +45,12 @@ public class CopyCommand extends Command implements StorageSubSystemCommand {
         return true;
     }
 
+    public DataTO getCacheTO() {
+        return cacheTO;
+    }
+
+    public void setCacheTO(DataTO cacheTO) {
+        this.cacheTO = cacheTO;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
index 38fea16..6d98045 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
@@ -2,21 +2,43 @@ package org.apache.cloudstack.storage.to;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
+import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
 
 import com.cloud.agent.api.to.DataStoreTO;
 
 public class SnapshotObjectTO implements DataTO {
 	private String path;
+	private VolumeObjectTO volume;
+	private String parentSnapshotPath;
+	private DataStoreTO dataStore;
+	private String vmName;
+	private String name;
+	private long id;
+	
+	public SnapshotObjectTO() {
+	    
+	}
+	
+	public SnapshotObjectTO(SnapshotInfo snapshot) {
+	    this.path = snapshot.getPath();
+	    this.setId(snapshot.getId());
+	    this.volume = (VolumeObjectTO)snapshot.getBaseVolume().getTO();
+	    this.setVmName(snapshot.getBaseVolume().getAttachedVmName());
+	    if (snapshot.getParent() != null) {
+	        this.parentSnapshotPath = snapshot.getParent().getPath();
+	    }
+	    this.dataStore = snapshot.getDataStore().getTO();
+	    this.setName(snapshot.getName());
+	}
+	
 	@Override
 	public DataObjectType getObjectType() {
-		// TODO Auto-generated method stub
-		return null;
+		return DataObjectType.SNAPSHOT;
 	}
 
 	@Override
 	public DataStoreTO getDataStore() {
-		// TODO Auto-generated method stub
-		return null;
+		return this.dataStore;
 	}
 
 	@Override
@@ -27,4 +49,44 @@ public class SnapshotObjectTO implements DataTO {
 	public void setPath(String path) {
 		this.path = path;
 	}
+
+    public VolumeObjectTO getVolume() {
+        return volume;
+    }
+
+    public void setVolume(VolumeObjectTO volume) {
+        this.volume = volume;
+    }
+
+    public String getParentSnapshotPath() {
+        return parentSnapshotPath;
+    }
+
+    public void setParentSnapshotPath(String parentSnapshotPath) {
+        this.parentSnapshotPath = parentSnapshotPath;
+    }
+
+    public String getVmName() {
+        return vmName;
+    }
+
+    public void setVmName(String vmName) {
+        this.vmName = vmName;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
index bf1bb3c..4ca1f9b 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
@@ -32,6 +32,7 @@ public class VolumeObjectTO implements DataTO {
     private String name;
     private long size;
     private String path;
+    private Long volumeId;
     
     public VolumeObjectTO() {
 
@@ -49,6 +50,7 @@ public class VolumeObjectTO implements DataTO {
         }
         //this.name = volume.getName();
         this.size = volume.getSize();
+        this.setVolumeId(volume.getId());
     }
     
     public String getUuid() {
@@ -103,4 +105,12 @@ public class VolumeObjectTO implements DataTO {
         this.path = path;
     }
 
+    public Long getVolumeId() {
+        return volumeId;
+    }
+
+    public void setVolumeId(Long volumeId) {
+        this.volumeId = volumeId;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
index d2aacde..3a445d4 100644
--- a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
+++ b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
@@ -164,10 +164,24 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager {
 		return null;
 	}
 	
+	@Override
+    public DataObject getCacheObject(DataObject data, Scope scope) {
+        DataStore cacheStore = this.getCacheStorage(scope);
+        DataObject objOnCacheStore = cacheStore.create(data);
+        
+        return objOnCacheStore;
+    }
+	
 	protected Void createCacheObjectCallBack(AsyncCallbackDispatcher<StorageCacheManagerImpl, CopyCommandResult> callback, 
 	        CreateCacheObjectContext<CopyCommandResult> context) {
 	    AsyncCallFuture<CopyCommandResult> future = context.future;
 	    future.complete(callback.getResult());
 	    return null;
 	}
+
+    @Override
+    public DataObject deleteCacheObject(DataObject data) {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
index 79ae289..2075ef6 100644
--- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
+++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
@@ -60,6 +60,8 @@ import com.cloud.agent.api.UpgradeSnapshotCommand;
 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.to.DataStoreTO;
+import com.cloud.agent.api.to.NfsTO;
 import com.cloud.agent.api.to.S3TO;
 import com.cloud.agent.api.to.SwiftTO;
 import com.cloud.configuration.Config;
@@ -127,10 +129,6 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
     @Inject
     VolumeManager volumeMgr;
     @Inject
-    private SwiftManager _swiftMgr;
-    @Inject
-    private S3Manager _s3Mgr;
-    @Inject
     StorageCacheManager cacheMgr;
 
     @Override
@@ -179,112 +177,55 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
             return answer;
         }
     }
+    
+    protected DataObject cacheSnapshotChain(SnapshotInfo snapshot) {
+        DataObject leafData = null;
+        while(snapshot != null) {
+            DataObject cacheData = cacheMgr.createCacheObject(snapshot, snapshot.getDataStore().getScope());
+            if (leafData == null) {
+                leafData = cacheData;
+            }
+            snapshot = snapshot.getParent();
+        }
+        return leafData;
+    }
+    
+    protected void deleteSnapshotCacheChain(SnapshotInfo snapshot) {
+        
+    }
 
-    protected Answer copyFromSnapshot(DataObject snapObj, DataObject volObj) {
-        SnapshotVO snapshot = this.snapshotDao.findById(snapObj.getId());
+    protected Answer copyVolumeFromSnapshot(DataObject snapObj, DataObject volObj) {
+        SnapshotInfo snapshot = (SnapshotInfo)snapObj;
         StoragePool pool = (StoragePool) volObj.getDataStore();
-        String vdiUUID = null;
-        Long snapshotId = snapshot.getId();
-        Long volumeId = snapshot.getVolumeId();
-        Long dcId = snapshot.getDataCenterId();
-        String secondaryStoragePoolUrl = this.snapshotMgr
-                .getSecondaryStorageURL(snapshot);
-        long accountId = snapshot.getAccountId();
 
-        String backedUpSnapshotUuid = snapshot.getBackupSnapshotId();
-        snapshot = snapshotDao.findById(snapshotId);
-        if (snapshot.getVersion().trim().equals("2.1")) {
-            VolumeVO volume = this.volDao.findByIdIncludingRemoved(volumeId);
-            if (volume == null) {
-                throw new CloudRuntimeException("failed to upgrade snapshot "
-                        + snapshotId + " due to unable to find orignal volume:"
-                        + volumeId + ", try it later ");
-            }
-            if (volume.getTemplateId() == null) {
-                snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2");
-            } else {
-                VMTemplateVO template = templateDao
-                        .findByIdIncludingRemoved(volume.getTemplateId());
-                if (template == null) {
-                    throw new CloudRuntimeException(
-                            "failed to upgrade snapshot "
-                                    + snapshotId
-                                    + " due to unalbe to find orignal template :"
-                                    + volume.getTemplateId()
-                                    + ", try it later ");
-                }
-                Long templateId = template.getId();
-                Long tmpltAccountId = template.getAccountId();
-                if (!snapshotDao.lockInLockTable(snapshotId.toString(), 10)) {
-                    throw new CloudRuntimeException(
-                            "failed to upgrade snapshot "
-                                    + snapshotId
-                                    + " due to this snapshot is being used, try it later ");
-                }
-                UpgradeSnapshotCommand cmd = new UpgradeSnapshotCommand(null,
-                        secondaryStoragePoolUrl, dcId, accountId, volumeId,
-                        templateId, tmpltAccountId, null,
-                        snapshot.getBackupSnapshotId(), snapshot.getName(),
-                        "2.1");
-                Answer answer = null;
-                try {
-                    answer = this.storageMgr.sendToPool(pool, cmd);
-                } catch (StorageUnavailableException e) {
-                } finally {
-                    snapshotDao.unlockFromLockTable(snapshotId.toString());
-                }
-                if ((answer != null) && answer.getResult()) {
-                    snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2");
-                } else {
-                    throw new CloudRuntimeException("Unable to upgrade snapshot from 2.1 to 2.2 for "
-                            + snapshot.getId());
-                }
-            }
-        }
         String basicErrMsg = "Failed to create volume from "
                 + snapshot.getName() + " on pool " + pool;
-
+        DataStore store = snapObj.getDataStore();
+        DataStoreTO storTO = store.getTO();
+        DataObject srcData = snapObj;
         try {
-            if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) {
-                snapshotMgr.downloadSnapshotsFromSwift(snapshot);
-            } else if (snapshot.getS3Id() != null && snapshot.getS3Id() != 0) {
-                snapshotMgr.downloadSnapshotsFromS3(snapshot);
+            if (!(storTO instanceof NfsTO)) {
+                srcData = cacheSnapshotChain(snapshot);
             }
+            
             String value = configDao
                     .getValue(Config.CreateVolumeFromSnapshotWait.toString());
             int _createVolumeFromSnapshotWait = NumbersUtil.parseInt(value,
                     Integer.parseInt(Config.CreateVolumeFromSnapshotWait
                             .getDefaultValue()));
-            CreateVolumeFromSnapshotCommand createVolumeFromSnapshotCommand = new CreateVolumeFromSnapshotCommand(
-                    pool, secondaryStoragePoolUrl, dcId, accountId, volumeId,
-                    backedUpSnapshotUuid, snapshot.getName(),
-                    _createVolumeFromSnapshotWait);
-            CreateVolumeFromSnapshotAnswer answer;
-            if (!snapshotDao.lockInLockTable(snapshotId.toString(), 10)) {
-                throw new CloudRuntimeException("failed to create volume from "
-                        + snapshotId
-                        + " due to this snapshot is being used, try it later ");
-            }
-            answer = (CreateVolumeFromSnapshotAnswer) this.storageMgr
-                    .sendToPool(pool, createVolumeFromSnapshotCommand);
-            if (answer != null && answer.getResult()) {
-                vdiUUID = answer.getVdi();
-                VolumeVO vol = this.volDao.findById(volObj.getId());
-                vol.setPath(vdiUUID);
-                this.volDao.update(vol.getId(), vol);
-                return null;
-            } else {
-                s_logger.error(basicErrMsg + " due to "
-                        + ((answer == null) ? "null" : answer.getDetails()));
-                throw new CloudRuntimeException(basicErrMsg);
-            }
+            
+            CopyCommand cmd = new CopyCommand(srcData.getTO(), volObj.getTO(), _createVolumeFromSnapshotWait);
+          
+
+            Answer answer = this.storageMgr
+                    .sendToPool(pool, cmd);
+           return answer;
         } catch (StorageUnavailableException e) {
             s_logger.error(basicErrMsg, e);
             throw new CloudRuntimeException(basicErrMsg);
         } finally {
-            if (snapshot.getSwiftId() != null) {
-                snapshotMgr.deleteSnapshotsDirForVolume(
-                        secondaryStoragePoolUrl, dcId, accountId, volumeId);
+            if (!(storTO instanceof NfsTO)) {
+                deleteSnapshotCacheChain((SnapshotInfo)srcData);
             }
         }
     }
@@ -328,7 +269,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
             	answer = copyTemplate(srcData, destData);
             } else if (srcData.getType() == DataObjectType.SNAPSHOT
                     && destData.getType() == DataObjectType.VOLUME) {
-            	answer = copyFromSnapshot(srcData, destData);
+            	answer = copyVolumeFromSnapshot(srcData, destData);
             } else if (srcData.getType() == DataObjectType.SNAPSHOT
                     && destData.getType() == DataObjectType.TEMPLATE) {
             	answer = createTemplateFromSnapshot(srcData, destData);
@@ -359,49 +300,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
     @DB
     protected Answer createTemplateFromSnapshot(DataObject srcData,
             DataObject destData) {
-        long snapshotId = srcData.getId();
-        SnapshotVO snapshot = snapshotDao.findById(snapshotId);
-        if (snapshot == null) {
-            throw new CloudRuntimeException("Unable to find Snapshot for Id "
-                    + srcData.getId());
-        }
-        Long zoneId = snapshot.getDataCenterId();
-        DataStore secStore = destData.getDataStore();
-        /*
-        HostVO secondaryStorageHost = this.templateMgr
-                .getSecondaryStorageHost(zoneId);
-                */
-        String secondaryStorageURL = snapshotMgr
-                .getSecondaryStorageURL(snapshot);
-        VMTemplateVO template = this.templateDao.findById(destData.getId());
-        String name = template.getName();
-        String backupSnapshotUUID = snapshot.getBackupSnapshotId();
-        if (backupSnapshotUUID == null) {
-            throw new CloudRuntimeException(
-                    "Unable to create private template from snapshot "
-                            + snapshotId
-                            + " due to there is no backupSnapshotUUID for this snapshot");
-        }
-
-        Long dcId = snapshot.getDataCenterId();
-        Long accountId = snapshot.getAccountId();
-        Long volumeId = snapshot.getVolumeId();
-
-        String origTemplateInstallPath = null;
-        List<StoragePoolVO> pools = this.storageMgr
-                .ListByDataCenterHypervisor(zoneId,
-                        snapshot.getHypervisorType());
-        if (pools == null || pools.size() == 0) {
-            throw new CloudRuntimeException(
-                    "Unable to find storage pools in zone " + zoneId);
-        }
-        StoragePoolVO poolvo = pools.get(0);
-        StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore(
-                poolvo.getId(), DataStoreRole.Primary);
-        
-        if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) {
-            snapshotMgr.downloadSnapshotsFromSwift(snapshot);
-        }
+      
         String value = configDao
                 .getValue(Config.CreatePrivateTemplateFromSnapshotWait
                         .toString());
@@ -410,172 +309,71 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
                         .parseInt(Config.CreatePrivateTemplateFromSnapshotWait
                                 .getDefaultValue()));
 
-        CreatePrivateTemplateFromSnapshotCommand cmd = new CreatePrivateTemplateFromSnapshotCommand(
-                pool, secondaryStorageURL, dcId, accountId,
-                snapshot.getVolumeId(), backupSnapshotUUID, snapshot.getName(),
-                origTemplateInstallPath, template.getId(), name,
-                _createprivatetemplatefromsnapshotwait);
-
-        return sendCommand(cmd, pool, template.getId(), dcId, secStore);
-    }
-
-    @DB
-    protected Answer sendCommand(Command cmd, StoragePool pool,
-            long templateId, long zoneId, DataStore secStore) {
-
-        CreatePrivateTemplateAnswer answer = null;
-        try {
-            answer = (CreatePrivateTemplateAnswer) this.storageMgr.sendToPool(
-                    pool, cmd);
-        } catch (StorageUnavailableException e) {
-            throw new CloudRuntimeException(
-                    "Failed to execute CreatePrivateTemplateFromSnapshotCommand",
-                    e);
-        }
-
-        if (answer == null || !answer.getResult()) {
-        	return answer;
-        }
-
-        VMTemplateVO privateTemplate = templateDao.findById(templateId);
-        String answerUniqueName = answer.getUniqueName();
-        if (answerUniqueName != null) {
-            privateTemplate.setUniqueName(answerUniqueName);
-        }
-        ImageFormat format = answer.getImageFormat();
-        if (format != null) {
-            privateTemplate.setFormat(format);
-        } else {
-            // This never occurs.
-            // Specify RAW format makes it unusable for snapshots.
-            privateTemplate.setFormat(ImageFormat.RAW);
+        if (srcData.getDataStore().getRole() != DataStoreRole.ImageCache && destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
+            SnapshotInfo snapshot = (SnapshotInfo)srcData;
+            srcData = cacheSnapshotChain(snapshot);
         }
 
-        String checkSum = this.templateMgr
-                .getChecksum(secStore, answer.getPath());
-
-        Transaction txn = Transaction.currentTxn();
-
-        txn.start();
-
-        privateTemplate.setChecksum(checkSum);
-        templateDao.update(privateTemplate.getId(), privateTemplate);
-
-        // add template zone ref for this template
-        templateDao.addTemplateToZone(privateTemplate, zoneId);
-        TemplateDataStoreVO templateHostVO = new TemplateDataStoreVO(secStore.getId(),
-                privateTemplate.getId());
-        templateHostVO.setDownloadPercent(100);
-        templateHostVO.setDownloadState(Status.DOWNLOADED);
-        templateHostVO.setInstallPath(answer.getPath());
-        templateHostVO.setLastUpdated(new Date());
-        templateHostVO.setSize(answer.getVirtualSize());
-        templateHostVO.setPhysicalSize(answer.getphysicalSize());
-        templateStoreDao.persist(templateHostVO);
-        txn.close();
+        CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _createprivatetemplatefromsnapshotwait);
+        EndPoint ep = selector.select(srcData, destData);
+        Answer answer = ep.sendMessage(cmd);
         return answer;
     }
 
-    private Answer createTemplateFromVolume(DataObject srcObj,
-            DataObject destObj) {
-        long volumeId = srcObj.getId();
-        VolumeVO volume = this.volDao.findById(volumeId);
-        if (volume == null) {
-            throw new CloudRuntimeException("Unable to find volume for Id "
-                    + volumeId);
-        }
-        long accountId = volume.getAccountId();
 
-        String vmName = this.volumeMgr.getVmNameOnVolume(volume);
-        Long zoneId = volume.getDataCenterId();
-        DataStore secStore = destObj.getDataStore();
-        String secondaryStorageURL = secStore.getUri();
-        VMTemplateVO template = this.templateDao.findById(destObj.getId());
-        StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore(
-                volume.getPoolId(), DataStoreRole.Primary);
+    private Answer createTemplateFromVolume(DataObject srcData,
+            DataObject destData) {
+  
         String value = configDao
                 .getValue(Config.CreatePrivateTemplateFromVolumeWait.toString());
         int _createprivatetemplatefromvolumewait = NumbersUtil.parseInt(value,
                 Integer.parseInt(Config.CreatePrivateTemplateFromVolumeWait
                         .getDefaultValue()));
-
-        CreatePrivateTemplateFromVolumeCommand cmd = new CreatePrivateTemplateFromVolumeCommand(
-                pool, secondaryStorageURL, destObj.getId(), accountId,
-                template.getName(), template.getUniqueName(), volume.getPath(),
-                vmName, _createprivatetemplatefromvolumewait);
-
-        return sendCommand(cmd, pool, template.getId(), zoneId, secStore);
-    }
-
-    private DataStore getSecHost(long volumeId, long dcId) {
-        Long id = snapshotDao.getSecHostId(volumeId);
-        if ( id != null) {
-            return this.dataStoreMgr.getDataStore(id, DataStoreRole.Image);
+       
+        if (srcData.getDataStore().getRole() != DataStoreRole.ImageCache && destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
+            //need to copy it to image cache store
+            DataObject cacheData = cacheMgr.createCacheObject(srcData, destData.getDataStore().getScope());
+            CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _createprivatetemplatefromvolumewait);
+            EndPoint ep = selector.select(cacheData, destData);
+            Answer answer = ep.sendMessage(cmd);
+            return answer;
+        } else {
+            //handle copy it to/from cache store
+            CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _createprivatetemplatefromvolumewait);
+            EndPoint ep = selector.select(srcData, destData);
+            Answer answer = ep.sendMessage(cmd);
+            return answer;
         }
-        return this.dataStoreMgr.getImageStore(dcId);
     }
 
-    protected Answer copySnapshot(DataObject srcObject, DataObject destObject) {
-    	SnapshotInfo srcSnapshot = (SnapshotInfo)srcObject;
-    	VolumeInfo baseVolume = srcSnapshot.getBaseVolume();
-    	 Long dcId = baseVolume.getDataCenterId();
-         Long accountId = baseVolume.getAccountId();
-
-         DataStore secStore = getSecHost(baseVolume.getId(), baseVolume.getDataCenterId());
-         Long secHostId = secStore.getId();
-         String secondaryStoragePoolUrl = secStore.getUri();
-         String snapshotUuid = srcSnapshot.getPath();
-         // In order to verify that the snapshot is not empty,
-         // we check if the parent of the snapshot is not the same as the parent of the previous snapshot.
-         // We pass the uuid of the previous snapshot to the plugin to verify this.
-         SnapshotVO prevSnapshot = null;
-         String prevSnapshotUuid = null;
-         String prevBackupUuid = null;
-
-
-         SwiftTO swift = _swiftMgr.getSwiftTO();
-         S3TO s3 = _s3Mgr.getS3TO();
-
-         long prevSnapshotId = srcSnapshot.getPrevSnapshotId();
-         if (prevSnapshotId > 0) {
-             prevSnapshot = snapshotDao.findByIdIncludingRemoved(prevSnapshotId);
-             if ( prevSnapshot.getBackupSnapshotId() != null && swift == null) {
-                 if (prevSnapshot.getVersion() != null && prevSnapshot.getVersion().equals("2.2")) {
-                     prevBackupUuid = prevSnapshot.getBackupSnapshotId();
-                     prevSnapshotUuid = prevSnapshot.getPath();
-                 }
-             } else if ((prevSnapshot.getSwiftId() != null && swift != null)
-                     || (prevSnapshot.getS3Id() != null && s3 != null)) {
-                 prevBackupUuid = prevSnapshot.getBackupSnapshotId();
-                 prevSnapshotUuid = prevSnapshot.getPath();
-             }
-         }
-         boolean isVolumeInactive = this.volumeMgr.volumeInactive(baseVolume);
-         String vmName = this.volumeMgr.getVmNameOnVolume(baseVolume);
-         StoragePool srcPool = (StoragePool)dataStoreMgr.getPrimaryDataStore(baseVolume.getPoolId());
-         String value = configDao.getValue(Config.BackupSnapshotWait.toString());
-         int _backupsnapshotwait = NumbersUtil.parseInt(value, Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue()));
-         BackupSnapshotCommand backupSnapshotCommand = new BackupSnapshotCommand(secondaryStoragePoolUrl, dcId, accountId, baseVolume.getId(), srcSnapshot.getId(), secHostId, baseVolume.getPath(), srcPool, snapshotUuid,
-        		 srcSnapshot.getName(), prevSnapshotUuid, prevBackupUuid, isVolumeInactive, vmName, _backupsnapshotwait);
+    protected Answer copySnapshot(DataObject srcData, DataObject destData) {
+        String value = configDao.getValue(Config.BackupSnapshotWait.toString());
+        int _backupsnapshotwait = NumbersUtil.parseInt(value, Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue()));
 
-         if ( swift != null ) {
-             backupSnapshotCommand.setSwift(swift);
-         } else if (s3 != null) {
-             backupSnapshotCommand.setS3(s3);
-         }
-         BackupSnapshotAnswer answer = (BackupSnapshotAnswer) this.snapshotMgr.sendToPool(baseVolume, backupSnapshotCommand);
-         if (answer != null && answer.getResult()) {
-        	 SnapshotVO snapshotVO = this.snapshotDao.findById(srcSnapshot.getId());
-        	 snapshotVO.setBackupSnapshotId(answer.getBackupSnapshotName());
-        	 // persist an entry in snapshot_store_ref
-        	 SnapshotDataStoreVO snapshotStore = new SnapshotDataStoreVO(secStore.getId(), snapshotVO.getId());
-        	 this._snapshotStoreDao.persist(snapshotStore);
- 			if (answer.isFull()) {
- 				snapshotVO.setPrevSnapshotId(0L);
-			}
-        	 this.snapshotDao.update(srcSnapshot.getId(), snapshotVO);
-         }
-         return answer;
+        DataObject cacheData = null;
+        try {
+        if (destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
+            cacheData = cacheMgr.getCacheObject(srcData, destData.getDataStore().getScope());
+        
+            CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait);
+            cmd.setCacheTO(cacheData.getTO());
+            EndPoint ep = selector.select(srcData, destData);
+            Answer answer = ep.sendMessage(cmd);
+            return answer;
+        } else {
+            CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait);
+            EndPoint ep = selector.select(srcData, destData);
+            Answer answer = ep.sendMessage(cmd);
+            return answer;
+        }
+        } catch (Exception e) {
+            s_logger.debug("copy snasphot failed: " + e.toString());
+            if (cacheData != null) {
+                cacheMgr.deleteCacheObject(cacheData);
+            }
+            throw new CloudRuntimeException(e.toString());
+        }
+       
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
index 50f3819..6fddcda 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
@@ -30,6 +30,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat;
+import org.apache.cloudstack.storage.command.CopyCmdAnswer;
 import org.apache.cloudstack.storage.command.CreateObjectAnswer;
 import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
 import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
@@ -234,6 +235,13 @@ public class SnapshotObject implements SnapshotInfo {
     		SnapshotObjectTO snapshotTO = (SnapshotObjectTO)((CreateObjectAnswer) answer).getData();
     		snapshotStore.setInstallPath(snapshotTO.getPath());
     		this.snapshotStore.update(snapshotStore.getId(), snapshotStore);
+    	} else if (answer instanceof CopyCmdAnswer) {
+    	    SnapshotObjectTO snapshotTO = (SnapshotObjectTO)((CopyCmdAnswer) answer).getNewData();
+    	    snapshotStore.setInstallPath(snapshotTO.getPath());
+    	    if (snapshotTO.getParentSnapshotPath() == null) {
+    	        snapshotStore.setParentSnapshotId(0L);
+    	    }
+    	    this.snapshotStore.update(snapshotStore.getId(), snapshotStore);
     	} else {
     		throw new CloudRuntimeException("Unknown answer: " + answer.getClass());
     	}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
index 2fb4609..615ed20 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
@@ -399,7 +399,7 @@ public class SnapshotServiceImpl implements SnapshotService {
 
 	@Override
 	public boolean deleteSnapshot(SnapshotInfo snapInfo) {
-		
+		return true;
 
 	}
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java
index aa1cf68..489ba28 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java
@@ -44,6 +44,12 @@ SnapshotStateMachineManager {
 		stateMachine.addTransition(Snapshot.State.CreatedOnPrimary, Event.BackupToSecondary, Snapshot.State.BackingUp);
 		stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationSucceeded, Snapshot.State.BackedUp);
 		stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationFailed, Snapshot.State.CreatedOnPrimary);
+		stateMachine.addTransition(Snapshot.State.BackedUp, Event.DestroyRequested, Snapshot.State.Destroying);
+		stateMachine.addTransition(Snapshot.State.BackedUp, Event.CopyingRequested, Snapshot.State.Copying);
+		stateMachine.addTransition(Snapshot.State.Copying, Event.OperationSucceeded, Snapshot.State.BackedUp);
+		stateMachine.addTransition(Snapshot.State.Copying, Event.OperationFailed, Snapshot.State.BackedUp);
+		stateMachine.addTransition(Snapshot.State.Destroying, Event.OperationSucceeded, Snapshot.State.Destroyed);
+		stateMachine.addTransition(Snapshot.State.Destroying, Event.OperationFailed, Snapshot.State.Error);
 		
 		stateMachine.registerListener(new SnapshotStateListener());
 	}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java
index 70c30a0..fa0006a 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java
@@ -9,9 +9,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy;
 public abstract class SnapshotStrategyBase implements SnapshotStrategy {
 	@Inject
 	SnapshotService snapshotSvr;
-	//the default strategy is:
-	//create snapshot,
-	//backup, then delete snapshot on primary storage
+
 	@Override
 	public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
 		return snapshotSvr.takeSnapshot(snapshot).getSnashot();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
index 0fa044b..df2264a 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
@@ -27,6 +27,7 @@ import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Snapshot;
 import com.cloud.storage.SnapshotVO;
 import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.SnapshotDao;
 import com.cloud.storage.snapshot.SnapshotManager;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.exception.CloudRuntimeException;
@@ -48,6 +49,8 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
 	@Inject
 	ConfigurationDao configDao;
 	@Inject
+	SnapshotDao snapshotDao;
+	@Inject
 	SnapshotDataFactory snapshotDataFactory;
 
 	@Override
@@ -114,82 +117,72 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
 		snapshot.addPayload(fullBackup);
 		return this.snapshotSvr.backupSnapshot(snapshot);
 	}
+	
+	protected void deleteSnapshotChain(SnapshotInfo snapshot) {
+	    while(snapshot != null) {
+	        SnapshotInfo child = snapshot.getChild();
+	        SnapshotInfo parent = snapshot.getParent();
+	        if (child == null) {
+	            if (!parent.getPath().equalsIgnoreCase(snapshot.getPath())) {
+	                this.snapshotSvr.deleteSnapshot(snapshot);
+	                snapshot = parent;
+	                continue;
+	            }
+	            break;
+	        } else {
+	            break;
+	        }
+	    }
+	}
 
 	@Override
-	public boolean deleteSnapshot(SnapshotInfo snapshot) {
-		Long snapshotId = snapshot.getId();
-		SnapshotObject snapObj = (SnapshotObject)snapshot;
-
-		if (!Snapshot.State.BackedUp.equals(snapshot.getState()) || !Snapshot) {
+	public boolean deleteSnapshot(Long snapshotId) {
+	    SnapshotVO snapshotVO = snapshotDao.findById(snapshotId);
+	    if (snapshotVO.getState() == Snapshot.State.Destroyed) {
+	        return true;
+	    }
+	    
+		if (!Snapshot.State.BackedUp.equals(snapshotVO.getState())) {
 			throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is not in BackedUp Status");
 		}
 
 		if (s_logger.isDebugEnabled()) {
 			s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId);
 		}
-		SnapshotVO lastSnapshot = null;
-		if (snapshot.getPrevSnapshotId() != null) {
-			List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(snapshot.getVolumeId(), snapshot.getBackupSnapshotId());
-			if (snaps != null && snaps.size() > 1) {
-				snapshot.setBackupSnapshotId(null);
-				SnapshotVO snapshotVO = this._snapshotDao.findById(snapshotId);
-				_snapshotDao.update(snapshot.getId(), snapshotVO);
-			}
-		}
-
-		_snapshotDao.remove(snapshotId);
-
-		long lastId = snapshotId;
-		boolean destroy = false;
-		while (true) {
-			lastSnapshot = _snapshotDao.findNextSnapshot(lastId);
-			if (lastSnapshot == null) {
-				// if all snapshots after this snapshot in this chain are removed, remove those snapshots.
-				destroy = true;
-				break;
-			}
-			if (lastSnapshot.getRemoved() == null) {
-				// if there is one child not removed, then can not remove back up snapshot.
-				break;
-			}
-			lastId = lastSnapshot.getId();
-		}
-		if (destroy) {
-			lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
-			while (lastSnapshot.getRemoved() != null) {
-				String BackupSnapshotId = lastSnapshot.getBackupSnapshotId();
-				if (BackupSnapshotId != null) {
-					List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(lastSnapshot.getVolumeId(), BackupSnapshotId);
-					if (snaps != null && snaps.size() > 1) {
-						lastSnapshot.setBackupSnapshotId(null);
-						_snapshotDao.update(lastSnapshot.getId(), lastSnapshot);
-					} else {
-						if (destroySnapshotBackUp(lastSnapshot)) {
-
-						} else {
-							s_logger.debug("Destroying snapshot backup failed " + lastSnapshot);
-							break;
-						}
-					}
-				}
-				lastId = lastSnapshot.getPrevSnapshotId();
-				if (lastId == 0) {
-					break;
-				}
-				lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
-			}
+		
+		
+		//firt mark the snapshot as destroyed, so that ui can't see it, but we may not destroy the snapshot on the storage, as other snaphosts may depend on it.
+		SnapshotInfo snapshotOnPrimary = this.snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary);
+		SnapshotObject obj = (SnapshotObject)snapshotOnPrimary;
+		try {
+            obj.processEvent(Snapshot.Event.DestroyRequested);
+        } catch (NoTransitionException e) {
+            s_logger.debug("Failed to destroy snapshot: " + e.toString());
+            return false;
+        }
+		
+		try {
+		    if (snapshotOnPrimary != null) {
+		        deleteSnapshotChain(snapshotOnPrimary);
+		    }
+
+		    SnapshotInfo snapshotOnImage = this.snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Image);
+		    if (snapshotOnImage != null) {
+		        deleteSnapshotChain(snapshotOnImage);
+		    }
+		    
+		    obj.processEvent(Snapshot.Event.OperationSucceeded);
+		} catch (Exception e) {
+		    s_logger.debug("Failed to delete snapshot: " + e.toString());
+		    try {
+                obj.processEvent(Snapshot.Event.OperationFailed);
+            } catch (NoTransitionException e1) {
+                s_logger.debug("Failed to change snapshot state: " + e.toString());
+            }
 		}
+		
 		return true;
 	}
-
-	@Override
-	public boolean canHandle(SnapshotInfo snapshot) {
-		if (snapshot.getHypervisorType() == HypervisorType.XenServer) {
-			return true;
-		} else {
-			return false;
-		}
-	}
 	
 	@Override
 	public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
@@ -197,4 +190,13 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
 		//TODO: add async
 		return this.backupSnapshot(snapshot);
 	}
+
+    @Override
+    public boolean canHandle(Snapshot snapshot) {
+        if (snapshot.getHypervisorType() == HypervisorType.XenServer) {
+            return true;
+        } else {
+            return false;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java
index 7ff22c6..3b01475 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java
@@ -84,33 +84,17 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
 
     public ObjectInDataStoreManagerImpl() {
         stateMachines = new StateMachine2<State, Event, DataObjectInStore>();
-        stateMachines.addTransition(State.Allocated, Event.CreateRequested,
+        stateMachines.addTransition(State.Allocated, Event.CreateOnlyRequested,
                 State.Creating);
-        stateMachines.addTransition(State.Creating, Event.OperationSuccessed,
-                State.Created);
         stateMachines.addTransition(State.Creating, Event.OperationFailed,
-                State.Failed);
-        stateMachines.addTransition(State.Failed, Event.CreateRequested,
-                State.Creating);
-        stateMachines.addTransition(State.Ready, Event.DestroyRequested,
-                State.Destroying);
-        stateMachines.addTransition(State.Destroying, Event.OperationSuccessed,
-                State.Destroyed);
-        stateMachines.addTransition(State.Destroying, Event.OperationFailed,
-                State.Destroying);
-        stateMachines.addTransition(State.Destroying, Event.DestroyRequested,
-                State.Destroying);
-        stateMachines.addTransition(State.Created, Event.CopyingRequested,
+                State.Allocated);
+        stateMachines.addTransition(State.Creating, Event.OperationSuccessed,
+                State.Ready);
+        stateMachines.addTransition(State.Ready, Event.CopyingRequested,
                 State.Copying);
-        stateMachines.addTransition(State.Copying, Event.OperationFailed,
-                State.Created);
         stateMachines.addTransition(State.Copying, Event.OperationSuccessed,
                 State.Ready);
-        stateMachines.addTransition(State.Allocated, Event.CreateOnlyRequested,
-                State.Creating2);
-        stateMachines.addTransition(State.Creating2, Event.OperationFailed,
-                State.Allocated);
-        stateMachines.addTransition(State.Creating2, Event.OperationSuccessed,
+        stateMachines.addTransition(State.Copying, Event.OperationFailed,
                 State.Ready);
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
index e95a1f3..11babcb 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
@@ -149,4 +149,10 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
         sc.setParameters("store_role", role);
         return findOneBy(sc);
     }
+
+    @Override
+    public SnapshotDataStoreVO findByStoreSnapshot(long storeId, long snapshotId, boolean lock) {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java b/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java
index 0a91186..a59e594 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java
@@ -88,12 +88,6 @@ public class SnapshotEntityImpl implements SnapshotEntity {
 	}
 
 	@Override
-	public String getPath() {
-		// TODO Auto-generated method stub
-		return null;
-	}
-
-	@Override
 	public String getName() {
 		// TODO Auto-generated method stub
 		return null;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
index 41e3560..567905d 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
@@ -46,6 +46,8 @@ import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.fsm.NoTransitionException;
 import com.cloud.utils.fsm.StateMachine2;
 import com.cloud.utils.storage.encoding.EncodingType;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.dao.VMInstanceDao;
 
 public class VolumeObject implements VolumeInfo {
     private static final Logger s_logger = Logger.getLogger(VolumeObject.class);
@@ -58,6 +60,8 @@ public class VolumeObject implements VolumeInfo {
     VolumeDataStoreDao volumeStoreDao;
     @Inject
     ObjectInDataStoreManager ojbectInStoreMgr;
+    @Inject
+    VMInstanceDao vmInstanceDao;
     private Object payload;
 
     public VolumeObject() {
@@ -74,6 +78,19 @@ public class VolumeObject implements VolumeInfo {
         vo.configure(dataStore, volumeVO);
         return vo;
     }
+    
+    public String getAttachedVmName() {
+        Long vmId = this.volumeVO.getInstanceId();
+        if (vmId != null) {
+            VMInstanceVO vm = vmInstanceDao.findById(vmId);
+
+            if (vm == null) {
+                return null;
+            }
+            return vm.getInstanceName();
+        }
+        return null;
+    }
 
     @Override
     public String getUuid() {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
index e5876b2..b57333e 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
@@ -408,15 +408,17 @@ public class VolumeServiceImpl implements VolumeService {
         private final AsyncCallFuture<VolumeApiResult> future;
         private final DataStore primaryStore;
         private final DataObject templateOnStore;
+        private final SnapshotInfo snapshot;
         public CreateVolumeFromBaseImageContext(AsyncCompletionCallback<T> callback, VolumeObject vo,
                 DataStore primaryStore,
                 DataObject templateOnStore,
-                AsyncCallFuture<VolumeApiResult> future) {
+                AsyncCallFuture<VolumeApiResult> future, SnapshotInfo snapshot) {
             super(callback);
             this.vo = vo;
             this.future = future;
             this.primaryStore = primaryStore;
             this.templateOnStore = templateOnStore;
+            this.snapshot = snapshot;
         }
 
 
@@ -428,7 +430,7 @@ public class VolumeServiceImpl implements VolumeService {
     @DB
     protected void createVolumeFromBaseImageAsync(VolumeInfo volume, DataObject templateOnPrimaryStore, PrimaryDataStore pd, AsyncCallFuture<VolumeApiResult> future) {
         VolumeObject vo = (VolumeObject)volume;
-        CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, vo, pd, templateOnPrimaryStore, future);
+        CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, vo, pd, templateOnPrimaryStore, future, null);
         AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller =  AsyncCallbackDispatcher.create(this);
         caller.setCallback(caller.getTarget().createVolumeFromBaseImageCallBack(null, null))
         .setContext(context);
@@ -497,8 +499,9 @@ public class VolumeServiceImpl implements VolumeService {
         try {
         	DataObject volumeOnStore = store.create(volume);
         	volume.processEvent(Event.CreateOnlyRequested);
+        	snapshot.processEvent(Event.CopyingRequested);
         	 CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null,
-        			 (VolumeObject)volume, store, volumeOnStore, future);
+        			 (VolumeObject)volume, store, volumeOnStore, future, snapshot);
              AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller =  AsyncCallbackDispatcher.create(this);
              caller.setCallback(caller.getTarget().createVolumeFromSnapshotCallback(null, null))
              .setContext(context);
@@ -517,6 +520,7 @@ public class VolumeServiceImpl implements VolumeService {
     		CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
     	CopyCommandResult result = callback.getResult();
     	VolumeInfo volume = context.vo;
+    	SnapshotInfo snapshot = context.snapshot;
     	VolumeApiResult apiResult = new VolumeApiResult(volume);
     	Event event = null;
     	if (result.isFailed()) {
@@ -528,6 +532,7 @@ public class VolumeServiceImpl implements VolumeService {
 
     	try {
     		volume.processEvent(event);
+    		snapshot.processEvent(event);
     	} catch (Exception e) {
     		s_logger.debug("create volume from snapshot failed", e);
     		apiResult.setResult(e.toString());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/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 046827d..cdc8da9 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
@@ -3620,7 +3620,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         return false;
     }
 
-    private void swiftBackupSnapshot(Connection conn, SwiftTO swift, String srUuid, String snapshotUuid, String container, Boolean isISCSI, int wait)  {
+    public void swiftBackupSnapshot(Connection conn, SwiftTO swift, String srUuid, String snapshotUuid, String container, Boolean isISCSI, int wait)  {
         String lfilename;
         String ldir;
         if ( isISCSI ) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java
index 98527a9..8d76241 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java
@@ -18,12 +18,20 @@
  */
 package com.cloud.hypervisor.xen.resource;
 
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -43,6 +51,7 @@ import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
 import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol;
 import org.apache.cloudstack.storage.to.ImageStoreTO;
 import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.apache.cloudstack.storage.to.SnapshotObjectTO;
 import org.apache.cloudstack.storage.to.TemplateObjectTO;
 import org.apache.cloudstack.storage.to.VolumeObjectTO;
 import org.apache.http.HttpEntity;
@@ -54,18 +63,25 @@ import org.apache.log4j.Logger;
 import org.apache.xmlrpc.XmlRpcException;
 
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.BackupSnapshotAnswer;
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.ManageSnapshotAnswer;
+import com.cloud.agent.api.ManageSnapshotCommand;
 import com.cloud.agent.api.storage.CopyVolumeAnswer;
 import com.cloud.agent.api.storage.CreateAnswer;
 import com.cloud.agent.api.storage.DeleteVolumeCommand;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
 import com.cloud.agent.api.to.DataStoreTO;
 import com.cloud.agent.api.to.NfsTO;
+import com.cloud.agent.api.to.S3TO;
 import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.agent.api.to.SwiftTO;
 import com.cloud.agent.api.to.VolumeTO;
 import com.cloud.exception.InternalErrorException;
 import com.cloud.hypervisor.xen.resource.CitrixResourceBase.SRType;
 import com.cloud.storage.DataStoreRole;
+import com.cloud.utils.S3Utils;
+import com.cloud.utils.StringUtils;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.storage.encoding.DecodedDataObject;
 import com.cloud.utils.storage.encoding.DecodedDataStore;
@@ -80,8 +96,6 @@ import com.xensource.xenapi.Types.BadServerResponse;
 import com.xensource.xenapi.Types.XenAPIException;
 import com.xensource.xenapi.VDI;
 
-import edu.emory.mathcs.backport.java.util.Arrays;
-
 public class XenServerStorageResource {
     private static final Logger s_logger = Logger.getLogger(XenServerStorageResource.class);
     protected CitrixResourceBase hypervisorResource;
@@ -146,12 +160,62 @@ public class XenServerStorageResource {
         return new CreateObjectAnswer(cmd, templateUrl, size);*/
         return null;
     }
+    
+    protected CreateObjectAnswer createSnapshot(SnapshotObjectTO snapshotTO) {
+        Connection conn = hypervisorResource.getConnection();
+        long snapshotId = snapshotTO.getId();
+        String snapshotName = snapshotTO.getName();
+        String details = "create snapshot operation Failed for snapshotId: " + snapshotId;
+        String snapshotUUID = null;
+
+        try {
+                String volumeUUID = snapshotTO.getVolume().getPath();
+                VDI volume = VDI.getByUuid(conn, volumeUUID);
+
+                VDI snapshot = volume.snapshot(conn, new HashMap<String, String>());
+
+                if (snapshotName != null) {
+                    snapshot.setNameLabel(conn, snapshotName);
+                }
+
+                snapshotUUID = snapshot.getUuid(conn);
+                String preSnapshotUUID = snapshotTO.getPath();
+                //check if it is a empty snapshot
+                if( preSnapshotUUID != null) {
+                    SR sr = volume.getSR(conn);
+                    String srUUID = sr.getUuid(conn);
+                    String type = sr.getType(conn);
+                    Boolean isISCSI = IsISCSI(type);
+                    String snapshotParentUUID = getVhdParent(conn, srUUID, snapshotUUID, isISCSI);
+
+                    String preSnapshotParentUUID = getVhdParent(conn, srUUID, preSnapshotUUID, isISCSI);
+                    if( snapshotParentUUID != null && snapshotParentUUID.equals(preSnapshotParentUUID)) {
+                        // this is empty snapshot, remove it
+                        snapshot.destroy(conn);
+                        snapshotUUID = preSnapshotUUID;
+                    }
+                }
+                SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
+                newSnapshot.setPath(snapshotUUID);
+                return new CreateObjectAnswer(newSnapshot);
+        } catch (XenAPIException e) {
+            details += ", reason: " + e.toString();
+            s_logger.warn(details, e);
+        } catch (Exception e) {
+            details += ", reason: " + e.toString();
+            s_logger.warn(details, e);
+        }
+
+        return new CreateObjectAnswer(details);
+    }
     protected CreateObjectAnswer execute(CreateObjectCommand cmd) {
        DataTO data = cmd.getData();
        try {
            if (data.getObjectType() == DataObjectType.VOLUME) {
                return createVolume(data);
-           } 
+           } else if (data.getObjectType() == DataObjectType.SNAPSHOT) {
+               return createSnapshot((SnapshotObjectTO)data);
+           }
            return new CreateObjectAnswer("not supported type");
        } catch (Exception e) {
            s_logger.debug("Failed to create object: " + data.getObjectType() + ": " + e.toString());
@@ -821,6 +885,330 @@ public class XenServerStorageResource {
         return new CopyCmdAnswer("unsupported protocol"); 
     }
     
+    boolean swiftUpload(Connection conn, SwiftTO swift, String container, String ldir, String lfilename, Boolean isISCSI, int wait) {
+        String result = null;
+        try {
+            result = hypervisorResource.callHostPluginAsync(conn, "swiftxen", "swift", wait,
+                    "op", "upload", "url", swift.getUrl(), "account", swift.getAccount(),
+                    "username", swift.getUserName(), "key", swift.getKey(), "container", container,
+                    "ldir", ldir, "lfilename", lfilename, "isISCSI", isISCSI.toString());
+            if( result != null && result.equals("true")) {
+                return true;
+            }
+        } catch (Exception e) {
+            s_logger.warn("swift upload failed due to " + e.toString(), e);
+        }
+        return false;
+    }
+    
+    protected String deleteSnapshotBackup(Connection conn, String path, String secondaryStorageMountPath, String backupUUID) {
+
+        // If anybody modifies the formatting below again, I'll skin them
+        String result = hypervisorResource.callHostPlugin(conn, "vmopsSnapshot", "deleteSnapshotBackup", "backupUUID", backupUUID, "path", path, "secondaryStorageMountPath", secondaryStorageMountPath);
+
+        return result;
+    }
+    
+    public void swiftBackupSnapshot(Connection conn, SwiftTO swift, String srUuid, String snapshotUuid, String container, Boolean isISCSI, int wait)  {
+        String lfilename;
+        String ldir;
+        if ( isISCSI ) {
+            ldir = "/dev/VG_XenStorage-" + srUuid;
+            lfilename = "VHD-" + snapshotUuid;
+        } else {
+            ldir = "/var/run/sr-mount/" + srUuid;
+            lfilename = snapshotUuid + ".vhd";
+        }
+        swiftUpload(conn, swift, container, ldir, lfilename, isISCSI, wait);
+    }
+    
+    private static List<String> serializeProperties(final Object object,
+            final Class<?> propertySet) {
+
+        assert object != null;
+        assert propertySet != null;
+        assert propertySet.isAssignableFrom(object.getClass());
+
+        try {
+
+            final BeanInfo beanInfo = Introspector.getBeanInfo(propertySet);
+            final PropertyDescriptor[] descriptors = beanInfo
+                    .getPropertyDescriptors();
+
+            final List<String> serializedProperties = new ArrayList<String>();
+            for (final PropertyDescriptor descriptor : descriptors) {
+
+                serializedProperties.add(descriptor.getName());
+                final Object value = descriptor.getReadMethod().invoke(object);
+                serializedProperties.add(value != null ? value.toString()
+                        : "null");
+
+            }
+
+            return Collections.unmodifiableList(serializedProperties);
+
+        } catch (IntrospectionException e) {
+            s_logger.warn(
+                    "Ignored IntrospectionException when serializing class "
+                            + object.getClass().getCanonicalName(), e);
+        } catch (IllegalArgumentException e) {
+            s_logger.warn(
+                    "Ignored IllegalArgumentException when serializing class "
+                            + object.getClass().getCanonicalName(), e);
+        } catch (IllegalAccessException e) {
+            s_logger.warn(
+                    "Ignored IllegalAccessException when serializing class "
+                            + object.getClass().getCanonicalName(), e);
+        } catch (InvocationTargetException e) {
+            s_logger.warn(
+                    "Ignored InvocationTargetException when serializing class "
+                            + object.getClass().getCanonicalName(), e);
+        }
+
+        return Collections.emptyList();
+
+    }
+    
+    private boolean backupSnapshotToS3(final Connection connection,
+            final S3TO s3, final String srUuid, final String snapshotUuid,
+            final Boolean iSCSIFlag, final int wait) {
+
+        final String filename = iSCSIFlag ? "VHD-" + snapshotUuid
+                : snapshotUuid + ".vhd";
+        final String dir = (iSCSIFlag ? "/dev/VG_XenStorage-"
+                : "/var/run/sr-mount/") + srUuid;
+        final String key = StringUtils.join("/", "snapshots", snapshotUuid);
+
+        try {
+
+            final List<String> parameters = new ArrayList<String>(
+                    serializeProperties(s3, S3Utils.ClientOptions.class));
+            parameters.addAll(Arrays.asList("operation", "put", "directory",
+                    dir, "filename", filename, "iSCSIFlag",
+                    iSCSIFlag.toString(), "key", key));
+            final String result = hypervisorResource.callHostPluginAsync(connection, "s3xen",
+                    "s3", wait,
+                    parameters.toArray(new String[parameters.size()]));
+
+            if (result != null && result.equals("true")) {
+                return true;
+            }
+
+        } catch (Exception e) {
+            s_logger.error(String.format(
+                    "S3 upload failed of snapshot %1$s due to %2$s.",
+                    snapshotUuid, e.toString()), e);
+        }
+
+        return false;
+
+    }
+    
+    protected String backupSnapshot(Connection conn, String primaryStorageSRUuid, String path, String secondaryStorageMountPath, String snapshotUuid, String prevBackupUuid, Boolean isISCSI, int wait) {
+        String backupSnapshotUuid = null;
+
+        if (prevBackupUuid == null) {
+            prevBackupUuid = "";
+        }
+
+        // Each argument is put in a separate line for readability.
+        // Using more lines does not harm the environment.
+        String backupUuid = UUID.randomUUID().toString();
+        String results = hypervisorResource.callHostPluginAsync(conn, "vmopsSnapshot", "backupSnapshot", wait,
+                "primaryStorageSRUuid", primaryStorageSRUuid, "path", path, "secondaryStorageMountPath", secondaryStorageMountPath,
+                "snapshotUuid", snapshotUuid, "prevBackupUuid", prevBackupUuid, "backupUuid", backupUuid, "isISCSI", isISCSI.toString());
+        String errMsg = null;
+        if (results == null || results.isEmpty()) {
+            errMsg = "Could not copy backupUuid: " + backupSnapshotUuid 
+                    + " from primary storage " + primaryStorageSRUuid + " to secondary storage "
+                    + secondaryStorageMountPath + " due to null";
+        } else {
+
+            String[] tmp = results.split("#");
+            String status = tmp[0];
+            backupSnapshotUuid = tmp[1];
+            // status == "1" if and only if backupSnapshotUuid != null
+            // So we don't rely on status value but return backupSnapshotUuid as an
+            // indicator of success.
+            if (status != null && status.equalsIgnoreCase("1") && backupSnapshotUuid != null) {
+                s_logger.debug("Successfully copied backupUuid: " + backupSnapshotUuid
+                        + " to secondary storage");
+                return backupSnapshotUuid;
+            } else {
+                errMsg = "Could not copy backupUuid: " + backupSnapshotUuid
+                        + " from primary storage " + primaryStorageSRUuid + " to secondary storage "
+                        + secondaryStorageMountPath + " due to " + tmp[1];
+            }
+        }
+        String source = backupUuid + ".vhd";
+        hypervisorResource.killCopyProcess(conn, source);
+        s_logger.warn(errMsg);
+        return null;
+
+    }
+    
+    private boolean destroySnapshotOnPrimaryStorageExceptThis(Connection conn, String volumeUuid, String avoidSnapshotUuid){
+        try {
+            VDI volume = getVDIbyUuid(conn, volumeUuid);
+            if (volume == null) {
+                throw new InternalErrorException("Could not destroy snapshot on volume " + volumeUuid + " due to can not find it");
+            }
+            Set<VDI> snapshots = volume.getSnapshots(conn);
+            for( VDI snapshot : snapshots ) {
+                try {
+                    if(! snapshot.getUuid(conn).equals(avoidSnapshotUuid)) {
+                        snapshot.destroy(conn);
+                    }
+                } catch (Exception e) {
+                    String msg = "Destroying snapshot: " + snapshot+ " on primary storage failed due to " + e.toString();
+                    s_logger.warn(msg, e);
+                }
+            }
+            s_logger.debug("Successfully destroyed snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid );
+            return true;
+        } catch (XenAPIException e) {
+            String msg = "Destroying snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid + " failed due to " + e.toString();
+            s_logger.error(msg, e);
+        } catch (Exception e) {
+            String msg = "Destroying snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid + " failed due to " + e.toString();
+            s_logger.warn(msg, e);
+        }
+
+        return false;
+    }
+    
+    protected Answer backupSnasphot(DataTO srcData, DataTO destData, DataTO cacheData, int wait) {
+        Connection conn = hypervisorResource.getConnection();
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)srcData.getDataStore();
+        String primaryStorageNameLabel = primaryStore.getUuid();
+        String secondaryStorageUrl = null;
+        NfsTO cacheStore = null;
+        String destPath = null;
+        if (cacheData != null) {
+            cacheStore = (NfsTO)cacheData.getDataStore();
+            secondaryStorageUrl = cacheStore.getUrl();
+            destPath = cacheData.getPath();
+        } else {
+            cacheStore = (NfsTO)destData.getDataStore();
+            secondaryStorageUrl = cacheStore.getUrl();
+            destPath = destData.getPath();
+        }
+        
+        SnapshotObjectTO snapshotTO = (SnapshotObjectTO)srcData;
+        SnapshotObjectTO snapshotOnImage = (SnapshotObjectTO)destData;
+        String snapshotUuid = snapshotTO.getPath();
+        
+        String prevBackupUuid = snapshotOnImage.getParentSnapshotPath();
+        String prevSnapshotUuid = snapshotTO.getParentSnapshotPath();
+
+        // By default assume failure
+        String details = null;
+        String snapshotBackupUuid = null;
+        boolean fullbackup = true;
+        try {
+            SR primaryStorageSR = hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel);
+            if (primaryStorageSR == null) {
+                throw new InternalErrorException("Could not backup snapshot because the primary Storage SR could not be created from the name label: " + primaryStorageNameLabel);
+            }
+            String psUuid = primaryStorageSR.getUuid(conn);
+            Boolean isISCSI = IsISCSI(primaryStorageSR.getType(conn));
+       
+            VDI snapshotVdi = getVDIbyUuid(conn, snapshotUuid);
+            String snapshotPaUuid = null;
+            if ( prevBackupUuid != null ) {
+                try {
+                    snapshotPaUuid = getVhdParent(conn, psUuid, snapshotUuid, isISCSI);
+                    if( snapshotPaUuid != null ) {
+                        String snashotPaPaPaUuid = getVhdParent(conn, psUuid, snapshotPaUuid, isISCSI);
+                        String prevSnashotPaUuid = getVhdParent(conn, psUuid, prevSnapshotUuid, isISCSI);
+                        if (snashotPaPaPaUuid != null && prevSnashotPaUuid!= null && prevSnashotPaUuid.equals(snashotPaPaPaUuid)) {
+                            fullbackup = false;
+                        }
+                    }
+                } catch (Exception e) {
+                }
+            }
+
+            URI uri = new URI(secondaryStorageUrl);
+            String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
+            DataStoreTO destStore = destData.getDataStore();
+            String folder = destPath;
+            if (fullbackup) {
+                // the first snapshot is always a full snapshot
+               
+                if( !hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, folder)) {
+                    details = " Filed to create folder " + folder + " in secondary storage";
+                    s_logger.warn(details);
+                    return new CopyCmdAnswer(details);
+                }
+                String snapshotMountpoint = secondaryStorageUrl + "/" + folder;
+                SR snapshotSr = null;
+                try {
+                    snapshotSr = hypervisorResource.createNfsSRbyURI(conn, new URI(snapshotMountpoint), false);
+                    VDI backedVdi = hypervisorResource.cloudVDIcopy(conn, snapshotVdi, snapshotSr, wait);
+                    snapshotBackupUuid = backedVdi.getUuid(conn);
+                    
+                    if( destStore instanceof SwiftTO) {
+                        try {
+                            hypervisorResource.swiftBackupSnapshot(conn, (SwiftTO)destStore, snapshotSr.getUuid(conn), snapshotBackupUuid, "S-" + snapshotTO.getVolume().getVolumeId().toString(), false, wait);
+                            snapshotBackupUuid = snapshotBackupUuid + ".vhd";
+                        } finally {
+                            deleteSnapshotBackup(conn, folder, secondaryStorageMountPath, snapshotBackupUuid);
+                        }
+                    } else if (destStore instanceof S3TO) {
+                        try {
+                            backupSnapshotToS3(conn, (S3TO)destStore, snapshotSr.getUuid(conn), snapshotBackupUuid, isISCSI, wait);
+                            snapshotBackupUuid = snapshotBackupUuid + ".vhd";
+                        } finally {
+                            deleteSnapshotBackup(conn, folder, secondaryStorageMountPath, snapshotBackupUuid);
+                        }
+                    }                    
+
+                } finally {
+                    if( snapshotSr != null) {
+                        hypervisorResource.removeSR(conn, snapshotSr);
+                    }
+                }
+            } else {
+                String primaryStorageSRUuid = primaryStorageSR.getUuid(conn);
+                if( destStore instanceof SwiftTO ) {
+                    swiftBackupSnapshot(conn, (SwiftTO)destStore, primaryStorageSRUuid, snapshotPaUuid, "S-" + snapshotTO.getVolume().getVolumeId().toString(), isISCSI, wait);
+                    if ( isISCSI ) {
+                        snapshotBackupUuid = "VHD-" + snapshotPaUuid;
+                    } else {
+                        snapshotBackupUuid = snapshotPaUuid + ".vhd";
+                    }
+
+                } else if (destStore instanceof S3TO ) {
+                    backupSnapshotToS3(conn, (S3TO)destStore, primaryStorageSRUuid, snapshotPaUuid, isISCSI, wait);
+                } else {
+                    snapshotBackupUuid = backupSnapshot(conn, primaryStorageSRUuid, folder + File.separator + UUID.nameUUIDFromBytes(secondaryStorageMountPath.getBytes())
+                             , secondaryStorageMountPath, snapshotUuid, prevBackupUuid, isISCSI, wait);
+
+                }
+            }
+            String volumeUuid = snapshotTO.getVolume().getPath();
+            destroySnapshotOnPrimaryStorageExceptThis(conn, volumeUuid, snapshotUuid);
+            
+            SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
+            newSnapshot.setPath(snapshotBackupUuid);
+            if (fullbackup) {
+                newSnapshot.setParentSnapshotPath(null);
+            } else {
+                newSnapshot.setParentSnapshotPath(prevBackupUuid);
+            }
+            return new CopyCmdAnswer(newSnapshot);
+        } catch (XenAPIException e) {
+            details = "BackupSnapshot Failed due to " + e.toString();
+            s_logger.warn(details, e);
+        } catch (Exception e) {
+            details = "BackupSnapshot Failed due to " + e.getMessage();
+            s_logger.warn(details, e);
+        }
+
+        return new CopyCmdAnswer(details);
+    }
+    
     protected Answer execute(CopyCommand cmd) {
         DataTO srcData = cmd.getSrcTO();
         DataTO destData = cmd.getDestTO();
@@ -838,6 +1226,9 @@ public class XenServerStorageResource {
             return copyVolumeFromImageCacheToPrimary(srcData, destData, cmd.getWait());
         } else if (srcData.getObjectType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
             return copyVolumeFromPrimaryToSecondary(srcData, destData, cmd.getWait());
+        } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
+            DataTO cacheData = cmd.getCacheTO();
+            return backupSnasphot(srcData, destData, cacheData, cmd.getWait());
         }
 
         return new Answer(cmd, false, "not implemented yet");