diff options
author | toby <smorgrav@yahoo-inc.com> | 2017-07-20 11:17:03 +0200 |
---|---|---|
committer | toby <smorgrav@yahoo-inc.com> | 2017-08-14 11:27:08 +0200 |
commit | be257d41f011bbe6d8bf9838ac4cf01f9dae7b00 (patch) | |
tree | 596171b2c18d18ec97bf386fc7d44e5fa9886076 /node-repository | |
parent | 9deb2785feb43f76c34eae81a44e63adba8923c8 (diff) |
NodePrioritizer
Diffstat (limited to 'node-repository')
5 files changed, 27 insertions, 87 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerAllocator.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerAllocator.java index fca15283e5d..eaa1663158f 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerAllocator.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/DockerAllocator.java @@ -133,7 +133,7 @@ public class DockerAllocator { * * TODO propagate this information either through the node object or from the configserver deployer */ - private static boolean isReplacement(NodeSpec nodeSpec, List<Node> nodesBefore, List<Node> nodesReserved) { + public static boolean isReplacement(NodeSpec nodeSpec, List<Node> nodesBefore, List<Node> nodesReserved) { int wantedCount = 0; if (nodeSpec instanceof NodeSpec.CountNodeSpec) { NodeSpec.CountNodeSpec countSpec = (NodeSpec.CountNodeSpec) nodeSpec; diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java index caa2de2f973..ab69db260c7 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java @@ -3,23 +3,14 @@ package com.yahoo.vespa.hosted.provision.provisioning; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterSpec; -import com.yahoo.config.provision.Flavor; -import com.yahoo.config.provision.NodeType; import com.yahoo.config.provision.OutOfCapacityException; import com.yahoo.lang.MutableInteger; import com.yahoo.transaction.Mutex; import com.yahoo.vespa.hosted.provision.Node; -import com.yahoo.vespa.hosted.provision.NodeList; import com.yahoo.vespa.hosted.provision.NodeRepository; -import java.net.InetAddress; -import java.net.UnknownHostException; import java.time.Clock; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.Optional; -import java.util.Set; import java.util.function.BiConsumer; /** @@ -65,24 +56,20 @@ class GroupPreparer { NodePrioritizer prioritizer = new NodePrioritizer( nodeRepository.getNodes(), + application, + cluster, + requestedNodes, nodeRepository.getAvailableFlavors(), - a -> nodeRepository.getNode(a.parentHostname().orElse(" NOT-A-NODE !"), Node.State.values()), - getDockerFlavor(requestedNodes), - requestedNodes.specifiesNonStockFlavor(), 1, nofSpares); - prioritizer.addApplicationNodes(nodeRepository.getNodes(application, Node.State.active, Node.State.inactive, Node.State.reserved)); - prioritizer.addSurplusNodes(surplusActiveNodes); - prioritizer.addReadyNodes(nodeRepository.getNodes(Node.State.ready)); - prioritizer.addNewNodes(createNewNodes(nodeRepository.getNodes(), getDockerFlavor(requestedNodes), cluster)); - + prioritizer.initNodes(surplusActiveNodes, nodeRepository.dynamicAllocationEnabled()); NodeAllocation allocation = new NodeAllocation(application, cluster, requestedNodes, highestIndex, clock); - List<Node> acceptedNodes = allocation.offer(prioritizer.toPrioritizedNodeList(false), false); //TODO replacement + prioritizer.offer(allocation); if (allocation.fullfilled()) { - nodeRepository.reserve(prioritizer.filterInactiveAndReadyNodes(acceptedNodes)); - nodeRepository.addDockerNodes(prioritizer.filterNewNodes(acceptedNodes)); - surplusActiveNodes.removeAll(prioritizer.filterSurplusNodes(acceptedNodes)); + nodeRepository.reserve(prioritizer.filterInactiveAndReadyNodes(allocation.getAcceptedNodes())); + nodeRepository.addDockerNodes(prioritizer.filterNewNodes(allocation.getAcceptedNodes())); + surplusActiveNodes.removeAll(prioritizer.filterSurplusNodes(allocation.getAcceptedNodes())); return allocation.finalNodes(surplusActiveNodes); } else { throw new OutOfCapacityException("Could not satisfy " + requestedNodes + " for " + cluster + @@ -92,14 +79,6 @@ class GroupPreparer { } } - private Optional<Flavor> getDockerFlavor(NodeSpec nodeSpec) { - if (nodeSpec instanceof NodeSpec.CountNodeSpec) { - NodeSpec.CountNodeSpec countSpec = (NodeSpec.CountNodeSpec) nodeSpec; - return Optional.of(countSpec.getFlavor()); - } - return Optional.empty(); - } - private String outOfCapacityDetails(NodeAllocation allocation) { if (allocation.wouldBeFulfilledWithClashingParentHost()) { return ": Not enough nodes available on separate physical hosts."; @@ -109,59 +88,4 @@ class GroupPreparer { } return "."; } - - /** - * Create new nodes on all hosts that have capacity for the requested flavor - * (regardless of headroom and spare constraints) and where the parent nodes does not have - * a conflicting node (a node in the same cluster). - * - * @param allNodes The existing nodes in the node-repository (thus no headroom and spares here) - */ - private List<Node> createNewNodes(List<Node> allNodes, Optional<Flavor> dockerFlavor, ClusterSpec clusterSpec) { - List<Node> newNodes = new ArrayList<>(); - // Only create nodes if this is docker and the dynamic allocation is enabled - if (!nodeRepository.dynamicAllocationEnabled() || !dockerFlavor.isPresent()) return newNodes; - - Flavor flavor = dockerFlavor.get(); - DockerHostCapacity capacity = new DockerHostCapacity(allNodes); - for (Node node : allNodes) { - // For each host - if (node.type() == NodeType.host) { - NodeList list = new NodeList(allNodes); - NodeList childrenWithSameApp = list.childNodes(node).owner(null); - for (Node child : childrenWithSameApp.asList()) { - // Look for nodes from the same cluster - if (child.allocation().get().membership().cluster().id().equals(clusterSpec.id())) { - - } - } - - if (capacity.hasCapacity(node, flavor)) { - Set<String> ipAddresses = DockerHostCapacity.findFreeIps(node, allNodes); - if (ipAddresses.isEmpty()) continue; - String ipAddress = ipAddresses.stream().findFirst().get(); - String hostname = lookupHostname(ipAddress); - if (hostname == null) continue; - Node newNode = Node.createDockerNode("fake-" + hostname, Collections.singleton(ipAddress), - Collections.emptySet(), hostname, Optional.of(node.hostname()), flavor, NodeType.tenant); - newNodes.add(newNode); - } - } - } - return newNodes; - } - - /** - * From ipAddress - get hostname - * - * @return hostname or null if not able to do the loopup - */ - private static String lookupHostname(String ipAddress) { - try { - return InetAddress.getByName(ipAddress).getHostName(); - } catch (UnknownHostException e) { - e.printStackTrace(); - } - return null; - } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java index b8d0495095b..e0d776a223e 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java @@ -236,6 +236,10 @@ public class NodeAllocation { return new ArrayList<>(nodes); } + public Set<Node> getAcceptedNodes() { + return nodes; + } + private List<Node> byDecreasingIndex(Set<Node> nodes) { return nodes.stream().sorted(nodeIndexComparator().reversed()).collect(Collectors.toList()); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java index ad66f86de69..fb8fdee222c 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java @@ -60,6 +60,10 @@ public class MockNodeRepository extends NodeRepository { Collections.sort(ipAddressesForAllHost); final HashSet<String> ipAddresses = new HashSet<>(ipAddressesForAllHost); + final List<String> additionalIpAddressesForAllHost = Arrays.asList("::2", "::3", "::4"); + Collections.sort(additionalIpAddressesForAllHost); + final HashSet<String> additionalIpAddresses = new HashSet<>(additionalIpAddressesForAllHost); + nodes.add(createNode("node1", "host1.yahoo.com", ipAddresses, Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.tenant)); nodes.add(createNode("node2", "host2.yahoo.com", ipAddresses, Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.tenant)); nodes.add(createNode("node3", "host3.yahoo.com", ipAddresses, Optional.empty(), flavors.getFlavorOrThrow("expensive"), NodeType.tenant)); @@ -83,7 +87,8 @@ public class MockNodeRepository extends NodeRepository { nodes.add(node10); nodes.add(createNode("node55", "host55.yahoo.com", ipAddresses, Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.tenant)); - nodes.add(createNode("parent1", "parent1.yahoo.com", ipAddresses, Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.host)); + nodes.add(createNode("parent1", "parent1.yahoo.com", ipAddresses, additionalIpAddresses, Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.host)); + nodes.add(createNode("parent2", "dockerhost4", ipAddresses, additionalIpAddresses, Optional.empty(), flavors.getFlavorOrThrow("default"), NodeType.host)); nodes = addNodes(nodes); nodes.remove(6); @@ -93,6 +98,12 @@ public class MockNodeRepository extends NodeRepository { fail("host5.yahoo.com", Agent.system, "Failing to unit test"); setDirty("host55.yahoo.com"); + ApplicationId zoneApp = ApplicationId.from(TenantName.from("zoneapp"), ApplicationName.from("zoneapp"), InstanceName.from("zoneapp")); + ClusterSpec zoneCluster = ClusterSpec.request(ClusterSpec.Type.container, + ClusterSpec.Id.from("node-admin"), + Version.fromString("6.42")); + activate(provisioner.prepare(zoneApp, zoneCluster, Capacity.fromRequiredNodeType(NodeType.host), 1, null), zoneApp, provisioner); + ApplicationId app1 = ApplicationId.from(TenantName.from("tenant1"), ApplicationName.from("application1"), InstanceName.from("instance1")); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.container, ClusterSpec.Id.from("id1"), Version.fromString("6.42")); provisioner.prepare(app1, cluster1, Capacity.fromNodeCount(2), 1, null); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java index dd2b64a7854..aa54eb292a3 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java @@ -506,7 +506,8 @@ public class RestApiTest { private JDisc container; @Before - public void startContainer() { container = JDisc.fromServicesXml(ContainerConfig.servicesXmlV2(0), Networking.disable); } + public void startContainer() { + container = JDisc.fromServicesXml(ContainerConfig.servicesXmlV2(0), Networking.disable); } @After public void stopContainer() { container.close(); } |