package org.ovirt.engine.core.bll.scheduling.policyunits; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.inject.Inject; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.bll.CpuFlagsManagerHandler; 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.ServerCpu; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.scheduling.PerHostMessages; import org.ovirt.engine.core.common.scheduling.PolicyUnit; import org.ovirt.engine.core.common.scheduling.PolicyUnitType; import org.ovirt.engine.core.compat.Version; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @SchedulingUnit( guid = "438b052c-90ab-40e8-9be0-a22560202ea6", name = "CPU-Level", type = PolicyUnitType.FILTER, description = "Runs VMs only on hosts with a proper CPU level" ) public class CpuLevelFilterPolicyUnit extends PolicyUnitImpl { private static final Logger log = LoggerFactory.getLogger(CpuLevelFilterPolicyUnit.class); @Inject private CpuFlagsManagerHandler cpuFlagsManagerHandler; public CpuLevelFilterPolicyUnit(PolicyUnit policyUnit, PendingResourceManager pendingResourceManager) { super(policyUnit, pendingResourceManager); } @Override public List<VDS> filter(Cluster cluster, List<VDS> hosts, VM vm, Map<String, String> parameters, PerHostMessages messages) { List<VDS> hostsToRunOn = new ArrayList<>(); String customCpu; // full name of the vm cpu Version latestVer = cpuFlagsManagerHandler.getLatestDictionaryVersion(); /* get required cpu name */ if (StringUtils.isNotEmpty(vm.getCpuName())) { // dynamic check - used for 1.migrating vms 2.run-once 3.after dynamic field is updated with current static-field\cluster customCpu = vm.getCpuName(); } else if (StringUtils.isNotEmpty(vm.getCustomCpuName())) { // static check - used only for cases where the dynamic value hasn't been updated yet(validate) customCpu = vm.getCustomCpuName(); } else { // use cluster default - all hosts are valid return hosts; } customCpu = cpuFlagsManagerHandler.getCpuNameByCpuId(customCpu, latestVer); // translate vdsVerb to full cpu name if(StringUtils.isNotEmpty(customCpu)) { // checks if there's a cpu with the given vdsVerb /* find compatible hosts */ for (VDS host : hosts) { ServerCpu cpu = cpuFlagsManagerHandler.findMaxServerCpuByFlags(host.getCpuFlags(), latestVer); String hostCpuName = cpu == null ? null : cpu.getCpuName(); if (StringUtils.isNotEmpty(hostCpuName)) { if (cpuFlagsManagerHandler.checkIfCpusSameManufacture(customCpu, hostCpuName, latestVer)) { // verify comparison uses only one cpu-level scale int compareResult = cpuFlagsManagerHandler.compareCpuLevels(customCpu, hostCpuName, latestVer); if (compareResult <= 0) { hostsToRunOn.add(host); log.debug("Host '{}' wasn't filtered out as it has a CPU level ({}) which is higher or equal than the CPU level the VM was run with ({})", host.getName(), hostCpuName, customCpu); } else { log.debug("Host '{}' was filtered out as it has a CPU level ({}) which is lower than the CPU level the VM was run with ({})", host.getName(), hostCpuName, customCpu); messages.addMessage(host.getId(), String.format("$hostCPULevel %1$s", hostCpuName)); messages.addMessage(host.getId(), String.format("$vmCPULevel %1$s", customCpu)); messages.addMessage(host.getId(), EngineMessage.VAR__DETAIL__LOW_CPU_LEVEL.toString()); } } } } } return hostsToRunOn; } }