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/25 03:54:14 UTC

git commit: updated refs/heads/object_store to 4029e7a

Updated Branches:
  refs/heads/object_store 79151f5f5 -> 4029e7af4


refactor data motion service for volumes


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

Branch: refs/heads/object_store
Commit: 4029e7af444c681936935eee85873d2f43d1146e
Parents: 79151f5
Author: Edison Su <su...@gmail.com>
Authored: Wed Apr 24 18:53:36 2013 -0700
Committer: Edison Su <su...@gmail.com>
Committed: Wed Apr 24 18:53:57 2013 -0700

----------------------------------------------------------------------
 .../subsystem/api/storage/CreateCmdResult.java     |   18 ++-
 .../cloudstack/storage/to/TemplateObjectTO.java    |    6 +-
 .../cloudstack/storage/to/VolumeObjectTO.java      |    9 +-
 .../storage/motion/AncientDataMotionStrategy.java  |  106 +++------------
 .../cloudstack/storage/volume/VolumeObject.java    |   13 ++
 .../storage/volume/VolumeServiceImpl.java          |   21 ++--
 .../xen/resource/XenServerStorageResource.java     |   78 +++++++++++-
 .../driver/SampleImageStoreDriverImpl.java         |    2 +-
 8 files changed, 144 insertions(+), 109 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4029e7af/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CreateCmdResult.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CreateCmdResult.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CreateCmdResult.java
index b6d5b68..4b78e54 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CreateCmdResult.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/CreateCmdResult.java
@@ -18,20 +18,26 @@
  */
 package org.apache.cloudstack.engine.subsystem.api.storage;
 
+import com.cloud.agent.api.Answer;
+
 public class CreateCmdResult extends CommandResult {
     private String path;
-    private Long size;
-    public CreateCmdResult(String path, Long size) {
+    private Answer answer;
+    public CreateCmdResult(String path, Answer answer) {
         super();
         this.path = path;
-        this.size = size;
     }
     
     public String getPath() {
         return this.path;
     }
-    
-    public Long getSize() {
-        return this.size;
+
+    public Answer getAnswer() {
+        return answer;
     }
+
+    public void setAnswer(Answer answer) {
+        this.answer = answer;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4029e7af/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java
index 1e72ea0..3a3564a 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java
@@ -28,7 +28,7 @@ public class TemplateObjectTO implements DataTO {
     private  String path;
     private  String uuid;
     private  DiskFormat diskType;
-    private  ImageStoreTO imageDataStore;
+    private  DataStoreTO imageDataStore;
     private  String name;
 
     public TemplateObjectTO() {
@@ -38,7 +38,7 @@ public class TemplateObjectTO implements DataTO {
         this.path = template.getUri();
         this.uuid = template.getUuid();
         //this.diskType = template.getDiskType();
-        this.imageDataStore = new ImageStoreTO((ImageStoreInfo)template.getDataStore());
+        this.imageDataStore = template.getDataStore().getTO();
         this.name = template.getUniqueName();
     }
     
@@ -55,7 +55,7 @@ public class TemplateObjectTO implements DataTO {
         return this.diskType;
     }
     
-    public ImageStoreTO getImageDataStore() {
+    public DataStoreTO getImageDataStore() {
         return this.imageDataStore;
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4029e7af/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 1fecf68..bf1bb3c 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
@@ -18,16 +18,17 @@ 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.PrimaryDataStoreInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat;
 import org.apache.cloudstack.engine.subsystem.api.storage.type.VolumeType;
 
+import com.cloud.agent.api.to.DataStoreTO;
+
 public class VolumeObjectTO implements DataTO {
     private String uuid;
     private VolumeType volumeType;
     private DiskFormat diskType;
-    private PrimaryDataStoreTO dataStore;
+    private DataStoreTO dataStore;
     private String name;
     private long size;
     private String path;
@@ -42,7 +43,7 @@ public class VolumeObjectTO implements DataTO {
         //this.volumeType = volume.getType();
         //this.diskType = volume.getDiskType();
         if (volume.getDataStore() != null) {
-            this.dataStore = new PrimaryDataStoreTO((PrimaryDataStoreInfo)volume.getDataStore());
+            this.dataStore = volume.getDataStore().getTO();
         } else {
             this.dataStore = null;
         }
@@ -66,7 +67,7 @@ public class VolumeObjectTO implements DataTO {
         return this.diskType;
     }
     
-    public PrimaryDataStoreTO getDataStore() {
+    public DataStoreTO getDataStore() {
         return this.dataStore;
     }
     

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4029e7af/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 84d2b16..6a37c9d 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
@@ -141,47 +141,24 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
 
     @DB
     protected Answer copyVolumeFromImage(DataObject srcData, DataObject destData) {
-        String value = configDao.getValue(Config.RecreateSystemVmEnabled.key());
+        String value = configDao.getValue(Config.CopyVolumeWait.key());
         int _copyvolumewait = NumbersUtil.parseInt(value,
                 Integer.parseInt(Config.CopyVolumeWait.getDefaultValue()));
 
-        VolumeDataStoreVO volumeStoreVO = volumeStoreDao.findByVolume(srcData
-                .getId());
-        DataStore srcStore = srcData.getDataStore();
-        String[] volumePath = volumeStoreVO.getInstallPath().split("/");
-        String volumeUUID = volumePath[volumePath.length - 1].split("\\.")[0];
-        StoragePool destPool = (StoragePool) destData.getDataStore();
-        CopyVolumeCommand cvCmd = new CopyVolumeCommand(srcData.getId(),
-                volumeUUID, destPool, srcStore.getUri(), false,
-                _copyvolumewait);
-        CopyVolumeAnswer cvAnswer = null;
-        String errMsg = null;
-        try {
-            cvAnswer = (CopyVolumeAnswer) this.storageMgr.sendToPool(destPool,
-                    cvCmd);
-        } catch (StorageUnavailableException e1) {
-            s_logger.debug("Failed to copy volume " + srcData.getId() + " to "
-                    + destData.getId(), e1);
-            errMsg = e1.toString();
-        }
-
-        if (cvAnswer == null || !cvAnswer.getResult()) {
-            errMsg = cvAnswer.getDetails();
+        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(), _copyvolumewait);
+            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(), _copyvolumewait);
+            EndPoint ep = selector.select(srcData, destData);
+            Answer answer = ep.sendMessage(cmd);
+            return answer;
         }
-
-        VolumeVO vol = this.volDao.findById(destData.getId());
-        Transaction txn = Transaction.currentTxn();
-        txn.start();
-        vol.setPath(cvAnswer.getVolumePath());
-        vol.setFolder(destPool.getPath());
-        vol.setPodId(destPool.getPodId());
-        vol.setPoolId(destPool.getId());
-        vol.setPodId(destPool.getPodId());
-
-        this.volDao.update(vol.getId(), vol);
-        volumeStoreDao.remove(volumeStoreVO.getId());
-        txn.commit();
-        return cvAnswer;
     }
 
     private Answer copyTemplate(DataObject srcData, DataObject destData) {
@@ -195,7 +172,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
             Answer answer = ep.sendMessage(cmd);
             return answer;
         } else {
-            //handle copy it to cache store
+            //handle copy it to/from cache store
             CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _primaryStorageDownloadWait);
             EndPoint ep = selector.select(srcData, destData);
             Answer answer = ep.sendMessage(cmd);
@@ -326,56 +303,15 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
     }
 
     protected Answer copyVolumeBetweenPools(DataObject srcData, DataObject destData) {
-        VolumeInfo volume = (VolumeInfo)srcData;
-        VolumeInfo destVolume = (VolumeInfo)destData;
-        String secondaryStorageURL = this.templateMgr.getSecondaryStorageURL(volume
-                .getDataCenterId());
-        StoragePool srcPool = (StoragePool)this.dataStoreMgr.getDataStore(volume
-                .getPoolId(), DataStoreRole.Primary);
-
-        StoragePool destPool = (StoragePool)this.dataStoreMgr.getDataStore(destVolume.getPoolId(), DataStoreRole.Primary);
-
-        String value = this.configDao.getValue(Config.CopyVolumeWait.toString());
+        String value = configDao.getValue(Config.CopyVolumeWait.key());
         int _copyvolumewait = NumbersUtil.parseInt(value,
                 Integer.parseInt(Config.CopyVolumeWait.getDefaultValue()));
-        CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(),
-                volume.getPath(), srcPool, secondaryStorageURL, true,
-                _copyvolumewait);
-        CopyVolumeAnswer cvAnswer;
-        try {
-            cvAnswer = (CopyVolumeAnswer) this.storageMgr.sendToPool(srcPool, cvCmd);
-        } catch (StorageUnavailableException e1) {
-            throw new CloudRuntimeException(
-                    "Failed to copy the volume from the source primary storage pool to secondary storage.",
-                    e1);
-        }
-
-        if (cvAnswer == null || !cvAnswer.getResult()) {
-            throw new CloudRuntimeException(
-                    "Failed to copy the volume from the source primary storage pool to secondary storage.");
-        }
-
-        String secondaryStorageVolumePath = cvAnswer.getVolumePath();
 
-        cvCmd = new CopyVolumeCommand(volume.getId(),
-                secondaryStorageVolumePath, destPool,
-                secondaryStorageURL, false, _copyvolumewait);
-        try {
-            cvAnswer = (CopyVolumeAnswer) this.storageMgr.sendToPool(destPool, cvCmd);
-        } catch (StorageUnavailableException e1) {
-            throw new CloudRuntimeException(
-                    "Failed to copy the volume from secondary storage to the destination primary storage pool.");
-        }
-
-        if (cvAnswer == null || !cvAnswer.getResult()) {
-            throw new CloudRuntimeException(
-                    "Failed to copy the volume from secondary storage to the destination primary storage pool.");
-        }
-
-        VolumeVO destVol = this.volDao.findById(destVolume.getId());
-        destVol.setPath(cvAnswer.getVolumePath());
-        this.volDao.update(destVol.getId(), destVol);
-        return cvAnswer;
+        DataObject cacheData = cacheMgr.createCacheObject(srcData, destData.getDataStore().getScope());
+        CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _copyvolumewait);
+        EndPoint ep = selector.select(cacheData, destData);
+        Answer answer = ep.sendMessage(cmd);
+        return answer;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4029e7af/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 d5f5fbc..41e3560 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
@@ -29,10 +29,13 @@ 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.datastore.ObjectInDataStoreManager;
+import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
 import org.apache.cloudstack.storage.to.VolumeObjectTO;
 import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.storage.DownloadAnswer;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Volume;
@@ -52,6 +55,8 @@ public class VolumeObject implements VolumeInfo {
     @Inject
     VolumeDao volumeDao;
     @Inject
+    VolumeDataStoreDao volumeStoreDao;
+    @Inject
     ObjectInDataStoreManager ojbectInStoreMgr;
     private Object payload;
 
@@ -357,6 +362,14 @@ public class VolumeObject implements VolumeInfo {
                vol.setSize(newVol.getSize());
                volumeDao.update(vol.getId(), vol);
            }
+       } else if (this.dataStore.getRole() == DataStoreRole.Image) {
+           if (answer instanceof DownloadAnswer) {
+               DownloadAnswer dwdAnswer = (DownloadAnswer)answer;
+               VolumeDataStoreVO volStore = this.volumeStoreDao.findByStoreVolume(this.dataStore.getId(), this.getId());
+               volStore.setInstallPath(dwdAnswer.getInstallPath());
+               volStore.setChecksum(dwdAnswer.getCheckSum());
+               this.volumeStoreDao.update(volStore.getId(), volStore);
+           }
        }
        
        this.processEvent(event);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4029e7af/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 3bf2036..47d99bd 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
@@ -621,7 +621,7 @@ public class VolumeServiceImpl implements VolumeService {
                 return null;
             }
             srcVolume.processEvent(Event.OperationSuccessed);
-            destVolume.processEvent(Event.OperationSuccessed);
+            destVolume.processEvent(Event.OperationSuccessed, result.getAnswer());
             AsyncCallFuture<VolumeApiResult> destroyFuture = this.expungeVolumeAsync(srcVolume);
             destroyFuture.get();
             future.complete(res);
@@ -639,25 +639,28 @@ public class VolumeServiceImpl implements VolumeService {
     public AsyncCallFuture<VolumeApiResult> registerVolume(VolumeInfo volume, DataStore store) {
 
         AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
-        VolumeObject vo = (VolumeObject) volume;
-
-        CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, vo, future);
+        DataObject volumeOnStore = store.create(volume);
+        
+        volumeOnStore.processEvent(Event.CreateOnlyRequested);
+        
+        CreateVolumeContext<VolumeApiResult> context = new CreateVolumeContext<VolumeApiResult>(null, volumeOnStore, future);
         AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher.create(this);
         caller.setCallback(caller.getTarget().registerVolumeCallback(null, null))
         .setContext(context);
 
-        dataObjectMgr.createAsync(volume, store, caller, true);
+        store.getDriver().createAsync(volumeOnStore, caller);
         return future;
     }
 
     protected Void registerVolumeCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> callback, CreateVolumeContext<VolumeApiResult> context) {
         CreateCmdResult result = callback.getResult();
+        
         VolumeObject vo = (VolumeObject)context.volume;
-        /*if (result.isFailed()) {
-            vo.stateTransit(Volume.Event.OperationFailed);
+        if (result.isFailed()) {
+            vo.processEvent(Event.OperationFailed);
         } else {
-            vo.stateTransit(Volume.Event.OperationSucceeded);
-        }*/
+            vo.processEvent(Event.OperationSuccessed, result.getAnswer());
+        }
 
     	_resourceLimitMgr.incrementResourceCount(vo.getAccountId(), ResourceType.secondary_storage,
               	vo.getSize());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4029e7af/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 4c25bfa..9f47e06 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
@@ -55,12 +55,15 @@ import org.apache.xmlrpc.XmlRpcException;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
+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.StorageFilerTO;
 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.exception.CloudRuntimeException;
@@ -774,7 +777,75 @@ public class XenServerStorageResource {
             return new CopyCmdAnswer(e.toString());
         }
     }
- 
+    
+    
+    protected Answer copyVolumeFromImageCacheToPrimary(DataTO srcData, DataTO destData, int wait) {
+        Connection conn = hypervisorResource.getConnection();
+        VolumeObjectTO srcVolume = (VolumeObjectTO)srcData;
+        VolumeObjectTO destVolume = (VolumeObjectTO)destData;
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)destVolume.getDataStore();
+        DataStoreTO srcStore = srcVolume.getDataStore();
+
+        if (srcStore instanceof NfsTO) {
+            NfsTO nfsStore = (NfsTO)srcStore;
+            try {
+                SR primaryStoragePool = hypervisorResource.getStorageRepository(conn, primaryStore.getUuid());
+                String srUuid = primaryStoragePool.getUuid(conn);
+                String volumePath = nfsStore.getUrl() + ":" + srcVolume.getPath();
+                String uuid = copy_vhd_from_secondarystorage(conn, volumePath, srUuid, wait );
+                VolumeObjectTO newVol = new VolumeObjectTO();
+                newVol.setPath(uuid);
+                newVol.setSize(srcVolume.getSize());
+
+                return new CopyCmdAnswer(newVol);
+            } catch (Exception e) {
+                String msg = "Catch Exception " + e.getClass().getName() + " due to " + e.toString();
+                s_logger.warn(msg, e);
+                return new CopyCmdAnswer(e.toString());
+            }
+        }
+        
+        s_logger.debug("unsupported protocol");
+        return new CopyCmdAnswer("unsupported protocol"); 
+    }
+
+    protected Answer copyVolumeFromPrimaryToSecondary(DataTO srcData, DataTO destData, int wait) {
+        Connection conn = hypervisorResource.getConnection();
+        VolumeObjectTO srcVolume = (VolumeObjectTO)srcData;
+        VolumeObjectTO destVolume = (VolumeObjectTO)destData;
+        DataStoreTO destStore = destVolume.getDataStore();
+
+        if (destStore instanceof NfsTO) {
+            SR secondaryStorage = null;
+            try {
+                NfsTO nfsStore = (NfsTO)destStore;
+                URI uri = new URI(nfsStore.getUrl());
+                // Create the volume folder
+                if (!hypervisorResource.createSecondaryStorageFolder(conn, uri.getHost() + ":" + uri.getPath(), destVolume.getPath())) {
+                    throw new InternalErrorException("Failed to create the volume folder.");
+                }
+
+                // Create a SR for the volume UUID folder
+                secondaryStorage = hypervisorResource.createNfsSRbyURI(conn, new URI(nfsStore.getUrl() + destVolume.getPath()), false);
+                // Look up the volume on the source primary storage pool
+                VDI srcVdi = getVDIbyUuid(conn, srcVolume.getPath());
+                // Copy the volume to secondary storage
+                VDI destVdi = hypervisorResource.cloudVDIcopy(conn, srcVdi, secondaryStorage, wait);
+                String destVolumeUUID = destVdi.getUuid(conn);
+
+                VolumeObjectTO newVol = new VolumeObjectTO();
+                newVol.setPath(destVolumeUUID);
+                newVol.setSize(srcVolume.getSize());
+                return new CopyCmdAnswer(newVol);
+            } catch (Exception e) {
+                s_logger.debug("Failed to copy volume to secondary: " + e.toString());
+                return new CopyCmdAnswer("Failed to copy volume to secondary: " + e.toString()); 
+            } finally {
+                hypervisorResource.removeSR(conn, secondaryStorage);
+            }
+        }
+        return new CopyCmdAnswer("unsupported protocol"); 
+    }
     
     protected Answer execute(CopyCommand cmd) {
         DataTO srcData = cmd.getSrcTO();
@@ -788,6 +859,11 @@ public class XenServerStorageResource {
         } else if (srcData.getObjectType() == DataObjectType.TEMPLATE && srcDataStore.getRole() == DataStoreRole.Primary && destDataStore.getRole() == DataStoreRole.Primary) {
             //clone template to a volume
             return cloneVolumeFromBaseTemplate(srcData, destData);
+        } else if (srcData.getObjectType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.ImageCache) {
+            //copy volume from image cache to primary
+            return copyVolumeFromImageCacheToPrimary(srcData, destData, cmd.getWait());
+        } else if (srcData.getObjectType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
+            return copyVolumeFromPrimaryToSecondary(srcData, destData, cmd.getWait());
         }
 
         return new Answer(cmd, false, "not implemented yet");

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4029e7af/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java b/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java
index acf6796..91f9cd0 100644
--- a/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java
+++ b/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java
@@ -101,7 +101,7 @@ public class SampleImageStoreDriverImpl implements ImageStoreDriver {
             if (answer.getResult()) {
                 //update imagestorevo
 
-                result = new CreateCmdResult(answer.getPath(), answer.getSize());
+                result = new CreateCmdResult(answer.getPath(), null);
             } else {
                 result.setResult(answer.getDetails());
             }