package org.ovirt.engine.core.bll.scheduling;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.VM;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SlaValidator {
private static final Logger log = LoggerFactory.getLogger(SlaValidator.class);
private static final SlaValidator instance = new SlaValidator();
public static SlaValidator getInstance() {
return instance;
}
/**
* Check whether a host has enough physical memory to start or receive the VM.
* We have to take swap into account here as it will increase the theoretical
* limit QEMU/kernel uses to determine whether the required memory space can
* be allocated (the actual memory is then allocated only when needed, but the
* full check is done in advance).
*
* The overcommit rules do not apply here as we can reclaim some memory back
* only after the VM was successfully started.
*
* @param curVds The host in question
* @param vm The currently scheduled VM
* @return true when there is enough memory, false otherwise
*/
public boolean hasPhysMemoryToRunVM(VDS curVds, VM vm, int pendingMemory) {
if (curVds.getMemFree() != null && curVds.getGuestOverhead() != null) {
double vmMemRequired = vm.getMemSizeMb() + curVds.getGuestOverhead();
double vdsMemLimit = curVds.getMemFree() - pendingMemory;
log.debug("hasPhysMemoryToRunVM: host '{}'; free memory is : {} MB (+ {} MB pending); free swap is: {} MB, required memory is {} MB; Guest overhead {} MB",
curVds.getName(),
vdsMemLimit,
pendingMemory,
curVds.getSwapFree(),
vmMemRequired,
curVds.getGuestOverhead());
if (curVds.getSwapFree() != null) {
vdsMemLimit += curVds.getSwapFree();
}
log.debug("{} <= ??? {}", vmMemRequired, vdsMemLimit);
return vmMemRequired <= vdsMemLimit;
} else {
return false;
}
}
/**
* Check whether a host has enough memory to host the new VM while
* taking the engine overcommit limits into account.
*
* Swap space and real available memory is not important here, only
* the theoretical sum of all VM assigned memory against the host
* memory multiplied by overcommit.
*
* @param curVds The host in question
* @param vm The currently scheduled VM
* @return true when there is enough memory, false otherwise
*/
public boolean hasOvercommitMemoryToRunVM(VDS curVds, VM vm) {
double vmMemRequired = vm.getMemSizeMb() + curVds.getGuestOverhead();
double vdsMemLimit = curVds.getMaxSchedulingMemory();
log.debug("hasOvercommitMemoryToRunVM: host '{}'; max scheduling memory : {} MB; required memory is {} MB; Guest overhead {} MB",
curVds.getName(),
vdsMemLimit,
vmMemRequired,
curVds.getGuestOverhead());
log.debug("{} <= ??? {}", vmMemRequired, vdsMemLimit);
return vmMemRequired <= vdsMemLimit;
}
public static Integer getEffectiveCpuCores(VDS vds, boolean countThreadsAsCores) {
if (vds.getCpuThreads() != null
&& countThreadsAsCores) {
return vds.getCpuThreads();
} else {
return vds.getCpuCores();
}
}
/**
* Find out which cpus are currently online at the provided host.
* <p>
* When no cpus are reported to be online or no information is provided (a running host without a CPU does not make
* sense and is therefore equivalent to no information available), an empty collection is returned.
*
* @param host to check for online cpus
* @return online cpus or empty collection if no information is available
*/
public static Collection<Integer> getOnlineCpus(final VDS host) {
final Collection<Integer> cpus = new ArrayList<>();
if (StringUtils.isEmpty(host.getOnlineCpus())) {
return cpus;
}
for (String cpu : StringUtils.split(host.getOnlineCpus(), ",")) {
cpu = StringUtils.trim(cpu);
if (!StringUtils.isEmpty(cpu)) {
cpus.add(Integer.parseInt(cpu));
}
}
return cpus;
}
}