package org.ovirt.engine.core.bll.scheduling.policyunits;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.ovirt.engine.core.bll.scheduling.PolicyUnitImpl;
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.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VdsDynamic;
import org.ovirt.engine.core.common.scheduling.PolicyUnit;
import org.ovirt.engine.core.common.scheduling.PolicyUnitType;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.utils.OS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Make sure that hosts with newer major versions of an OS will be preferred when a VM is migrating.
* Hosts with older major OS versions than the source host are heavy penalized.
* Hosts with the same major OS version as the source host are slightly penalized.
* Hosts with a newer major OS version are preferred.
*
* When running this policy in combination with {@link InClusterUpgradeFilterPolicyUnit} hosts with older major OS
* versions will be filtered by the other policy.
*
*/
@SchedulingUnit(
guid = "84e6ddee-ab0d-42dd-82f0-c298889db568",
name = "InClusterUpgrade",
description = "Penalize hosts with older OS version more than hosts with the same OS version where a vm is "
+ "currently running on. Newer OS versions are not penalized",
type = PolicyUnitType.WEIGHT
)
public class InClusterUpgradeWeightPolicyUnit extends PolicyUnitImpl {
private static final Logger log = LoggerFactory.getLogger(CpuLevelFilterPolicyUnit.class);
public static final int BAD_WEIGHT = 1000000;
public static final int BETTER_WEIGHT = 100000;
public static final int BEST_WEIGHT = 0;
public InClusterUpgradeWeightPolicyUnit(PolicyUnit policyUnit,
PendingResourceManager pendingResourceManager) {
super(policyUnit, pendingResourceManager);
}
@Override
public List<Pair<Guid, Integer>> score(Cluster cluster, List<VDS> hosts, VM vm, Map<String, String> parameters) {
VdsDynamic referenceHost = getLastHost(vm);
boolean isVmStartup = false;
// Check if the VM is starting
if (referenceHost == null) {
isVmStartup = true;
final Map<String, Version> highestVersions = new HashMap<>();
for (VDS host : hosts) {
OS os = OS.fromPackageVersionString(host.getHostOs());
if (!os.isValid()) {
continue;
}
Version version = highestVersions.get(os.getOsFamily());
if (version == null || version.getMajor() < os.getVersion().getMajor()) {
highestVersions.put(os.getOsFamily(), os.getVersion());
referenceHost = host.getDynamicData();
}
}
if (highestVersions.isEmpty()) {
log.debug("No valid OS descriptors detected. Will not weight hosts on VM startup.");
return noWeights(hosts);
} else if (highestVersions.size() > 1) {
log.debug("More than one OS family detected. Will not weight hosts on VM startup.");
return noWeights(hosts);
}
}
final OS lastHostOs = OS.fromPackageVersionString(referenceHost.getHostOs());
if (!lastHostOs.isValid()) {
log.debug("Reference host {} provides an invalid or incomplete OS identifier. Found {}.",
referenceHost.getId(),
referenceHost.getHostOs());
return noWeights(hosts);
}
final List<Pair<Guid, Integer>> weights = new ArrayList<>();
for (final VDS host : hosts) {
final OS hostOs = OS.fromPackageVersionString(host.getHostOs());
if (!hostOs.isValid()) {
log.debug("Host {} does not provide an valid OS identifier. Found {}.",
host.getId(),
host.getHostOs());
weights.add(toWeight(host, BAD_WEIGHT));
} else if (!hostOs.isSameOsFamily(lastHostOs)) {
log.debug("Host {} does not run the same operating system. Expected {}, found {}",
host.getId(),
lastHostOs.getName(),
hostOs.getName());
weights.add(toWeight(host, BAD_WEIGHT));
} else if (hostOs.isOlderThan(lastHostOs) && !hostOs.isSameMajorVersion(lastHostOs)) {
weights.add(toWeight(host, BAD_WEIGHT));
} else if (hostOs.isSameMajorVersion(lastHostOs) && !isVmStartup) {
weights.add(toWeight(host, BETTER_WEIGHT));
} else {
weights.add(toWeight(host, BEST_WEIGHT));
}
}
return weights;
}
private static List<Pair<Guid, Integer>> noWeights(final List<VDS> hosts) {
final List<Pair<Guid, Integer>> weights = new ArrayList<>();
for (final VDS host : hosts) {
weights.add(new Pair(host.getId(), BEST_WEIGHT));
}
return weights;
}
private static Pair<Guid, Integer> toWeight(final VDS host, int weight) {
return new Pair<>(host.getId(), weight);
}
}