Skip to content

Commit cd60b8d

Browse files
authored
host-allocator: check capacity for suitable hosts (apache#4884)
Fixes apache#4517 Adds capacity checks for RandomAllocator (host allocator) Factors out host cpu capability and capacity check wrt serviceoffering code into CapacityManager. Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
1 parent cb91a76 commit cd60b8d

File tree

4 files changed

+90
-92
lines changed

4 files changed

+90
-92
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
2323

2424
import com.cloud.host.Host;
25+
import com.cloud.offering.ServiceOffering;
2526
import com.cloud.service.ServiceOfferingVO;
2627
import com.cloud.storage.VMTemplateVO;
28+
import com.cloud.utils.Pair;
2729
import com.cloud.vm.VirtualMachine;
2830

2931
/**
@@ -141,4 +143,6 @@ boolean checkIfHostHasCapacity(long hostId, Integer cpu, long ram, boolean check
141143
long getUsedBytes(StoragePoolVO pool);
142144

143145
long getUsedIops(StoragePoolVO pool);
146+
147+
Pair<Boolean, Boolean> checkIfHostHasCpuCapabilityAndCapacity(Host host, ServiceOffering offering, boolean considerReservedCapacity);
144148
}

plugins/host-allocators/random/src/main/java/com/cloud/agent/manager/allocator/impl/RandomAllocator.java

Lines changed: 62 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,14 @@
2222

2323
import javax.inject.Inject;
2424

25+
import org.apache.commons.collections.CollectionUtils;
2526
import org.apache.log4j.Logger;
2627
import org.springframework.stereotype.Component;
2728

2829
import com.cloud.agent.manager.allocator.HostAllocator;
30+
import com.cloud.capacity.CapacityManager;
31+
import com.cloud.dc.ClusterDetailsDao;
32+
import com.cloud.dc.dao.ClusterDao;
2933
import com.cloud.deploy.DeploymentPlan;
3034
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
3135
import com.cloud.host.Host;
@@ -34,6 +38,7 @@
3438
import com.cloud.host.dao.HostDao;
3539
import com.cloud.offering.ServiceOffering;
3640
import com.cloud.resource.ResourceManager;
41+
import com.cloud.utils.Pair;
3742
import com.cloud.utils.component.AdapterBase;
3843
import com.cloud.vm.VirtualMachine;
3944
import com.cloud.vm.VirtualMachineProfile;
@@ -45,120 +50,104 @@ public class RandomAllocator extends AdapterBase implements HostAllocator {
4550
private HostDao _hostDao;
4651
@Inject
4752
private ResourceManager _resourceMgr;
53+
@Inject
54+
private ClusterDao clusterDao;
55+
@Inject
56+
private ClusterDetailsDao clusterDetailsDao;
57+
@Inject
58+
private CapacityManager capacityManager;
4859

49-
@Override
50-
public List<Host> allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo) {
51-
return allocateTo(vmProfile, plan, type, avoid, returnUpTo, true);
52-
}
53-
54-
@Override
55-
public List<Host> allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, List<? extends Host> hosts, int returnUpTo,
56-
boolean considerReservedCapacity) {
60+
private List<Host> findSuitableHosts(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type,
61+
ExcludeList avoid, List<? extends Host> hosts, int returnUpTo,
62+
boolean considerReservedCapacity) {
5763
long dcId = plan.getDataCenterId();
5864
Long podId = plan.getPodId();
5965
Long clusterId = plan.getClusterId();
6066
ServiceOffering offering = vmProfile.getServiceOffering();
67+
List<? extends Host> hostsCopy = null;
6168
List<Host> suitableHosts = new ArrayList<Host>();
62-
List<Host> hostsCopy = new ArrayList<Host>(hosts);
6369

6470
if (type == Host.Type.Storage) {
6571
return suitableHosts;
6672
}
67-
6873
String hostTag = offering.getHostTag();
6974
if (hostTag != null) {
7075
s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId + " having host tag:" + hostTag);
7176
} else {
7277
s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId);
7378
}
74-
75-
// list all computing hosts, regardless of whether they support routing...it's random after all
76-
if (hostTag != null) {
77-
hostsCopy.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag));
79+
if (hosts != null) {
80+
// retain all computing hosts, regardless of whether they support routing...it's random after all
81+
hostsCopy = new ArrayList<Host>(hosts);
82+
if (hostTag != null) {
83+
hostsCopy.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag));
84+
} else {
85+
hostsCopy.retainAll(_resourceMgr.listAllUpAndEnabledHosts(type, clusterId, podId, dcId));
86+
}
7887
} else {
79-
hostsCopy.retainAll(_resourceMgr.listAllUpAndEnabledHosts(type, clusterId, podId, dcId));
88+
// list all computing hosts, regardless of whether they support routing...it's random after all
89+
hostsCopy = new ArrayList<HostVO>();
90+
if (hostTag != null) {
91+
hostsCopy = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag);
92+
} else {
93+
hostsCopy = _resourceMgr.listAllUpAndEnabledHosts(type, clusterId, podId, dcId);
94+
}
8095
}
81-
8296
s_logger.debug("Random Allocator found " + hostsCopy.size() + " hosts");
8397
if (hostsCopy.size() == 0) {
8498
return suitableHosts;
8599
}
86-
87100
Collections.shuffle(hostsCopy);
88101
for (Host host : hostsCopy) {
89102
if (suitableHosts.size() == returnUpTo) {
90103
break;
91104
}
92-
93-
if (!avoid.shouldAvoid(host)) {
94-
suitableHosts.add(host);
95-
} else {
105+
if (avoid.shouldAvoid(host)) {
96106
if (s_logger.isDebugEnabled()) {
97-
s_logger.debug("Host name: " + host.getName() + ", hostId: " + host.getId() + " is in avoid set, " + "skipping this and trying other available hosts");
107+
s_logger.debug("Host name: " + host.getName() + ", hostId: " + host.getId() + " is in avoid set, skipping this and trying other available hosts");
98108
}
109+
continue;
99110
}
111+
Pair<Boolean, Boolean> cpuCapabilityAndCapacity = capacityManager.checkIfHostHasCpuCapabilityAndCapacity(host, offering, considerReservedCapacity);
112+
if (!cpuCapabilityAndCapacity.first() || !cpuCapabilityAndCapacity.second()) {
113+
if (s_logger.isDebugEnabled()) {
114+
s_logger.debug("Not using host " + host.getId() + "; host has cpu capability? " + cpuCapabilityAndCapacity.first() + ", host has capacity?" + cpuCapabilityAndCapacity.second());
115+
}
116+
continue;
117+
}
118+
if (s_logger.isDebugEnabled()) {
119+
s_logger.debug("Found a suitable host, adding to list: " + host.getId());
120+
}
121+
suitableHosts.add(host);
100122
}
101-
102123
if (s_logger.isDebugEnabled()) {
103124
s_logger.debug("Random Host Allocator returning " + suitableHosts.size() + " suitable hosts");
104125
}
105-
106126
return suitableHosts;
107127
}
108128

109129
@Override
110-
public List<Host> allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity) {
111-
112-
long dcId = plan.getDataCenterId();
113-
Long podId = plan.getPodId();
114-
Long clusterId = plan.getClusterId();
115-
ServiceOffering offering = vmProfile.getServiceOffering();
116-
117-
List<Host> suitableHosts = new ArrayList<Host>();
118-
119-
if (type == Host.Type.Storage) {
120-
return suitableHosts;
121-
}
122-
123-
String hostTag = offering.getHostTag();
124-
if (hostTag != null) {
125-
s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId + " having host tag:" + hostTag);
126-
} else {
127-
s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId);
128-
}
129-
130-
// list all computing hosts, regardless of whether they support routing...it's random after all
131-
List<? extends Host> hosts = new ArrayList<HostVO>();
132-
if (hostTag != null) {
133-
hosts = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag);
134-
} else {
135-
hosts = _resourceMgr.listAllUpAndEnabledHosts(type, clusterId, podId, dcId);
136-
}
137-
138-
s_logger.debug("Random Allocator found " + hosts.size() + " hosts");
139-
140-
if (hosts.size() == 0) {
141-
return suitableHosts;
142-
}
143-
144-
Collections.shuffle(hosts);
145-
for (Host host : hosts) {
146-
if (suitableHosts.size() == returnUpTo) {
147-
break;
148-
}
130+
public List<Host> allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo) {
131+
return allocateTo(vmProfile, plan, type, avoid, returnUpTo, true);
132+
}
149133

150-
if (!avoid.shouldAvoid(host)) {
151-
suitableHosts.add(host);
152-
} else {
153-
if (s_logger.isDebugEnabled()) {
154-
s_logger.debug("Host name: " + host.getName() + ", hostId: " + host.getId() + " is in avoid set, skipping this and trying other available hosts");
155-
}
134+
@Override
135+
public List<Host> allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan, Type type,
136+
ExcludeList avoid, List<? extends Host> hosts, int returnUpTo,
137+
boolean considerReservedCapacity) {
138+
if (CollectionUtils.isEmpty(hosts)) {
139+
if (s_logger.isDebugEnabled()) {
140+
s_logger.debug("Random Allocator found 0 hosts as given host list is empty");
156141
}
142+
return new ArrayList<Host>();
157143
}
158-
if (s_logger.isDebugEnabled()) {
159-
s_logger.debug("Random Host Allocator returning " + suitableHosts.size() + " suitable hosts");
160-
}
161-
return suitableHosts;
144+
return findSuitableHosts(vmProfile, plan, type, avoid, hosts, returnUpTo, considerReservedCapacity);
145+
}
146+
147+
@Override
148+
public List<Host> allocateTo(VirtualMachineProfile vmProfile, DeploymentPlan plan,
149+
Type type, ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity) {
150+
return findSuitableHosts(vmProfile, plan, type, avoid, null, returnUpTo, considerReservedCapacity);
162151
}
163152

164153
@Override

server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import com.cloud.capacity.dao.CapacityDao;
3636
import com.cloud.configuration.Config;
3737
import com.cloud.dc.ClusterDetailsDao;
38-
import com.cloud.dc.ClusterDetailsVO;
3938
import com.cloud.dc.dao.ClusterDao;
4039
import com.cloud.deploy.DeploymentPlan;
4140
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
@@ -47,7 +46,6 @@
4746
import com.cloud.host.dao.HostDao;
4847
import com.cloud.host.dao.HostDetailsDao;
4948
import com.cloud.offering.ServiceOffering;
50-
import com.cloud.org.Cluster;
5149
import com.cloud.resource.ResourceManager;
5250
import com.cloud.service.ServiceOfferingDetailsVO;
5351
import com.cloud.service.dao.ServiceOfferingDetailsDao;
@@ -57,12 +55,13 @@
5755
import com.cloud.storage.dao.GuestOSCategoryDao;
5856
import com.cloud.storage.dao.GuestOSDao;
5957
import com.cloud.user.Account;
58+
import com.cloud.utils.Pair;
6059
import com.cloud.utils.component.AdapterBase;
60+
import com.cloud.vm.UserVmDetailVO;
6161
import com.cloud.vm.VirtualMachine;
6262
import com.cloud.vm.VirtualMachineProfile;
63-
import com.cloud.vm.dao.VMInstanceDao;
64-
import com.cloud.vm.UserVmDetailVO;
6563
import com.cloud.vm.dao.UserVmDetailsDao;
64+
import com.cloud.vm.dao.VMInstanceDao;
6665

6766

6867
/**
@@ -336,27 +335,15 @@ protected List<Host> allocateTo(DeploymentPlan plan, ServiceOffering offering, V
336335
continue;
337336
}
338337
}
339-
340-
int cpu_requested = offering.getCpu() * offering.getSpeed();
341-
long ram_requested = offering.getRamSize() * 1024L * 1024L;
342-
Cluster cluster = _clusterDao.findById(host.getClusterId());
343-
ClusterDetailsVO clusterDetailsCpuOvercommit = _clusterDetailsDao.findDetail(cluster.getId(), "cpuOvercommitRatio");
344-
ClusterDetailsVO clusterDetailsRamOvercommmt = _clusterDetailsDao.findDetail(cluster.getId(), "memoryOvercommitRatio");
345-
Float cpuOvercommitRatio = Float.parseFloat(clusterDetailsCpuOvercommit.getValue());
346-
Float memoryOvercommitRatio = Float.parseFloat(clusterDetailsRamOvercommmt.getValue());
347-
348-
boolean hostHasCpuCapability = _capacityMgr.checkIfHostHasCpuCapability(host.getId(), offering.getCpu(), offering.getSpeed());
349-
boolean hostHasCapacity = _capacityMgr.checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, false, cpuOvercommitRatio, memoryOvercommitRatio,
350-
considerReservedCapacity);
351-
352-
if (hostHasCpuCapability && hostHasCapacity) {
338+
Pair<Boolean, Boolean> cpuCapabilityAndCapacity = _capacityMgr.checkIfHostHasCpuCapabilityAndCapacity(host, offering, considerReservedCapacity);
339+
if (cpuCapabilityAndCapacity.first() && cpuCapabilityAndCapacity.second()) {
353340
if (s_logger.isDebugEnabled()) {
354341
s_logger.debug("Found a suitable host, adding to list: " + host.getId());
355342
}
356343
suitableHosts.add(host);
357344
} else {
358345
if (s_logger.isDebugEnabled()) {
359-
s_logger.debug("Not using host " + host.getId() + "; host has cpu capability? " + hostHasCpuCapability + ", host has capacity?" + hostHasCapacity);
346+
s_logger.debug("Not using host " + host.getId() + "; host has cpu capability? " + cpuCapabilityAndCapacity.first() + ", host has capacity?" + cpuCapabilityAndCapacity.second());
360347
}
361348
avoid.addHost(host.getId());
362349
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import com.cloud.hypervisor.Hypervisor.HypervisorType;
6161
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
6262
import com.cloud.offering.ServiceOffering;
63+
import com.cloud.org.Cluster;
6364
import com.cloud.resource.ResourceListener;
6465
import com.cloud.resource.ResourceManager;
6566
import com.cloud.resource.ResourceState;
@@ -1091,6 +1092,23 @@ public boolean checkIfClusterCrossesThreshold(Long clusterId, Integer cpuRequest
10911092

10921093
}
10931094

1095+
@Override
1096+
public Pair<Boolean, Boolean> checkIfHostHasCpuCapabilityAndCapacity(Host host, ServiceOffering offering, boolean considerReservedCapacity) {
1097+
int cpu_requested = offering.getCpu() * offering.getSpeed();
1098+
long ram_requested = offering.getRamSize() * 1024L * 1024L;
1099+
Cluster cluster = _clusterDao.findById(host.getClusterId());
1100+
ClusterDetailsVO clusterDetailsCpuOvercommit = _clusterDetailsDao.findDetail(cluster.getId(), "cpuOvercommitRatio");
1101+
ClusterDetailsVO clusterDetailsRamOvercommmt = _clusterDetailsDao.findDetail(cluster.getId(), "memoryOvercommitRatio");
1102+
Float cpuOvercommitRatio = Float.parseFloat(clusterDetailsCpuOvercommit.getValue());
1103+
Float memoryOvercommitRatio = Float.parseFloat(clusterDetailsRamOvercommmt.getValue());
1104+
1105+
boolean hostHasCpuCapability = checkIfHostHasCpuCapability(host.getId(), offering.getCpu(), offering.getSpeed());
1106+
boolean hostHasCapacity = checkIfHostHasCapacity(host.getId(), cpu_requested, ram_requested, false, cpuOvercommitRatio, memoryOvercommitRatio,
1107+
considerReservedCapacity);
1108+
1109+
return new Pair<>(hostHasCpuCapability, hostHasCapacity);
1110+
}
1111+
10941112
@Override
10951113
public boolean processAnswers(long agentId, long seq, Answer[] answers) {
10961114
// TODO Auto-generated method stub

0 commit comments

Comments
 (0)