/* * Copyright (c) Fabien Hermenier * * 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.configuration; import java.util.Collections; import java.util.EnumSet; import java.util.List; /** * Common tools related to Configuration * * @author Fabien Hermenier */ public final class Configurations { public static enum State { /** * Specify running virtual machines. */ Runnings, /** * Specify sleeping virtual machines. */ Sleepings } /** * Utility class. No instantiation. */ private Configurations() { } /** * Return the subset of online nodes that host at least one virtual machines * * @param cfg the configuration to browse * @param wrt the hosting type to consider * @return subset of node that may be empty */ public static ManagedElementSet<Node> usedNodes(Configuration cfg, EnumSet<State> wrt) { ManagedElementSet<Node> ns = new SimpleManagedElementSet<Node>(); if (wrt.contains(State.Runnings)) { for (VirtualMachine vm : cfg.getRunnings()) { ns.add(cfg.getLocation(vm)); } } if (wrt.contains(State.Sleepings)) { for (VirtualMachine vm : cfg.getSleepings()) { ns.add(cfg.getLocation(vm)); } } return ns; } /** * Return the subset of online nodes that does not host virtual machines. * * @param cfg the configuration to browse * @param wrt the hosting type to consider * @return a subset of node that may be empty */ public static ManagedElementSet<Node> unusedNodes(Configuration cfg, State wrt) { ManagedElementSet<Node> ns = new SimpleManagedElementSet<Node>(); for (Node n : cfg.getOnlines()) { if (wrt == State.Runnings && cfg.getRunnings(n).size() == 0) { ns.add(n); } if (wrt == State.Sleepings && cfg.getSleepings(n).size() == 0) { ns.add(n); } } return ns; } /** * Return the subset of nodes that are currently overloaded. * A node is considered as overloaded if the total memory or CPU currently * consumed by the virtual machines it hosts is greater than its memory or CPU capacity. * * @return a subset of nodes, may be empty. */ public static ManagedElementSet<Node> currentlyOverloadedNodes(Configuration cfg) { ManagedElementSet<Node> nodes = new SimpleManagedElementSet<Node>(); for (Node n : cfg.getOnlines()) { int cpuCapa = n.getCPUCapacity(); int memCapa = n.getMemoryCapacity(); for (VirtualMachine vm : cfg.getRunnings(n)) { cpuCapa -= vm.getCPUConsumption(); memCapa -= vm.getMemoryConsumption(); if (cpuCapa < 0 || memCapa < 0) { nodes.add(n); break; } } } return nodes; } /** * Return the subset of nodes that can not satisfy the resource demand of the VMs. * A node is considered as overloaded if the total memory or CPU demand * of the virtual machines it hosts is greater than its memory or CPU capacity. * * @return a subset of nodes, may be empty. */ public static ManagedElementSet<Node> futureOverloadedNodes(Configuration cfg) { ManagedElementSet<Node> nodes = new SimpleManagedElementSet<Node>(); for (Node n : cfg.getOnlines()) { int cpuCapa = n.getCPUCapacity(); int memCapa = n.getMemoryCapacity(); for (VirtualMachine vm : cfg.getRunnings(n)) { cpuCapa -= vm.getCPUDemand(); memCapa -= vm.getMemoryDemand(); if (cpuCapa < 0 || memCapa < 0) { nodes.add(n); break; } } } return nodes; } /** * Check whether the current configuration is overloaded or not. * * @return true if at least one node is overloaded */ public static boolean isCurrentlyViable(Configuration cfg) { for (Node n : cfg.getOnlines()) { int cpuCapa = n.getCPUCapacity(); int memCapa = n.getMemoryCapacity(); for (VirtualMachine vm : cfg.getRunnings(n)) { cpuCapa -= vm.getCPUConsumption(); memCapa -= vm.getMemoryConsumption(); if (cpuCapa < 0 || memCapa < 0) { return false; } } } return true; } /** * Check whether the current configuration will be overloaded once * all the virtual machines will want to uses their demanded resources. * * @return true if at least one node is overloaded */ public static boolean isFutureViable(Configuration cfg) { for (Node n : cfg.getOnlines()) { int cpuCapa = n.getCPUCapacity(); int memCapa = n.getMemoryCapacity(); for (VirtualMachine vm : cfg.getRunnings(n)) { cpuCapa -= vm.getCPUDemand(); memCapa -= vm.getMemoryDemand(); if (cpuCapa < 0 || memCapa < 0) { return false; } } } return true; } /** * Compute a sub configuration that only consider a subset of nodes and virtual machines * All the virtual machines must be hosted on the subset of nodes or be in a waiting state * * @param vms the subset of virtual machines * @param nodes the subset of nodes * @return a new configuration is the operation succeed, {@code null} otherwise */ public static Configuration subConfiguration(Configuration cfg, ManagedElementSet<VirtualMachine> vms, ManagedElementSet<Node> nodes) throws ConfigurationsException { Configuration sub = new SimpleConfiguration(); ManagedElementSet<VirtualMachine> cpy = vms.clone(); for (Node n : nodes) { if (cfg.isOffline(n)) { sub.addOffline(n); } else if (cfg.isOnline(n)) { sub.addOnline(n); ManagedElementSet<VirtualMachine> runs = cfg.getRunnings(n); ManagedElementSet<VirtualMachine> sleeps = cfg.getSleepings(n); if (!cpy.containsAll(runs)) { throw new ConfigurationsException(cfg, "VMs on node " + n.getName() + "(" + runs + ") does not only contains VMs in " + cpy); } if (!cpy.containsAll(sleeps)) { throw new ConfigurationsException(cfg, "VMs on node " + n.getName() + "(" + sleeps + ") does not only contains VMs in " + cpy); } cpy.removeAll(runs); cpy.removeAll(sleeps); for (VirtualMachine vm : runs) { sub.setRunOn(vm, n); } for (VirtualMachine vm : sleeps) { sub.setSleepOn(vm, n); } } else { throw new ConfigurationsException(cfg, "Unknown node " + n.getName()); } } if (!cfg.getWaitings().isEmpty() && !cfg.getWaitings().containsAll(cpy)) { throw new ConfigurationsException(cfg, "Waiting VMs (" + cfg.getWaitings() + ") does not only contains VMs in " + cpy); } for (VirtualMachine vm : cpy) { sub.addWaiting(vm); } return sub; } /** * Merge a list of Configurations. * The set of virtual machines in the configuration is supposed to be disjoint while * if some nodes are presents in different configurations, there state have to be the same * * @param cfgs the list of configurations to merge * @return the resulting configuration * @throws ConfigurationsException if configurations are conflicting between each other */ public static Configuration merge(List<Configuration> cfgs) throws ConfigurationsException { return merge(cfgs.toArray(new Configuration[cfgs.size()])); } /** * Merge a list of Configurations. * The set of virtual machines in the configuration is supposed to be disjoint while * if some nodes are presents in different configurations, there state have to be the same * * @param cfgs the list of configurations to merge * @return the resulting configuration * @throws ConfigurationsException if configurations are conflicting between each other */ public static Configuration merge(Configuration... cfgs) throws ConfigurationsException { Configuration res = new SimpleConfiguration(); for (Configuration c : cfgs) { if (!Collections.disjoint(c.getAllVirtualMachines(), res.getAllVirtualMachines())) { throw new ConfigurationsException(c, "Set of virtual machines are not disjoint with already merged configurations"); } for (Node n : c.getOfflines()) { if (res.isOnline(n)) { throw new ConfigurationsException(c, "Conflicting state for node '" + n.getName() + "'"); } if (!res.isOffline(n)) { res.addOffline(n); } } for (Node n : c.getOnlines()) { if (res.isOffline(n)) { throw new ConfigurationsException(c, "Conflicting state for node '" + n.getName() + "'"); } if (!res.isOnline(n)) { res.addOnline(n); } for (VirtualMachine vm : c.getRunnings(n)) { if (!res.setRunOn(vm, n)) { throw new ConfigurationsException(c, "Unable to place running '" + vm.getName() + "' on '" + n.getName() + "'"); } } for (VirtualMachine vm : c.getSleepings(n)) { if (!res.setSleepOn(vm, n)) { throw new ConfigurationsException(c, "Unable to place sleeping '" + vm.getName() + "' on '" + n.getName() + "'"); } } } for (VirtualMachine vm : c.getWaitings()) { res.addWaiting(vm); } } return res; } }