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.HaReservationHandling; import org.ovirt.engine.core.bll.scheduling.PolicyUnitImpl; 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.businessentities.VM; 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.ovirt.engine.core.common.utils.Pair; import org.ovirt.engine.core.compat.Guid; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @SchedulingUnit( guid = "7f262d70-6cac-11e3-981f-0800200c9a66", name = "OptimalForHaReservation", description = "Weights hosts according to their HA score regardless of hosted engine", type = PolicyUnitType.WEIGHT, parameters = { PolicyUnitParameter.SCALE_DOWN } ) public class HaReservationWeightPolicyUnit extends PolicyUnitImpl { private static final Logger log = LoggerFactory.getLogger(HaReservationWeightPolicyUnit.class); private static final int RATIO_FACTOR = 100; private static final int DEFAULT_SCORE = 0; public HaReservationWeightPolicyUnit(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) { log.debug("Started HA reservation scoring method"); List<Pair<Guid, Integer>> scores = new ArrayList<>(); Map<Guid, Integer> hostsHaVmCount = new HashMap<>(); // If the vm is not HA or the cluster is not marked as HA Reservation set default score. if (!vm.isAutoStartup() || !cluster.supportsHaReservation()) { fillDefaultScores(hosts, scores); } else { // Use a single call to the DB to retrieve all VM in the Cluster and map them by Host id Map<Guid, List<VM>> hostId2HaVmMapping = HaReservationHandling.mapHaVmToHostByCluster(cluster.getId()); int maxCount = 0; for (VDS host : hosts) { int count = 0; if (hostId2HaVmMapping.containsKey(host.getId())) { count = hostId2HaVmMapping.get(host.getId()).size(); } maxCount = Math.max(maxCount, count); hostsHaVmCount.put(host.getId(), count); } // Fit count to scale of 0 to RATIO_FACTOR if (maxCount > 0) { for (VDS host : hosts) { int fittedCount = Math.round(hostsHaVmCount.get(host.getId()).floatValue() / maxCount * RATIO_FACTOR); hostsHaVmCount.put(host.getId(), fittedCount); } } // Get scale down param Integer scaleDownParameter = 1; if (parameters.get("ScaleDown") != null) { scaleDownParameter = Integer.parseInt(parameters.get(PolicyUnitParameter.SCALE_DOWN.getDbName())); } else { scaleDownParameter = Config.<Integer> getValue(ConfigValues.ScaleDownForHaReservation); } // Set the score pairs for (VDS host : hosts) { // Scale down if needed int haCount = hostsHaVmCount.get(host.getId()); haCount = (int) Math.ceil(haCount / scaleDownParameter.floatValue()); scores.add(new Pair<>(host.getId(), haCount)); log.info("Score for host '{}' is {}", host.getName(), haCount); } } log.debug("Ended HA reservation scoring method"); return scores; } // Fill all host with a neutral score private void fillDefaultScores(List<VDS> hosts, List<Pair<Guid, Integer>> scores) { for (VDS host : hosts) { scores.add(new Pair<>(host.getId(), DEFAULT_SCORE)); } } }