You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mc...@apache.org on 2014/03/13 19:05:49 UTC

[02/50] [abbrv] git commit: updated refs/heads/rbac to 99bdc8d

CLOUDSTACK-6170


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

Branch: refs/heads/rbac
Commit: c427e8db1c4294bec93aa9295052950888c0fecf
Parents: e37a6cd
Author: Mike Tutkowski <mi...@solidfire.com>
Authored: Thu Mar 6 14:00:56 2014 -0700
Committer: Mike Tutkowski <mi...@solidfire.com>
Committed: Fri Mar 7 15:38:50 2014 -0700

----------------------------------------------------------------------
 .../com/cloud/offering/DiskOfferingInfo.java    | 47 ++++++++++++++++++
 .../api/command/user/vm/DeployVMCmd.java        | 50 ++++++++++++++++++++
 .../src/com/cloud/vm/VirtualMachineManager.java |  4 +-
 .../service/VolumeOrchestrationService.java     |  2 +-
 .../com/cloud/vm/VirtualMachineManagerImpl.java | 11 +++--
 .../engine/orchestration/CloudOrchestrator.java | 40 ++++++++++++----
 .../orchestration/VolumeOrchestrator.java       | 10 ++--
 ui/css/cloudstack3.css                          | 40 ++++++++++++++++
 ui/index.jsp                                    | 11 +++++
 ui/scripts/instanceWizard.js                    | 16 ++++++-
 ui/scripts/ui-custom/instanceWizard.js          |  8 ++++
 11 files changed, 218 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c427e8db/api/src/com/cloud/offering/DiskOfferingInfo.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/offering/DiskOfferingInfo.java b/api/src/com/cloud/offering/DiskOfferingInfo.java
new file mode 100644
index 0000000..e9e7da1
--- /dev/null
+++ b/api/src/com/cloud/offering/DiskOfferingInfo.java
@@ -0,0 +1,47 @@
+package com.cloud.offering;
+
+public class DiskOfferingInfo {
+    private DiskOffering _diskOffering;
+    private Long _size;
+    private Long _minIops;
+    private Long _maxIops;
+
+    public DiskOfferingInfo() {
+    }
+
+    public DiskOfferingInfo(DiskOffering diskOffering) {
+        _diskOffering = diskOffering;
+    }
+
+    public void setDiskOffering(DiskOffering diskOffering) {
+        _diskOffering = diskOffering;
+    }
+
+    public DiskOffering getDiskOffering() {
+        return _diskOffering;
+    }
+
+    public void setSize(Long size) {
+        _size = size;
+    }
+
+    public Long getSize() {
+        return _size;
+    }
+
+    public void setMinIops(Long minIops) {
+        _minIops = minIops;
+    }
+
+    public Long getMinIops() {
+        return _minIops;
+    }
+
+    public void setMaxIops(Long maxIops) {
+        _maxIops = maxIops;
+    }
+
+    public Long getMaxIops() {
+        return _maxIops;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c427e8db/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
index d33e04e..bd363da 100755
--- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
@@ -462,12 +462,62 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd {
         }
     }
 
+    // this is an opportunity to verify that parameters that came in via the Details Map are OK
+    // for example, minIops and maxIops should either both be specified or neither be specified and,
+    // if specified, minIops should be <= maxIops
+    private void verifyDetails() {
+        Map<String, String> map = getDetails();
+
+        if (map != null) {
+            String minIops = (String)map.get("minIops");
+            String maxIops = (String)map.get("maxIops");
+
+            if ((minIops != null && maxIops == null) || (minIops == null && maxIops != null)) {
+                throw new InvalidParameterValueException("Either 'Min IOPS' and 'Max IOPS' must both be specified or neither be specified.");
+            }
+
+            long lMinIops;
+
+            try {
+                if (minIops != null) {
+                    lMinIops = Long.valueOf(minIops);
+                }
+                else {
+                    lMinIops = 0;
+                }
+            }
+            catch (NumberFormatException ex) {
+                throw new InvalidParameterValueException("'Min IOPS' must be a whole number.");
+            }
+
+            long lMaxIops;
+
+            try {
+                if (maxIops != null) {
+                    lMaxIops = Long.valueOf(maxIops);
+                }
+                else {
+                    lMaxIops = 0;
+                }
+            }
+            catch (NumberFormatException ex) {
+                throw new InvalidParameterValueException("'Max IOPS' must be a whole number.");
+            }
+
+            if (lMinIops > lMaxIops) {
+                throw new InvalidParameterValueException("'Min IOPS' must be less than or equal to 'Max IOPS'.");
+            }
+        }
+    }
+
     @Override
     public void create() throws ResourceAllocationException {
         try {
             //Verify that all objects exist before passing them to the service
             Account owner = _accountService.getActiveAccountById(getEntityOwnerId());
 
+            verifyDetails();
+
             DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId);
             if (zone == null) {
                 throw new InvalidParameterValueException("Unable to find zone by id=" + zoneId);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c427e8db/engine/api/src/com/cloud/vm/VirtualMachineManager.java
----------------------------------------------------------------------
diff --git a/engine/api/src/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
index 3535a32..350f396 100644
--- a/engine/api/src/com/cloud/vm/VirtualMachineManager.java
+++ b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
@@ -37,11 +37,11 @@ import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.network.Network;
 import com.cloud.offering.DiskOffering;
+import com.cloud.offering.DiskOfferingInfo;
 import com.cloud.offering.ServiceOffering;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.Volume;
 import com.cloud.template.VirtualMachineTemplate;
-import com.cloud.utils.Pair;
 import com.cloud.utils.component.Manager;
 import com.cloud.utils.fsm.NoTransitionException;
 
@@ -76,7 +76,7 @@ public interface VirtualMachineManager extends Manager {
      * @param hyperType Hypervisor type
      * @throws InsufficientCapacityException If there are insufficient capacity to deploy this vm.
      */
-    void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering, Pair<? extends DiskOffering, Long> rootDiskOffering,
+    void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering, DiskOfferingInfo rootDiskOfferingInfo,
         LinkedHashMap<? extends DiskOffering, Long> dataDiskOfferings, LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, DeploymentPlan plan,
         HypervisorType hyperType) throws InsufficientCapacityException;
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c427e8db/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
index f79d336..2531074 100644
--- a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
+++ b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
@@ -106,7 +106,7 @@ public interface VolumeOrchestrationService {
 
     boolean canVmRestartOnAnotherServer(long vmId);
 
-    DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, VirtualMachineTemplate template, VirtualMachine vm,
+    DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm,
         Account owner);
 
     String getVmNameFromVolumeId(long volumeId);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c427e8db/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
index c13cde7..8edbb76 100755
--- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -154,6 +154,7 @@ import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.network.rules.RulesManager;
 import com.cloud.offering.DiskOffering;
+import com.cloud.offering.DiskOfferingInfo;
 import com.cloud.offering.ServiceOffering;
 import com.cloud.org.Cluster;
 import com.cloud.resource.ResourceManager;
@@ -372,7 +373,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     @Override
     @DB
     public void allocate(String vmInstanceName, final VirtualMachineTemplate template, ServiceOffering serviceOffering,
-            final Pair<? extends DiskOffering, Long> rootDiskOffering, LinkedHashMap<? extends DiskOffering, Long> dataDiskOfferings,
+            final DiskOfferingInfo rootDiskOfferingInfo, LinkedHashMap<? extends DiskOffering, Long> dataDiskOfferings,
             final LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, DeploymentPlan plan, HypervisorType hyperType)
                     throws InsufficientCapacityException {
 
@@ -412,11 +413,13 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
                         }
 
                         if (template.getFormat() == ImageFormat.ISO) {
-                            volumeMgr.allocateRawVolume(Type.ROOT, "ROOT-" + vmFinal.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vmFinal, template, owner);
+                            volumeMgr.allocateRawVolume(Type.ROOT, "ROOT-" + vmFinal.getId(), rootDiskOfferingInfo.getDiskOffering(), rootDiskOfferingInfo.getSize(), vmFinal,
+                                    template, owner);
                         } else if (template.getFormat() == ImageFormat.BAREMETAL) {
                             // Do nothing
                         } else {
-                            volumeMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vmFinal.getId(), rootDiskOffering.first(), rootDiskOffering.second(), template, vmFinal, owner);
+                            volumeMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vmFinal.getId(), rootDiskOfferingInfo.getDiskOffering(), rootDiskOfferingInfo.getSize(),
+                                    rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), template, vmFinal, owner);
                         }
 
                         for (Map.Entry<? extends DiskOffering, Long> offering : dataDiskOfferingsFinal.entrySet()) {
@@ -433,7 +436,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     @Override
     public void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering,
             LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, DeploymentPlan plan, HypervisorType hyperType) throws InsufficientCapacityException {
-        allocate(vmInstanceName, template, serviceOffering, new Pair<DiskOffering, Long>(serviceOffering, null), null, networks, plan, hyperType);
+        allocate(vmInstanceName, template, serviceOffering, new DiskOfferingInfo(serviceOffering), null, networks, plan, hyperType);
     }
 
     private VirtualMachineGuru getVmGuru(VirtualMachine vm) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c427e8db/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java
index b00b5ad..7969e43 100755
--- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java
+++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/CloudOrchestrator.java
@@ -46,18 +46,19 @@ import com.cloud.network.Network;
 import com.cloud.network.dao.NetworkDao;
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.offering.DiskOffering;
+import com.cloud.offering.DiskOfferingInfo;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.storage.DiskOfferingVO;
 import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.storage.dao.VMTemplateDao;
 import com.cloud.user.dao.AccountDao;
-import com.cloud.utils.Pair;
 import com.cloud.utils.component.ComponentContext;
 import com.cloud.vm.NicProfile;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachineManager;
 import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.dao.UserVmDetailsDao;
 import com.cloud.vm.dao.VMInstanceDao;
 
 @Component
@@ -79,6 +80,9 @@ public class CloudOrchestrator implements OrchestrationService {
     protected UserVmDao _userVmDao = null;
 
     @Inject
+    protected UserVmDetailsDao _userVmDetailsDao = null;
+
+    @Inject
     protected ServiceOfferingDao _serviceOfferingDao;
 
     @Inject
@@ -176,12 +180,25 @@ public class CloudOrchestrator implements OrchestrationService {
         // If the template represents an ISO, a disk offering must be passed in, and will be used to create the root disk
         // Else, a disk offering is optional, and if present will be used to create the data disk
 
-        Pair<DiskOfferingVO, Long> rootDiskOffering = new Pair<DiskOfferingVO, Long>(null, null);
+        DiskOfferingInfo rootDiskOfferingInfo = new DiskOfferingInfo();
         LinkedHashMap<DiskOfferingVO, Long> dataDiskOfferings = new LinkedHashMap<DiskOfferingVO, Long>();
 
         ServiceOfferingVO offering = _serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
-        rootDiskOffering.first(offering);
-        rootDiskOffering.second(rootDiskSize);
+
+        rootDiskOfferingInfo.setDiskOffering(offering);
+        rootDiskOfferingInfo.setSize(rootDiskSize);
+
+        if (offering.isCustomizedIops()) {
+            Map<String, String> userVmDetails = _userVmDetailsDao.listDetailsKeyPairs(vm.getId());
+
+            if (userVmDetails != null) {
+                String minIops = userVmDetails.get("minIops");
+                String maxIops = userVmDetails.get("maxIops");
+
+                rootDiskOfferingInfo.setMinIops(minIops != null && minIops.trim().length() > 0 ? Long.parseLong(minIops) : null);
+                rootDiskOfferingInfo.setMaxIops(maxIops != null && maxIops.trim().length() > 0 ? Long.parseLong(maxIops) : null);
+            }
+        }
 
         if (vm.getDiskOfferingId() != null) {
             DiskOfferingVO diskOffering = _diskOfferingDao.findById(vm.getDiskOfferingId());
@@ -199,7 +216,7 @@ public class CloudOrchestrator implements OrchestrationService {
             dataDiskOfferings.put(diskOffering, size);
         }
 
-        _itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new Long(templateId)), offering, rootDiskOffering, dataDiskOfferings, networkIpMap, plan,
+        _itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new Long(templateId)), offering, rootDiskOfferingInfo, dataDiskOfferings, networkIpMap, plan,
             hypervisorType);
 
         return vmEntity;
@@ -217,9 +234,11 @@ public class CloudOrchestrator implements OrchestrationService {
         //load vm instance and offerings and call virtualMachineManagerImpl
         VMInstanceVO vm = _vmDao.findByUuid(id);
 
-        Pair<DiskOffering, Long> rootDiskOffering = new Pair<DiskOffering, Long>(null, null);
         ServiceOfferingVO offering = _serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
-        rootDiskOffering.first(offering);
+
+        DiskOfferingInfo rootDiskOfferingInfo = new DiskOfferingInfo();
+
+        rootDiskOfferingInfo.setDiskOffering(offering);
 
         LinkedHashMap<DiskOffering, Long> dataDiskOfferings = new LinkedHashMap<DiskOffering, Long>();
         Long diskOfferingId = vm.getDiskOfferingId();
@@ -238,8 +257,9 @@ public class CloudOrchestrator implements OrchestrationService {
             }
             _volumeMgr.validateVolumeSizeRange(size * 1024 * 1024 * 1024);
         }
-        rootDiskOffering.first(diskOffering);
-        rootDiskOffering.second(size);
+
+        rootDiskOfferingInfo.setDiskOffering(diskOffering);
+        rootDiskOfferingInfo.setSize(size);
 
         LinkedHashMap<Network, List<? extends NicProfile>> networkIpMap = new LinkedHashMap<Network, List<? extends NicProfile>>();
         for (String uuid : networkNicMap.keySet()) {
@@ -251,7 +271,7 @@ public class CloudOrchestrator implements OrchestrationService {
 
         HypervisorType hypervisorType = HypervisorType.valueOf(hypervisor);
 
-        _itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new Long(isoId)), offering, rootDiskOffering, dataDiskOfferings, networkIpMap, plan, hypervisorType);
+        _itMgr.allocate(vm.getInstanceName(), _templateDao.findById(new Long(isoId)), offering, rootDiskOfferingInfo, dataDiskOfferings, networkIpMap, plan, hypervisorType);
 
         return vmEntity;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c427e8db/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
index 4d0c787..f3753a7 100644
--- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
+++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
@@ -605,15 +605,19 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
     }
 
     @Override
-    public DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, VirtualMachineTemplate template, VirtualMachine vm, Account owner) {
+    public DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm, Account owner) {
         assert (template.getFormat() != ImageFormat.ISO) : "ISO is not a template really....";
 
         Long size = _tmpltMgr.getTemplateSize(template.getId(), vm.getDataCenterId());
         if (rootDisksize != null) {
             size = (rootDisksize * 1024 * 1024 * 1024);
         }
-        VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), owner.getDomainId(), owner.getId(), offering.getId(), size, offering.getMinIops(), offering.getMaxIops(),
-                null);
+
+        minIops = minIops != null ? minIops : offering.getMinIops();
+        maxIops = maxIops != null ? maxIops : offering.getMaxIops();
+
+        VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), owner.getDomainId(), owner.getId(), offering.getId(), size, minIops, maxIops, null);
+
         vol.setFormat(getSupportedImageFormatForCluster(template.getHypervisorType()));
         if (vm != null) {
             vol.setInstanceId(vm.getId());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c427e8db/ui/css/cloudstack3.css
----------------------------------------------------------------------
diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css
index 162f77b..11c1c7e 100644
--- a/ui/css/cloudstack3.css
+++ b/ui/css/cloudstack3.css
@@ -6050,6 +6050,13 @@ label.error {
   border-radius: 4px;
 }
 
+.multi-wizard.instance-wizard .section.custom-iops {
+  position: relative;
+  background: #F4F4F4;
+  padding: 7px;
+  border-radius: 4px;
+}
+
 .multi-wizard.instance-wizard .section.custom-size input[type=radio] {
   float: left;
 }
@@ -6060,6 +6067,12 @@ label.error {
   margin: 6px -1px 0 8px;
 }
 
+.multi-wizard.instance-wizard .section.custom-iops input[type=text] {
+  float: left;
+  width: 28px;
+  margin: 6px -1px 0 8px;
+}
+
 .multi-wizard.instance-wizard .section.custom-size label.error {
   position: absolute;
   top: 29px;
@@ -6075,29 +6088,56 @@ label.error {
   height: 235px;
 }
 
+.instance-wizard .step.service-offering.custom-iops .select-container {
+  height: 235px;
+}
+
 .instance-wizard .step.service-offering .custom-size {
   display: none;
 }
 
+.instance-wizard .step.service-offering .custom-iops {
+  display: none;
+}
+
 .instance-wizard .step.service-offering.custom-size .custom-size {
   display: block;
 }
 
+.instance-wizard .step.service-offering.custom-iops .custom-iops {
+  display: block;
+}
+
 .instance-wizard .step.service-offering .custom-size .field {
   width: 30%;
   float: left;
   margin-bottom: 13px;
 }
 
+.instance-wizard .step.service-offering .custom-iops .field {
+  width: 30%;
+  float: left;
+  margin-bottom: 13px;
+}
+
 .instance-wizard .step.service-offering .custom-size .field label {
   text-indent: 20px;
 }
 
+.instance-wizard .step.service-offering .custom-iops .field label {
+  text-indent: 20px;
+}
+
 .instance-wizard .step.service-offering .custom-size .field input {
   width: 88%;
   margin-left: 26px;
 }
 
+.instance-wizard .step.service-offering .custom-iops .field input {
+  width: 88%;
+  margin-left: 26px;
+}
+
 /*** Network*/
 .multi-wizard.instance-wizard .no-network {
   background: #FFFFFF;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c427e8db/ui/index.jsp
----------------------------------------------------------------------
diff --git a/ui/index.jsp b/ui/index.jsp
index 4daa9eb..d46c395 100644
--- a/ui/index.jsp
+++ b/ui/index.jsp
@@ -221,6 +221,17 @@
                                         <input type="text" class="required disallowSpecialCharacters" name="compute-memory" />
                                     </div>
                                 </div>
+                                <!-- Custom iops slider -->
+                                <div class="section custom-iops">
+                                    <div class="field">
+                                        <label><fmt:message key="label.disk.iops.min"/></label>
+                                        <input type="text" class="disallowSpecialCharacters" name="disk-min-iops" />
+                                    </div>
+                                    <div class="field">
+                                        <label><fmt:message key="label.disk.iops.max"/></label>
+                                        <input type="text" class="disallowSpecialCharacters" name="disk-max-iops" />
+                                    </div>
+                                </div>
                             </div>
                         </div>
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c427e8db/ui/scripts/instanceWizard.js
----------------------------------------------------------------------
diff --git a/ui/scripts/instanceWizard.js b/ui/scripts/instanceWizard.js
index 3ee9af1..5c04d0e 100644
--- a/ui/scripts/instanceWizard.js
+++ b/ui/scripts/instanceWizard.js
@@ -301,6 +301,7 @@
                         args.response.success({
                             customFlag: 'iscustomized',
                         	//customFlag: 'offerha', //for testing only
+                        	customIopsFlag: 'iscustomizediops',
                             data: {
                                 serviceOfferings: serviceOfferingObjs
                             }
@@ -631,7 +632,20 @@
 	            	});
 	            }               
             }
-            
+
+            if (args.$wizard.find('input[name=disk-min-iops]').parent().parent().css('display') != 'none') {
+	            if (args.$wizard.find('input[name=disk-min-iops]').val().length > 0) {
+	            	$.extend(deployVmData, {
+	            	    'details[0].minIops' : args.$wizard.find('input[name=disk-min-iops]').val()
+	            	});
+	            }
+	            if (args.$wizard.find('input[name=disk-max-iops]').val().length > 0) {
+	            	$.extend(deployVmData, {
+	            	    'details[0].maxIops' : args.$wizard.find('input[name=disk-max-iops]').val()
+	            	});
+	            }
+            }
+
             //step 4: select disk offering
             if (args.data.diskofferingid != null && args.data.diskofferingid != "0") {                
             	$.extend(deployVmData, {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c427e8db/ui/scripts/ui-custom/instanceWizard.js
----------------------------------------------------------------------
diff --git a/ui/scripts/ui-custom/instanceWizard.js b/ui/scripts/ui-custom/instanceWizard.js
index 8884ebe..f5f7b10 100644
--- a/ui/scripts/ui-custom/instanceWizard.js
+++ b/ui/scripts/ui-custom/instanceWizard.js
@@ -458,6 +458,14 @@
                                             $step.removeClass('custom-size');
                                         }
 
+                                        var customIops = item[args.customIopsFlag];
+
+                                        if (customIops) {
+                                            $step.addClass('custom-iops');
+                                        } else {
+                                            $step.removeClass('custom-iops');
+                                        }
+
                                         return true;
                                     });