cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sw...@apache.org
Subject [1/8] git commit: updated refs/heads/master to 82b702d
Date Fri, 20 May 2016 12:33:30 GMT
Repository: cloudstack
Updated Branches:
  refs/heads/master 3f5b3a16d -> 82b702dc9


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java
index e505cd0..f88041a 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java
@@ -52,24 +52,24 @@ import com.cloud.storage.dao.StoragePoolHostDao;
 import com.cloud.utils.exception.CloudRuntimeException;
 
 public class SolidFireSharedHostListener implements HypervisorHostListener {
-    private static final Logger s_logger = Logger.getLogger(SolidFireSharedHostListener.class);
-
-    @Inject private AgentManager _agentMgr;
-    @Inject private AlertManager _alertMgr;
-    @Inject private ClusterDao _clusterDao;
-    @Inject private ClusterDetailsDao _clusterDetailsDao;
-    @Inject private DataStoreManager _dataStoreMgr;
-    @Inject private HostDao _hostDao;
-    @Inject private PrimaryDataStoreDao _storagePoolDao;
-    @Inject private StoragePoolHostDao _storagePoolHostDao;
-    @Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
+    private static final Logger LOGGER = Logger.getLogger(SolidFireSharedHostListener.class);
+
+    @Inject private AgentManager agentMgr;
+    @Inject private AlertManager alertMgr;
+    @Inject private ClusterDao clusterDao;
+    @Inject private ClusterDetailsDao clusterDetailsDao;
+    @Inject private DataStoreManager dataStoreMgr;
+    @Inject private HostDao hostDao;
+    @Inject private PrimaryDataStoreDao storagePoolDao;
+    @Inject private StoragePoolHostDao storagePoolHostDao;
+    @Inject private StoragePoolDetailsDao storagePoolDetailsDao;
 
     @Override
     public boolean hostAdded(long hostId) {
-        HostVO host = _hostDao.findById(hostId);
+        HostVO host = hostDao.findById(hostId);
 
         SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, host.getClusterId(), true, SolidFireUtil.SHARED_PROVIDER_NAME,
-                _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao);
+                clusterDao, clusterDetailsDao, storagePoolDao, storagePoolDetailsDao, hostDao);
 
         handleVMware(hostId, true);
 
@@ -78,37 +78,37 @@ public class SolidFireSharedHostListener implements HypervisorHostListener {
 
     @Override
     public boolean hostConnect(long hostId, long storagePoolId) {
-        StoragePool storagePool = (StoragePool)_dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
+        StoragePool storagePool = (StoragePool) dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
         ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool);
 
         ModifyStoragePoolAnswer answer = sendModifyStoragePoolCommand(cmd, storagePool, hostId);
 
-        StoragePoolHostVO storagePoolHost = _storagePoolHostDao.findByPoolHost(storagePoolId, hostId);
+        StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId);
 
         if (storagePoolHost != null) {
             storagePoolHost.setLocalPath(answer.getPoolInfo().getLocalPath().replaceAll("//", "/"));
         } else {
             storagePoolHost = new StoragePoolHostVO(storagePoolId, hostId, answer.getPoolInfo().getLocalPath().replaceAll("//", "/"));
 
-            _storagePoolHostDao.persist(storagePoolHost);
+            storagePoolHostDao.persist(storagePoolHost);
         }
 
-        StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId);
+        StoragePoolVO storagePoolVO = storagePoolDao.findById(storagePoolId);
 
         storagePoolVO.setCapacityBytes(answer.getPoolInfo().getCapacityBytes());
         storagePoolVO.setUsedBytes(answer.getPoolInfo().getCapacityBytes() - answer.getPoolInfo().getAvailableBytes());
 
-        _storagePoolDao.update(storagePoolId, storagePoolVO);
+        storagePoolDao.update(storagePoolId, storagePoolVO);
 
         return true;
     }
 
     @Override
     public boolean hostDisconnected(long hostId, long storagePoolId) {
-        StoragePoolHostVO storagePoolHost = _storagePoolHostDao.findByPoolHost(storagePoolId, hostId);
+        StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId);
 
         if (storagePoolHost != null) {
-            _storagePoolHostDao.deleteStoragePoolHostDetails(hostId, storagePoolId);
+            storagePoolHostDao.deleteStoragePoolHostDetails(hostId, storagePoolId);
         }
 
         return true;
@@ -124,16 +124,16 @@ public class SolidFireSharedHostListener implements HypervisorHostListener {
     @Override
     public boolean hostRemoved(long hostId, long clusterId) {
         SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, clusterId, false, SolidFireUtil.SHARED_PROVIDER_NAME,
-                _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao);
+                clusterDao, clusterDetailsDao, storagePoolDao, storagePoolDetailsDao, hostDao);
 
         return true;
     }
 
     private void handleVMware(long hostId, boolean add) {
-        HostVO host = _hostDao.findById(hostId);
+        HostVO host = hostDao.findById(hostId);
 
         if (HypervisorType.VMware.equals(host.getHypervisorType())) {
-            List<StoragePoolVO> storagePools = _storagePoolDao.findPoolsByProvider(SolidFireUtil.SHARED_PROVIDER_NAME);
+            List<StoragePoolVO> storagePools = storagePoolDao.findPoolsByProvider(SolidFireUtil.SHARED_PROVIDER_NAME);
 
             if (storagePools != null && storagePools.size() > 0) {
                 List<Map<String, String>> targets = new ArrayList<>();
@@ -142,15 +142,15 @@ public class SolidFireSharedHostListener implements HypervisorHostListener {
                     if (storagePool.getClusterId().equals(host.getClusterId())) {
                         long storagePoolId = storagePool.getId();
 
-                        StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.IQN);
+                        StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.IQN);
 
                         String iqn = storagePoolDetail.getValue();
 
-                        storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_VIP);
+                        storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_VIP);
 
                         String sVip = storagePoolDetail.getValue();
 
-                        storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_PORT);
+                        storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_PORT);
 
                         String sPort = storagePoolDetail.getValue();
 
@@ -177,7 +177,7 @@ public class SolidFireSharedHostListener implements HypervisorHostListener {
     }
 
     private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) {
-        Answer answer = _agentMgr.easySend(hostId, cmd);
+        Answer answer = agentMgr.easySend(hostId, cmd);
 
         if (answer == null) {
             throw new CloudRuntimeException("Unable to get an answer to the modify targets command");
@@ -186,16 +186,16 @@ public class SolidFireSharedHostListener implements HypervisorHostListener {
         if (!answer.getResult()) {
             String msg = "Unable to modify targets on the following host: " + hostId;
 
-            HostVO host = _hostDao.findById(hostId);
+            HostVO host = hostDao.findById(hostId);
 
-            _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), msg, msg);
+            alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), msg, msg);
 
             throw new CloudRuntimeException(msg);
         }
     }
 
     private ModifyStoragePoolAnswer sendModifyStoragePoolCommand(ModifyStoragePoolCommand cmd, StoragePool storagePool, long hostId) {
-        Answer answer = _agentMgr.easySend(hostId, cmd);
+        Answer answer = agentMgr.easySend(hostId, cmd);
 
         if (answer == null) {
             throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command for storage pool: " + storagePool.getId());
@@ -204,7 +204,7 @@ public class SolidFireSharedHostListener implements HypervisorHostListener {
         if (!answer.getResult()) {
             String msg = "Unable to attach storage pool " + storagePool.getId() + " to the host " + hostId;
 
-            _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg);
+            alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg);
 
             throw new CloudRuntimeException(msg);
         }
@@ -212,7 +212,7 @@ public class SolidFireSharedHostListener implements HypervisorHostListener {
         assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer not returned from ModifyStoragePoolCommand; Storage pool = " +
             storagePool.getId() + "; Host = " + hostId;
 
-        s_logger.info("Connection established between storage pool " + storagePool + " and host " + hostId);
+        LOGGER.info("Connection established between storage pool " + storagePool + " and host " + hostId);
 
         return (ModifyStoragePoolAnswer)answer;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
index 7268e72..a9c1227 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
@@ -30,6 +30,7 @@ import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -55,6 +56,7 @@ import org.apache.log4j.Logger;
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
 
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
@@ -104,6 +106,15 @@ public class SolidFireUtil {
 
     public static final String ACCOUNT_ID = "accountId";
     public static final String VOLUME_ID = "volumeId";
+    public static final String TEMP_VOLUME_ID = "tempVolumeId";
+    public static final String SNAPSHOT_ID = "snapshotId";
+
+    public static final String CloudStackVolumeId = "CloudStackVolumeId";
+    public static final String CloudStackVolumeSize = "CloudStackVolumeSize";
+    public static final String CloudStackSnapshotId = "CloudStackSnapshotId";
+    public static final String CloudStackSnapshotSize = "CloudStackSnapshotSize";
+    public static final String CloudStackTemplateId = "CloudStackTemplateId";
+    public static final String CloudStackTemplateSize = "CloudStackTemplateSize";
 
     public static final String VOLUME_SIZE = "sfVolumeSize";
 
@@ -562,13 +573,44 @@ public class SolidFireUtil {
     }
 
     public static long createSolidFireVolume(SolidFireConnection sfConnection, String strSfVolumeName, long lSfAccountId, long lTotalSize,
-            boolean bEnable512e, String strCloudStackVolumeSize, long minIops, long maxIops, long burstIops)
+            boolean bEnable512e, Map<String, String> mapAttributes, long minIops, long maxIops, long burstIops)
     {
-        final Gson gson = new GsonBuilder().create();
+        JsonObject volumeToCreate = new JsonObject();
+
+        volumeToCreate.addProperty("method", "CreateVolume");
+
+        JsonObject params = new JsonObject();
+
+        volumeToCreate.add("params", params);
+
+        params.addProperty("name", strSfVolumeName);
+        params.addProperty("accountID", lSfAccountId);
+        params.addProperty("totalSize", lTotalSize);
+        params.addProperty("enable512e", bEnable512e);
+
+        JsonObject qos = new JsonObject();
+
+        params.add("qos", qos);
+
+        qos.addProperty("minIOPS", minIops);
+        qos.addProperty("maxIOPS", maxIops);
+        qos.addProperty("burstIOPS", burstIops);
+
+        if (mapAttributes != null && mapAttributes.size() > 0) {
+            JsonObject attributes = new JsonObject();
+
+            params.add("attributes", attributes);
+
+            Iterator<Map.Entry<String, String>> itr = mapAttributes.entrySet().iterator();
+
+            while (itr.hasNext()) {
+                Map.Entry<String, String> pair = itr.next();
+
+                attributes.addProperty(pair.getKey(), pair.getValue());
+            }
+        }
 
-        Object volumeToCreate = strCloudStackVolumeSize != null && strCloudStackVolumeSize.trim().length() > 0 ?
-                new VolumeToCreateWithCloudStackVolumeSize(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, strCloudStackVolumeSize, minIops, maxIops, burstIops) :
-                new VolumeToCreate(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, minIops, maxIops, burstIops);
+        final Gson gson = new GsonBuilder().create();
 
         String strVolumeToCreateJson = gson.toJson(volumeToCreate);
 
@@ -581,14 +623,46 @@ public class SolidFireUtil {
         return volumeCreateResult.result.volumeID;
     }
 
-    public static void modifySolidFireVolume(SolidFireConnection sfConnection, long volumeId, long totalSize, String strCloudStackVolumeSize,
+    public static void modifySolidFireVolume(SolidFireConnection sfConnection, long volumeId, Long totalSize, Map<String, String> mapAttributes,
             long minIops, long maxIops, long burstIops)
     {
-        final Gson gson = new GsonBuilder().create();
+        JsonObject volumeToModify = new JsonObject();
+
+        volumeToModify.addProperty("method", "ModifyVolume");
+
+        JsonObject params = new JsonObject();
+
+        volumeToModify.add("params", params);
+
+        params.addProperty("volumeID", volumeId);
+
+        if (totalSize != null) {
+            params.addProperty("totalSize", totalSize);
+        }
+
+        JsonObject qos = new JsonObject();
+
+        params.add("qos", qos);
+
+        qos.addProperty("minIOPS", minIops);
+        qos.addProperty("maxIOPS", maxIops);
+        qos.addProperty("burstIOPS", burstIops);
+
+        if (mapAttributes != null && mapAttributes.size() > 0) {
+            JsonObject attributes = new JsonObject();
+
+            params.add("attributes", attributes);
+
+            Iterator<Map.Entry<String, String>> itr = mapAttributes.entrySet().iterator();
 
-        Object volumeToModify = strCloudStackVolumeSize != null && strCloudStackVolumeSize.trim().length() > 0 ?
-                new VolumeToModifyWithCloudStackVolumeSize(volumeId, totalSize, strCloudStackVolumeSize, minIops, maxIops, burstIops) :
-                new VolumeToModify(volumeId, totalSize, minIops, maxIops, burstIops);
+            while (itr.hasNext()) {
+                Map.Entry<String, String> pair = itr.next();
+
+                attributes.addProperty(pair.getKey(), pair.getValue());
+            }
+        }
+
+        final Gson gson = new GsonBuilder().create();
 
         String strVolumeToModifyJson = gson.toJson(volumeToModify);
 
@@ -687,7 +761,7 @@ public class SolidFireUtil {
         executeJsonRpc(sfConnection, strVolumeToDeleteJson);
     }
 
-   public static void purgeSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
+    public static void purgeSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -800,10 +874,51 @@ public class SolidFireUtil {
         }
     }
 
-    public static long createSolidFireSnapshot(SolidFireConnection sfConnection, long lVolumeId, String snapshotName) {
-        final Gson gson = new GsonBuilder().create();
+    public static class SolidFireSnapshot {
+        private final long _id;
+        private final String _name;
+
+        public SolidFireSnapshot(long id, String name) {
+            _id = id;
+            _name = name;
+        }
+
+        public long getId() {
+            return _id;
+        }
+
+        public String getName() {
+            return _name;
+        }
+    }
+
+    public static long createSolidFireSnapshot(SolidFireConnection sfConnection, long lVolumeId, String snapshotName, Map<String, String> mapAttributes) {
+        JsonObject snapshotToCreate = new JsonObject();
+
+        snapshotToCreate.addProperty("method", "CreateSnapshot");
 
-        SnapshotToCreate snapshotToCreate = new SnapshotToCreate(lVolumeId, snapshotName);
+        JsonObject params = new JsonObject();
+
+        snapshotToCreate.add("params", params);
+
+        params.addProperty("volumeID", lVolumeId);
+        params.addProperty("name", snapshotName);
+
+        if (mapAttributes != null && mapAttributes.size() > 0) {
+            JsonObject attributes = new JsonObject();
+
+            params.add("attributes", attributes);
+
+            Iterator<Map.Entry<String, String>> itr = mapAttributes.entrySet().iterator();
+
+            while (itr.hasNext()) {
+                Map.Entry<String, String> pair = itr.next();
+
+                attributes.addProperty(pair.getKey(), pair.getValue());
+            }
+        }
+
+        final Gson gson = new GsonBuilder().create();
 
         String strSnapshotToCreateJson = gson.toJson(snapshotToCreate);
 
@@ -816,6 +931,38 @@ public class SolidFireUtil {
         return snapshotCreateResult.result.snapshotID;
     }
 
+    public static SolidFireSnapshot getSolidFireSnapshot(SolidFireConnection sfConnection, long lVolumeId, long lSnapshotId) {
+        final Gson gson = new GsonBuilder().create();
+
+        SnapshotsToGet snapshotsToGet = new SnapshotsToGet(lVolumeId);
+
+        String strSnapshotsToGetJson = gson.toJson(snapshotsToGet);
+
+        String strSnapshotsGetResultJson = executeJsonRpc(sfConnection, strSnapshotsToGetJson);
+
+        SnapshotsGetResult snapshotsGetResult = gson.fromJson(strSnapshotsGetResultJson, SnapshotsGetResult.class);
+
+        verifyResult(snapshotsGetResult.result, strSnapshotsGetResultJson, gson);
+
+        String snapshotName = null;
+
+        if (snapshotsGetResult.result.snapshots != null) {
+            for (SnapshotsGetResult.Result.Snapshot snapshot : snapshotsGetResult.result.snapshots) {
+                if (snapshot.snapshotID == lSnapshotId) {
+                    snapshotName = snapshot.name;
+
+                    break;
+                }
+            }
+        }
+
+        if (snapshotName == null) {
+            throw new CloudRuntimeException("Could not find SolidFire snapshot ID: " + lSnapshotId + " for the following SolidFire volume ID: " + lVolumeId);
+        }
+
+        return new SolidFireSnapshot(lSnapshotId, snapshotName);
+    }
+
     public static void deleteSolidFireSnapshot(SolidFireConnection sfConnection, long lSnapshotId)
     {
         final Gson gson = new GsonBuilder().create();
@@ -841,10 +988,40 @@ public class SolidFireUtil {
         verifyResult(rollbackInitiatedResult.result, strRollbackInitiatedResultJson, gson);
     }
 
-    public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId, long lSnapshotId, String cloneName) {
-        final Gson gson = new GsonBuilder().create();
+    public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId, long lSnapshotId, long sfAccountId,
+            String cloneName, Map<String, String> mapAttributes) {
+        JsonObject cloneToCreate = new JsonObject();
+
+        cloneToCreate.addProperty("method", "CloneVolume");
+
+        JsonObject params = new JsonObject();
+
+        cloneToCreate.add("params", params);
+
+        params.addProperty("volumeID", lVolumeId);
+
+        if (lSnapshotId > 0) {
+            params.addProperty("snapshotID", lSnapshotId);
+        }
+
+        params.addProperty("newAccountID", sfAccountId);
+        params.addProperty("name", cloneName);
+
+        if (mapAttributes != null && mapAttributes.size() > 0) {
+            JsonObject attributes = new JsonObject();
 
-        CloneToCreate cloneToCreate = new CloneToCreate(lVolumeId, lSnapshotId, cloneName);
+            params.add("attributes", attributes);
+
+            Iterator<Map.Entry<String, String>> itr = mapAttributes.entrySet().iterator();
+
+            while (itr.hasNext()) {
+                Map.Entry<String, String> pair = itr.next();
+
+                attributes.addProperty(pair.getKey(), pair.getValue());
+            }
+        }
+
+        final Gson gson = new GsonBuilder().create();
 
         String strCloneToCreateJson = gson.toJson(cloneToCreate);
 
@@ -854,7 +1031,33 @@ public class SolidFireUtil {
 
         verifyResult(cloneCreateResult.result, strCloneCreateResultJson, gson);
 
-        return cloneCreateResult.result.cloneID;
+        // Clone is an async operation. Poll until we get data.
+
+        AsyncJobToPoll asyncJobToPoll = new AsyncJobToPoll(cloneCreateResult.result.asyncHandle);
+
+        String strAsyncJobToPollJson = gson.toJson(asyncJobToPoll);
+
+        do {
+            String strAsyncJobResultJson = executeJsonRpc(sfConnection, strAsyncJobToPollJson);
+
+            AsyncJobResult asyncJobResult = gson.fromJson(strAsyncJobResultJson, AsyncJobResult.class);
+
+            verifyResult(asyncJobResult.result, strAsyncJobResultJson, gson);
+
+            if (asyncJobResult.result.status.equals("complete")) {
+                break;
+            }
+
+            try {
+                Thread.sleep(500); // sleep for 1/2 of a second
+            }
+            catch (Exception ex) {
+                // ignore
+            }
+        }
+        while (true);
+
+        return cloneCreateResult.result.volumeID;
     }
 
     public static long createSolidFireAccount(SolidFireConnection sfConnection, String strAccountName)
@@ -1135,189 +1338,6 @@ public class SolidFireUtil {
     }
 
     @SuppressWarnings("unused")
-    private static final class VolumeToCreateWithCloudStackVolumeSize {
-        private final String method = "CreateVolume";
-        private final VolumeToCreateParams params;
-
-        private VolumeToCreateWithCloudStackVolumeSize(final String strVolumeName, final long lAccountId, final long lTotalSize,
-                final boolean bEnable512e, final String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
-            params = new VolumeToCreateParams(strVolumeName, lAccountId, lTotalSize, bEnable512e, strCloudStackVolumeSize, lMinIOPS, lMaxIOPS, lBurstIOPS);
-        }
-
-        private static final class VolumeToCreateParams {
-            private final String name;
-            private final long accountID;
-            private final long totalSize;
-            private final boolean enable512e;
-            private final VolumeToCreateParamsAttributes attributes;
-            private final VolumeToCreateParamsQoS qos;
-
-            private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e,
-                    final String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
-                name = strVolumeName;
-                accountID = lAccountId;
-                totalSize = lTotalSize;
-                enable512e = bEnable512e;
-
-                attributes = new VolumeToCreateParamsAttributes(strCloudStackVolumeSize);
-                qos = new VolumeToCreateParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS);
-            }
-
-            private static final class VolumeToCreateParamsAttributes {
-                private final String CloudStackVolumeSize;
-
-                private VolumeToCreateParamsAttributes(final String strCloudStackVolumeSize) {
-                    CloudStackVolumeSize = strCloudStackVolumeSize;
-                }
-            }
-
-            private static final class VolumeToCreateParamsQoS {
-                private final long minIOPS;
-                private final long maxIOPS;
-                private final long burstIOPS;
-
-                private VolumeToCreateParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
-                    minIOPS = lMinIOPS;
-                    maxIOPS = lMaxIOPS;
-                    burstIOPS = lBurstIOPS;
-                }
-            }
-        }
-    }
-
-    @SuppressWarnings("unused")
-    private static final class VolumeToCreate {
-        private final String method = "CreateVolume";
-        private final VolumeToCreateParams params;
-
-        private VolumeToCreate(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e,
-                final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
-            params = new VolumeToCreateParams(strVolumeName, lAccountId, lTotalSize, bEnable512e, lMinIOPS, lMaxIOPS, lBurstIOPS);
-        }
-
-        private static final class VolumeToCreateParams {
-            private final String name;
-            private final long accountID;
-            private final long totalSize;
-            private final boolean enable512e;
-            private final VolumeToCreateParamsQoS qos;
-
-            private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e,
-                    final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
-                name = strVolumeName;
-                accountID = lAccountId;
-                totalSize = lTotalSize;
-                enable512e = bEnable512e;
-
-                qos = new VolumeToCreateParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS);
-            }
-
-            private static final class VolumeToCreateParamsQoS {
-                private final long minIOPS;
-                private final long maxIOPS;
-                private final long burstIOPS;
-
-                private VolumeToCreateParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
-                    minIOPS = lMinIOPS;
-                    maxIOPS = lMaxIOPS;
-                    burstIOPS = lBurstIOPS;
-                }
-            }
-        }
-    }
-
-    @SuppressWarnings("unused")
-    private static final class VolumeToModifyWithCloudStackVolumeSize
-    {
-        private final String method = "ModifyVolume";
-        private final VolumeToModifyParams params;
-
-        private VolumeToModifyWithCloudStackVolumeSize(final long lVolumeId, final long lTotalSize, final String strCloudStackVolumeSize,
-                final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
-        {
-            params = new VolumeToModifyParams(lVolumeId, lTotalSize, strCloudStackVolumeSize, lMinIOPS, lMaxIOPS, lBurstIOPS);
-        }
-
-        private static final class VolumeToModifyParams
-        {
-            private final long volumeID;
-            private final long totalSize;
-            private final VolumeToModifyParamsAttributes attributes;
-            private final VolumeToModifyParamsQoS qos;
-
-            private VolumeToModifyParams(final long lVolumeId, final long lTotalSize, String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
-            {
-                volumeID = lVolumeId;
-
-                totalSize = lTotalSize;
-
-                attributes = new VolumeToModifyParamsAttributes(strCloudStackVolumeSize);
-                qos = new VolumeToModifyParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS);
-            }
-        }
-
-        private static final class VolumeToModifyParamsAttributes {
-            private final String CloudStackVolumeSize;
-
-            private VolumeToModifyParamsAttributes(final String strCloudStackVolumeSize) {
-                CloudStackVolumeSize = strCloudStackVolumeSize;
-            }
-        }
-
-        private static final class VolumeToModifyParamsQoS {
-            private final long minIOPS;
-            private final long maxIOPS;
-            private final long burstIOPS;
-
-            private VolumeToModifyParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
-                minIOPS = lMinIOPS;
-                maxIOPS = lMaxIOPS;
-                burstIOPS = lBurstIOPS;
-            }
-        }
-    }
-
-    @SuppressWarnings("unused")
-    private static final class VolumeToModify
-    {
-        private final String method = "ModifyVolume";
-        private final VolumeToModifyParams params;
-
-        private VolumeToModify(final long lVolumeId, final long lTotalSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
-        {
-            params = new VolumeToModifyParams(lVolumeId, lTotalSize, lMinIOPS, lMaxIOPS, lBurstIOPS);
-        }
-
-        private static final class VolumeToModifyParams
-        {
-            private final long volumeID;
-            private final long totalSize;
-            private final VolumeToModifyParamsQoS qos;
-
-            private VolumeToModifyParams(final long lVolumeId, final long lTotalSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
-            {
-                volumeID = lVolumeId;
-
-                totalSize = lTotalSize;
-
-                qos = new VolumeToModifyParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS);
-            }
-        }
-
-        private static final class VolumeToModifyParamsQoS {
-            private final long minIOPS;
-            private final long maxIOPS;
-            private final long burstIOPS;
-
-            private VolumeToModifyParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
-                minIOPS = lMinIOPS;
-                maxIOPS = lMaxIOPS;
-                burstIOPS = lBurstIOPS;
-            }
-        }
-    }
-
-    @SuppressWarnings("unused")
     private static final class VolumeToGet
     {
         private final String method = "ListActiveVolumes";
@@ -1407,21 +1427,20 @@ public class SolidFireUtil {
     }
 
     @SuppressWarnings("unused")
-    private static final class SnapshotToCreate {
-        private final String method = "CreateSnapshot";
-        private final SnapshotToCreateParams params;
+    private static final class SnapshotsToGet
+    {
+        private final String method = "ListSnapshots";
+        private final SnapshotsToGetParams params;
 
-        private SnapshotToCreate(final long lVolumeId, final String snapshotName) {
-            params = new SnapshotToCreateParams(lVolumeId, snapshotName);
+        private SnapshotsToGet(final long lVolumeId) {
+            params = new SnapshotsToGetParams(lVolumeId);
         }
 
-        private static final class SnapshotToCreateParams {
+        private static final class SnapshotsToGetParams {
             private final long volumeID;
-            private final String name;
 
-            private SnapshotToCreateParams(final long lVolumeId, final String snapshotName) {
+            private SnapshotsToGetParams(final long lVolumeId) {
                 volumeID = lVolumeId;
-                name = snapshotName;
             }
         }
     }
@@ -1466,28 +1485,6 @@ public class SolidFireUtil {
     }
 
     @SuppressWarnings("unused")
-    private static final class CloneToCreate {
-        private final String method = "CloneVolume";
-        private final CloneToCreateParams params;
-
-        private CloneToCreate(final long lVolumeId, final long lSnapshotId, final String cloneName) {
-            params = new CloneToCreateParams(lVolumeId, lSnapshotId, cloneName);
-        }
-
-        private static final class CloneToCreateParams {
-            private final long volumeID;
-            private final long snapshotID;
-            private final String name;
-
-            private CloneToCreateParams(final long lVolumeId, final long lSnapshotId, final String cloneName) {
-                volumeID = lVolumeId;
-                snapshotID = lSnapshotId;
-                name = cloneName;
-            }
-        }
-    }
-
-    @SuppressWarnings("unused")
     private static final class AccountToAdd
     {
         private final String method = "AddAccount";
@@ -1680,6 +1677,28 @@ public class SolidFireUtil {
         }
     }
 
+    @SuppressWarnings("unused")
+    private static final class AsyncJobToPoll
+    {
+        private final String method = "GetAsyncResult";
+        private final AsyncJobToPollParams params;
+
+        private AsyncJobToPoll(final long asyncHandle)
+        {
+            params = new AsyncJobToPollParams(asyncHandle);
+        }
+
+        private static final class AsyncJobToPollParams
+        {
+            private final long asyncHandle;
+
+            private AsyncJobToPollParams(final long asyncHandle)
+            {
+                this.asyncHandle = asyncHandle;
+            }
+        }
+    }
+
     private static final class VolumeCreateResult {
         private Result result;
 
@@ -1721,6 +1740,19 @@ public class SolidFireUtil {
         }
     }
 
+    private static final class SnapshotsGetResult {
+        private Result result;
+
+        private static final class Result {
+            private Snapshot[] snapshots;
+
+            private static final class Snapshot {
+                private long snapshotID;
+                private String name;
+            }
+        }
+    }
+
     @SuppressWarnings("unused")
     private static final class RollbackInitiatedResult {
         private Result result;
@@ -1734,7 +1766,8 @@ public class SolidFireUtil {
         private Result result;
 
         private static final class Result {
-            private long cloneID;
+            private long volumeID;
+            private long asyncHandle;
         }
     }
 
@@ -1786,6 +1819,15 @@ public class SolidFireUtil {
         }
     }
 
+    private static final class AsyncJobResult {
+        private AsyncResult result;
+
+        private static final class AsyncResult
+        {
+            private String status;
+        }
+    }
+
     private static final class JsonError
     {
         private Error error;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/server/src/com/cloud/capacity/CapacityManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java
index 13794c7..d0ae3e9 100644
--- a/server/src/com/cloud/capacity/CapacityManagerImpl.java
+++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java
@@ -549,28 +549,35 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
             return getUsedBytes(pool);
         }
         else {
-            // Get size for all the non-destroyed volumes
+            // Get size for all the non-destroyed volumes.
             Pair<Long, Long> sizes = _volumeDao.getNonDestroyedCountAndTotalByPool(pool.getId());
 
             totalAllocatedSize = sizes.second() + sizes.first() * _extraBytesPerVolume;
         }
 
-        // Get size for VM Snapshots
-        totalAllocatedSize = totalAllocatedSize + _volumeDao.getVMSnapshotSizeByPool(pool.getId());
+        // Get size for VM Snapshots.
+        totalAllocatedSize += _volumeDao.getVMSnapshotSizeByPool(pool.getId());
 
-        // Iterate through all templates on this storage pool
-        boolean tmpinstalled = false;
-        List<VMTemplateStoragePoolVO> templatePoolVOs;
-        templatePoolVOs = _templatePoolDao.listByPoolId(pool.getId());
+        boolean tmpInstalled = false;
+        // Iterate through all templates on this storage pool.
+        List<VMTemplateStoragePoolVO> templatePoolVOs = _templatePoolDao.listByPoolId(pool.getId());
 
         for (VMTemplateStoragePoolVO templatePoolVO : templatePoolVOs) {
-            if ((templateForVmCreation != null) && !tmpinstalled && (templatePoolVO.getTemplateId() == templateForVmCreation.getId())) {
-                tmpinstalled = true;
+            if ((templateForVmCreation != null) && !tmpInstalled && (templatePoolVO.getTemplateId() == templateForVmCreation.getId())) {
+                tmpInstalled = true;
             }
+
             long templateSize = templatePoolVO.getTemplateSize();
+
             totalAllocatedSize += templateSize + _extraBytesPerVolume;
         }
 
+        if ((templateForVmCreation != null) && !tmpInstalled) {
+            long templateForVmCreationSize = templateForVmCreation.getSize() != null ? templateForVmCreation.getSize() : 0;
+
+            totalAllocatedSize += templateForVmCreationSize + _extraBytesPerVolume;
+        }
+
         return totalAllocatedSize;
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
index 2b3358a..ef0ad19 100644
--- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
+++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
@@ -1234,7 +1234,8 @@ StateListener<State, VirtualMachine.Event, VirtualMachine> {
                                 requestVolumes = new ArrayList<Volume>();
                             requestVolumes.add(vol);
 
-                            if (!_storageMgr.storagePoolHasEnoughSpace(requestVolumes, potentialSPool))
+                            if (!_storageMgr.storagePoolHasEnoughIops(requestVolumes, potentialSPool) ||
+                                !_storageMgr.storagePoolHasEnoughSpace(requestVolumes, potentialSPool, potentialHost.getClusterId()))
                                 continue;
                             volumeAllocationMap.put(potentialSPool, requestVolumes);
                         }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/server/src/com/cloud/hypervisor/CloudZonesStartupProcessor.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/hypervisor/CloudZonesStartupProcessor.java b/server/src/com/cloud/hypervisor/CloudZonesStartupProcessor.java
index 4bdb2bc..2aa9b04 100644
--- a/server/src/com/cloud/hypervisor/CloudZonesStartupProcessor.java
+++ b/server/src/com/cloud/hypervisor/CloudZonesStartupProcessor.java
@@ -44,9 +44,11 @@ import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.DataCenterDetailsDao;
 import com.cloud.dc.dao.HostPodDao;
 import com.cloud.exception.ConnectionException;
+import com.cloud.host.DetailVO;
 import com.cloud.host.Host;
 import com.cloud.host.HostVO;
 import com.cloud.host.dao.HostDao;
+import com.cloud.host.dao.HostDetailsDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.utils.component.AdapterBase;
 import com.cloud.utils.exception.CloudRuntimeException;
@@ -69,6 +71,8 @@ public class CloudZonesStartupProcessor extends AdapterBase implements StartupCo
     @Inject
     HostDao _hostDao = null;
     @Inject
+    private HostDetailsDao hostDetailsDao;
+    @Inject
     HostPodDao _podDao = null;
     @Inject
     DataCenterDetailsDao _zoneDetailsDao = null;
@@ -319,6 +323,25 @@ public class CloudZonesStartupProcessor extends AdapterBase implements StartupCo
         host.setHypervisorType(hyType);
         host.setHypervisorVersion(scc.getHypervisorVersion());
 
+        updateHostDetails(host, scc);
+    }
+
+    private void updateHostDetails(HostVO host, StartupRoutingCommand startupRoutingCmd) {
+        final String name = "supportsResign";
+        final String value = String.valueOf(startupRoutingCmd.getSupportsClonedVolumes());
+
+        DetailVO hostDetail = hostDetailsDao.findDetail(host.getId(), name);
+
+        if (hostDetail != null) {
+            hostDetail.setValue(value);
+
+            hostDetailsDao.update(hostDetail.getId(), hostDetail);
+        }
+        else {
+            hostDetail = new DetailVO(host.getId(), name, value);
+
+            hostDetailsDao.persist(hostDetail);
+        }
     }
 
     private boolean checkCIDR(Host.Type type, HostPodVO pod, String serverPrivateIP, String serverPrivateNetmask) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/server/src/com/cloud/resource/ResourceManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java
index cca4add..0b59e39 100644
--- a/server/src/com/cloud/resource/ResourceManagerImpl.java
+++ b/server/src/com/cloud/resource/ResourceManagerImpl.java
@@ -1733,6 +1733,12 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
             _hostDao.update(host.getId(), host);
         }
 
+        if (startup instanceof StartupRoutingCommand) {
+            final StartupRoutingCommand ssCmd = (StartupRoutingCommand)startup;
+
+            updateHostDetails(host, ssCmd);
+        }
+
         try {
             resourceStateTransitTo(host, ResourceState.Event.InternalCreated, _nodeId);
             /* Agent goes to Connecting status */
@@ -1750,6 +1756,24 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
         return host;
     }
 
+    private void updateHostDetails(HostVO host, StartupRoutingCommand startupRoutingCmd) {
+        final String name = "supportsResign";
+        final String value = String.valueOf(startupRoutingCmd.getSupportsClonedVolumes());
+
+        DetailVO hostDetail = _hostDetailsDao.findDetail(host.getId(), name);
+
+        if (hostDetail != null) {
+            hostDetail.setValue(value);
+
+            _hostDetailsDao.update(hostDetail.getId(), hostDetail);
+        }
+        else {
+            hostDetail = new DetailVO(host.getId(), name, value);
+
+            _hostDetailsDao.persist(hostDetail);
+        }
+    }
+
     private boolean isFirstHostInCluster(final HostVO host) {
         boolean isFirstHost = true;
         if (host.getClusterId() != null) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/server/src/com/cloud/storage/ResizeVolumePayload.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/ResizeVolumePayload.java b/server/src/com/cloud/storage/ResizeVolumePayload.java
index 7a927b2..9e4c3ec 100644
--- a/server/src/com/cloud/storage/ResizeVolumePayload.java
+++ b/server/src/com/cloud/storage/ResizeVolumePayload.java
@@ -21,16 +21,21 @@ public class ResizeVolumePayload {
     public final Long newSize;
     public final Long newMinIops;
     public final Long newMaxIops;
+    public final Integer newHypervisorSnapshotReserve;
     public final boolean shrinkOk;
     public final String instanceName;
     public final long[] hosts;
+    public final boolean isManaged;
 
-    public ResizeVolumePayload(Long newSize, Long newMinIops, Long newMaxIops, boolean shrinkOk, String instanceName, long[] hosts) {
+    public ResizeVolumePayload(Long newSize, Long newMinIops, Long newMaxIops, Integer newHypervisorSnapshotReserve, boolean shrinkOk,
+                               String instanceName, long[] hosts, boolean isManaged) {
         this.newSize = newSize;
         this.newMinIops = newMinIops;
         this.newMaxIops = newMaxIops;
+        this.newHypervisorSnapshotReserve = newHypervisorSnapshotReserve;
         this.shrinkOk = shrinkOk;
         this.instanceName = instanceName;
         this.hosts = hosts;
+        this.isManaged = isManaged;
     }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/server/src/com/cloud/storage/StorageManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/StorageManager.java b/server/src/com/cloud/storage/StorageManager.java
index a399a08..0bf0011 100644
--- a/server/src/com/cloud/storage/StorageManager.java
+++ b/server/src/com/cloud/storage/StorageManager.java
@@ -106,6 +106,30 @@ public interface StorageManager extends StorageService {
 
     boolean storagePoolHasEnoughSpace(List<Volume> volume, StoragePool pool);
 
+    /**
+     * This comment is relevant to managed storage only.
+     *
+     *  Long clusterId = only used for managed storage
+     *
+     *  Some managed storage can be more efficient handling VM templates (via cloning) if it knows the capabilities of the compute cluster it is dealing with.
+     *  If the compute cluster supports UUID resigning and the storage system can clone a volume from a volume, then this determines how much more space a
+     *  new root volume (that makes use of a template) will take up on the storage system.
+     *
+     *  For example, if a storage system can clone a volume from a volume and the compute cluster supports UUID resigning (relevant for hypervisors like
+     *  XenServer and ESXi that put virtual disks in clustered file systems), then the storage system will need to determine if it already has a copy of
+     *  the template or if it will need to create one first before cloning the template to a new volume to be used for the new root disk (assuming the root
+     *  disk is being deployed from a template). If the template doesn't already exists on the storage system, then you need to take into consideration space
+     *  required for that template (stored in one volume) and space required for a new volume created from that template volume (for your new root volume).
+     *
+     *  If UUID resigning is not available in the compute cluster or the storage system doesn't support cloning a volume from a volume, then for each new
+     *  root disk that uses a template, CloudStack will have the template be copied down to a newly created volume on the storage system (i.e. no need
+     *  to take into consideration the possible need to first create a volume on the storage system for a template that will be used for the root disk
+     *  via cloning).
+     *
+     *  Cloning volumes on the back-end instead of copying down a new template for each new volume helps to alleviate load on the hypervisors.
+     */
+    boolean storagePoolHasEnoughSpace(List<Volume> volume, StoragePool pool, Long clusterId);
+
     boolean registerHostListener(String providerUuid, HypervisorHostListener listener);
 
     void connectHostToSharedPool(long hostId, long poolId) throws StorageUnavailableException, StorageConflictException;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/server/src/com/cloud/storage/StorageManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java
index 0509abc..331f09e 100644
--- a/server/src/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/com/cloud/storage/StorageManagerImpl.java
@@ -70,6 +70,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCy
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory;
+import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService.TemplateApiResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
@@ -1668,9 +1669,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
             return false;
         }
 
-        // Only IOPS guaranteed primary storage like SolidFire is using/setting IOPS.
+        // Only IOPS-guaranteed primary storage like SolidFire is using/setting IOPS.
         // This check returns true for storage that does not specify IOPS.
-        if (pool.getCapacityIops() == null ) {
+        if (pool.getCapacityIops() == null) {
             s_logger.info("Storage pool " + pool.getName() + " (" + pool.getId() + ") does not supply IOPS capacity, assuming enough capacity");
 
             return true;
@@ -1696,6 +1697,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
 
     @Override
     public boolean storagePoolHasEnoughSpace(List<Volume> volumes, StoragePool pool) {
+        return storagePoolHasEnoughSpace(volumes, pool, null);
+    }
+
+    @Override
+    public boolean storagePoolHasEnoughSpace(List<Volume> volumes, StoragePool pool, Long clusterId) {
         if (volumes == null || volumes.isEmpty()) {
             return false;
         }
@@ -1704,10 +1710,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
             return false;
         }
 
-        // allocated space includes template of specified volume
+        // allocated space includes templates
         StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId());
-        long allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null);
+        long allocatedSizeWithTemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null);
         long totalAskingSize = 0;
+
         for (Volume volume : volumes) {
             // refreshing the volume from the DB to get latest hv_ss_reserve (hypervisor snapshot reserve) field
             // I could have just assigned this to "volume", but decided to make a new variable for it so that it
@@ -1718,18 +1725,37 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
                 // update the volume's hv_ss_reserve (hypervisor snapshot reserve) from a disk offering (used for managed storage)
                 volService.updateHypervisorSnapshotReserveForVolume(getDiskOfferingVO(volumeVO), volumeVO.getId(), getHypervisorType(volumeVO));
 
-                // hv_ss_reserve field might have been updated; refresh from DB to make use of it in getVolumeSizeIncludingHypervisorSnapshotReserve
+                // hv_ss_reserve field might have been updated; refresh from DB to make use of it in getDataObjectSizeIncludingHypervisorSnapshotReserve
                 volumeVO = _volumeDao.findById(volume.getId());
             }
 
-            if (volumeVO.getTemplateId() != null) {
-                VMTemplateVO tmpl = _templateDao.findByIdIncludingRemoved(volumeVO.getTemplateId());
-                if (tmpl != null && tmpl.getFormat() != ImageFormat.ISO) {
-                    allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, tmpl);
+            // this if statement should resolve to true at most once per execution of the for loop its contained within (for a root disk that is
+            // to leverage a template)
+            if (volume.getTemplateId() != null) {
+                VMTemplateVO tmpl = _templateDao.findByIdIncludingRemoved(volume.getTemplateId());
+
+                if (tmpl != null && !ImageFormat.ISO.equals(tmpl.getFormat())) {
+                    allocatedSizeWithTemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, tmpl);
                 }
             }
+
             if (volumeVO.getState() != Volume.State.Ready) {
-                totalAskingSize = totalAskingSize + getVolumeSizeIncludingHypervisorSnapshotReserve(volumeVO, pool);
+                totalAskingSize += getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeVO, pool);
+
+                if (ScopeType.ZONE.equals(poolVO.getScope()) && volumeVO.getTemplateId() != null) {
+                    VMTemplateVO tmpl = _templateDao.findByIdIncludingRemoved(volumeVO.getTemplateId());
+
+                    if (tmpl != null && !ImageFormat.ISO.equals(tmpl.getFormat())) {
+                        // Storage plug-ins for zone-wide primary storage can be designed in such a way as to store a template on the
+                        // primary storage once and make use of it in different clusters (via cloning).
+                        // This next call leads to CloudStack asking how many more bytes it will need for the template (if the template is
+                        // already stored on the primary storage, then the answer is 0).
+
+                        if (clusterId != null && _clusterDao.computeWhetherClusterSupportsResigning(clusterId)) {
+                            totalAskingSize += getBytesRequiredForTemplate(tmpl, pool);
+                        }
+                    }
+                }
             }
         }
 
@@ -1749,11 +1775,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
         double storageAllocatedThreshold = CapacityManager.StorageAllocatedCapacityDisableThreshold.valueIn(pool.getDataCenterId());
         if (s_logger.isDebugEnabled()) {
             s_logger.debug("Checking pool: " + pool.getId() + " for volume allocation " + volumes.toString() + ", maxSize : " + totalOverProvCapacity +
-                    ", totalAllocatedSize : " + allocatedSizeWithtemplate + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " +
+                    ", totalAllocatedSize : " + allocatedSizeWithTemplate + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " +
                     storageAllocatedThreshold);
         }
 
-        double usedPercentage = (allocatedSizeWithtemplate + totalAskingSize) / (double)(totalOverProvCapacity);
+        double usedPercentage = (allocatedSizeWithTemplate + totalAskingSize) / (double)(totalOverProvCapacity);
         if (usedPercentage > storageAllocatedThreshold) {
             if (s_logger.isDebugEnabled()) {
                 s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() +
@@ -1763,10 +1789,10 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
             return false;
         }
 
-        if (totalOverProvCapacity < (allocatedSizeWithtemplate + totalAskingSize)) {
+        if (totalOverProvCapacity < (allocatedSizeWithTemplate + totalAskingSize)) {
             if (s_logger.isDebugEnabled()) {
                 s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() +
-                        ", not enough storage, maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithtemplate + ", askingSize : " +
+                        ", not enough storage, maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithTemplate + ", askingSize : " +
                         totalAskingSize);
             }
             return false;
@@ -1792,19 +1818,36 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
         return null;
     }
 
-    private long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
+    private long getDataObjectSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
         DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName());
         DataStoreDriver storeDriver = storeProvider.getDataStoreDriver();
 
         if (storeDriver instanceof PrimaryDataStoreDriver) {
             PrimaryDataStoreDriver primaryStoreDriver = (PrimaryDataStoreDriver)storeDriver;
 
-            return primaryStoreDriver.getVolumeSizeIncludingHypervisorSnapshotReserve(volume, pool);
+            VolumeInfo volumeInfo = volFactory.getVolume(volume.getId());
+
+            return primaryStoreDriver.getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, pool);
         }
 
         return volume.getSize();
     }
 
+    private long getBytesRequiredForTemplate(VMTemplateVO tmpl, StoragePool pool) {
+        DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName());
+        DataStoreDriver storeDriver = storeProvider.getDataStoreDriver();
+
+        if (storeDriver instanceof PrimaryDataStoreDriver) {
+            PrimaryDataStoreDriver primaryStoreDriver = (PrimaryDataStoreDriver)storeDriver;
+
+            TemplateInfo templateInfo = tmplFactory.getReadyTemplateOnImageStore(tmpl.getId(), pool.getDataCenterId());
+
+            return primaryStoreDriver.getBytesRequiredForTemplate(templateInfo, pool);
+        }
+
+        return tmpl.getSize();
+    }
+
     @Override
     public void createCapacityEntry(long poolId) {
         StoragePoolVO storage = _storagePoolDao.findById(poolId);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/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 4c3de3e..395b00c 100644
--- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
@@ -839,6 +839,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
         Long newSize = null;
         Long newMinIops = null;
         Long newMaxIops = null;
+        Integer newHypervisorSnapshotReserve = null;
         boolean shrinkOk = cmd.getShrinkOk();
 
         VolumeVO volume = _volsDao.findById(cmd.getEntityId());
@@ -881,6 +882,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
         // if we are to use the existing disk offering
         if (newDiskOffering == null) {
             newSize = cmd.getSize();
+            newHypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve();
 
             // if the caller is looking to change the size of the volume
             if (newSize != null) {
@@ -939,10 +941,6 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
                 throw new InvalidParameterValueException("There are no tags on the current disk offering. The new disk offering needs to have no tags, as well.");
             }
 
-            if (!areIntegersEqual(diskOffering.getHypervisorSnapshotReserve(), newDiskOffering.getHypervisorSnapshotReserve())) {
-                throw new InvalidParameterValueException("The hypervisor snapshot reverse on the new and old disk offerings must be equal.");
-            }
-
             if (newDiskOffering.getDomainId() != null) {
                 // not a public offering; check access
                 _configMgr.checkDiskOfferingAccess(CallContext.current().getCallingAccount(), newDiskOffering);
@@ -975,6 +973,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
                 newMinIops = newDiskOffering.getMinIops();
                 newMaxIops = newDiskOffering.getMaxIops();
             }
+
+            // if the hypervisor snapshot reserve value is null, it must remain null (currently only KVM uses null and null is all KVM uses for a value here)
+            newHypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve() != null ? newDiskOffering.getHypervisorSnapshotReserve() : null;
         }
 
         long currentSize = volume.getSize();
@@ -1013,6 +1014,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
             volume.setSize(newSize);
             volume.setMinIops(newMinIops);
             volume.setMaxIops(newMaxIops);
+            volume.setHypervisorSnapshotReserve(newHypervisorSnapshotReserve);
 
             if (newDiskOffering != null) {
                 volume.setDiskOfferingId(cmd.getNewDiskOfferingId());
@@ -1038,13 +1040,13 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
 
                 try {
                     return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops,
-                            newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk);
+                            newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk);
                 } finally {
                     _workJobDao.expunge(placeHolder.getId());
                 }
             } else {
                 Outcome<Volume> outcome = resizeVolumeThroughJobQueue(userVm.getId(), volume.getId(), currentSize, newSize, newMinIops, newMaxIops,
-                        newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk);
+                        newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk);
 
                 try {
                     outcome.get();
@@ -1079,19 +1081,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
         }
 
         return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops,
-                newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk);
-    }
-
-    private static boolean areIntegersEqual(Integer i1, Integer i2) {
-        if (i1 == null) {
-            i1 = 0;
-        }
-
-        if (i2 == null) {
-            i2 = 0;
-        }
-
-        return i1.equals(i2);
+                newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk);
     }
 
     private void validateIops(Long minIops, Long maxIops) {
@@ -1106,9 +1096,12 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
         }
     }
 
-    private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long newSize, Long newMinIops, Long newMaxIops, Long newDiskOfferingId, boolean shrinkOk) {
+    private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long newSize, Long newMinIops, Long newMaxIops,
+                                             Integer newHypervisorSnapshotReserve, Long newDiskOfferingId, boolean shrinkOk) {
         VolumeVO volume = _volsDao.findById(volumeId);
         UserVmVO userVm = _userVmDao.findById(volume.getInstanceId());
+        StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId());
+        boolean isManaged = storagePool.isManaged();
         /*
          * get a list of hosts to send the commands to, try the system the
          * associated vm is running on first, then the last known place it ran.
@@ -1127,8 +1120,6 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
 
             final String errorMsg = "The VM must be stopped or the disk detached in order to resize with the XenServer Hypervisor.";
 
-            StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId());
-
             if (storagePool.isManaged() && storagePool.getHypervisor() == HypervisorType.Any && hosts != null && hosts.length > 0) {
                 HostVO host = _hostDao.findById(hosts[0]);
 
@@ -1143,13 +1134,20 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
             }
         }
 
-        ResizeVolumePayload payload = new ResizeVolumePayload(newSize, newMinIops, newMaxIops, shrinkOk, instanceName, hosts);
+        ResizeVolumePayload payload = new ResizeVolumePayload(newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve,
+                shrinkOk, instanceName, hosts, isManaged);
 
         try {
             VolumeInfo vol = volFactory.getVolume(volume.getId());
             vol.addPayload(payload);
 
-            StoragePoolVO storagePool = _storagePoolDao.findById(vol.getPoolId());
+            // this call to resize has a different impact depending on whether the
+            // underlying primary storage is managed or not
+            // if managed, this is the chance for the plug-in to change IOPS value, if applicable
+            // if not managed, this is the chance for the plug-in to talk to the hypervisor layer
+            // to change the size of the disk
+            AsyncCallFuture<VolumeApiResult> future = volService.resize(vol);
+            VolumeApiResult result = future.get();
 
             // managed storage is designed in such a way that the storage plug-in does not
             // talk to the hypervisor layer; as such, if the storage is managed and the
@@ -1165,14 +1163,6 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
                 _volsDao.update(volume.getId(), volume);
             }
 
-            // this call to resize has a different impact depending on whether the
-            // underlying primary storage is managed or not
-            // if managed, this is the chance for the plug-in to change IOPS value, if applicable
-            // if not managed, this is the chance for the plug-in to talk to the hypervisor layer
-            // to change the size of the disk
-            AsyncCallFuture<VolumeApiResult> future = volService.resize(vol);
-            VolumeApiResult result = future.get();
-
             if (result.isFailed()) {
                 s_logger.warn("Failed to resize the volume " + volume);
                 String details = "";
@@ -2758,9 +2748,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
         return new VmJobVolumeOutcome(workJob, volumeId);
     }
 
-    public Outcome<Volume> resizeVolumeThroughJobQueue(final Long vmId, final long volumeId,
-            final long currentSize, final long newSize, final Long newMinIops, final Long newMaxIops, final Long newServiceOfferingId, final boolean shrinkOk) {
-
+    public Outcome<Volume> resizeVolumeThroughJobQueue(final Long vmId, final long volumeId, final long currentSize, final long newSize,
+                                                       final Long newMinIops, final Long newMaxIops, final Integer newHypervisorSnapshotReserve,
+                                                       final Long newServiceOfferingId, final boolean shrinkOk) {
         final CallContext context = CallContext.current();
         final User callingUser = context.getCallingUser();
         final Account callingAccount = context.getCallingAccount();
@@ -2781,7 +2771,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
 
         // save work context info (there are some duplications)
         VmWorkResizeVolume workInfo = new VmWorkResizeVolume(callingUser.getId(), callingAccount.getId(), vm.getId(),
-                VolumeApiServiceImpl.VM_WORK_JOB_HANDLER, volumeId, currentSize, newSize, newMinIops, newMaxIops, newServiceOfferingId, shrinkOk);
+                VolumeApiServiceImpl.VM_WORK_JOB_HANDLER, volumeId, currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, newServiceOfferingId, shrinkOk);
         workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
 
         _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId());
@@ -2915,7 +2905,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
     @ReflectionUse
     private Pair<JobInfo.Status, String> orchestrateResizeVolume(VmWorkResizeVolume work) throws Exception {
         Volume vol = orchestrateResizeVolume(work.getVolumeId(), work.getCurrentSize(), work.getNewSize(), work.getNewMinIops(), work.getNewMaxIops(),
-                work.getNewServiceOfferingId(), work.isShrinkOk());
+                work.getNewHypervisorSnapshotReserve(), work.getNewServiceOfferingId(), work.isShrinkOk());
         return new Pair<JobInfo.Status, String>(JobInfo.Status.SUCCEEDED,
                 _jobMgr.marshallResultObject(new Long(vol.getId())));
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/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 757ab61..16762c5 100644
--- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
+++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
@@ -35,6 +35,7 @@ import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd;
 import org.apache.cloudstack.api.command.user.snapshot.UpdateSnapshotPolicyCmd;
 import org.apache.cloudstack.context.CallContext;
 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;
@@ -1013,9 +1014,14 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
 
             try {
                 postCreateSnapshot(volume.getId(), snapshotId, payload.getSnapshotPolicyId());
-                SnapshotDataStoreVO snapshotStoreRef = _snapshotStoreDao.findBySnapshot(snapshotId, DataStoreRole.Image);
+
+                DataStoreRole dataStoreRole = getDataStoreRole(snapshot, _snapshotStoreDao, dataStoreMgr);
+
+                SnapshotDataStoreVO snapshotStoreRef = _snapshotStoreDao.findBySnapshot(snapshotId, dataStoreRole);
+
                 UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(), snapshot.getDataCenterId(), snapshotId, snapshot.getName(),
                     null, null, snapshotStoreRef.getPhysicalSize(), volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid());
+
                 // Correct the resource count of snapshot in case of delta snapshots.
                 _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.secondary_storage, new Long(volume.getSize() - snapshotStoreRef.getPhysicalSize()));
             } catch (Exception e) {
@@ -1030,6 +1036,30 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
         return snapshot;
     }
 
+    private 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);
+
+        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
     public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/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 4b27c8b..ceee616 100644
--- a/server/src/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/com/cloud/template/TemplateManagerImpl.java
@@ -38,7 +38,7 @@ import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 
 import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd;
-import org.apache.cloudstack.api.response.GetUploadParamsResponse;
+import org.apache.cloudstack.framework.async.AsyncCallFuture;
 import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand;
 import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
 import org.apache.commons.collections.CollectionUtils;
@@ -62,12 +62,14 @@ import org.apache.cloudstack.api.command.user.template.ListTemplatePermissionsCm
 import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
 import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd;
 import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd;
+import org.apache.cloudstack.api.response.GetUploadParamsResponse;
 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.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
+import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
@@ -79,7 +81,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService.Templa
 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.ZoneScope;
-import org.apache.cloudstack.framework.async.AsyncCallFuture;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
@@ -689,7 +690,9 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
         }
 
         try {
+            templateStoragePoolRef.setTemplateSize(0);
             templateStoragePoolRef.setDownloadState(VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED);
+
             _tmpltPoolDao.update(templateStoragePoolRefId, templateStoragePoolRef);
         } finally {
             _tmpltPoolDao.releaseFromLockTable(templateStoragePoolRefId);
@@ -873,41 +876,55 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
     @Override
     @DB
     public void evictTemplateFromStoragePool(VMTemplateStoragePoolVO templatePoolVO) {
-        //Need to hold the lock, otherwise, another thread may create a volume from the template at the same time.
-        //Assumption here is that, we will hold the same lock during create volume from template
+        // Need to hold the lock; otherwise, another thread may create a volume from the template at the same time.
+        // Assumption here is that we will hold the same lock during create volume from template.
         VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.acquireInLockTable(templatePoolVO.getId());
+
         if (templatePoolRef == null) {
-            s_logger.debug("can't aquire the lock for template pool ref:" + templatePoolVO.getId());
+            s_logger.debug("Can't aquire the lock for template pool ref: " + templatePoolVO.getId());
+
             return;
         }
 
-        try {
-            StoragePool pool = (StoragePool)_dataStoreMgr.getPrimaryDataStore(templatePoolVO.getPoolId());
-            VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templatePoolVO.getTemplateId());
+        PrimaryDataStore pool = (PrimaryDataStore)_dataStoreMgr.getPrimaryDataStore(templatePoolVO.getPoolId());
+        TemplateInfo template = _tmplFactory.getTemplate(templatePoolRef.getTemplateId(), pool);
 
+        try {
             if (s_logger.isDebugEnabled()) {
                 s_logger.debug("Evicting " + templatePoolVO);
             }
-            DestroyCommand cmd = new DestroyCommand(pool, templatePoolVO);
 
-            try {
+            if (pool.isManaged()) {
+                // For managed store, just delete the template volume.
+                AsyncCallFuture<TemplateApiResult> future = _tmpltSvr.deleteTemplateOnPrimary(template, pool);
+                TemplateApiResult result = future.get();
+
+                if (result.isFailed()) {
+                    s_logger.debug("Failed to delete template " + template.getId() + " from storage pool " + pool.getId());
+                } else {
+                    // Remove the templatePoolVO.
+                    if (_tmpltPoolDao.remove(templatePoolVO.getId())) {
+                        s_logger.debug("Successfully evicted template " + template.getName() + " from storage pool " + pool.getName());
+                    }
+                }
+            } else {
+                DestroyCommand cmd = new DestroyCommand(pool, templatePoolVO);
                 Answer answer = _storageMgr.sendToPool(pool, cmd);
 
                 if (answer != null && answer.getResult()) {
-                    // Remove the templatePoolVO
+                    // Remove the templatePoolVO.
                     if (_tmpltPoolDao.remove(templatePoolVO.getId())) {
-                        s_logger.debug("Successfully evicted template: " + template.getName() + " from storage pool: " + pool.getName());
+                        s_logger.debug("Successfully evicted template " + template.getName() + " from storage pool " + pool.getName());
                     }
                 } else {
-                    s_logger.info("Will retry evicte template: " + template.getName() + " from storage pool: " + pool.getName());
+                    s_logger.info("Will retry evict template " + template.getName() + " from storage pool " + pool.getName());
                 }
-            } catch (StorageUnavailableException e) {
-                s_logger.info("Storage is unavailable currently.  Will retry evicte template: " + template.getName() + " from storage pool: " + pool.getName());
             }
+        } catch (StorageUnavailableException | InterruptedException | ExecutionException e) {
+            s_logger.info("Storage is unavailable currently. Will retry evicte template " + template.getName() + " from storage pool " + pool.getName());
         } finally {
             _tmpltPoolDao.releaseFromLockTable(templatePoolRef.getId());
         }
-
     }
 
     @Override
@@ -1482,14 +1499,17 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
                 future = _tmpltSvr.createTemplateFromSnapshotAsync(snapInfo, tmplInfo, store);
             } else if (volumeId != null) {
                 VolumeInfo volInfo = _volFactory.getVolume(volumeId);
+
                 future = _tmpltSvr.createTemplateFromVolumeAsync(volInfo, tmplInfo, store);
             } else {
                 throw new CloudRuntimeException("Creating private Template need to specify snapshotId or volumeId");
             }
 
             CommandResult result = null;
+
             try {
                 result = future.get();
+
                 if (result.isFailed()) {
                     privateTemplate = null;
                     s_logger.debug("Failed to create template" + result.getResult());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/ui/scripts/storage.js
----------------------------------------------------------------------
diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js
index 39dfccf..29cd4c1 100644
--- a/ui/scripts/storage.js
+++ b/ui/scripts/storage.js
@@ -1550,6 +1550,8 @@
                                     preFilter: function(args) {
                                         if (args.context.volumes != null && args.context.volumes[0].type == 'ROOT') {
                                             args.$form.find('.form-item[rel=newdiskoffering]').hide();
+
+                                            selectedDiskOfferingObj = null;
                                         } else {
                                             args.$form.find('.form-item[rel=newsize]').hide();
                                         }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2bd035d1/utils/src/main/java/com/cloud/utils/Utils.java
----------------------------------------------------------------------
diff --git a/utils/src/main/java/com/cloud/utils/Utils.java b/utils/src/main/java/com/cloud/utils/Utils.java
new file mode 100644
index 0000000..53f0a80
--- /dev/null
+++ b/utils/src/main/java/com/cloud/utils/Utils.java
@@ -0,0 +1,38 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package com.cloud.utils;
+
+import java.util.Map;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+public class Utils {
+    public static <K, V> Map getImmutableMap(Map<K, V> map) {
+        Map<K, V> filteredMap = Maps.filterValues(map, new Predicate<V>() {
+            public boolean apply(final V input) {
+                return input != null;
+            }
+        });
+
+        return ImmutableMap.<K, V>builder().putAll(filteredMap).build();
+    }
+}


Mime
View raw message