Repository: cloudstack
Updated Branches:
  refs/heads/master 240e8ef8a -> 0f84e042b


Adding support for creating a volume from a snapshot when the snapshot is on 
managed storage


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

Branch: refs/heads/master
Commit: 0f84e042b99e58e3d2293c0a988e1baa019c8c56
Parents: 240e8ef
Author: Mike Tutkowski <[email protected]>
Authored: Wed Jan 7 17:21:52 2015 -0700
Committer: Mike Tutkowski <[email protected]>
Committed: Tue Jan 20 15:24:33 2015 -0700

----------------------------------------------------------------------
 .../cloudstack/storage/command/CopyCommand.java |  13 +-
 .../service/VolumeOrchestrationService.java     |   1 +
 .../orchestration/VolumeOrchestrator.java       |  54 +++-
 .../src/com/cloud/storage/SnapshotVO.java       |  18 +-
 .../schema/src/com/cloud/storage/VolumeVO.java  |   3 +-
 .../motion/StorageSystemDataMotionStrategy.java | 279 +++++++++++++++----
 .../cloudstack/storage/volume/VolumeObject.java |   4 -
 .../resource/XenServerStorageProcessor.java     |  49 ++++
 .../resource/Xenserver625StorageProcessor.java  |   6 +-
 server/src/com/cloud/api/ApiResponseHelper.java |   8 +-
 .../com/cloud/storage/VolumeApiServiceImpl.java |   3 +
 .../storage/snapshot/SnapshotManagerImpl.java   |   8 +-
 .../com/cloud/template/TemplateManagerImpl.java |  29 +-
 setup/db/db/schema-450to460.sql                 |   3 +
 14 files changed, 378 insertions(+), 100 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/core/src/org/apache/cloudstack/storage/command/CopyCommand.java
----------------------------------------------------------------------
diff --git a/core/src/org/apache/cloudstack/storage/command/CopyCommand.java 
b/core/src/org/apache/cloudstack/storage/command/CopyCommand.java
index 08b4b51..cfede14 100644
--- a/core/src/org/apache/cloudstack/storage/command/CopyCommand.java
+++ b/core/src/org/apache/cloudstack/storage/command/CopyCommand.java
@@ -29,8 +29,9 @@ public final class CopyCommand extends Command implements 
StorageSubSystemComman
     private DataTO srcTO;
     private DataTO destTO;
     private DataTO cacheTO;
-    boolean executeInSequence = false;
-    Map<String, String> options = new HashMap<String, String>();
+    private boolean executeInSequence = false;
+    private Map<String, String> options = new HashMap<String, String>();
+    private Map<String, String> options2 = new HashMap<String, String>();
 
     public CopyCommand(DataTO srcData, DataTO destData, int timeout, boolean 
executeInSequence) {
         super();
@@ -81,6 +82,14 @@ public final class CopyCommand extends Command implements 
StorageSubSystemComman
         return options;
     }
 
+    public void setOptions2(Map<String, String> options2) {
+        this.options2 = options2;
+    }
+
+    public Map<String, String> getOptions2() {
+        return options2;
+    }
+
     @Override
     public void setExecuteInSequence(boolean inSeq) {
         this.executeInSequence = inSeq;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
----------------------------------------------------------------------
diff --git 
a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
 
b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
index 1f198a2..497db3d 100644
--- 
a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
+++ 
b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
@@ -125,4 +125,5 @@ public interface VolumeOrchestrationService {
 
     void updateVolumeDiskChain(long volumeId, String path, String chainInfo);
 
+    VolumeInfo updateHypervisorSnapshotReserveForVolume(DiskOffering 
diskOffering, VolumeInfo volumeInfo, HypervisorType hyperType);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
----------------------------------------------------------------------
diff --git 
a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
 
b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
index 396a49c..ab90fa7 100644
--- 
a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
+++ 
b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
@@ -36,6 +36,7 @@ import 
org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationSer
 import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import 
org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
@@ -59,6 +60,7 @@ import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
 import org.apache.cloudstack.storage.command.CommandResult;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
@@ -374,16 +376,23 @@ public class VolumeOrchestrator extends ManagerBase 
implements VolumeOrchestrati
 
         VolumeInfo vol = volFactory.getVolume(volume.getId());
         DataStore store = dataStoreMgr.getDataStore(pool.getId(), 
DataStoreRole.Primary);
-        SnapshotInfo snapInfo = snapshotFactory.getSnapshot(snapshot.getId(), 
DataStoreRole.Image);
-        // sync snapshot to region store if necessary
-        DataStore snapStore = snapInfo.getDataStore();
-        long snapVolId = snapInfo.getVolumeId();
-        try {
-            _snapshotSrv.syncVolumeSnapshotsToRegionStore(snapVolId, 
snapStore);
-        } catch (Exception ex) {
-            // log but ignore the sync error to avoid any potential S3 down 
issue, it should be sync next time
-            s_logger.warn(ex.getMessage(), ex);
+        DataStoreRole dataStoreRole = getDataStoreRole(snapshot);
+        SnapshotInfo snapInfo = snapshotFactory.getSnapshot(snapshot.getId(), 
dataStoreRole);
+
+        // don't try to perform a sync if the DataStoreRole of the snapshot is 
equal to DataStoreRole.Primary
+        if (!DataStoreRole.Primary.equals(dataStoreRole)) {
+            try {
+                // sync snapshot to region store if necessary
+                DataStore snapStore = snapInfo.getDataStore();
+                long snapVolId = snapInfo.getVolumeId();
+
+                _snapshotSrv.syncVolumeSnapshotsToRegionStore(snapVolId, 
snapStore);
+            } catch (Exception ex) {
+                // log but ignore the sync error to avoid any potential S3 
down issue, it should be sync next time
+                s_logger.warn(ex.getMessage(), ex);
+            }
         }
+
         // create volume on primary from snapshot
         AsyncCallFuture<VolumeApiResult> future = 
volService.createVolumeFromSnapshot(vol, store, snapInfo);
         try {
@@ -403,6 +412,30 @@ public class VolumeOrchestrator extends ManagerBase 
implements VolumeOrchestrati
 
     }
 
+    public DataStoreRole getDataStoreRole(Snapshot snapshot) {
+        SnapshotDataStoreVO snapshotStore = 
_snapshotDataStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Primary);
+
+        if (snapshotStore == null) {
+            return DataStoreRole.Image;
+        }
+
+        long storagePoolId = snapshotStore.getDataStoreId();
+        DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, 
DataStoreRole.Primary);
+
+        Map<String, String> mapCapabilities = 
dataStore.getDriver().getCapabilities();
+
+        if (mapCapabilities != null) {
+            String value = 
mapCapabilities.get(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString());
+            Boolean supportsStorageSystemSnapshots = new Boolean(value);
+
+            if (supportsStorageSystemSnapshots) {
+                return DataStoreRole.Primary;
+            }
+        }
+
+        return DataStoreRole.Image;
+    }
+
     protected DiskProfile createDiskCharacteristics(VolumeInfo volume, 
VirtualMachineTemplate template, DataCenter dc, DiskOffering diskOffering) {
         if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != 
template.getFormat()) {
             TemplateDataStoreVO ss = 
_vmTemplateStoreDao.findByTemplateZoneDownloadStatus(template.getId(), 
dc.getId(), VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
@@ -517,7 +550,8 @@ public class VolumeOrchestrator extends ManagerBase 
implements VolumeOrchestrati
     // The disk offering can collect this information and pass it on to the 
volume that's about to be created.
     // Ex. if you want a 10 GB CloudStack volume to reside on managed storage 
on Xen, this leads to an SR
     // that is a total size of (10 GB * (hypervisorSnapshotReserveSpace / 100) 
+ 10 GB).
-    private VolumeInfo updateHypervisorSnapshotReserveForVolume(DiskOffering 
diskOffering, VolumeInfo volumeInfo, HypervisorType hyperType) {
+    @Override
+    public VolumeInfo updateHypervisorSnapshotReserveForVolume(DiskOffering 
diskOffering, VolumeInfo volumeInfo, HypervisorType hyperType) {
         Integer hypervisorSnapshotReserve = 
diskOffering.getHypervisorSnapshotReserve();
 
         if (hyperType == HypervisorType.KVM) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/engine/schema/src/com/cloud/storage/SnapshotVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/storage/SnapshotVO.java 
b/engine/schema/src/com/cloud/storage/SnapshotVO.java
index dae049f..950c5e9 100644
--- a/engine/schema/src/com/cloud/storage/SnapshotVO.java
+++ b/engine/schema/src/com/cloud/storage/SnapshotVO.java
@@ -92,12 +92,18 @@ public class SnapshotVO implements Snapshot {
     @Column(name = "uuid")
     String uuid;
 
+    @Column(name = "min_iops")
+    Long minIops;
+
+    @Column(name = "max_iops")
+    Long maxIops;
+
     public SnapshotVO() {
         uuid = UUID.randomUUID().toString();
     }
 
     public SnapshotVO(long dcId, long accountId, long domainId, Long volumeId, 
Long diskOfferingId, String name, short snapshotType, String typeDescription, 
long size,
-            HypervisorType hypervisorType) {
+            Long minIops, Long maxIops, HypervisorType hypervisorType) {
         dataCenterId = dcId;
         this.accountId = accountId;
         this.domainId = domainId;
@@ -107,6 +113,8 @@ public class SnapshotVO implements Snapshot {
         this.snapshotType = snapshotType;
         this.typeDescription = typeDescription;
         this.size = size;
+        this.minIops = minIops;
+        this.maxIops = maxIops;
         state = State.Allocated;
         this.hypervisorType = hypervisorType;
         version = "2.2";
@@ -184,6 +192,14 @@ public class SnapshotVO implements Snapshot {
         return size;
     }
 
+    public Long getMinIops() {
+        return minIops;
+    }
+
+    public Long getMaxIops() {
+        return maxIops;
+    }
+
     public String getTypeDescription() {
         return typeDescription;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/engine/schema/src/com/cloud/storage/VolumeVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/storage/VolumeVO.java 
b/engine/schema/src/com/cloud/storage/VolumeVO.java
index e2f717d..d8323e9 100644
--- a/engine/schema/src/com/cloud/storage/VolumeVO.java
+++ b/engine/schema/src/com/cloud/storage/VolumeVO.java
@@ -164,7 +164,7 @@ public class VolumeVO implements Volume {
     String reservationId;
 
     @Column(name = "hv_ss_reserve")
-    Integer hypervisorSnapshotReserve;
+    private Integer hypervisorSnapshotReserve;
 
     // Real Constructor
     public VolumeVO(Type type, String name, long dcId, long domainId,
@@ -628,7 +628,6 @@ public class VolumeVO implements Volume {
     @Override
     public Integer getHypervisorSnapshotReserve() {
         return hypervisorSnapshotReserve;
-
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java
----------------------------------------------------------------------
diff --git 
a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java
 
b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java
index cf9e9dc..525aa70 100644
--- 
a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java
+++ 
b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java
@@ -27,6 +27,8 @@ import javax.inject.Inject;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
+import 
org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
+import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
@@ -34,8 +36,13 @@ import 
org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import 
org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority;
+import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
+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.VolumeService;
+import 
org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
+import 
org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult;
+import org.apache.cloudstack.framework.async.AsyncCallFuture;
 import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.storage.command.CopyCommand;
@@ -56,8 +63,15 @@ import com.cloud.org.Grouping.AllocationState;
 import com.cloud.resource.ResourceState;
 import com.cloud.server.ManagementService;
 import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.DiskOfferingVO;
+import com.cloud.storage.SnapshotVO;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.Storage.ImageFormat;
+import com.cloud.storage.dao.DiskOfferingDao;
+import com.cloud.storage.dao.SnapshotDao;
 import com.cloud.storage.dao.SnapshotDetailsDao;
 import com.cloud.storage.dao.SnapshotDetailsVO;
+import com.cloud.storage.dao.VolumeDao;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.VirtualMachineManager;
@@ -68,16 +82,30 @@ public class StorageSystemDataMotionStrategy implements 
DataMotionStrategy {
 
     @Inject private AgentManager _agentMgr;
     @Inject private ConfigurationDao _configDao;
+    @Inject private DiskOfferingDao _diskOfferingDao;
     @Inject private HostDao _hostDao;
     @Inject private ManagementService _mgr;
     @Inject private PrimaryDataStoreDao _storagePoolDao;
+    @Inject private SnapshotDao _snapshotDao;
     @Inject private SnapshotDetailsDao _snapshotDetailsDao;
-    @Inject private VolumeService _volService;
+    @Inject private VolumeDao _volumeDao;
+    @Inject private VolumeDataFactory _volumeDataFactory;
+    @Inject private VolumeOrchestrationService _volumeMgr;
+    @Inject private VolumeService _volumeService;
 
     @Override
     public StrategyPriority canHandle(DataObject srcData, DataObject destData) 
{
-        if (srcData instanceof SnapshotInfo && 
destData.getDataStore().getRole() == DataStoreRole.Image || 
destData.getDataStore().getRole() == DataStoreRole.ImageCache) {
-            DataStore dataStore = srcData.getDataStore();
+        if (srcData instanceof SnapshotInfo) {
+            if (canHandle(srcData.getDataStore()) || 
canHandle(destData.getDataStore())) {
+                return StrategyPriority.HIGHEST;
+            }
+        }
+
+        return StrategyPriority.CANT_HANDLE;
+    }
+
+    private boolean canHandle(DataStore dataStore) {
+        if (dataStore.getRole() == DataStoreRole.Primary) {
             Map<String, String> mapCapabilities = 
dataStore.getDriver().getCapabilities();
 
             if (mapCapabilities != null) {
@@ -87,12 +115,12 @@ public class StorageSystemDataMotionStrategy implements 
DataMotionStrategy {
                 if (supportsStorageSystemSnapshots) {
                     s_logger.info("Using 'StorageSystemDataMotionStrategy'");
 
-                    return StrategyPriority.HIGHEST;
+                    return true;
                 }
             }
         }
 
-        return StrategyPriority.CANT_HANDLE;
+        return false;
     }
 
     @Override
@@ -102,75 +130,207 @@ public class StorageSystemDataMotionStrategy implements 
DataMotionStrategy {
 
     @Override
     public Void copyAsync(DataObject srcData, DataObject destData, Host 
destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
-        if (srcData instanceof SnapshotInfo && 
destData.getDataStore().getRole() == DataStoreRole.Image || 
destData.getDataStore().getRole() == DataStoreRole.ImageCache) {
+        if (srcData instanceof SnapshotInfo) {
             SnapshotInfo snapshotInfo = (SnapshotInfo)srcData;
-            HostVO hostVO = getHost(srcData);
-            DataStore srcDataStore = srcData.getDataStore();
 
-            String value = 
_configDao.getValue(Config.PrimaryStorageDownloadWait.toString());
-            int primaryStorageDownloadWait = NumbersUtil.parseInt(value, 
Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue()));
-            CopyCommand copyCommand = new CopyCommand(srcData.getTO(), 
destData.getTO(), primaryStorageDownloadWait, 
VirtualMachineManager.ExecuteInSequence.value());
+            validate(snapshotInfo);
 
-            CopyCmdAnswer copyCmdAnswer = null;
+            boolean canHandleSrc = canHandle(srcData.getDataStore());
 
-            try {
-                _volService.grantAccess(snapshotInfo, hostVO, srcDataStore);
+            if (canHandleSrc && destData instanceof TemplateInfo &&
+                    (destData.getDataStore().getRole() == DataStoreRole.Image 
|| destData.getDataStore().getRole() == DataStoreRole.ImageCache)) {
+                return handleCreateTemplateFromSnapshot(snapshotInfo, 
(TemplateInfo)destData, callback);
+            }
 
-                Map<String, String> srcDetails = 
getSourceDetails(_storagePoolDao.findById(srcDataStore.getId()), snapshotInfo);
+            if (destData instanceof VolumeInfo) {
+                VolumeInfo volumeInfo = (VolumeInfo)destData;
+
+                boolean canHandleDest = canHandle(destData.getDataStore());
+
+                if (canHandleSrc && canHandleDest) {
+                    return 
handleCreateVolumeFromSnapshotBothOnStorageSystem(snapshotInfo, volumeInfo, 
callback);
+                }
 
-                copyCommand.setOptions(srcDetails);
+                if (canHandleSrc) {
+                    // return 
handleCreateVolumeFromSnapshotOnlySourceOnStorageSystem();
+                }
 
-                copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), 
copyCommand);
+                if (canHandleDest) {
+                    // return 
handleCreateVolumeFromSnapshotOnlyDestinationOnStorageSystem();
+                }
+            }
+        }
+
+        throw new UnsupportedOperationException("This operation is not 
supported.");
+    }
+
+    private void validate(SnapshotInfo snapshotInfo) {
+        long volumeId = snapshotInfo.getVolumeId();
+
+        VolumeVO volumeVO = _volumeDao.findByIdIncludingRemoved(volumeId);
+
+        if (volumeVO.getFormat() != ImageFormat.VHD) {
+            throw new CloudRuntimeException("Only the " + 
ImageFormat.VHD.toString() + " image type is currently supported.");
+        }
+    }
+
+    private Void handleCreateTemplateFromSnapshot(SnapshotInfo snapshotInfo, 
TemplateInfo templateInfo, AsyncCompletionCallback<CopyCommandResult> callback) 
{
+        HostVO hostVO = getHost(snapshotInfo.getDataStore().getId());
+        DataStore srcDataStore = snapshotInfo.getDataStore();
+
+        String value = 
_configDao.getValue(Config.PrimaryStorageDownloadWait.toString());
+        int primaryStorageDownloadWait = NumbersUtil.parseInt(value, 
Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue()));
+        CopyCommand copyCommand = new CopyCommand(snapshotInfo.getTO(), 
templateInfo.getTO(), primaryStorageDownloadWait, 
VirtualMachineManager.ExecuteInSequence.value());
+
+        CopyCmdAnswer copyCmdAnswer = null;
+
+        try {
+            _volumeService.grantAccess(snapshotInfo, hostVO, srcDataStore);
+
+            Map<String, String> srcDetails = 
getSnapshotDetails(_storagePoolDao.findById(srcDataStore.getId()), 
snapshotInfo);
+
+            copyCommand.setOptions(srcDetails);
+
+            copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), 
copyCommand);
+        }
+        catch (Exception ex) {
+            throw new CloudRuntimeException(ex.getMessage());
+        }
+        finally {
+            try {
+                _volumeService.revokeAccess(snapshotInfo, hostVO, 
srcDataStore);
             }
             catch (Exception ex) {
-                throw new CloudRuntimeException(ex.getMessage());
+                s_logger.debug(ex.getMessage(), ex);
             }
-            finally {
-                try {
-                    _volService.revokeAccess(snapshotInfo, hostVO, 
srcDataStore);
-                }
-                catch (Exception ex) {
-                    s_logger.debug(ex.getMessage(), ex);
-                }
+        }
+
+        String errMsg = null;
+
+        if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) {
+            if (copyCmdAnswer != null && copyCmdAnswer.getDetails() != null && 
!copyCmdAnswer.getDetails().isEmpty()) {
+                errMsg = copyCmdAnswer.getDetails();
+            }
+            else {
+                errMsg = "Unable to perform host-side operation";
             }
+        }
 
-            String errMsg = null;
+        CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer);
 
-            if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) {
-                if (copyCmdAnswer != null && copyCmdAnswer.getDetails() != 
null && !copyCmdAnswer.getDetails().isEmpty()) {
-                    errMsg = copyCmdAnswer.getDetails();
-                }
-                else {
-                    errMsg = "Unable to perform host-side operation";
-                }
+        result.setResult(errMsg);
+
+        callback.complete(result);
+
+        return null;
+    }
+
+    private Void 
handleCreateVolumeFromSnapshotBothOnStorageSystem(SnapshotInfo snapshotInfo, 
VolumeInfo volumeInfo, AsyncCompletionCallback<CopyCommandResult> callback) {
+        try {
+            // at this point, the snapshotInfo and volumeInfo should have the 
same disk offering ID (so either one should be OK to get a DiskOfferingVO 
instance)
+            DiskOfferingVO diskOffering = 
_diskOfferingDao.findByIdIncludingRemoved(volumeInfo.getDiskOfferingId());
+            SnapshotVO snapshot = _snapshotDao.findById(snapshotInfo.getId());
+
+            // update the volume's hypervisor_ss_reserve from its disk 
offering (used for managed storage)
+            _volumeMgr.updateHypervisorSnapshotReserveForVolume(diskOffering, 
volumeInfo, snapshot.getHypervisorType());
+
+            AsyncCallFuture<VolumeApiResult> future = 
_volumeService.createVolumeAsync(volumeInfo, volumeInfo.getDataStore());
+
+            VolumeApiResult result = future.get();
+
+            if (result.isFailed()) {
+                s_logger.debug("Failed to create a volume: " + 
result.getResult());
+
+                throw new CloudRuntimeException(result.getResult());
+            }
+        }
+        catch (Exception ex) {
+            throw new CloudRuntimeException(ex.getMessage());
+        }
+
+        volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), 
volumeInfo.getDataStore());
+
+        volumeInfo.processEvent(Event.MigrationRequested);
+
+        volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), 
volumeInfo.getDataStore());
+
+        HostVO hostVO = getHost(snapshotInfo.getDataStore().getId());
+
+        String value = 
_configDao.getValue(Config.PrimaryStorageDownloadWait.toString());
+        int primaryStorageDownloadWait = NumbersUtil.parseInt(value, 
Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue()));
+        CopyCommand copyCommand = new CopyCommand(snapshotInfo.getTO(), 
volumeInfo.getTO(), primaryStorageDownloadWait, 
VirtualMachineManager.ExecuteInSequence.value());
+
+        CopyCmdAnswer copyCmdAnswer = null;
+
+        try {
+            _volumeService.grantAccess(snapshotInfo, hostVO, 
snapshotInfo.getDataStore());
+            _volumeService.grantAccess(volumeInfo, hostVO, 
volumeInfo.getDataStore());
+
+            Map<String, String> srcDetails = 
getSnapshotDetails(_storagePoolDao.findById(snapshotInfo.getDataStore().getId()),
 snapshotInfo);
+
+            copyCommand.setOptions(srcDetails);
+
+            Map<String, String> destDetails = getVolumeDetails(volumeInfo);
+
+            copyCommand.setOptions2(destDetails);
+
+            copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), 
copyCommand);
+        }
+        catch (Exception ex) {
+            throw new CloudRuntimeException(ex.getMessage());
+        }
+        finally {
+            try {
+                _volumeService.revokeAccess(snapshotInfo, hostVO, 
snapshotInfo.getDataStore());
+            }
+            catch (Exception ex) {
+                s_logger.debug(ex.getMessage(), ex);
             }
 
-            CopyCommandResult result = new CopyCommandResult(null, 
copyCmdAnswer);
+            try {
+                _volumeService.revokeAccess(volumeInfo, hostVO, 
volumeInfo.getDataStore());
+            }
+            catch (Exception ex) {
+                s_logger.debug(ex.getMessage(), ex);
+            }
+        }
 
-            result.setResult(errMsg);
+        String errMsg = null;
 
-            callback.complete(result);
+        if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) {
+            if (copyCmdAnswer != null && copyCmdAnswer.getDetails() != null && 
!copyCmdAnswer.getDetails().isEmpty()) {
+                errMsg = copyCmdAnswer.getDetails();
+            }
+            else {
+                errMsg = "Unable to perform host-side operation";
+            }
         }
 
+        CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer);
+
+        result.setResult(errMsg);
+
+        callback.complete(result);
+
         return null;
     }
 
-    private Map<String, String> getSourceDetails(StoragePoolVO storagePoolVO, 
SnapshotInfo snapshotInfo) {
-        Map<String, String> srcDetails = new HashMap<String, String>();
+    private Map<String, String> getSnapshotDetails(StoragePoolVO 
storagePoolVO, SnapshotInfo snapshotInfo) {
+        Map<String, String> details = new HashMap<String, String>();
 
-        srcDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress());
-        srcDetails.put(DiskTO.STORAGE_PORT, 
String.valueOf(storagePoolVO.getPort()));
+        details.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress());
+        details.put(DiskTO.STORAGE_PORT, 
String.valueOf(storagePoolVO.getPort()));
 
         long snapshotId = snapshotInfo.getId();
 
-        srcDetails.put(DiskTO.IQN, getProperty(snapshotId, DiskTO.IQN));
+        details.put(DiskTO.IQN, getProperty(snapshotId, DiskTO.IQN));
 
-        srcDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, getProperty(snapshotId, 
DiskTO.CHAP_INITIATOR_USERNAME));
-        srcDetails.put(DiskTO.CHAP_INITIATOR_SECRET, getProperty(snapshotId, 
DiskTO.CHAP_INITIATOR_SECRET));
-        srcDetails.put(DiskTO.CHAP_TARGET_USERNAME, getProperty(snapshotId, 
DiskTO.CHAP_TARGET_USERNAME));
-        srcDetails.put(DiskTO.CHAP_TARGET_SECRET, getProperty(snapshotId, 
DiskTO.CHAP_TARGET_SECRET));
+        details.put(DiskTO.CHAP_INITIATOR_USERNAME, getProperty(snapshotId, 
DiskTO.CHAP_INITIATOR_USERNAME));
+        details.put(DiskTO.CHAP_INITIATOR_SECRET, getProperty(snapshotId, 
DiskTO.CHAP_INITIATOR_SECRET));
+        details.put(DiskTO.CHAP_TARGET_USERNAME, getProperty(snapshotId, 
DiskTO.CHAP_TARGET_USERNAME));
+        details.put(DiskTO.CHAP_TARGET_SECRET, getProperty(snapshotId, 
DiskTO.CHAP_TARGET_SECRET));
 
-        return srcDetails;
+        return details;
     }
 
     private String getProperty(long snapshotId, String property) {
@@ -183,8 +343,31 @@ public class StorageSystemDataMotionStrategy implements 
DataMotionStrategy {
         return null;
     }
 
-    public HostVO getHost(DataObject srcData) {
-        long dataStoreId = srcData.getDataStore().getId();
+    private Map<String, String> getVolumeDetails(VolumeInfo volumeInfo) {
+        Map<String, String> sourceDetails = new HashMap<String, String>();
+
+        VolumeVO volumeVO = _volumeDao.findById(volumeInfo.getId());
+
+        long storagePoolId = volumeVO.getPoolId();
+        StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId);
+
+        sourceDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress());
+        sourceDetails.put(DiskTO.STORAGE_PORT, 
String.valueOf(storagePoolVO.getPort()));
+        sourceDetails.put(DiskTO.IQN, volumeVO.get_iScsiName());
+
+        ChapInfo chapInfo = _volumeService.getChapInfo(volumeInfo, 
volumeInfo.getDataStore());
+
+        if (chapInfo != null) {
+            sourceDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, 
chapInfo.getInitiatorUsername());
+            sourceDetails.put(DiskTO.CHAP_INITIATOR_SECRET, 
chapInfo.getInitiatorSecret());
+            sourceDetails.put(DiskTO.CHAP_TARGET_USERNAME, 
chapInfo.getTargetUsername());
+            sourceDetails.put(DiskTO.CHAP_TARGET_SECRET, 
chapInfo.getTargetSecret());
+        }
+
+        return sourceDetails;
+    }
+
+    public HostVO getHost(long dataStoreId) {
         StoragePoolVO storagePoolVO = _storagePoolDao.findById(dataStoreId);
 
         List<? extends Cluster> clusters = 
_mgr.searchForClusters(storagePoolVO.getDataCenterId(), new Long(0), 
Long.MAX_VALUE, HypervisorType.XenServer.toString());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/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 6a42435..1f574d5 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
@@ -154,10 +154,6 @@ public class VolumeObject implements VolumeInfo {
         return volumeVO.getMaxIops();
     }
 
-    public void setHypervisorSnapshotReserve(Integer 
hypervisorSnapshotReserve) {
-        volumeVO.setHypervisorSnapshotReserve(hypervisorSnapshotReserve);
-    }
-
     @Override
     public Integer getHypervisorSnapshotReserve() {
         return volumeVO.getHypervisorSnapshotReserve();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
----------------------------------------------------------------------
diff --git 
a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
 
b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
index f261410..9d483d7 100644
--- 
a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
+++ 
b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
@@ -1589,6 +1589,10 @@ public class XenServerStorageProcessor implements 
StorageProcessor {
         DataTO destData = cmd.getDestTO();
         DataStoreTO imageStore = srcData.getDataStore();
 
+        if (srcData.getDataStore() instanceof PrimaryDataStoreTO && 
destData.getDataStore() instanceof PrimaryDataStoreTO) {
+            return createVolumeFromSnapshot2(cmd);
+        }
+
         if (!(imageStore instanceof NfsTO)) {
             return new CopyCmdAnswer("unsupported protocol");
         }
@@ -1647,6 +1651,51 @@ public class XenServerStorageProcessor implements 
StorageProcessor {
         return new CopyCmdAnswer(details);
     }
 
+    protected Answer createVolumeFromSnapshot2(CopyCommand cmd) {
+        try {
+            Connection conn = hypervisorResource.getConnection();
+
+            Map<String, String> srcOptions = cmd.getOptions();
+
+            String src_iScsiName = srcOptions.get(DiskTO.IQN);
+            String srcStorageHost = srcOptions.get(DiskTO.STORAGE_HOST);
+            String srcChapInitiatorUsername = 
srcOptions.get(DiskTO.CHAP_INITIATOR_USERNAME);
+            String srcChapInitiatorSecret = 
srcOptions.get(DiskTO.CHAP_INITIATOR_SECRET);
+
+            SR srcSr = hypervisorResource.getIscsiSR(conn, src_iScsiName, 
srcStorageHost, src_iScsiName, srcChapInitiatorUsername, 
srcChapInitiatorSecret, false);
+
+            Map<String, String> destOptions = cmd.getOptions2();
+
+            String dest_iScsiName = destOptions.get(DiskTO.IQN);
+            String destStorageHost = destOptions.get(DiskTO.STORAGE_HOST);
+            String destChapInitiatorUsername = 
destOptions.get(DiskTO.CHAP_INITIATOR_USERNAME);
+            String destChapInitiatorSecret = 
destOptions.get(DiskTO.CHAP_INITIATOR_SECRET);
+
+            SR destSr = hypervisorResource.getIscsiSR(conn, dest_iScsiName, 
destStorageHost, dest_iScsiName, destChapInitiatorUsername, 
destChapInitiatorSecret, false);
+
+            // there should only be one VDI in this SR
+            VDI srcVdi = srcSr.getVDIs(conn).iterator().next();
+
+            VDI vdiCopy = srcVdi.copy(conn, destSr);
+
+            VolumeObjectTO newVol = new VolumeObjectTO();
+
+            newVol.setSize(vdiCopy.getVirtualSize(conn));
+            newVol.setPath(vdiCopy.getUuid(conn));
+            newVol.setFormat(ImageFormat.VHD);
+
+            hypervisorResource.removeSR(conn, srcSr);
+            hypervisorResource.removeSR(conn, destSr);
+
+            return new CopyCmdAnswer(newVol);
+        }
+        catch (Exception ex) {
+            s_logger.warn("Failed to copy snapshot to volume: " + 
ex.toString(), ex);
+
+            return new CopyCmdAnswer(ex.getMessage());
+        }
+    }
+
     @Override
     public Answer deleteSnapshot(DeleteCommand cmd) {
         SnapshotObjectTO snapshot = (SnapshotObjectTO) cmd.getData();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java
----------------------------------------------------------------------
diff --git 
a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java
 
b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java
index 0bb02c3..043514b 100644
--- 
a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java
+++ 
b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java
@@ -656,7 +656,11 @@ public class Xenserver625StorageProcessor extends 
XenServerStorageProcessor {
         DataTO destData = cmd.getDestTO();
         PrimaryDataStoreTO pool = (PrimaryDataStoreTO)destData.getDataStore();
         VolumeObjectTO volume = (VolumeObjectTO)destData;
-                DataStoreTO imageStore = srcData.getDataStore();
+        DataStoreTO imageStore = srcData.getDataStore();
+
+        if (srcData.getDataStore() instanceof PrimaryDataStoreTO && 
destData.getDataStore() instanceof PrimaryDataStoreTO) {
+            return createVolumeFromSnapshot2(cmd);
+        }
 
         if (!(imageStore instanceof NfsTO)) {
             return new CopyCmdAnswer("unsupported protocol");

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/server/src/com/cloud/api/ApiResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java 
b/server/src/com/cloud/api/ApiResponseHelper.java
index 4726c24..98a4a85 100644
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -483,7 +483,7 @@ public class ApiResponseHelper implements ResponseGenerator 
{
         if (snapshot instanceof SnapshotInfo) {
             snapshotInfo = (SnapshotInfo)snapshot;
         } else {
-            DataStoreRole dataStoreRole = getDataStoreRole(snapshot);
+            DataStoreRole dataStoreRole = getDataStoreRole(snapshot, 
_snapshotStoreDao, _dataStoreMgr);
 
             snapshotInfo = snapshotfactory.getSnapshot(snapshot.getId(), 
dataStoreRole);
         }
@@ -509,15 +509,15 @@ public class ApiResponseHelper implements 
ResponseGenerator {
         return snapshotResponse;
     }
 
-    private DataStoreRole getDataStoreRole(Snapshot snapshot) {
-        SnapshotDataStoreVO snapshotStore = 
_snapshotStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Primary);
+    public static DataStoreRole getDataStoreRole(Snapshot snapshot, 
SnapshotDataStoreDao snapshotStoreDao, DataStoreManager dataStoreMgr) {
+        SnapshotDataStoreVO snapshotStore = 
snapshotStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Primary);
 
         if (snapshotStore == null) {
             return DataStoreRole.Image;
         }
 
         long storagePoolId = snapshotStore.getDataStoreId();
-        DataStore dataStore = _dataStoreMgr.getDataStore(storagePoolId, 
DataStoreRole.Primary);
+        DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, 
DataStoreRole.Primary);
 
         Map<String, String> mapCapabilities = 
dataStore.getDriver().getCapabilities();
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/server/src/com/cloud/storage/VolumeApiServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java 
b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
index ca83890..0abb629 100644
--- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
@@ -522,6 +522,9 @@ public class VolumeApiServiceImpl extends ManagerBase 
implements VolumeApiServic
             size = snapshotCheck.getSize(); // ; disk offering is used for tags
             // purposes
 
+            minIops = snapshotCheck.getMinIops();
+            maxIops = snapshotCheck.getMaxIops();
+
             provisioningType = diskOffering.getProvisioningType();
             // check snapshot permissions
             _accountMgr.checkAccess(caller, null, true, snapshotCheck);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/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 0591175..baa0488 100644
--- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
+++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
@@ -87,6 +87,7 @@ import com.cloud.storage.SnapshotPolicyVO;
 import com.cloud.storage.SnapshotScheduleVO;
 import com.cloud.storage.SnapshotVO;
 import com.cloud.storage.Storage;
+import com.cloud.storage.Storage.ImageFormat;
 import com.cloud.storage.StorageManager;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.VMTemplateVO;
@@ -1132,13 +1133,18 @@ public class SnapshotManagerImpl extends ManagerBase 
implements SnapshotManager,
         StoragePoolVO storagePool = 
_storagePoolDao.findById(volume.getDataStore().getId());
         if (storagePool.getScope() == ScopeType.ZONE) {
             hypervisorType = storagePool.getHypervisor();
+
+            // at the time being, managed storage only supports XenServer, 
ESX(i), and KVM (i.e. not Hyper-V), so the VHD file type can be mapped to 
XenServer
+            if (storagePool.isManaged() && 
HypervisorType.Any.equals(hypervisorType) && 
ImageFormat.VHD.equals(volume.getFormat())) {
+                hypervisorType = HypervisorType.XenServer;
+            }
         } else {
             hypervisorType = volume.getHypervisorType();
         }
 
         SnapshotVO snapshotVO =
             new SnapshotVO(volume.getDataCenterId(), volume.getAccountId(), 
volume.getDomainId(), volume.getId(), volume.getDiskOfferingId(), snapshotName,
-                (short)snapshotType.ordinal(), snapshotType.name(), 
volume.getSize(), hypervisorType);
+                (short)snapshotType.ordinal(), snapshotType.name(), 
volume.getSize(), volume.getMinIops(), volume.getMaxIops(), hypervisorType);
 
         SnapshotVO snapshot = _snapshotDao.persist(snapshotVO);
         if (snapshot == null) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/server/src/com/cloud/template/TemplateManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java 
b/server/src/com/cloud/template/TemplateManagerImpl.java
index f244673..330b19e 100644
--- a/server/src/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/com/cloud/template/TemplateManagerImpl.java
@@ -54,7 +54,6 @@ import 
org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissions
 import org.apache.cloudstack.context.CallContext;
 import 
org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
-import 
org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
@@ -81,7 +80,6 @@ import org.apache.cloudstack.storage.command.CommandResult;
 import org.apache.cloudstack.storage.command.DettachCommand;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
-import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
@@ -97,6 +95,7 @@ import com.cloud.agent.api.to.DataTO;
 import com.cloud.agent.api.to.DiskTO;
 import com.cloud.agent.api.to.NfsTO;
 import com.cloud.api.ApiDBUtils;
+import com.cloud.api.ApiResponseHelper;
 import com.cloud.api.query.dao.UserVmJoinDao;
 import com.cloud.api.query.vo.UserVmJoinVO;
 import com.cloud.configuration.Config;
@@ -1379,7 +1378,7 @@ public class TemplateManagerImpl extends ManagerBase 
implements TemplateManager,
             AsyncCallFuture<TemplateApiResult> future = null;
 
             if (snapshotId != null) {
-                DataStoreRole dataStoreRole = getDataStoreRole(snapshot);
+                DataStoreRole dataStoreRole = 
ApiResponseHelper.getDataStoreRole(snapshot, _snapshotStoreDao, _dataStoreMgr);
 
                 SnapshotInfo snapInfo = 
_snapshotFactory.getSnapshot(snapshotId, dataStoreRole);
 
@@ -1474,30 +1473,6 @@ public class TemplateManagerImpl extends ManagerBase 
implements TemplateManager,
         }
     }
 
-    private DataStoreRole getDataStoreRole(Snapshot snapshot) {
-        SnapshotDataStoreVO snapshotStore = 
_snapshotStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Primary);
-
-        if (snapshotStore == null) {
-            return DataStoreRole.Image;
-        }
-
-        long storagePoolId = snapshotStore.getDataStoreId();
-        DataStore dataStore = _dataStoreMgr.getDataStore(storagePoolId, 
DataStoreRole.Primary);
-
-        Map<String, String> mapCapabilities = 
dataStore.getDriver().getCapabilities();
-
-        if (mapCapabilities != null) {
-            String value = 
mapCapabilities.get(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString());
-            Boolean supportsStorageSystemSnapshots = new Boolean(value);
-
-            if (supportsStorageSystemSnapshots) {
-                return DataStoreRole.Primary;
-            }
-        }
-
-        return DataStoreRole.Image;
-    }
-
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, 
eventDescription = "creating template", create = true)
     public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, 
Account templateOwner) throws ResourceAllocationException {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0f84e042/setup/db/db/schema-450to460.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-450to460.sql b/setup/db/db/schema-450to460.sql
index 0493184..95d6532 100644
--- a/setup/db/db/schema-450to460.sql
+++ b/setup/db/db/schema-450to460.sql
@@ -19,6 +19,9 @@
 -- Schema upgrade from 4.5.0 to 4.6.0
 --
 
+ALTER TABLE `cloud`.`snapshots` ADD COLUMN `min_iops` bigint(20) unsigned 
COMMENT 'Minimum IOPS';
+ALTER TABLE `cloud`.`snapshots` ADD COLUMN `max_iops` bigint(20) unsigned 
COMMENT 'Maximum IOPS';
+
 INSERT IGNORE INTO `cloud`.`configuration` VALUES ("Advanced", 'DEFAULT', 
'management-server', "stats.output.uri", "", "URI to additionally send 
StatsCollector statistics to", "", NULL, NULL, 0);
 
 DROP VIEW IF EXISTS `cloud`.`domain_view`;

Reply via email to