Updated Branches: refs/heads/4.3 fca7dd29a -> 5d9335fcc
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/5d9335fc Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/5d9335fc Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/5d9335fc Branch: refs/heads/4.3 Commit: 5d9335fcc32733777963db33022eb14c3c1d16d2 Parents: fca7dd2 Author: Nitin Mehta <[email protected]> Authored: Mon Dec 9 14:51:59 2013 -0800 Committer: Nitin Mehta <[email protected]> Committed: Mon Dec 9 14:51:59 2013 -0800 ---------------------------------------------------------------------- .../src/com/cloud/capacity/CapacityManager.java | 11 +++++ .../src/com/cloud/capacity/dao/CapacityDao.java | 2 + .../com/cloud/capacity/dao/CapacityDaoImpl.java | 26 ++++++++++- .../com/cloud/capacity/CapacityManagerImpl.java | 48 ++++++++++++++++++++ .../VirtualNetworkApplianceManagerImpl.java | 4 +- server/src/com/cloud/vm/UserVmManagerImpl.java | 27 ++++++++--- 6 files changed, 108 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5d9335fc/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 5483d09..0cda826 100755 --- a/engine/components-api/src/com/cloud/capacity/CapacityManager.java +++ b/engine/components-api/src/com/cloud/capacity/CapacityManager.java @@ -84,4 +84,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/5d9335fc/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 04466f4..7c5d420 100755 --- a/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java +++ b/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java @@ -42,4 +42,6 @@ public interface CapacityDao extends GenericDao<CapacityVO, Long> { 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/5d9335fc/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 64a1660..cf0d491 100755 --- a/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -28,7 +28,6 @@ import javax.ejb.Local; import javax.inject.Inject; import com.cloud.dc.ClusterDetailsDao; -import com.cloud.dc.ClusterDetailsVO; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; @@ -38,7 +37,6 @@ import com.cloud.capacity.Capacity; import com.cloud.capacity.CapacityVO; import com.cloud.storage.Storage; import com.cloud.utils.Pair; -import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.JoinBuilder.JoinType; @@ -159,6 +157,8 @@ public class CapacityDaoImpl extends GenericDaoBase<CapacityVO, Long> implements "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() { @@ -873,4 +873,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/5d9335fc/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 e52916f..6ff09a3 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.engine.subsystem.api.storage.DataStoreDriver; @@ -100,6 +103,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, @@ -920,6 +924,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/5d9335fc/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 85c5bc1..32db6f0 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -3433,9 +3433,9 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } protected boolean sendCommandsToRouter(final VirtualRouter router, Commands cmds) throws AgentUnavailableException { - if(!checkRouterVersion(router)){ + /*if(!checkRouterVersion(router)){ throw new CloudRuntimeException("Router requires upgrade. Unable to send command to router:" + router.getId()); - } + } */ Answer[] answers = null; try { answers = _agentMgr.send(router.getHostId(), cmds); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5d9335fc/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 5264c71..74b3439 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -34,6 +34,8 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.capacity.Capacity; +import com.cloud.exception.InsufficientServerCapacityException; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; @@ -1326,6 +1328,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) @@ -1349,14 +1353,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; @@ -1365,15 +1379,16 @@ 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()); } @@ -1413,8 +1428,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir if (newServiceOffering.isDynamic()) { removeCustomOfferingDetails(vmId); } - 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)); } } }
