Updated Branches:
  refs/heads/master 4a9da0376 -> e79350d25

CLOUDSTACK-3664:
scaling up vms was not considering parameter 
cluster.(memory/cpu).allocated.capacity.disablethreshold. Fixed it
Also added overprovisioning factor retrieval at the cluster level for host 
capacity check


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

Branch: refs/heads/master
Commit: e79350d256cbd2bb64393ddae453c815b5a68339
Parents: 4a9da03
Author: Nitin Mehta <[email protected]>
Authored: Mon Dec 9 15:40:17 2013 -0800
Committer: Nitin Mehta <[email protected]>
Committed: Mon Dec 9 15:40:17 2013 -0800

----------------------------------------------------------------------
 .../src/com/cloud/capacity/CapacityManager.java | 11 ++++
 .../src/com/cloud/capacity/dao/CapacityDao.java | 15 +++---
 .../com/cloud/capacity/dao/CapacityDaoImpl.java | 56 +++++++++++++++-----
 .../com/cloud/capacity/CapacityManagerImpl.java | 48 +++++++++++++++++
 server/src/com/cloud/vm/UserVmManagerImpl.java  | 29 +++++++---
 5 files changed, 133 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e79350d2/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 13624e6..bd1a610 100755
--- a/engine/components-api/src/com/cloud/capacity/CapacityManager.java
+++ b/engine/components-api/src/com/cloud/capacity/CapacityManager.java
@@ -91,4 +91,15 @@ public interface CapacityManager {
      * @return true if the count of host's running VMs >= hypervisor limit
      */
     boolean checkIfHostHasCpuCapability(long hostId, Integer cpuNum, Integer 
cpuSpeed);
+
+    /**
+     * Check if cluster will cross threshold if the cpu/memory requested are 
accomodated
+     * @param clusterId the clusterId to check
+     * @param cpuRequested cpu requested
+     * @param ramRequested cpu requested
+     * @return true if the customer crosses threshold, false otherwise
+     */
+    boolean checkIfClusterCrossesThreshold(Long clusterId, Integer 
cpuRequested, long ramRequested);
+
+    float getClusterOverProvisioningFactor(Long clusterId, short capacityType);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e79350d2/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java 
b/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java
index e32f96e..079d9a8 100755
--- a/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java
+++ b/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java
@@ -45,11 +45,12 @@ public interface CapacityDao extends GenericDao<CapacityVO, 
Long> {
 
     Pair<List<Long>, Map<Long, Double>> orderPodsByAggregateCapacity(long 
zoneId, short capacityType);
 
-    List<SummedCapacity> findCapacityBy(Integer capacityType, Long zoneId, 
Long podId, Long clusterId, String resourceState);
-
-    List<SummedCapacity> listCapacitiesGroupedByLevelAndType(Integer 
capacityType, Long zoneId, Long podId, Long clusterId, int level, Long limit);
-
-    void updateCapacityState(Long dcId, Long podId, Long clusterId, Long 
hostId, String capacityState);
-
-    List<Long> listClustersCrossingThreshold(short capacityType, Long zoneId, 
String ConfigName, long computeRequested);
+    List<SummedCapacity> findCapacityBy(Integer capacityType, Long zoneId,
+            Long podId, Long clusterId, String resourceState);
+    List<SummedCapacity> listCapacitiesGroupedByLevelAndType(Integer 
capacityType, Long zoneId, Long podId, Long clusterId, int level, Long limit);  
+    void updateCapacityState(Long dcId, Long podId, Long clusterId,
+            Long hostId, String capacityState);
+       List<Long> listClustersCrossingThreshold(short capacityType, Long 
zoneId, String ConfigName, long computeRequested);
+
+    float findClusterConsumption(Long clusterId, short capacityType, long 
computeRequested);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e79350d2/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java 
b/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java
index cb916c3..7919ed5 100755
--- a/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java
+++ b/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java
@@ -27,6 +27,9 @@ import java.util.Map;
 import javax.ejb.Local;
 import javax.inject.Inject;
 
+import com.cloud.dc.ClusterDetailsDao;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
@@ -161,19 +164,24 @@ public class CapacityDaoImpl extends 
GenericDaoBase<CapacityVO, Long> implements
     *     query from the configuration table
     *
     *     */
-    private static final String LIST_CLUSTERS_CROSSING_THRESHOLD =
-        "SELECT clusterList.cluster_id "
-            + "FROM (SELECT cluster.cluster_id cluster_id, ( 
(sum(cluster.used) + sum(cluster.reserved) + ?)/sum(cluster.total) ) ratio, 
cluster.configValue value "
-            + "FROM (SELECT capacity.cluster_id cluster_id, 
capacity.used_capacity used, capacity.reserved_capacity reserved, 
capacity.total_capacity * overcommit.value total, "
-            + "CASE (SELECT count(*) FROM `cloud`.`cluster_details` details 
WHERE details.cluster_id = capacity.cluster_id AND details.name = ? ) "
-            + "WHEN 1 THEN (CASE WHEN (SELECT details.value FROM 
`cloud`.`cluster_details` details WHERE details.cluster_id = 
capacity.cluster_id AND details.name = ?) is NULL "
-            + "THEN (SELECT config.value FROM `cloud`.`configuration` config 
WHERE config.name = ?)"
-            + "ELSE (SELECT details.value FROM `cloud`.`cluster_details` 
details WHERE details.cluster_id = capacity.cluster_id AND details.name = ? ) 
END )"
-            + "ELSE (    SELECT config.value FROM `cloud`.`configuration` 
config WHERE config.name = ?) " + "END configValue "
-            + "FROM `cloud`.`op_host_capacity` capacity INNER JOIN 
`cloud`.`cluster_details` overcommit ON overcommit.cluster_id = 
capacity.cluster_id "
-            + "WHERE capacity.data_center_id = ? AND capacity.capacity_type = 
? AND capacity.total_capacity > 0 AND overcommit.name = ?) cluster " +
-
-            "GROUP BY cluster.cluster_id)  clusterList " + "WHERE 
clusterList.ratio > clusterList.value; ";
+
+    private static final String LIST_CLUSTERS_CROSSING_THRESHOLD = "SELECT 
clusterList.cluster_id " +
+                       "FROM ( SELECT cluster.cluster_id cluster_id, ( 
(sum(cluster.used) + sum(cluster.reserved) + ?)/sum(cluster.total) ) ratio, 
cluster.configValue value " +
+                                "FROM (        SELECT capacity.cluster_id 
cluster_id, capacity.used_capacity used, capacity.reserved_capacity reserved, 
capacity.total_capacity * overcommit.value total, " +
+                                            "CASE (SELECT count(*) FROM 
`cloud`.`cluster_details` details WHERE details.cluster_id = 
capacity.cluster_id AND details.name = ? ) " +
+                                                "WHEN 1 THEN ( CASE WHEN 
(SELECT details.value FROM `cloud`.`cluster_details` details WHERE 
details.cluster_id = capacity.cluster_id AND details.name = ?) is NULL " +
+                                                                    "THEN 
(SELECT config.value FROM `cloud`.`configuration` config WHERE config.name = 
?)" +
+                                                                    "ELSE 
(SELECT details.value FROM `cloud`.`cluster_details` details WHERE 
details.cluster_id = capacity.cluster_id AND details.name = ? ) END )"  +
+                                                "ELSE (        SELECT 
config.value FROM `cloud`.`configuration` config WHERE config.name = ?) " +
+                                            "END configValue " +
+                                        "FROM `cloud`.`op_host_capacity` 
capacity INNER JOIN `cloud`.`cluster_details` overcommit ON 
overcommit.cluster_id = capacity.cluster_id " +
+                                        "WHERE capacity.data_center_id = ? AND 
capacity.capacity_type = ? AND capacity.total_capacity > 0 AND overcommit.name 
= ?) cluster " +
+
+                                "GROUP BY cluster.cluster_id)  clusterList " +
+                        "WHERE clusterList.ratio > clusterList.value; ";
+
+    private static final String  FIND_CLUSTER_CONSUMPTION_RATIO = "select ( 
(sum(capacity.used_capacity) + sum(capacity.reserved_capacity) + 
?)/sum(capacity.total_capacity) ) " +
+            "from op_host_capacity capacity where cluster_id = ? and 
capacity_type = ?;";
 
     public CapacityDaoImpl() {
         _hostIdTypeSearch = createSearchBuilder();
@@ -883,4 +891,26 @@ public class CapacityDaoImpl extends 
GenericDaoBase<CapacityVO, Long> implements
             s_logger.warn("Error updating CapacityVO", e);
         }
     }
+
+    @Override
+    public float findClusterConsumption(Long clusterId, short capacityType, 
long computeRequested){
+        TransactionLegacy txn = TransactionLegacy.currentTxn();
+        StringBuilder sql = new StringBuilder(FIND_CLUSTER_CONSUMPTION_RATIO);
+        PreparedStatement pstmt = null;
+        try {
+            pstmt = txn.prepareAutoCloseStatement(sql.toString());
+
+            pstmt.setLong(1, computeRequested);
+            pstmt.setLong(2, clusterId);
+            pstmt.setShort(3, capacityType);
+            ResultSet rs = pstmt.executeQuery();
+            while (rs.next()) {
+                return rs.getFloat(1);
+            }
+        } catch (Exception e) {
+            s_logger.warn("Error checking cluster threshold", e);
+        }
+        return 0;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e79350d2/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 2358f92..e42879c 100755
--- a/server/src/com/cloud/capacity/CapacityManagerImpl.java
+++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java
@@ -27,7 +27,10 @@ import javax.ejb.Local;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.deploy.DeploymentClusterPlanner;
+import com.cloud.deploy.DeploymentPlanner;
 import com.cloud.event.UsageEventVO;
+import com.cloud.utils.exception.CloudRuntimeException;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.framework.config.ConfigDepot;
@@ -94,6 +97,7 @@ import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.UserVmDetailsDao;
 import com.cloud.vm.dao.VMInstanceDao;
 import com.cloud.vm.snapshot.dao.VMSnapshotDao;
+import 
org.springframework.instrument.classloading.glassfish.GlassFishLoadTimeWeaver;
 
 @Local(value = CapacityManager.class)
 public class CapacityManagerImpl extends ManagerBase implements 
CapacityManager, StateListener<State, VirtualMachine.Event, VirtualMachine>, 
Listener, ResourceListener,
@@ -853,6 +857,50 @@ public class CapacityManagerImpl extends ManagerBase 
implements CapacityManager,
     }
 
     @Override
+    public float getClusterOverProvisioningFactor(Long clusterId, short 
capacityType){
+
+        String capacityOverProvisioningName = "";
+        if(capacityType == Capacity.CAPACITY_TYPE_CPU){
+            capacityOverProvisioningName = "cpuOvercommitRatio";
+        }else if(capacityType == Capacity.CAPACITY_TYPE_MEMORY){
+            capacityOverProvisioningName = "memoryOvercommitRatio";
+        }else{
+            throw new CloudRuntimeException("Invalid capacityType - " + 
capacityType);
+        }
+
+        ClusterDetailsVO clusterDetailCpu = 
_clusterDetailsDao.findDetail(clusterId, capacityOverProvisioningName);
+        Float clusterOverProvisioningRatio = 
Float.parseFloat(clusterDetailCpu.getValue());
+        return clusterOverProvisioningRatio;
+
+    }
+
+    @Override
+    public boolean checkIfClusterCrossesThreshold(Long clusterId, Integer 
cpuRequested, long ramRequested){
+
+        Float clusterCpuOverProvisioning = 
getClusterOverProvisioningFactor(clusterId, Capacity.CAPACITY_TYPE_CPU);
+        Float clusterMemoryOverProvisioning = 
getClusterOverProvisioningFactor(clusterId, Capacity.CAPACITY_TYPE_MEMORY);
+        Float clusterCpuCapacityDisableThreshold = 
DeploymentClusterPlanner.ClusterCPUCapacityDisableThreshold.valueIn(clusterId);
+        Float clusterMemoryCapacityDisableThreshold = 
DeploymentClusterPlanner.ClusterMemoryCapacityDisableThreshold.valueIn(clusterId);
+
+        float cpuConsumption = _capacityDao.findClusterConsumption(clusterId, 
Capacity.CAPACITY_TYPE_CPU, cpuRequested);
+        if(cpuConsumption/clusterCpuOverProvisioning > 
clusterCpuCapacityDisableThreshold){
+            s_logger.debug("Cluster: " +clusterId + " cpu consumption " + 
cpuConsumption/clusterCpuOverProvisioning
+                    + " crosses disable threshold " + 
clusterCpuCapacityDisableThreshold);
+            return true;
+        }
+
+        float memoryConsumption = 
_capacityDao.findClusterConsumption(clusterId, Capacity.CAPACITY_TYPE_MEMORY, 
ramRequested);
+        if(memoryConsumption/clusterMemoryOverProvisioning > 
clusterMemoryCapacityDisableThreshold){
+            s_logger.debug("Cluster: " +clusterId + " memory consumption " + 
memoryConsumption/clusterMemoryOverProvisioning
+                    + " crosses disable threshold " + 
clusterMemoryCapacityDisableThreshold);
+            return true;
+        }
+
+        return false;
+
+    }
+
+    @Override
     public boolean processAnswers(long agentId, long seq, Answer[] answers) {
         // TODO Auto-generated method stub
         return false;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e79350d2/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java 
b/server/src/com/cloud/vm/UserVmManagerImpl.java
index 1752c22..582ddcf 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -36,6 +36,8 @@ import javax.naming.ConfigurationException;
 
 import com.cloud.event.UsageEventVO;
 import com.cloud.uuididentity.UUIDManager;
+import com.cloud.capacity.Capacity;
+import com.cloud.exception.InsufficientServerCapacityException;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.log4j.Logger;
 
@@ -1306,6 +1308,8 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
         int currentCpu = currentServiceOffering.getCpu();
         int currentMemory = currentServiceOffering.getRamSize();
         int currentSpeed = currentServiceOffering.getSpeed();
+        int memoryDiff = newMemory - currentMemory;
+        int cpuDiff =  newCpu*newSpeed - currentCpu*currentSpeed;
 
         // Don't allow to scale when (Any of the new values less than current 
values) OR (All current and new values are same)
         if ((newSpeed < currentSpeed || newMemory < currentMemory || newCpu < 
currentCpu) ||
@@ -1328,14 +1332,24 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
         if (vmInstance.getState().equals(State.Running)) {
             int retry = _scaleRetry;
             ExcludeList excludes = new ExcludeList();
+
+            // Check zone wide flag
             boolean enableDynamicallyScaleVm = 
EnableDynamicallyScaleVm.valueIn(vmInstance.getDataCenterId());
             if (!enableDynamicallyScaleVm) {
                 throw new PermissionDeniedException("Dynamically scaling 
virtual machines is disabled for this zone, please contact your admin");
             }
+
+            // Check vm flag
             if (!vmInstance.isDynamicallyScalable()) {
                 throw new CloudRuntimeException("Unable to Scale the vm: " + 
vmInstance.getUuid() + " as vm does not have tools to support dynamic scaling");
             }
 
+            // Check disable threshold for cluster is not crossed
+            HostVO host = _hostDao.findById(vmInstance.getHostId());
+            
if(_capacityMgr.checkIfClusterCrossesThreshold(host.getClusterId(), cpuDiff, 
memoryDiff)){
+                throw new CloudRuntimeException("Unable to scale vm: " + 
vmInstance.getUuid() + " due to insufficient resources");
+            }
+
             while (retry-- != 0) { // It's != so that it can match -1.
                 try {
                     boolean existingHostHasCapacity = false;
@@ -1344,15 +1358,17 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
                     if (newCpu > currentCpu) {
                         
_resourceLimitMgr.incrementResourceCount(caller.getAccountId(), 
ResourceType.cpu, new Long(newCpu - currentCpu));
                     }
-                    if (newMemory > currentMemory) {
-                        
_resourceLimitMgr.incrementResourceCount(caller.getAccountId(), 
ResourceType.memory, new Long(newMemory - currentMemory));
+
+                    if (memoryDiff > 0) {
+                        
_resourceLimitMgr.incrementResourceCount(caller.getAccountId(), 
ResourceType.memory, new Long (memoryDiff));
                     }
 
                     // #1 Check existing host has capacity
                     if( 
!excludes.shouldAvoid(ApiDBUtils.findHostById(vmInstance.getHostId())) ){
                         existingHostHasCapacity = 
_capacityMgr.checkIfHostHasCpuCapability(vmInstance.getHostId(), newCpu, 
newSpeed)
-                                && 
_capacityMgr.checkIfHostHasCapacity(vmInstance.getHostId(), 
newServiceOffering.getSpeed() - currentServiceOffering.getSpeed(),
-                                (newServiceOffering.getRamSize() - 
currentServiceOffering.getRamSize()) * 1024L * 1024L, false, 
ApiDBUtils.getCpuOverprovisioningFactor(), 1f, false); // TO DO fill it with 
mem.
+                                && 
_capacityMgr.checkIfHostHasCapacity(vmInstance.getHostId(), cpuDiff,
+                                (memoryDiff) * 1024L * 1024L, false, 
_capacityMgr.getClusterOverProvisioningFactor(host.getClusterId(), 
Capacity.CAPACITY_TYPE_CPU),
+                                
_capacityMgr.getClusterOverProvisioningFactor(host.getClusterId(), 
Capacity.CAPACITY_TYPE_MEMORY), false);
                         excludes.addHost(vmInstance.getHostId());
                     }
 
@@ -1392,8 +1408,9 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
                         if (newCpu > currentCpu) {
                             
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), 
ResourceType.cpu, new Long(newCpu - currentCpu));
                         }
-                        if (newMemory > currentMemory) {
-                            
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), 
ResourceType.memory, new Long(newMemory - currentMemory));
+
+                        if (memoryDiff > 0) {
+                            
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), 
ResourceType.memory, new Long (memoryDiff));
                         }
                     }
                 }

Reply via email to