Skip to content

Commit e79350d

Browse files
committed
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
1 parent 4a9da03 commit e79350d

5 files changed

Lines changed: 133 additions & 26 deletions

File tree

engine/components-api/src/com/cloud/capacity/CapacityManager.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,15 @@ boolean checkIfHostHasCapacity(long hostId, Integer cpu, long ram, boolean check
9191
* @return true if the count of host's running VMs >= hypervisor limit
9292
*/
9393
boolean checkIfHostHasCpuCapability(long hostId, Integer cpuNum, Integer cpuSpeed);
94+
95+
/**
96+
* Check if cluster will cross threshold if the cpu/memory requested are accomodated
97+
* @param clusterId the clusterId to check
98+
* @param cpuRequested cpu requested
99+
* @param ramRequested cpu requested
100+
* @return true if the customer crosses threshold, false otherwise
101+
*/
102+
boolean checkIfClusterCrossesThreshold(Long clusterId, Integer cpuRequested, long ramRequested);
103+
104+
float getClusterOverProvisioningFactor(Long clusterId, short capacityType);
94105
}

engine/schema/src/com/cloud/capacity/dao/CapacityDao.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,12 @@ public interface CapacityDao extends GenericDao<CapacityVO, Long> {
4545

4646
Pair<List<Long>, Map<Long, Double>> orderPodsByAggregateCapacity(long zoneId, short capacityType);
4747

48-
List<SummedCapacity> findCapacityBy(Integer capacityType, Long zoneId, Long podId, Long clusterId, String resourceState);
49-
50-
List<SummedCapacity> listCapacitiesGroupedByLevelAndType(Integer capacityType, Long zoneId, Long podId, Long clusterId, int level, Long limit);
51-
52-
void updateCapacityState(Long dcId, Long podId, Long clusterId, Long hostId, String capacityState);
53-
54-
List<Long> listClustersCrossingThreshold(short capacityType, Long zoneId, String ConfigName, long computeRequested);
48+
List<SummedCapacity> findCapacityBy(Integer capacityType, Long zoneId,
49+
Long podId, Long clusterId, String resourceState);
50+
List<SummedCapacity> listCapacitiesGroupedByLevelAndType(Integer capacityType, Long zoneId, Long podId, Long clusterId, int level, Long limit);
51+
void updateCapacityState(Long dcId, Long podId, Long clusterId,
52+
Long hostId, String capacityState);
53+
List<Long> listClustersCrossingThreshold(short capacityType, Long zoneId, String ConfigName, long computeRequested);
54+
55+
float findClusterConsumption(Long clusterId, short capacityType, long computeRequested);
5556
}

engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
import javax.ejb.Local;
2828
import javax.inject.Inject;
2929

30+
import com.cloud.dc.ClusterDetailsDao;
31+
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
32+
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
3033
import org.apache.log4j.Logger;
3134
import org.springframework.stereotype.Component;
3235

@@ -161,19 +164,24 @@ public class CapacityDaoImpl extends GenericDaoBase<CapacityVO, Long> implements
161164
* query from the configuration table
162165
*
163166
* */
164-
private static final String LIST_CLUSTERS_CROSSING_THRESHOLD =
165-
"SELECT clusterList.cluster_id "
166-
+ "FROM (SELECT cluster.cluster_id cluster_id, ( (sum(cluster.used) + sum(cluster.reserved) + ?)/sum(cluster.total) ) ratio, cluster.configValue value "
167-
+ "FROM (SELECT capacity.cluster_id cluster_id, capacity.used_capacity used, capacity.reserved_capacity reserved, capacity.total_capacity * overcommit.value total, "
168-
+ "CASE (SELECT count(*) FROM `cloud`.`cluster_details` details WHERE details.cluster_id = capacity.cluster_id AND details.name = ? ) "
169-
+ "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 "
170-
+ "THEN (SELECT config.value FROM `cloud`.`configuration` config WHERE config.name = ?)"
171-
+ "ELSE (SELECT details.value FROM `cloud`.`cluster_details` details WHERE details.cluster_id = capacity.cluster_id AND details.name = ? ) END )"
172-
+ "ELSE ( SELECT config.value FROM `cloud`.`configuration` config WHERE config.name = ?) " + "END configValue "
173-
+ "FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster_details` overcommit ON overcommit.cluster_id = capacity.cluster_id "
174-
+ "WHERE capacity.data_center_id = ? AND capacity.capacity_type = ? AND capacity.total_capacity > 0 AND overcommit.name = ?) cluster " +
175-
176-
"GROUP BY cluster.cluster_id) clusterList " + "WHERE clusterList.ratio > clusterList.value; ";
167+
168+
private static final String LIST_CLUSTERS_CROSSING_THRESHOLD = "SELECT clusterList.cluster_id " +
169+
"FROM ( SELECT cluster.cluster_id cluster_id, ( (sum(cluster.used) + sum(cluster.reserved) + ?)/sum(cluster.total) ) ratio, cluster.configValue value " +
170+
"FROM ( SELECT capacity.cluster_id cluster_id, capacity.used_capacity used, capacity.reserved_capacity reserved, capacity.total_capacity * overcommit.value total, " +
171+
"CASE (SELECT count(*) FROM `cloud`.`cluster_details` details WHERE details.cluster_id = capacity.cluster_id AND details.name = ? ) " +
172+
"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 " +
173+
"THEN (SELECT config.value FROM `cloud`.`configuration` config WHERE config.name = ?)" +
174+
"ELSE (SELECT details.value FROM `cloud`.`cluster_details` details WHERE details.cluster_id = capacity.cluster_id AND details.name = ? ) END )" +
175+
"ELSE ( SELECT config.value FROM `cloud`.`configuration` config WHERE config.name = ?) " +
176+
"END configValue " +
177+
"FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster_details` overcommit ON overcommit.cluster_id = capacity.cluster_id " +
178+
"WHERE capacity.data_center_id = ? AND capacity.capacity_type = ? AND capacity.total_capacity > 0 AND overcommit.name = ?) cluster " +
179+
180+
"GROUP BY cluster.cluster_id) clusterList " +
181+
"WHERE clusterList.ratio > clusterList.value; ";
182+
183+
private static final String FIND_CLUSTER_CONSUMPTION_RATIO = "select ( (sum(capacity.used_capacity) + sum(capacity.reserved_capacity) + ?)/sum(capacity.total_capacity) ) " +
184+
"from op_host_capacity capacity where cluster_id = ? and capacity_type = ?;";
177185

178186
public CapacityDaoImpl() {
179187
_hostIdTypeSearch = createSearchBuilder();
@@ -883,4 +891,26 @@ public void updateCapacityState(Long dcId, Long podId, Long clusterId, Long host
883891
s_logger.warn("Error updating CapacityVO", e);
884892
}
885893
}
894+
895+
@Override
896+
public float findClusterConsumption(Long clusterId, short capacityType, long computeRequested){
897+
TransactionLegacy txn = TransactionLegacy.currentTxn();
898+
StringBuilder sql = new StringBuilder(FIND_CLUSTER_CONSUMPTION_RATIO);
899+
PreparedStatement pstmt = null;
900+
try {
901+
pstmt = txn.prepareAutoCloseStatement(sql.toString());
902+
903+
pstmt.setLong(1, computeRequested);
904+
pstmt.setLong(2, clusterId);
905+
pstmt.setShort(3, capacityType);
906+
ResultSet rs = pstmt.executeQuery();
907+
while (rs.next()) {
908+
return rs.getFloat(1);
909+
}
910+
} catch (Exception e) {
911+
s_logger.warn("Error checking cluster threshold", e);
912+
}
913+
return 0;
914+
}
915+
886916
}

server/src/com/cloud/capacity/CapacityManagerImpl.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@
2727
import javax.inject.Inject;
2828
import javax.naming.ConfigurationException;
2929

30+
import com.cloud.deploy.DeploymentClusterPlanner;
31+
import com.cloud.deploy.DeploymentPlanner;
3032
import com.cloud.event.UsageEventVO;
33+
import com.cloud.utils.exception.CloudRuntimeException;
3134
import org.apache.log4j.Logger;
3235

3336
import org.apache.cloudstack.framework.config.ConfigDepot;
@@ -94,6 +97,7 @@
9497
import com.cloud.vm.dao.UserVmDetailsDao;
9598
import com.cloud.vm.dao.VMInstanceDao;
9699
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
100+
import org.springframework.instrument.classloading.glassfish.GlassFishLoadTimeWeaver;
97101

98102
@Local(value = CapacityManager.class)
99103
public class CapacityManagerImpl extends ManagerBase implements CapacityManager, StateListener<State, VirtualMachine.Event, VirtualMachine>, Listener, ResourceListener,
@@ -852,6 +856,50 @@ private void createCapacityEntry(StartupCommand startup, HostVO server) {
852856

853857
}
854858

859+
@Override
860+
public float getClusterOverProvisioningFactor(Long clusterId, short capacityType){
861+
862+
String capacityOverProvisioningName = "";
863+
if(capacityType == Capacity.CAPACITY_TYPE_CPU){
864+
capacityOverProvisioningName = "cpuOvercommitRatio";
865+
}else if(capacityType == Capacity.CAPACITY_TYPE_MEMORY){
866+
capacityOverProvisioningName = "memoryOvercommitRatio";
867+
}else{
868+
throw new CloudRuntimeException("Invalid capacityType - " + capacityType);
869+
}
870+
871+
ClusterDetailsVO clusterDetailCpu = _clusterDetailsDao.findDetail(clusterId, capacityOverProvisioningName);
872+
Float clusterOverProvisioningRatio = Float.parseFloat(clusterDetailCpu.getValue());
873+
return clusterOverProvisioningRatio;
874+
875+
}
876+
877+
@Override
878+
public boolean checkIfClusterCrossesThreshold(Long clusterId, Integer cpuRequested, long ramRequested){
879+
880+
Float clusterCpuOverProvisioning = getClusterOverProvisioningFactor(clusterId, Capacity.CAPACITY_TYPE_CPU);
881+
Float clusterMemoryOverProvisioning = getClusterOverProvisioningFactor(clusterId, Capacity.CAPACITY_TYPE_MEMORY);
882+
Float clusterCpuCapacityDisableThreshold = DeploymentClusterPlanner.ClusterCPUCapacityDisableThreshold.valueIn(clusterId);
883+
Float clusterMemoryCapacityDisableThreshold = DeploymentClusterPlanner.ClusterMemoryCapacityDisableThreshold.valueIn(clusterId);
884+
885+
float cpuConsumption = _capacityDao.findClusterConsumption(clusterId, Capacity.CAPACITY_TYPE_CPU, cpuRequested);
886+
if(cpuConsumption/clusterCpuOverProvisioning > clusterCpuCapacityDisableThreshold){
887+
s_logger.debug("Cluster: " +clusterId + " cpu consumption " + cpuConsumption/clusterCpuOverProvisioning
888+
+ " crosses disable threshold " + clusterCpuCapacityDisableThreshold);
889+
return true;
890+
}
891+
892+
float memoryConsumption = _capacityDao.findClusterConsumption(clusterId, Capacity.CAPACITY_TYPE_MEMORY, ramRequested);
893+
if(memoryConsumption/clusterMemoryOverProvisioning > clusterMemoryCapacityDisableThreshold){
894+
s_logger.debug("Cluster: " +clusterId + " memory consumption " + memoryConsumption/clusterMemoryOverProvisioning
895+
+ " crosses disable threshold " + clusterMemoryCapacityDisableThreshold);
896+
return true;
897+
}
898+
899+
return false;
900+
901+
}
902+
855903
@Override
856904
public boolean processAnswers(long agentId, long seq, Answer[] answers) {
857905
// TODO Auto-generated method stub

server/src/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636

3737
import com.cloud.event.UsageEventVO;
3838
import com.cloud.uuididentity.UUIDManager;
39+
import com.cloud.capacity.Capacity;
40+
import com.cloud.exception.InsufficientServerCapacityException;
3941
import org.apache.commons.codec.binary.Base64;
4042
import org.apache.log4j.Logger;
4143

@@ -1306,6 +1308,8 @@ private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingI
13061308
int currentCpu = currentServiceOffering.getCpu();
13071309
int currentMemory = currentServiceOffering.getRamSize();
13081310
int currentSpeed = currentServiceOffering.getSpeed();
1311+
int memoryDiff = newMemory - currentMemory;
1312+
int cpuDiff = newCpu*newSpeed - currentCpu*currentSpeed;
13091313

13101314
// Don't allow to scale when (Any of the new values less than current values) OR (All current and new values are same)
13111315
if ((newSpeed < currentSpeed || newMemory < currentMemory || newCpu < currentCpu) ||
@@ -1328,14 +1332,24 @@ private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingI
13281332
if (vmInstance.getState().equals(State.Running)) {
13291333
int retry = _scaleRetry;
13301334
ExcludeList excludes = new ExcludeList();
1335+
1336+
// Check zone wide flag
13311337
boolean enableDynamicallyScaleVm = EnableDynamicallyScaleVm.valueIn(vmInstance.getDataCenterId());
13321338
if (!enableDynamicallyScaleVm) {
13331339
throw new PermissionDeniedException("Dynamically scaling virtual machines is disabled for this zone, please contact your admin");
13341340
}
1341+
1342+
// Check vm flag
13351343
if (!vmInstance.isDynamicallyScalable()) {
13361344
throw new CloudRuntimeException("Unable to Scale the vm: " + vmInstance.getUuid() + " as vm does not have tools to support dynamic scaling");
13371345
}
13381346

1347+
// Check disable threshold for cluster is not crossed
1348+
HostVO host = _hostDao.findById(vmInstance.getHostId());
1349+
if(_capacityMgr.checkIfClusterCrossesThreshold(host.getClusterId(), cpuDiff, memoryDiff)){
1350+
throw new CloudRuntimeException("Unable to scale vm: " + vmInstance.getUuid() + " due to insufficient resources");
1351+
}
1352+
13391353
while (retry-- != 0) { // It's != so that it can match -1.
13401354
try {
13411355
boolean existingHostHasCapacity = false;
@@ -1344,15 +1358,17 @@ private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingI
13441358
if (newCpu > currentCpu) {
13451359
_resourceLimitMgr.incrementResourceCount(caller.getAccountId(), ResourceType.cpu, new Long(newCpu - currentCpu));
13461360
}
1347-
if (newMemory > currentMemory) {
1348-
_resourceLimitMgr.incrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long(newMemory - currentMemory));
1361+
1362+
if (memoryDiff > 0) {
1363+
_resourceLimitMgr.incrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long (memoryDiff));
13491364
}
13501365

13511366
// #1 Check existing host has capacity
13521367
if( !excludes.shouldAvoid(ApiDBUtils.findHostById(vmInstance.getHostId())) ){
13531368
existingHostHasCapacity = _capacityMgr.checkIfHostHasCpuCapability(vmInstance.getHostId(), newCpu, newSpeed)
1354-
&& _capacityMgr.checkIfHostHasCapacity(vmInstance.getHostId(), newServiceOffering.getSpeed() - currentServiceOffering.getSpeed(),
1355-
(newServiceOffering.getRamSize() - currentServiceOffering.getRamSize()) * 1024L * 1024L, false, ApiDBUtils.getCpuOverprovisioningFactor(), 1f, false); // TO DO fill it with mem.
1369+
&& _capacityMgr.checkIfHostHasCapacity(vmInstance.getHostId(), cpuDiff,
1370+
(memoryDiff) * 1024L * 1024L, false, _capacityMgr.getClusterOverProvisioningFactor(host.getClusterId(), Capacity.CAPACITY_TYPE_CPU),
1371+
_capacityMgr.getClusterOverProvisioningFactor(host.getClusterId(), Capacity.CAPACITY_TYPE_MEMORY), false);
13561372
excludes.addHost(vmInstance.getHostId());
13571373
}
13581374

@@ -1392,8 +1408,9 @@ private boolean upgradeRunningVirtualMachine(Long vmId, Long newServiceOfferingI
13921408
if (newCpu > currentCpu) {
13931409
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.cpu, new Long(newCpu - currentCpu));
13941410
}
1395-
if (newMemory > currentMemory) {
1396-
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long(newMemory - currentMemory));
1411+
1412+
if (memoryDiff > 0) {
1413+
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long (memoryDiff));
13971414
}
13981415
}
13991416
}

0 commit comments

Comments
 (0)