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/02/21 20:15:16 UTC

[36/45] git commit: refs/heads/storage_refactor - add copy volume and create volume from snapshot

add copy volume and create volume from snapshot


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

Branch: refs/heads/storage_refactor
Commit: 36efd77a44118ea1ba72852ce8bba02fd202a563
Parents: bb9aac0
Author: Edison Su <su...@gmail.com>
Authored: Fri Feb 8 18:22:00 2013 -0800
Committer: Edison Su <su...@gmail.com>
Committed: Thu Feb 21 10:03:38 2013 -0800

----------------------------------------------------------------------
 api/src/com/cloud/storage/VolumeApiService.java    |    3 +-
 .../api/command/user/volume/MigrateVolumeCmd.java  |    2 +-
 .../storage/motion/AncientDataMotionStrategy.java  |   58 ++++-
 .../storage/volume/VolumeServiceImpl.java          |   97 +++++++-
 server/src/com/cloud/storage/VolumeManager.java    |    8 +-
 .../src/com/cloud/storage/VolumeManagerImpl.java   |  212 +++------------
 .../cloud/storage/snapshot/SnapshotManager.java    |    3 +-
 .../storage/snapshot/SnapshotManagerImpl.java      |    2 +-
 .../com/cloud/vm/VirtualMachineManagerImpl.java    |    2 +-
 9 files changed, 205 insertions(+), 182 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/36efd77a/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 92880f4..8517988 100644
--- a/api/src/com/cloud/storage/VolumeApiService.java
+++ b/api/src/com/cloud/storage/VolumeApiService.java
@@ -21,6 +21,7 @@ package com.cloud.storage;
 import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
+import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
 
@@ -61,7 +62,7 @@ public interface VolumeApiService {
      */
     Volume resizeVolume(ResizeVolumeCmd cmd);
     
-    Volume migrateVolume(Long volumeId, Long storagePoolId) throws ConcurrentOperationException;
+    Volume migrateVolume(MigrateVolumeCmd cmd) throws ConcurrentOperationException;
 
     /**
      * Uploads the volume to secondary storage

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/36efd77a/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java
index 8c09f8f..287241a 100644
--- a/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java
@@ -92,7 +92,7 @@ public class MigrateVolumeCmd extends BaseAsyncCmd {
     public void execute(){
         Volume result;
         try {
-            result = _volumeService.migrateVolume(getVolumeId(), getStoragePoolId());
+            result = _volumeService.migrateVolume(this);
              if (result != null) {
                  VolumeResponse response = _responseGenerator.createVolumeResponse(result);
                  response.setResponseName(getCommandName());

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/36efd77a/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
index 70f65c7..ed3ca6a 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
@@ -329,6 +329,59 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
         
         return errMsg;
     }
+    
+    protected String 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());
+        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.storagMgr.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.storagMgr.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 null;
+    }
 
     @Override
     public Void copyAsync(DataObject srcData, DataObject destData,
@@ -336,7 +389,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
         String errMsg = null;
         try {
             if (destData.getType() == DataObjectType.VOLUME
-                    && srcData.getType() == DataObjectType.VOLUME) {
+                    && srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Image) {
                 errMsg = copyVolumeFromImage(srcData, destData);
             } else if (destData.getType() == DataObjectType.TEMPLATE
                     && srcData.getType() == DataObjectType.TEMPLATE) {
@@ -353,6 +406,9 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
             } else if (srcData.getType() == DataObjectType.TEMPLATE 
                     && destData.getType() == DataObjectType.VOLUME) {
                 errMsg = cloneVolume(srcData, destData);
+            } else if (destData.getType() == DataObjectType.VOLUME
+                    && srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
+                errMsg = copyVolumeBetweenPools(srcData, destData);
             }
         } catch (Exception e) {
             s_logger.debug("copy failed", e);

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/36efd77a/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 891ad12..ef99a49 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
@@ -45,12 +45,14 @@ import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
 import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.storage.StoragePool;
 import com.cloud.storage.Volume;
 import com.cloud.storage.Volume.Type;
 import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.VolumeDao;
 import com.cloud.storage.snapshot.SnapshotManager;
 import com.cloud.utils.db.DB;
+import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.dao.VMInstanceDao;
 
@@ -420,14 +422,105 @@ public class VolumeServiceImpl implements VolumeService {
     @Override
     public AsyncCallFuture<VolumeApiResult> createVolumeFromSnapshot(
             VolumeInfo volume, DataStore store, SnapshotInfo snapshot) {
-        // TODO Auto-generated method stub
+        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
+        VolumeApiResult result = new VolumeApiResult(volume);
         return null;
     }
+    
+    protected VolumeVO duplicateVolumeOnAnotherStorage(Volume volume, StoragePool pool) {
+        Long lastPoolId = volume.getPoolId();
+        VolumeVO newVol = new VolumeVO(volume);
+        newVol.setPoolId(pool.getId());
+        newVol.setFolder(pool.getPath());
+        newVol.setPodId(pool.getPodId());
+        newVol.setPoolId(pool.getId());
+        newVol.setLastPoolId(lastPoolId);
+        newVol.setPodId(pool.getPodId());
+        return this.volDao.persist(newVol);
+    }
+    
 
+    private class CopyVolumeContext<T> extends AsyncRpcConext<T> {
+        final VolumeInfo srcVolume;
+        final VolumeInfo destVolume;
+        final DataStore destStore;
+        final AsyncCallFuture<VolumeApiResult> future;
+        /**
+         * @param callback
+         */
+        public CopyVolumeContext(AsyncCompletionCallback<T> callback, AsyncCallFuture<VolumeApiResult> future, VolumeInfo srcVolume, VolumeInfo destVolume,
+                DataStore destStore) {
+            super(callback);
+            this.srcVolume = srcVolume;
+            this.destVolume = destVolume;
+            this.destStore = destStore;
+            this.future = future;
+        }
+        
+    }
     @Override
     public AsyncCallFuture<VolumeApiResult> copyVolume(VolumeInfo srcVolume,
             DataStore destStore) {
-        // TODO Auto-generated method stub
+        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
+        VolumeApiResult res = new VolumeApiResult(srcVolume);
+        try {
+            if (!this.snapshotMgr.canOperateOnVolume(srcVolume)) {
+                s_logger.debug(
+                        "There are snapshots creating on this volume, can not move this volume");
+                
+                res.setResult("There are snapshots creating on this volume, can not move this volume");
+                future.complete(res);
+                return future;
+            }
+
+            VolumeVO destVol = duplicateVolumeOnAnotherStorage(srcVolume, (StoragePool)destStore);
+            VolumeInfo destVolume = this.volFactory.getVolume(destVol.getId(), destStore);
+            destVolume.processEvent(Event.CreateOnlyRequested);
+            srcVolume.processEvent(Event.CopyingRequested);
+
+            CopyVolumeContext<VolumeApiResult> context = new CopyVolumeContext<VolumeApiResult>(null, future, srcVolume, 
+                    destVolume,
+                    destStore);
+            AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
+            caller.setCallback(caller.getTarget().copyVolumeCallBack(null, null))
+            .setContext(context);
+            this.motionSrv.copyAsync(srcVolume, destVolume, caller);
+        } catch (Exception e) {
+            s_logger.debug("Failed to copy volume", e);
+            res.setResult(e.toString());
+            future.complete(res);
+        }
+        return future;
+    }
+    
+    protected Void copyVolumeCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CopyVolumeContext<VolumeApiResult> context) {
+        VolumeInfo srcVolume = context.srcVolume;
+        VolumeInfo destVolume = context.destVolume;
+        CopyCommandResult result = callback.getResult();
+        AsyncCallFuture<VolumeApiResult> future = context.future;
+        VolumeApiResult res = new VolumeApiResult(destVolume);
+        try {
+            if (result.isFailed()) {
+                res.setResult(result.getResult());
+                destVolume.processEvent(Event.OperationFailed);
+                srcVolume.processEvent(Event.OperationFailed);
+                AsyncCallFuture<VolumeApiResult> destroyFuture = this.expungeVolumeAsync(destVolume);
+                destroyFuture.get();
+                future.complete(res);
+                return null;
+            }
+            srcVolume.processEvent(Event.OperationSuccessed);
+            destVolume.processEvent(Event.OperationSuccessed);
+            AsyncCallFuture<VolumeApiResult> destroyFuture = this.expungeVolumeAsync(srcVolume);
+            destroyFuture.get();
+            future.complete(res);
+            return null;
+        } catch (Exception e) {
+            s_logger.debug("Failed to process copy volume callback",e);
+            res.setResult(e.toString());
+            future.complete(res);
+        }
+        
         return null;
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/36efd77a/server/src/com/cloud/storage/VolumeManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/VolumeManager.java b/server/src/com/cloud/storage/VolumeManager.java
index 41434f4..ebb9e54 100644
--- a/server/src/com/cloud/storage/VolumeManager.java
+++ b/server/src/com/cloud/storage/VolumeManager.java
@@ -21,6 +21,7 @@ package com.cloud.storage;
 import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
+import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
@@ -76,12 +77,11 @@ public interface VolumeManager extends VolumeApiService {
 
     void cleanupVolumes(long vmId) throws ConcurrentOperationException;
 
-    Volume migrateVolume(Long volumeId, Long storagePoolId)
-            throws ConcurrentOperationException;
+    Volume migrateVolume(MigrateVolumeCmd cmd);
 
-    boolean StorageMigration(
+    boolean storageMigration(
             VirtualMachineProfile<? extends VirtualMachine> vm,
-            StoragePool destPool) throws ConcurrentOperationException;
+            StoragePool destPool);
 
     void prepareForMigration(
             VirtualMachineProfile<? extends VirtualMachine> vm,

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/36efd77a/server/src/com/cloud/storage/VolumeManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java
index 8c0e142..573b8e9 100644
--- a/server/src/com/cloud/storage/VolumeManagerImpl.java
+++ b/server/src/com/cloud/storage/VolumeManagerImpl.java
@@ -39,6 +39,7 @@ import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
+import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
@@ -351,11 +352,9 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
             throw new CloudRuntimeException(
                     "Failed to find a storage pool with enough capacity to move the volume to.");
         }
-
-        List<Volume> vols = new ArrayList<Volume>();
-        vols.add(volume);
-        migrateVolumes(vols, destPool);
-        return this.volFactory.getVolume(volume.getId());
+        
+        Volume newVol = migrateVolume(volume, destPool);
+        return this.volFactory.getVolume(newVol.getId());
     }
 
     /*
@@ -1012,10 +1011,15 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
     @DB
     @ActionEvent(eventType = EventTypes.EVENT_VOLUME_RESIZE, eventDescription = "resizing volume", async = true)
     public VolumeVO resizeVolume(ResizeVolumeCmd cmd) {
-        VolumeVO volume = _volsDao.findById(cmd.getEntityId());
         Long newSize = null;
         boolean shrinkOk = cmd.getShrinkOk();
         boolean success = false;
+        
+        VolumeVO volume = _volsDao.findById(cmd.getEntityId());
+        if (volume == null) {
+            throw new InvalidParameterValueException("No such volume");
+        }
+        
         DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume
                 .getDiskOfferingId());
         DiskOfferingVO newDiskOffering = null;
@@ -1039,9 +1043,6 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
                     "Cloudstack currently only supports volumes marked as KVM or XenServer hypervisor for resize");
         }
 
-        if (volume == null) {
-            throw new InvalidParameterValueException("No such volume");
-        }
 
         if (volume.getState() != Volume.State.Ready) {
             throw new InvalidParameterValueException(
@@ -1995,8 +1996,10 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
 
     @DB
     @Override
-    public Volume migrateVolume(Long volumeId, Long storagePoolId)
-            throws ConcurrentOperationException {
+    public Volume migrateVolume(MigrateVolumeCmd cmd) {
+        Long volumeId = cmd.getVolumeId();
+        Long storagePoolId = cmd.getStoragePoolId();
+        
         VolumeVO vol = _volsDao.findById(volumeId);
         if (vol == null) {
             throw new InvalidParameterValueException(
@@ -2025,171 +2028,36 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
                     "Migration of volume from local storage pool is not supported");
         }
 
-        List<Volume> vols = new ArrayList<Volume>();
-        vols.add(vol);
-
-        migrateVolumes(vols, destPool);
-        return vol;
+        Volume newVol = migrateVolume(vol, destPool);
+        return newVol;
     }
 
+    
+    
     @DB
-    public boolean migrateVolumes(List<Volume> volumes, StoragePool destPool)
-            throws ConcurrentOperationException {
-        Transaction txn = Transaction.currentTxn();
-        txn.start();
-
-        boolean transitResult = false;
-        long checkPointTaskId = -1;
-        try {
-            List<Long> volIds = new ArrayList<Long>();
-            for (Volume volume : volumes) {
-                if (!_snapshotMgr.canOperateOnVolume((VolumeVO) volume)) {
-                    throw new CloudRuntimeException(
-                            "There are snapshots creating on this volume, can not move this volume");
-                }
-
-                try {
-                    if (!stateTransitTo(volume, Volume.Event.MigrationRequested)) {
-                        throw new ConcurrentOperationException(
-                                "Failed to transit volume state");
-                    }
-                } catch (NoTransitionException e) {
-                    s_logger.debug("Failed to set state into migrate: "
-                            + e.toString());
-                    throw new CloudRuntimeException(
-                            "Failed to set state into migrate: " + e.toString());
-                }
-                volIds.add(volume.getId());
-            }
-
-            transitResult = true;
-        } finally {
-            if (!transitResult) {
-                txn.rollback();
-            } else {
-                txn.commit();
-            }
-        }
-
-        // At this stage, nobody can modify volumes. Send the copyvolume command
-        List<Pair<StoragePool, DestroyCommand>> destroyCmds = new ArrayList<Pair<StoragePool, DestroyCommand>>();
-        List<CopyVolumeAnswer> answers = new ArrayList<CopyVolumeAnswer>();
+    protected Volume migrateVolume(Volume volume, StoragePool destPool) {
+        VolumeInfo vol = this.volFactory.getVolume(volume.getId());
+        AsyncCallFuture<VolumeApiResult> future = this.volService.copyVolume(vol, (DataStore)destPool);
         try {
-            for (Volume volume : volumes) {
-                String secondaryStorageURL = this._tmpltMgr.getSecondaryStorageURL(volume
-                        .getDataCenterId());
-                StoragePool srcPool = (StoragePool)this.dataStoreMgr.getDataStore(volume
-                        .getPoolId(), DataStoreRole.Primary);
-                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();
-
-                // Copy the volume from secondary storage to the destination
-                // storage
-                // pool
-                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.");
-                }
-
-                answers.add(cvAnswer);
-                destroyCmds.add(new Pair<StoragePool, DestroyCommand>(
-                        srcPool, new DestroyCommand(srcPool, volume, null)));
-            }
-        } finally {
-            if (answers.size() != volumes.size()) {
-                // this means one of copying volume failed
-                for (Volume volume : volumes) {
-                    try {
-                        stateTransitTo(volume, Volume.Event.OperationFailed);
-                    } catch (NoTransitionException e) {
-                        s_logger.debug("Failed to change volume state: "
-                                + e.toString());
-                    }
-                }
-            } else {
-                // Need a transaction, make sure all the volumes get migrated to
-                // new storage pool
-                txn = Transaction.currentTxn();
-                txn.start();
-
-                transitResult = false;
-                try {
-                    for (int i = 0; i < volumes.size(); i++) {
-                        CopyVolumeAnswer answer = answers.get(i);
-                        VolumeVO volume = (VolumeVO) volumes.get(i);
-                        Long oldPoolId = volume.getPoolId();
-                        volume.setPath(answer.getVolumePath());
-                        volume.setFolder(destPool.getPath());
-                        volume.setPodId(destPool.getPodId());
-                        volume.setPoolId(destPool.getId());
-                        volume.setLastPoolId(oldPoolId);
-                        volume.setPodId(destPool.getPodId());
-                        try {
-                            stateTransitTo(volume,
-                                    Volume.Event.OperationSucceeded);
-                        } catch (NoTransitionException e) {
-                            s_logger.debug("Failed to change volume state: "
-                                    + e.toString());
-                            throw new CloudRuntimeException(
-                                    "Failed to change volume state: "
-                                            + e.toString());
-                        }
-                    }
-                    transitResult = true;
-                } finally {
-                    if (!transitResult) {
-                        txn.rollback();
-                    } else {
-                        txn.commit();
-                    }
-                }
-
-            }
-        }
-
-        // all the volumes get migrated to new storage pool, need to delete the
-        // copy on old storage pool
-        for (Pair<StoragePool, DestroyCommand> cmd : destroyCmds) {
-            try {
-                Answer cvAnswer = this.storageMgr.sendToPool(cmd.first(), cmd.second());
-            } catch (StorageUnavailableException e) {
-                s_logger.debug("Unable to delete the old copy on storage pool: "
-                        + e.toString());
+            VolumeApiResult result = future.get();
+            if (result.isFailed()) {
+                s_logger.debug("migrate volume failed:" + result.getResult());
+                return null;
             }
+            return result.getVolume();
+        } catch (InterruptedException e) {
+            s_logger.debug("migrate volume failed", e);
+            return null;
+        } catch (ExecutionException e) {
+            s_logger.debug("migrate volume failed", e);
+            return null;
         }
-        return true;
     }
 
     @Override
-    public boolean StorageMigration(
+    public boolean storageMigration(
             VirtualMachineProfile<? extends VirtualMachine> vm,
-            StoragePool destPool) throws ConcurrentOperationException {
+            StoragePool destPool) {
         List<VolumeVO> vols = _volsDao.findUsableVolumesForInstance(vm.getId());
         List<Volume> volumesNeedToMigrate = new ArrayList<Volume>();
 
@@ -2215,7 +2083,13 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
             return true;
         }
 
-        return migrateVolumes(volumesNeedToMigrate, destPool);
+        for (Volume vol : volumesNeedToMigrate) {
+            Volume result = migrateVolume(vol, destPool);
+            if (result == null) {
+                return false;
+            }
+        }
+        return true;
     }
     
     @Override
@@ -2452,9 +2326,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
                 vol = task.volume;
             } else if (task.type == VolumeTaskType.MIGRATE) {
                 pool = (StoragePool)dataStoreMgr.getDataStore(task.pool.getId(), DataStoreRole.Primary);
-                List<Volume> volumes = new ArrayList<Volume>();
-                volumes.add(task.volume);
-                migrateVolumes(volumes, pool);
+                migrateVolume(task.volume, pool);
                 vol = task.volume;
             } else if (task.type == VolumeTaskType.RECREATE) {
                 Pair<VolumeVO, DataStore> result = recreateVolume(task.volume, vm, dest);

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/36efd77a/server/src/com/cloud/storage/snapshot/SnapshotManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManager.java b/server/src/com/cloud/storage/snapshot/SnapshotManager.java
index a7692de..72e8163 100755
--- a/server/src/com/cloud/storage/snapshot/SnapshotManager.java
+++ b/server/src/com/cloud/storage/snapshot/SnapshotManager.java
@@ -22,6 +22,7 @@ import com.cloud.exception.ResourceAllocationException;
 import com.cloud.host.HostVO;
 import com.cloud.storage.SnapshotPolicyVO;
 import com.cloud.storage.SnapshotVO;
+import com.cloud.storage.Volume;
 import com.cloud.storage.VolumeVO;
 import com.cloud.utils.db.Filter;
 
@@ -138,5 +139,5 @@ public interface SnapshotManager {
 
     void deleteSnapshotsDirForVolume(String secondaryStoragePoolUrl, Long dcId, Long accountId, Long volumeId);
 
-	boolean canOperateOnVolume(VolumeVO volume);
+	boolean canOperateOnVolume(Volume volume);
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/36efd77a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
index 6b48b82..58ca9a4 100755
--- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
+++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
@@ -1578,7 +1578,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
     }
     
     @Override
-    public boolean canOperateOnVolume(VolumeVO volume) {
+    public boolean canOperateOnVolume(Volume volume) {
         List<SnapshotVO> snapshots = _snapshotDao.listByStatus(volume.getId(), Snapshot.State.Creating,
                 Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp);
     	if (snapshots.size() > 0) {

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/36efd77a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
index 5d48f14..4b7a4db 100755
--- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -1226,7 +1226,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
         boolean migrationResult = false;
         try {
-            migrationResult = this.volumeMgr.StorageMigration(profile, destPool);
+            migrationResult = this.volumeMgr.storageMigration(profile, destPool);
 
             if (migrationResult) {
                 //if the vm is migrated to different pod in basic mode, need to reallocate ip