package org.ovirt.engine.core.bll.scheduling.policyunits; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; 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.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.dal.dbbroker.DbFacade; import org.ovirt.engine.core.dao.VdsDao; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @SchedulingUnit( guid = "e659c871-0bf1-4ccc-b748-f28f5d08ddda", name = "Migration", description = "Prevent migration to the same host.", type = PolicyUnitType.FILTER ) public class MigrationPolicyUnit extends PolicyUnitImpl { private static final Logger log = LoggerFactory.getLogger(MigrationPolicyUnit.class); public MigrationPolicyUnit(PolicyUnit policyUnit, PendingResourceManager pendingResourceManager) { super(policyUnit, pendingResourceManager); } private boolean validateDestinationVdsAddress(VDS srcVds, VDS dstVds) { InetAddress dstAddress = null; try { dstAddress = InetAddress.getByName(dstVds.getHostName()); } catch (UnknownHostException e) { // no clues, better to not guess. Let libvirt sort out the mess, // as it already did before. return true; } if (dstAddress != null && dstAddress.isLoopbackAddress()) { log.warn("cannot migrate to VDS {}: resolved to loopback address", dstVds.getHostName()); return false; } if (srcVds != null) { // on runVm will be null InetAddress srcAddress = null; if (srcVds.getHostName().equals(dstVds.getHostName())) { log.warn("cannot migrate to VDS {}: same hostname as source", dstVds.getHostName()); return false; } try { srcAddress = InetAddress.getByName(srcVds.getHostName()); } catch (UnknownHostException e) { return true; // same as per dst address } if (srcAddress != null && dstAddress != null && srcAddress.equals(dstAddress)) { log.warn("cannot migrate to VDS {}: resolved address equal to source", dstVds.getHostName()); return false; } } return true; } @Override public List<VDS> filter(Cluster cluster, List<VDS> hosts, VM vm, Map<String, String> parameters, PerHostMessages messages) { if (vm.getRunOnVds() != null) { List<VDS> hostsToRunOn = new ArrayList<>(); VDS srcVds = getVdsDao().get(vm.getRunOnVds()); for (VDS host : hosts) { if (host.getId().equals(vm.getRunOnVds())) { log.debug("Vm '{}' already runs on host '{}'," + " the host is not filtered out for balancing purposes", vm.getName(), host.getName()); hostsToRunOn.add(host); continue; } if (!validateDestinationVdsAddress(srcVds, host)) { log.debug("Host '{}' resolves to the same machine as host '{}', filtering out", srcVds.getName(), host.getName()); messages.addMessage(host.getId(), EngineMessage.VAR__DETAIL__SAME_HOST.toString()); continue; } hostsToRunOn.add(host); } return hostsToRunOn; } return hosts; } protected VdsDao getVdsDao() { return DbFacade.getInstance().getVdsDao(); } }