You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mt...@apache.org on 2014/06/24 22:50:43 UTC

git commit: updated refs/heads/master to c344693

Repository: cloudstack
Updated Branches:
  refs/heads/master 0df156c09 -> c344693e4


Inform the applicable storage plug-in's life cycle that capacity (bytes and/or IOPS) can be updated


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

Branch: refs/heads/master
Commit: c344693e48d80313270d1a972b0a3badf315567d
Parents: 0df156c
Author: Mike Tutkowski <mi...@solidfire.com>
Authored: Tue Jun 17 19:22:52 2014 -0600
Committer: Mike Tutkowski <mi...@solidfire.com>
Committed: Tue Jun 24 14:39:57 2014 -0600

----------------------------------------------------------------------
 .../api/storage/PrimaryDataStoreLifeCycle.java  |   8 ++
 .../src/com/cloud/capacity/CapacityManager.java |   4 +
 .../ElastistorPrimaryDataStoreLifeCycle.java    |   4 +-
 ...CloudStackPrimaryDataStoreLifeCycleImpl.java |   3 +
 .../NexentaPrimaryDataStoreLifeCycle.java       |   5 +
 .../SamplePrimaryDataStoreLifeCycleImpl.java    |   4 +
 .../SolidFirePrimaryDataStoreLifeCycle.java     |  48 +++++--
 ...olidFireSharedPrimaryDataStoreLifeCycle.java |  59 +++++++-
 .../storage/datastore/util/SolidFireUtil.java   | 144 ++++++++++++++++++-
 .../com/cloud/capacity/CapacityManagerImpl.java |  18 ++-
 .../com/cloud/storage/StorageManagerImpl.java   |  39 ++---
 ui/scripts/sharedFunctions.js                   |  34 +++++
 ui/scripts/system.js                            |  10 ++
 13 files changed, 341 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c344693e/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreLifeCycle.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreLifeCycle.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreLifeCycle.java
index 28b06f5..7640cf3 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreLifeCycle.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreLifeCycle.java
@@ -18,5 +18,13 @@
  */
 package org.apache.cloudstack.engine.subsystem.api.storage;
 
+import java.util.Map;
+
+import com.cloud.storage.StoragePool;
+
 public interface PrimaryDataStoreLifeCycle extends DataStoreLifeCycle {
+    public static final String CAPACITY_BYTES = "capacityBytes";
+    public static final String CAPACITY_IOPS = "capacityIops";
+
+    void updateStoragePool(StoragePool storagePool, Map<String, String> details);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c344693e/engine/components-api/src/com/cloud/capacity/CapacityManager.java
----------------------------------------------------------------------
diff --git a/engine/components-api/src/com/cloud/capacity/CapacityManager.java b/engine/components-api/src/com/cloud/capacity/CapacityManager.java
index 038a2c0..51f7332 100755
--- a/engine/components-api/src/com/cloud/capacity/CapacityManager.java
+++ b/engine/components-api/src/com/cloud/capacity/CapacityManager.java
@@ -102,4 +102,8 @@ public interface CapacityManager {
     boolean checkIfClusterCrossesThreshold(Long clusterId, Integer cpuRequested, long ramRequested);
 
     float getClusterOverProvisioningFactor(Long clusterId, short capacityType);
+
+    long getUsedBytes(StoragePoolVO pool);
+
+    long getUsedIops(StoragePoolVO pool);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c344693e/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/lifecycle/ElastistorPrimaryDataStoreLifeCycle.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/lifecycle/ElastistorPrimaryDataStoreLifeCycle.java b/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/lifecycle/ElastistorPrimaryDataStoreLifeCycle.java
index aa33b2f..33004e3 100755
--- a/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/lifecycle/ElastistorPrimaryDataStoreLifeCycle.java
+++ b/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/lifecycle/ElastistorPrimaryDataStoreLifeCycle.java
@@ -493,5 +493,7 @@ public class ElastistorPrimaryDataStoreLifeCycle implements PrimaryDataStoreLife
         return false;
     }
 
-
+    @Override
+    public void updateStoragePool(StoragePool storagePool, Map<String, String> details) {
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c344693e/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java
index 65236d9..49eb8ef 100644
--- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java
+++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java
@@ -525,4 +525,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements PrimaryDataStore
         return false;
     }
 
+    @Override
+    public void updateStoragePool(StoragePool storagePool, Map<String, String> details) {
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c344693e/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/lifecylce/NexentaPrimaryDataStoreLifeCycle.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/lifecylce/NexentaPrimaryDataStoreLifeCycle.java b/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/lifecylce/NexentaPrimaryDataStoreLifeCycle.java
index c7ce33a..493f274 100644
--- a/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/lifecylce/NexentaPrimaryDataStoreLifeCycle.java
+++ b/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/lifecylce/NexentaPrimaryDataStoreLifeCycle.java
@@ -41,6 +41,7 @@ import com.cloud.host.HostVO;
 import com.cloud.hypervisor.Hypervisor;
 import com.cloud.resource.ResourceManager;
 import com.cloud.storage.StorageManager;
+import com.cloud.storage.StoragePool;
 import com.cloud.storage.StoragePoolAutomation;
 
 public class NexentaPrimaryDataStoreLifeCycle
@@ -173,4 +174,8 @@ public class NexentaPrimaryDataStoreLifeCycle
     public boolean migrateToObjectStore(DataStore store) {
         return false;
     }
+
+    @Override
+    public void updateStoragePool(StoragePool storagePool, Map<String, String> details) {
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c344693e/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/lifecycle/SamplePrimaryDataStoreLifeCycleImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/lifecycle/SamplePrimaryDataStoreLifeCycleImpl.java b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/lifecycle/SamplePrimaryDataStoreLifeCycleImpl.java
index 6b5e431..579cc24 100644
--- a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/lifecycle/SamplePrimaryDataStoreLifeCycleImpl.java
+++ b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/lifecycle/SamplePrimaryDataStoreLifeCycleImpl.java
@@ -41,6 +41,7 @@ import com.cloud.agent.api.StoragePoolInfo;
 import com.cloud.host.HostVO;
 import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.storage.StoragePool;
 import com.cloud.storage.StoragePoolStatus;
 
 public class SamplePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
@@ -135,4 +136,7 @@ public class SamplePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLife
         return false;
     }
 
+    @Override
+    public void updateStoragePool(StoragePool storagePool, Map<String, String> details) {
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c344693e/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
index 7fc3436..c23db14 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
@@ -33,15 +33,18 @@ import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCy
 import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
 import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
 import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
 
 import com.cloud.agent.api.StoragePoolInfo;
+import com.cloud.capacity.CapacityManager;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.host.HostVO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.resource.ResourceManager;
+import com.cloud.storage.StoragePool;
 import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.StorageManager;
 import com.cloud.storage.StoragePoolAutomation;
@@ -50,18 +53,13 @@ import com.cloud.utils.exception.CloudRuntimeException;
 public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle {
     private static final Logger s_logger = Logger.getLogger(SolidFirePrimaryDataStoreLifeCycle.class);
 
-    @Inject
-    private DataCenterDao zoneDao;
-    @Inject
-    private PrimaryDataStoreDao storagePoolDao;
-    @Inject
-    private PrimaryDataStoreHelper dataStoreHelper;
-    @Inject
-    private ResourceManager _resourceMgr;
-    @Inject
-    private StorageManager _storageMgr;
-    @Inject
-    private StoragePoolAutomation storagePoolAutomation;
+    @Inject CapacityManager _capacityMgr;
+    @Inject private DataCenterDao zoneDao;
+    @Inject private PrimaryDataStoreDao storagePoolDao;
+    @Inject private PrimaryDataStoreHelper dataStoreHelper;
+    @Inject private ResourceManager _resourceMgr;
+    @Inject private StorageManager _storageMgr;
+    @Inject private StoragePoolAutomation storagePoolAutomation;
 
     // invoked to add primary storage that is based on the SolidFire plug-in
     @Override
@@ -244,4 +242,30 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
         return false;
     }
 
+    @Override
+    public void updateStoragePool(StoragePool storagePool, Map<String, String> details) {
+        StoragePoolVO storagePoolVo = storagePoolDao.findById(storagePool.getId());
+
+        String strCapacityBytes = details.get(PrimaryDataStoreLifeCycle.CAPACITY_BYTES);
+        Long capacityBytes = strCapacityBytes != null ? Long.parseLong(strCapacityBytes) : null;
+
+        if (capacityBytes != null) {
+            long usedBytes = _capacityMgr.getUsedBytes(storagePoolVo);
+
+            if (capacityBytes < usedBytes) {
+                throw new CloudRuntimeException("Cannot reduce the number of bytes for this storage pool as it would lead to an insufficient number of bytes");
+            }
+        }
+
+        String strCapacityIops = details.get(PrimaryDataStoreLifeCycle.CAPACITY_IOPS);
+        Long capacityIops = strCapacityIops != null ? Long.parseLong(strCapacityIops) : null;
+
+        if (capacityIops != null) {
+            long usedIops = _capacityMgr.getUsedIops(storagePoolVo);
+
+            if (capacityIops < usedIops) {
+                throw new CloudRuntimeException("Cannot reduce the number of IOPS for this storage pool as it would lead to an insufficient number of IOPS");
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c344693e/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java
index ec2a52f..b03634b 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java
@@ -209,6 +209,10 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor
             throw new CloudRuntimeException("The parameter '" + CAPACITY_IOPS + "' must be equal to the parameter '" + SolidFireUtil.MIN_IOPS + "'.");
         }
 
+        if (lMinIops > SolidFireUtil.MAX_IOPS_PER_VOLUME || lMaxIops > SolidFireUtil.MAX_IOPS_PER_VOLUME || lBurstIops > SolidFireUtil.MAX_IOPS_PER_VOLUME) {
+            throw new CloudRuntimeException("This volume cannot exceed " + NumberFormat.getInstance().format(SolidFireUtil.MAX_IOPS_PER_VOLUME) + " IOPS.");
+        }
+
         details.put(SolidFireUtil.MIN_IOPS, String.valueOf(lMinIops));
         details.put(SolidFireUtil.MAX_IOPS, String.valueOf(lMaxIops));
         details.put(SolidFireUtil.BURST_IOPS, String.valueOf(lBurstIops));
@@ -302,7 +306,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor
             }
 
             long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeName), sfAccount.getId(), volumeSize,
-                    true, NumberFormat.getInstance().format(volumeSize), minIops, maxIops, burstIops);
+                    true, null, minIops, maxIops, burstIops);
             SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
 
             return sfVolume;
@@ -523,6 +527,14 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor
         return Long.parseLong(volumeId);
     }
 
+    private long getIopsValue(long storagePoolId, String iopsKey) {
+        StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, iopsKey);
+
+        String iops = storagePoolDetail.getValue();
+
+        return Long.parseLong(iops);
+    }
+
     private static boolean isSupportedHypervisorType(HypervisorType hypervisorType) {
         return HypervisorType.XenServer.equals(hypervisorType) || HypervisorType.VMware.equals(hypervisorType);
     }
@@ -545,4 +557,49 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor
         return false;
     }
 
+    @Override
+    public void updateStoragePool(StoragePool storagePool, Map<String, String> details) {
+        String strCapacityBytes = details.get(PrimaryDataStoreLifeCycle.CAPACITY_BYTES);
+        String strCapacityIops = details.get(PrimaryDataStoreLifeCycle.CAPACITY_IOPS);
+
+        Long capacityBytes = strCapacityBytes != null ? Long.parseLong(strCapacityBytes) : null;
+        Long capacityIops = strCapacityIops != null ? Long.parseLong(strCapacityIops) : null;
+
+        SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), _storagePoolDetailsDao);
+
+        long size = capacityBytes != null ? capacityBytes : storagePool.getCapacityBytes();
+
+        long currentMinIops = getIopsValue(storagePool.getId(), SolidFireUtil.MIN_IOPS);
+        long currentMaxIops = getIopsValue(storagePool.getId(), SolidFireUtil.MAX_IOPS);
+        long currentBurstIops = getIopsValue(storagePool.getId(), SolidFireUtil.BURST_IOPS);
+
+        long minIops = currentMinIops;
+        long maxIops = currentMaxIops;
+        long burstIops = currentBurstIops;
+
+        if (capacityIops != null) {
+            if (capacityIops > SolidFireUtil.MAX_IOPS_PER_VOLUME) {
+                throw new CloudRuntimeException("This volume cannot exceed " + NumberFormat.getInstance().format(SolidFireUtil.MAX_IOPS_PER_VOLUME) + " IOPS.");
+            }
+
+            float maxPercentOfMin = currentMaxIops / (float)currentMinIops;
+            float burstPercentOfMax = currentBurstIops / (float)currentMaxIops;
+
+            minIops = capacityIops;
+            maxIops = (long)(minIops * maxPercentOfMin);
+            burstIops = (long)(maxIops * burstPercentOfMax);
+
+            if (maxIops > SolidFireUtil.MAX_IOPS_PER_VOLUME) {
+                maxIops = SolidFireUtil.MAX_IOPS_PER_VOLUME;
+            }
+
+            if (burstIops > SolidFireUtil.MAX_IOPS_PER_VOLUME) {
+                burstIops = SolidFireUtil.MAX_IOPS_PER_VOLUME;
+            }
+        }
+
+        SolidFireUtil.modifySolidFireVolume(sfConnection, getVolumeId(storagePool.getId()), size, minIops, maxIops, burstIops);
+
+        SolidFireUtil.updateCsDbWithSolidFireIopsInfo(storagePool.getId(), _primaryDataStoreDao, _storagePoolDetailsDao, minIops, maxIops, burstIops);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c344693e/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 a27917b..3f35d71 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
@@ -28,7 +28,10 @@ import java.security.SecureRandom;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.UUID;
 
@@ -36,6 +39,7 @@ import javax.net.ssl.SSLContext;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
 
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
 import org.apache.commons.lang.StringUtils;
@@ -99,6 +103,8 @@ public class SolidFireUtil {
     public static final String DATASTORE_NAME = "datastoreName";
     public static final String IQN = "iqn";
 
+    public static final long MAX_IOPS_PER_VOLUME = 100000;
+
     private static final int DEFAULT_MANAGEMENT_PORT = 443;
     private static final int DEFAULT_STORAGE_PORT = 3260;
 
@@ -156,6 +162,30 @@ public class SolidFireUtil {
         return "CloudStack_" + csAccountUuid + "_" + csAccountId;
     }
 
+    public static void updateCsDbWithSolidFireIopsInfo(long storagePoolId, PrimaryDataStoreDao primaryDataStoreDao, StoragePoolDetailsDao storagePoolDetailsDao,
+            long minIops, long maxIops, long burstIops) {
+        Map<String, String> existingDetails = storagePoolDetailsDao.listDetailsKeyPairs(storagePoolId);
+        Set<String> existingKeys = existingDetails.keySet();
+
+        Map<String, String> existingDetailsToKeep = new HashMap<String, String>();
+
+        for (String existingKey : existingKeys) {
+            String existingValue = existingDetails.get(existingKey);
+
+            if (!SolidFireUtil.MIN_IOPS.equalsIgnoreCase(existingValue) &&
+                    !SolidFireUtil.MAX_IOPS.equalsIgnoreCase(existingValue) &&
+                    !SolidFireUtil.BURST_IOPS.equalsIgnoreCase(existingValue)) {
+                existingDetailsToKeep.put(existingKey, existingValue);
+            }
+        }
+
+        existingDetailsToKeep.put(SolidFireUtil.MIN_IOPS, String.valueOf(minIops));
+        existingDetailsToKeep.put(SolidFireUtil.MAX_IOPS, String.valueOf(maxIops));
+        existingDetailsToKeep.put(SolidFireUtil.BURST_IOPS, String.valueOf(burstIops));
+
+        primaryDataStoreDao.updateDetails(storagePoolId, existingDetailsToKeep);
+    }
+
     public static void updateCsDbWithSolidFireAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount,
             AccountDetailsDao accountDetailsDao) {
         AccountDetailVO accountDetail = new AccountDetailVO(csAccountId,
@@ -402,11 +432,13 @@ public class SolidFireUtil {
     }
 
     public static long createSolidFireVolume(SolidFireConnection sfConnection, String strSfVolumeName, long lSfAccountId, long lTotalSize,
-            boolean bEnable512e, final String strCloudStackVolumeSize, long lMinIops, long lMaxIops, long lBurstIops)
+            boolean bEnable512e, String strCloudStackVolumeSize, long minIops, long maxIops, long burstIops)
     {
         final Gson gson = new GsonBuilder().create();
 
-        VolumeToCreate volumeToCreate = new VolumeToCreate(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, strCloudStackVolumeSize, lMinIops, lMaxIops, lBurstIops);
+        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);
 
         String strVolumeToCreateJson = gson.toJson(volumeToCreate);
 
@@ -419,6 +451,23 @@ public class SolidFireUtil {
         return volumeCreateResult.result.volumeID;
     }
 
+    public static void modifySolidFireVolume(SolidFireConnection sfConnection, long volumeId, long totalSize, long minIops, long maxIops, long burstIops)
+    {
+        final Gson gson = new GsonBuilder().create();
+
+        VolumeToModify volumeToModify = new VolumeToModify(volumeId, totalSize, minIops, maxIops, burstIops);
+
+        String strVolumeToModifyJson = gson.toJson(volumeToModify);
+
+        String strVolumeModifyResultJson = executeJsonRpc(sfConnection, strVolumeToModifyJson);
+
+        JsonError jsonError = gson.fromJson(strVolumeModifyResultJson, JsonError.class);
+
+        if (jsonError.error != null) {
+            throw new IllegalStateException(jsonError.error.message);
+        }
+    }
+
     public static SolidFireVolume getSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
     {
         final Gson gson = new GsonBuilder().create();
@@ -868,12 +917,12 @@ public class SolidFireUtil {
     }
 
     @SuppressWarnings("unused")
-    private static final class VolumeToCreate {
+    private static final class VolumeToCreateWithCloudStackVolumeSize {
         private final String method = "CreateVolume";
         private final VolumeToCreateParams params;
 
-        private VolumeToCreate(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e, final String strCloudStackVolumeSize,
-                final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
+        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);
         }
 
@@ -919,6 +968,87 @@ public class SolidFireUtil {
     }
 
     @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 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";
@@ -1376,8 +1506,8 @@ public class SolidFireUtil {
         return iCode >= 200 && iCode < 300;
     }
 
-    private static void verifyResult(Object obj, String strJson, Gson gson) throws IllegalStateException {
-        if (obj != null) {
+    private static void verifyResult(Object result, String strJson, Gson gson) throws IllegalStateException {
+        if (result != null) {
             return;
         }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c344693e/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 14fbe7f..e57604e 100755
--- a/server/src/com/cloud/capacity/CapacityManagerImpl.java
+++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java
@@ -514,7 +514,8 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
 
     }
 
-    private long getUsedBytes(StoragePoolVO pool) {
+    @Override
+    public long getUsedBytes(StoragePoolVO pool) {
         long usedBytes = 0;
 
         List<VolumeVO> volumes = _volumeDao.findByPoolId(pool.getId(), null);
@@ -542,6 +543,21 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
     }
 
     @Override
+    public long getUsedIops(StoragePoolVO pool) {
+        long usedIops = 0;
+
+        List<VolumeVO> volumes = _volumeDao.findByPoolId(pool.getId(), null);
+
+        if (volumes != null && volumes.size() > 0) {
+            for (VolumeVO volume : volumes) {
+                usedIops += volume.getMinIops();
+            }
+        }
+
+        return usedIops;
+    }
+
+    @Override
     public long getAllocatedPoolCapacity(StoragePoolVO pool, VMTemplateVO templateForVmCreation) {
         long totalAllocatedSize = 0;
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c344693e/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 de4ad4b..07ae695 100755
--- a/server/src/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/com/cloud/storage/StorageManagerImpl.java
@@ -67,6 +67,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener
 import org.apache.cloudstack.engine.subsystem.api.storage.ImageStoreProvider;
 import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
 import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
+import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
 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;
@@ -755,10 +756,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
         Long capacityBytes = cmd.getCapacityBytes();
 
         if (capacityBytes != null) {
-            if (capacityBytes > pool.getCapacityBytes()) {
+            if (capacityBytes != pool.getCapacityBytes()) {
                 updatedCapacityBytes = capacityBytes;
-            } else if (capacityBytes < pool.getCapacityBytes()) {
-                throw new CloudRuntimeException("The value of 'Capacity bytes' cannot be reduced in this version.");
             }
         }
 
@@ -766,10 +765,23 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
         Long capacityIops = cmd.getCapacityIops();
 
         if (capacityIops != null) {
-            if (capacityIops > pool.getCapacityIops()) {
+            if (capacityIops != pool.getCapacityIops()) {
                 updatedCapacityIops = capacityIops;
-            } else if (capacityIops < pool.getCapacityIops()) {
-                throw new CloudRuntimeException("The value of 'Capacity IOPS' cannot be reduced in this version.");
+            }
+        }
+
+        if (updatedCapacityBytes != null || updatedCapacityIops != null) {
+            StoragePoolVO storagePool = _storagePoolDao.findById(id);
+            DataStoreProvider dataStoreProvider = dataStoreProviderMgr.getDataStoreProvider(storagePool.getStorageProviderName());
+            DataStoreLifeCycle dataStoreLifeCycle = dataStoreProvider.getDataStoreLifeCycle();
+
+            if (dataStoreLifeCycle instanceof PrimaryDataStoreLifeCycle) {
+                Map<String, String> details = new HashMap<String, String>();
+
+                details.put(PrimaryDataStoreLifeCycle.CAPACITY_BYTES, updatedCapacityBytes != null ? String.valueOf(updatedCapacityBytes) : null);
+                details.put(PrimaryDataStoreLifeCycle.CAPACITY_IOPS, updatedCapacityIops != null ? String.valueOf(updatedCapacityIops) : null);
+
+                ((PrimaryDataStoreLifeCycle)dataStoreLifeCycle).updateStoragePool(storagePool, details);
             }
         }
 
@@ -1507,20 +1519,13 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
         // 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 ) {
-            s_logger.info("Storage pool " + pool.getName() + " (" + pool.getId() + ") does not supply Iops capacity, assuming enough capacity");
+            s_logger.info("Storage pool " + pool.getName() + " (" + pool.getId() + ") does not supply IOPS capacity, assuming enough capacity");
+
             return true;
         }
 
-        long currentIops = 0;
-        List<VolumeVO> volumesInPool = _volumeDao.findByPoolId(pool.getId(), null);
-
-        for (VolumeVO volumeInPool : volumesInPool) {
-            Long minIops = volumeInPool.getMinIops();
-
-            if (minIops != null && minIops > 0) {
-                currentIops += minIops;
-            }
-        }
+        StoragePoolVO storagePoolVo = _storagePoolDao.findById(pool.getId());
+        long currentIops = _capacityMgr.getUsedIops(storagePoolVo);
 
         long requestedIops = 0;
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c344693e/ui/scripts/sharedFunctions.js
----------------------------------------------------------------------
diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js
index f58fdd2..e8c4fcb 100644
--- a/ui/scripts/sharedFunctions.js
+++ b/ui/scripts/sharedFunctions.js
@@ -900,6 +900,40 @@ cloudStack.converters = {
             return (bytes / 1024 / 1024 / 1024 / 1024).toFixed(2) + " TB";
         }
     },
+    toBytes: function(str) {
+        if (str === undefined) {
+            return "0";
+        }
+
+        var res = str.split(" ");
+
+        if (res.length === 1) {
+            // assume a number in GB
+
+            return parseInt(str, 10) * 1024 * 1024 * 1024;
+        }
+
+        // assume first string is a number and second string is a unit of size
+
+        if (res[1] === "KB") {
+            return parseInt(res[0], 10) * 1024;
+        }
+
+        if (res[1] === "MB") {
+            return parseInt(res[0], 10) * 1024 * 1024;
+        }
+
+        if (res[1] === "GB") {
+            return parseInt(res[0], 10) * 1024 * 1024 * 1024;
+        }
+
+        if (res[1] === "TB") {
+            return parseInt(res[0], 10) * 1024 * 1024 * 1024 * 1024;
+        }
+
+        // assume GB
+        return parseInt(res[0], 10) * 1024 * 1024 * 1024;
+    },
     toLocalDate: function(UtcDate) {
         var localDate = "";
         if (UtcDate != null && UtcDate.length > 0) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c344693e/ui/scripts/system.js
----------------------------------------------------------------------
diff --git a/ui/scripts/system.js b/ui/scripts/system.js
index 7d49d8d..9a98a5c 100644
--- a/ui/scripts/system.js
+++ b/ui/scripts/system.js
@@ -16113,6 +16113,14 @@
                                     var array1 =[];
                                     array1.push("&tags=" + todb(args.data.tags));
                                     
+                                    if (args.data.disksizetotal != null && args.data.disksizetotal.length > 0) {
+                                        array1.push("&capacitybytes=" + cloudStack.converters.toBytes(args.data.disksizetotal));
+                                    }
+
+                                    if (args.data.capacityiops != null && args.data.capacityiops.length > 0) {
+                                        array1.push("&capacityiops=" + args.data.capacityiops);
+                                    }
+
                                     $.ajax({
                                         url: createURL("updateStoragePool&id=" + args.context.primarystorages[0].id + array1.join("")),
                                         dataType: "json",
@@ -16279,6 +16287,7 @@
                                     },
                                     disksizetotal: {
                                         label: 'label.disk.total',
+                                        isEditable: true,
                                         converter: function (args) {
                                             if (args == null || args == 0)
                                             return ""; else
@@ -16295,6 +16304,7 @@
                                     },
                                     capacityiops: {
                                         label: 'label.disk.iops.total',
+                                        isEditable: true,
                                         converter: function (args) {
                                             if (args == null || args == 0)
                                             return ""; else