package org.ovirt.engine.core.bll.scheduling.policyunits;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.lang.math.NumberUtils;
import org.ovirt.engine.core.bll.scheduling.PolicyUnitParameter;
import org.ovirt.engine.core.bll.scheduling.SchedulingUnit;
import org.ovirt.engine.core.bll.scheduling.pending.PendingResourceManager;
import org.ovirt.engine.core.common.businessentities.Cluster;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.scheduling.PolicyUnit;
import org.ovirt.engine.core.common.scheduling.PolicyUnitType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SchedulingUnit(
guid = "d58c8e32-44e1-418f-9222-52cd887bf9e0",
name = "OptimalForEvenGuestDistribution",
type = PolicyUnitType.LOAD_BALANCING,
parameters = {
PolicyUnitParameter.SPM_VM_GRACE,
PolicyUnitParameter.HIGH_VM_COUNT,
PolicyUnitParameter.MIGRATION_THRESHOLD
}
)
public class EvenGuestDistributionBalancePolicyUnit extends EvenDistributionBalancePolicyUnit {
private final int spmVmGraceDefault;
private final int migrationThresholdDefault;
private final int highVmCountDefault;
protected static final Logger log = LoggerFactory.getLogger(EvenGuestDistributionBalancePolicyUnit.class);
public EvenGuestDistributionBalancePolicyUnit (PolicyUnit policyUnit,
PendingResourceManager pendingResourceManager) {
super(policyUnit, pendingResourceManager);
spmVmGraceDefault = Config.<Integer> getValue(ConfigValues.SpmVmGraceForEvenGuestDistribute);
migrationThresholdDefault = Config.<Integer> getValue(ConfigValues.MigrationThresholdForEvenGuestDistribute);
highVmCountDefault = Config.<Integer> getValue(ConfigValues.HighVmCountForEvenGuestDistribute);
}
/* returns the number of running VMS on given VDS
if the VDS is SPM the return value is the number of running VMS + SPMVMCountGrace
*/
private int getOccupiedVmSlots(VDS vds, Map<String, String> parameters) {
int occupiedSlots = vds.getVmActive();
final int spmVmCountGrace = NumberUtils.toInt(parameters.get(PolicyUnitParameter.SPM_VM_GRACE.getDbName()),
spmVmGraceDefault);
if (vds.isSpm()) {
occupiedSlots += spmVmCountGrace;
}
return occupiedSlots;
}
private VDS getWorstVDS(List<VDS> relevantHosts, Map<String, String> parameters) {
VDS worstVds = relevantHosts.get(0);
int worstVdsSlots = 0;
for (VDS vds: relevantHosts) {
if (getOccupiedVmSlots(vds, parameters) > worstVdsSlots) {
worstVds = vds;
worstVdsSlots = getOccupiedVmSlots(worstVds, parameters);
}
}
return worstVds;
}
@Override
protected List<VDS> getPrimarySources(Cluster cluster, List<VDS> candidateHosts, final Map<String, String> parameters) {
final int highVmCountUtilization = NumberUtils.toInt(parameters.get(PolicyUnitParameter.HIGH_VM_COUNT.getDbName()),
highVmCountDefault);
final VDS worstVDS = getWorstVDS(candidateHosts, parameters);
final int worstVdsOccupiedVmSlots = getOccupiedVmSlots(worstVDS, parameters);
if (worstVdsOccupiedVmSlots < highVmCountUtilization) {
log.info("There is no host with more than {} running guests, no balancing is needed",
highVmCountUtilization);
return null;
}
return candidateHosts.stream().filter(p -> getOccupiedVmSlots(p, parameters) >= worstVdsOccupiedVmSlots)
.collect(Collectors.toList());
}
@Override
protected List<VDS> getPrimaryDestinations(Cluster cluster, List<VDS> candidateHosts, final Map<String, String> parameters) {
final int migrationThreshold = NumberUtils.toInt(parameters.get(PolicyUnitParameter.MIGRATION_THRESHOLD.getDbName()),
migrationThresholdDefault);
final VDS worstVDS = getWorstVDS(candidateHosts, parameters);
final int worstVdsOccupiedVmSlots = getOccupiedVmSlots(worstVDS, parameters);
List<VDS> underUtilizedHosts = candidateHosts.stream()
.filter(p -> {
int distance = worstVdsOccupiedVmSlots - getOccupiedVmSlots(p, parameters);
return distance >= migrationThreshold;
}).collect(Collectors.toList());
if (underUtilizedHosts.size() == 0) {
log.warn("There is no host with less than {} running guests",
worstVdsOccupiedVmSlots - migrationThreshold);
}
return underUtilizedHosts;
}
@Override
protected List<VDS> getSecondarySources(Cluster cluster, List<VDS> candidateHosts, Map<String, String> parameters) {
return null;
}
@Override
protected List<VDS> getSecondaryDestinations(Cluster cluster, List<VDS> candidateHosts, Map<String, String> parameters) {
return null;
}
}