/* * Copyright (c) 2010 Ecole des Mines de Nantes. * * This file is part of Entropy. * * Entropy is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Entropy is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Entropy. If not, see <http://www.gnu.org/licenses/>. */ package entropy.vjob; import choco.kernel.solver.ContradictionException; import entropy.configuration.Configuration; import entropy.configuration.ManagedElementSet; import entropy.configuration.Node; import entropy.configuration.SimpleManagedElementSet; import entropy.configuration.VirtualMachine; import entropy.plan.choco.ReconfigurationProblem; import entropy.plan.choco.actionModel.slice.Slice; import gnu.trove.TIntHashSet; /** * A constraint to enforce a set of virtual machines * to be hosted on a single group of physical elements. * * @author Fabien Hermenier */ public class Fence implements PlacementConstraint { /** * The list of possible groups of nodes. */ private VJobSet<Node> group; /** * The list of VMs involved in the constraint. */ private VJobSet<VirtualMachine> vms; /** * Make a new constraint that enforce all the virtual machines * to be hosted on a single group of nodes. * * @param vms the set of VMs to assign. * @param group the group of nodes. */ public Fence(VJobSet<VirtualMachine> vms, VJobSet<Node> group) { this.vms = vms; this.group = group; } /** * Get the virtual machines involved in the constraint. * * @return a set of VMs. should not be empty */ @Override public ExplodedSet<VirtualMachine> getAllVirtualMachines() { return this.vms.flatten(); } /** * Get the set of nodes involved in the constraint. * * @return a set of nodes, should not be empty */ @Override public ExplodedSet<Node> getNodes() { return this.group.flatten(); } /** * Get the set of virtual machines involved in the constraint. * * @return a set of virtual machines, should not be empty */ public VJobSet<VirtualMachine> getVirtualMachines() { return this.vms; } @Override public String toString() { StringBuilder buffer = new StringBuilder(); buffer.append("fence(").append(vms.pretty()); buffer.append(", ").append(group.pretty()); buffer.append(")"); return buffer.toString(); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Fence that = (Fence) o; return group.equals(that.group) && vms.equals(that.vms); } @Override public int hashCode() { int result = vms.hashCode(); result = 31 * result + group.hashCode(); return result; } @Override public void inject(ReconfigurationProblem core) { ManagedElementSet<VirtualMachine> runnings = new SimpleManagedElementSet<VirtualMachine>(); ManagedElementSet<VirtualMachine> ignored = new SimpleManagedElementSet<VirtualMachine>(); for (VirtualMachine vm : getAllVirtualMachines()) { if (core.getFutureRunnings().contains(vm)) { runnings.add(vm); } else { ignored.add(vm); } } if (runnings.isEmpty()) { VJob.logger.debug(this + " is entailed. No VMs are running"); } else { if (!ignored.isEmpty()) { VJob.logger.debug(this + " ignores non-running VMs: " + ignored); } if (getNodes().size() == 1) { //Only 1 possible destination node, so we directly instantiate the variable. for (VirtualMachine vm : runnings) { Slice t = core.getAssociatedAction(vm).getDemandingSlice(); if (t != null) { try { t.hoster().setVal(core.getNode(getNodes().get(0))); } catch (ContradictionException e) { VJob.logger.error(e.getMessage(), e); } } } } else { TIntHashSet iExlude = new TIntHashSet(); for (Node n : core.getSourceConfiguration().getOnlines()) { if (!getNodes().contains(n)) { iExlude.add(core.getNode(n)); } } for (Node n : core.getSourceConfiguration().getOfflines()) { if (!getNodes().contains(n)) { iExlude.add(core.getNode(n)); } } //Domain restriction. Remove all the non-involved nodes int[] idxs = iExlude.toArray(); for (VirtualMachine vm : runnings) { Slice t = core.getAssociatedAction(vm).getDemandingSlice(); if (t != null) { for (int x : idxs) { try { t.hoster().remVal(x); } catch (ContradictionException e) { VJob.logger.error(e.getMessage(), e); } } } } } } } /** * Check that the constraint is satified in a configuration. * * @param cfg the configuration to check * @return true if the running VMs are hosted on more than one group */ @Override public boolean isSatisfied(Configuration cfg) { if (getNodes().isEmpty()) { VJob.logger.error("No group of nodes was specified"); return false; } for (VirtualMachine vm : getAllVirtualMachines()) { if (cfg.isRunning(vm) && !getNodes().getElements().contains(cfg.getLocation(vm))) { return false; } } return true; } @Override public ExplodedSet<VirtualMachine> getMisPlaced(Configuration cfg) { ExplodedSet<VirtualMachine> bad = new ExplodedSet<VirtualMachine>(); for (VirtualMachine vm : getAllVirtualMachines()) { if (cfg.isRunning(vm) && !getNodes().getElements().contains(cfg.getLocation(vm))) { bad.add(vm); } } return bad; } }