diff options
author | Haakon Dybdahl <dybis@users.noreply.github.com> | 2016-06-23 08:45:15 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-06-23 08:45:15 +0200 |
commit | 1409aeacf2b57bb374383a7a11481c6b93dbf66f (patch) | |
tree | 34595c482846be1d0fa192ea00e266253aceaa75 | |
parent | 9d52f5acc57f98c79f58bb9f724a29adca6b7388 (diff) | |
parent | 79edecea6a6a95d01f7f41710867ef48ea3bea0e (diff) |
Merge pull request #143 from yahoo/dybdahl/add-node-type-in-repo
Dybdahl/add node type in repo
45 files changed, 360 insertions, 138 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java index 2ab98f0c582..d4a955cf746 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java @@ -30,6 +30,7 @@ public final class Node { private final Configuration configuration; private final Status status; private final State state; + private final Type type; /** Record of the last event of each type happening to this node */ private final History history; @@ -38,19 +39,20 @@ public final class Node { private Optional<Allocation> allocation; /** Creates a node in the initial state (provisioned) */ - public static Node create(String openStackId, String hostname, Optional<String> parentHostname, Configuration configuration) { + public static Node create(String openStackId, String hostname, Optional<String> parentHostname, Configuration configuration, Type type) { return new Node(openStackId, hostname, parentHostname, configuration, Status.initial(), State.provisioned, - Optional.empty(), History.empty()); + Optional.empty(), History.empty(), type); } /** Do not use. Construct nodes by calling {@link NodeRepository#createNode} */ public Node(String openStackId, String hostname, Optional<String> parentHostname, - Configuration configuration, Status status, State state, Allocation allocation, History history) { - this(openStackId, hostname, parentHostname, configuration, status, state, Optional.of(allocation), history); + Configuration configuration, Status status, State state, Allocation allocation, History history, Type type) { + this(openStackId, hostname, parentHostname, configuration, status, state, Optional.of(allocation), history, type); } public Node(String openStackId, String hostname, Optional<String> parentHostname, - Configuration configuration, Status status, State state, Optional<Allocation> allocation, History history) { + Configuration configuration, Status status, State state, Optional<Allocation> allocation, + History history, Type type) { Objects.requireNonNull(openStackId, "A node must have an openstack id"); Objects.requireNonNull(hostname, "A node must have a hostname"); Objects.requireNonNull(parentHostname, "A null parentHostname is not permitted."); @@ -59,6 +61,7 @@ public final class Node { Objects.requireNonNull(state, "A null node state is not permitted"); Objects.requireNonNull(allocation, "A null node allocation is not permitted"); Objects.requireNonNull(history, "A null node history is not permitted"); + Objects.requireNonNull(type, "A null node type is not permitted"); this.id = hostname; this.hostname = hostname; @@ -69,6 +72,7 @@ public final class Node { this.state = state; this.allocation = allocation; this.history = history; + this.type = type; } /** @@ -96,6 +100,9 @@ public final class Node { /** Returns the current state of this node (in the node state machine) */ public State state() { return state; } + /** Returns the type of this node */ + public Type type() { return type; } + /** Returns the current allocation of this, if any */ public Optional<Allocation> allocation() { return allocation; } @@ -135,24 +142,29 @@ public final class Node { /** Returns a node with the status assigned to the given value */ public Node setStatus(Status status) { - return new Node(openStackId, hostname, parentHostname, configuration, status, state, allocation, history); + return new Node(openStackId, hostname, parentHostname, configuration, status, state, allocation, history, type); + } + + /** Returns a node with the type assigned to the given value */ + public Node setType(Type type) { + return new Node(openStackId, hostname, parentHostname, configuration, status, state, allocation, history, type); } /** Returns a node with the hardware configuration assigned to the given value */ public Node setConfiguration(Configuration configuration) { - return new Node(openStackId, hostname, parentHostname, configuration, status, state, allocation, history); + return new Node(openStackId, hostname, parentHostname, configuration, status, state, allocation, history, type); } /** Returns a copy of this with the current generation set to generation */ public Node setReboot(Generation generation) { return new Node(openStackId, hostname, parentHostname, configuration, status.setReboot(generation), state, - allocation, history); + allocation, history, type); } /** Returns a copy of this with the flavor set to flavor */ public Node setFlavor(Flavor flavor) { return new Node(openStackId, hostname, parentHostname, new Configuration(flavor), status, state, - allocation, history); + allocation, history, type); } /** Returns a copy of this with a history record saying it was detected to be down at this instant */ @@ -176,17 +188,17 @@ public final class Node { * Do not use this to allocate a node. */ public Node setAllocation(Allocation allocation) { - return new Node(openStackId, hostname, parentHostname, configuration, status, state, allocation, history); + return new Node(openStackId, hostname, parentHostname, configuration, status, state, allocation, history, type); } /** Returns a copy of this node with the parent hostname assigned to the given value. */ public Node setParentHostname(String parentHostname) { - return new Node(openStackId, hostname, Optional.of(parentHostname), configuration, status, state, allocation, history); + return new Node(openStackId, hostname, Optional.of(parentHostname), configuration, status, state, allocation, history, type); } /** Returns a copy of this node with the given history. */ private Node setHistory(History history) { - return new Node(openStackId, hostname, parentHostname, configuration, status, state, allocation, history); + return new Node(openStackId, hostname, parentHostname, configuration, status, state, allocation, history, type); } @Override @@ -209,6 +221,8 @@ public final class Node { (parentHostname.isPresent() ? " [on: " + parentHostname.get() + "]" : ""); } + + public enum State { /** This node has been requested (from OpenStack) but is not yet read for use */ @@ -236,7 +250,10 @@ public final class Node { public boolean isAllocated() { return this == reserved || this == active || this == inactive || this == failed; } - } + public enum Type { + tenant, + host; + } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java index 1980b1f5318..aff65652399 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java @@ -94,7 +94,9 @@ public class NodeRepository extends AbstractComponent { return zkClient.getNode(state, hostname); } - public List<Node> getNodes(Node.State ... inState) { return zkClient.getNodes(inState); } + public List<Node> getNodes(Node.Type type, Node.State ... inState) { + return zkClient.getNodes(inState).stream().filter(node -> node.type().equals(type)).collect(Collectors.toList()); + } public List<Node> getNodes(ApplicationId id, Node.State ... inState) { return zkClient.getNodes(id, inState); } public List<Node> getInactive() { return zkClient.getNodes(Node.State.inactive); } public List<Node> getFailed() { return zkClient.getNodes(Node.State.failed); } @@ -108,8 +110,9 @@ public class NodeRepository extends AbstractComponent { // ----------------- Node lifecycle ----------------------------------------------------------- /** Creates a new node object, without adding it to the node repo */ - public Node createNode(String openStackId, String hostname, Optional<String> parentHostname, Configuration configuration) { - return Node.create(openStackId, hostname, parentHostname, configuration); + public Node createNode(String openStackId, String hostname, Optional<String> parentHostname, + Configuration configuration, Node.Type type) { + return Node.create(openStackId, hostname, parentHostname, configuration, type); } /** Adds a list of (newly created) nodes to the node repository as <i>provisioned</i> nodes */ diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/assimilate/PopulateClient.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/assimilate/PopulateClient.java index 1ec20f6df0c..37e0fb2da17 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/assimilate/PopulateClient.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/assimilate/PopulateClient.java @@ -85,14 +85,15 @@ public class PopulateClient { private Node buildNode(String hostname, String clusterType, String clusterId, int nodeIndex) { return new Node( - hostname, // Id - hostname, // Hostname - Optional.empty(), // parent hostname - new Configuration(getFlavor(clusterType, clusterId).get()), // Flavor + hostname /* id */, + hostname /* Hostname */, + Optional.empty() /* parent hostname */, + new Configuration(getFlavor(clusterType, clusterId).get()), Status.initial(), - Node.State.active, // State = active/allocated - Optional.empty(), // Allocation - History.empty()) // History + Node.State.active, + Optional.empty() /* Allocation */, + History.empty(), + Node.Type.tenant) // History .allocate( ApplicationId.from( diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java index fd5e229fa1b..d12c7f2a5ae 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java @@ -35,7 +35,7 @@ public class ApplicationMaintainer extends Maintainer { @Override protected void maintain() { Set<ApplicationId> applications = - nodeRepository().getNodes(Node.State.active).stream().map(node -> node.allocation().get().owner()).collect(Collectors.toSet()); + nodeRepository().getNodes(Node.Type.tenant, Node.State.active).stream().map(node -> node.allocation().get().owner()).collect(Collectors.toSet()); for (ApplicationId application : applications) { try { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Expirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Expirer.java index 8333996c23e..495ff3b756f 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Expirer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Expirer.java @@ -47,7 +47,7 @@ public abstract class Expirer extends Maintainer { @Override protected void maintain() { List<Node> expired = new ArrayList<>(); - for (Node node : nodeRepository().getNodes(fromState)) { + for (Node node : nodeRepository().getNodes(Node.Type.tenant, fromState)) { Optional<History.Event> event = node.history().event(eventType); if (event.isPresent() && event.get().at().plus(expiryTime).isBefore(clock.instant())) expired.add(node); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/monitoring/ProvisionMetrics.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/monitoring/ProvisionMetrics.java index 2753f435bde..b1e0df929f4 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/monitoring/ProvisionMetrics.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/monitoring/ProvisionMetrics.java @@ -50,7 +50,7 @@ public class ProvisionMetrics extends AbstractComponent { log.log(LogLevel.DEBUG, "Running provision metrics task"); try { for (Node.State state : Node.State.values()) - metric.set("hostedVespa." + state.name() + "Hosts", nodeRepository.getNodes(state).size(), null); + metric.set("hostedVespa." + state.name() + "Hosts", nodeRepository.getNodes(Node.Type.tenant, state).size(), null); } catch (RuntimeException e) { log.log(LogLevel.INFO, "Failed gathering metrics data: " + e.getMessage()); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java index 5ff1f41272a..6805862baf3 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java @@ -145,7 +145,8 @@ public class CuratorDatabaseClient { newNodeStatus(node, toState), toState, toState.isAllocated() ? node.allocation() : Optional.empty(), - newNodeHistory(node, toState)); + newNodeHistory(node, toState), + node.type()); curatorTransaction.add(CuratorOperations.delete(toPath(node).getAbsolute())) .add(CuratorOperations.create(toPath(toState, newNode.hostname()).getAbsolute(), nodeSerializer.toJson(newNode))); writtenNodes.add(newNode); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java index 9e0a26be308..004cceee7cb 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java @@ -55,6 +55,9 @@ public class NodeSerializer { private static final String stateVersionKey = "stateVersion"; private static final String failCountKey = "failCount"; private static final String hardwareFailureKey = "hardwareFailure"; + private static final String nodeTypeKey = "type"; + private static final String nodeTypeTenant = "tenant"; + private static final String nodeTypeHost = "host"; // Configuration fields private static final String flavorKey = "flavor"; @@ -71,7 +74,7 @@ public class NodeSerializer { private static final String dockerImageKey = "dockerImage"; // History event fields - private static final String typeKey = "type"; + private static final String historyEventTypeKey = "type"; private static final String atKey = "at"; private static final String agentKey = "agent"; // retired events only @@ -107,6 +110,15 @@ public class NodeSerializer { object.setBool(hardwareFailureKey, node.status().hardwareFailure()); node.allocation().ifPresent(allocation -> toSlime(allocation, object.setObject(instanceKey))); toSlime(node.history(), object.setArray(historyKey)); + object.setString(nodeTypeKey, nodeTypeToString(node.type())); + } + + private String nodeTypeToString(Node.Type type) { + switch (type) { + case tenant: return nodeTypeTenant; + case host: return nodeTypeHost; + } + throw new IllegalArgumentException("Unknown node type '" + type.toString() + "'"); } private void toSlime(Configuration configuration, Cursor object) { @@ -131,7 +143,7 @@ public class NodeSerializer { } private void toSlime(History.Event event, Cursor object) { - object.setString(typeKey, toString(event.type())); + object.setString(historyEventTypeKey, toString(event.type())); object.setLong(atKey, event.at().toEpochMilli()); if (event instanceof History.RetiredEvent) object.setString(agentKey, toString(((History.RetiredEvent)event).agent())); @@ -151,7 +163,8 @@ public class NodeSerializer { statusFromSlime(object), state, allocationFromSlime(object.field(instanceKey)), - historyFromSlime(object.field(historyKey))); + historyFromSlime(object.field(historyKey)), + typeFromSlime(object)); } private Status statusFromSlime(Inspector object) { @@ -194,8 +207,19 @@ public class NodeSerializer { return new History(events); } + private Node.Type typeFromSlime(Inspector object) { + String typeString = object.field(nodeTypeKey).asString(); + switch (typeString) { + case nodeTypeTenant : return Node.Type.tenant; + case nodeTypeHost : return Node.Type.host; + // TODO: Remove this when all data is converted + case "" : return Node.Type.tenant; + } + throw new IllegalArgumentException("Unknown node type '" + typeString + "'"); + } + private History.Event eventFromSlime(Inspector object) { - History.Event.Type type = eventTypeFromString(object.field(typeKey).asString()); + History.Event.Type type = eventTypeFromString(object.field(historyEventTypeKey).asString()); if (type == null) return null; Instant at = Instant.ofEpochMilli(object.field(atKey).asLong()); if (type.equals(History.Event.Type.retired)) 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 6b5d37d812a..0f5549e1110 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 @@ -78,7 +78,7 @@ class GroupPreparer { // Use new, ready nodes. Need to lock ready pool to ensure that nodes are not grabbed by others. try (Mutex readyLock = nodeRepository.lockUnallocated()) { - List<Node> readyNodes = nodeRepository.getNodes(Node.State.ready); + List<Node> readyNodes = nodeRepository.getNodes(Node.Type.tenant, Node.State.ready); accepted = nodeList.offer(optimize(readyNodes), !canChangeGroup); nodeList.update(nodeRepository.reserve(accepted)); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/legacy/ProvisionResource.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/legacy/ProvisionResource.java index f4c52010415..867d45b4fcd 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/legacy/ProvisionResource.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/legacy/ProvisionResource.java @@ -47,7 +47,7 @@ public class ProvisionResource { public void addNodes(List<HostInfo> hostInfoList) { List<Node> nodes = new ArrayList<>(); for (HostInfo hostInfo : hostInfoList) - nodes.add(nodeRepository.createNode(hostInfo.openStackId, hostInfo.hostname, Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow(hostInfo.flavor)))); + nodes.add(nodeRepository.createNode(hostInfo.openStackId, hostInfo.hostname, Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow(hostInfo.flavor)), Node.Type.tenant)); nodeRepository.addNodes(nodes); } @@ -94,7 +94,7 @@ public class ProvisionResource { Map<String, TenantStatus.ApplicationUsage> appinstanceUsageMap = new HashMap<>(); - nodeRepository.getNodes(Node.State.active).stream() + nodeRepository.getNodes(Node.Type.tenant, Node.State.active).stream() .filter(node -> { return node.allocation().get().owner().tenant().value().equals(tenantId); }) @@ -115,11 +115,12 @@ public class ProvisionResource { } //TODO: move this to nodes/v2/ when the spec for this has been nailed. + //TODO: Change it to list host nodes, instead of hosts for tenant nodes. @GET @Path("/dockerhost/{hostname}") public ContainersForHost getContainersForHost(@PathParam("hostname") String hostname) { List<DockerContainer> dockerContainersForHost = - nodeRepository.getNodes(State.active, State.inactive).stream() + nodeRepository.getNodes(Node.Type.tenant, State.active, State.inactive).stream() .filter(runsOnDockerHost(hostname)) .flatMap(ProvisionResource::toDockerContainer) .collect(Collectors.toList()); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v1/NodesApiHandler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v1/NodesApiHandler.java index 00e232dcfd3..0c9ca701a6e 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v1/NodesApiHandler.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v1/NodesApiHandler.java @@ -78,13 +78,15 @@ public class } private void toSlime(Node.State state, Cursor object) { - List<Node> nodes = nodeRepository.getNodes(state); Cursor nodeArray = null; // create if there are nodes - for (Node node : nodes) { - if (hostnameFilter.isPresent() && ! node.hostname().equals(hostnameFilter.get())) continue; - if (nodeArray == null) - nodeArray = object.setArray(state.name()); - toSlime(node, nodeArray.addObject()); + for (Node.Type type : Node.Type.values()) { + List<Node> nodes = nodeRepository.getNodes(type, state); + for (Node node : nodes) { + if (hostnameFilter.isPresent() && !node.hostname().equals(hostnameFilter.get())) continue; + if (nodeArray == null) + nodeArray = object.setArray(state.name()); + toSlime(node, nodeArray.addObject()); + } } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesApiHandler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesApiHandler.java index 9981602e4d0..8c388fbd4db 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesApiHandler.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesApiHandler.java @@ -44,6 +44,8 @@ public class NodesApiHandler extends LoggingRequestHandler { private final NodeRepository nodeRepository; private final NodeFlavors nodeFlavors; + private static final String nodeTypeKey = "type"; + public NodesApiHandler(Executor executor, AccessLog accessLog, NodeRepository nodeRepository, NodeFlavors flavors) { super(executor, accessLog); @@ -189,7 +191,22 @@ public class NodesApiHandler extends LoggingRequestHandler { inspector.field("openStackId").asString(), inspector.field("hostname").asString(), parentHostname, - new Configuration(nodeFlavors.getFlavorOrThrow(inspector.field("flavor").asString()))); + new Configuration(nodeFlavors.getFlavorOrThrow(inspector.field("flavor").asString())), + nodeTypeFromSlime(inspector.field(nodeTypeKey))); + } + + private Node.Type nodeTypeFromSlime(Inspector object) { + // TODO: Remove this when 6.13 is deployed everywhere. + if (! object.valid()) { + return Node.Type.tenant; + } + String typeString = object.asString(); + switch (typeString) { + case "tenant" : return Node.Type.tenant; + case "host" : return Node.Type.host; + } + // TODO: Change this to throw an exception when 6.13 is deployed everywhere. + return Node.Type.tenant; } // TODO: Move most of this to node repo diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesResponse.java index 4e8fbe6099b..9318c6d0d7b 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesResponse.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesResponse.java @@ -1,7 +1,6 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.provision.restapi.v2; -import com.yahoo.component.Version; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterMembership; import com.yahoo.container.jdisc.HttpRequest; @@ -42,7 +41,7 @@ class NodesResponse extends HttpResponse { private final Slime slime; - public NodesResponse(ResponseType type, HttpRequest request, NodeRepository nodeRepository) { + public NodesResponse(ResponseType responseType, HttpRequest request, NodeRepository nodeRepository) { super(200); this.parentUrl = toParentUrl(request); this.nodeParentUrl = toNodeParentUrl(request); @@ -52,7 +51,7 @@ class NodesResponse extends HttpResponse { slime = new Slime(); Cursor root = slime.setObject(); - switch (type) { + switch (responseType) { case nodeList: nodesToSlime(root); break; case stateList : statesToSlime(root); break; case nodesInStateList: nodesToSlime(stateFromString(lastElement(parentUrl)), root); break; @@ -103,14 +102,17 @@ class NodesResponse extends HttpResponse { /** Outputs the nodes in the given state to a node array */ private void nodesToSlime(Node.State state, Cursor parentObject) { Cursor nodeArray = parentObject.setArray("nodes"); - toSlime(nodeRepository.getNodes(state), nodeArray); + for (Node.Type type : Node.Type.values()) + toSlime(nodeRepository.getNodes(type, state), nodeArray); } /** Outputs all the nodes to a node array */ private void nodesToSlime(Cursor parentObject) { Cursor nodeArray = parentObject.setArray("nodes"); - for (Node.State state : Node.State.values()) - toSlime(nodeRepository.getNodes(state), nodeArray); + for (Node.State state : Node.State.values()) { + for (Node.Type type : Node.Type.values()) + toSlime(nodeRepository.getNodes(type, state), nodeArray); + } } private void toSlime(List<Node> nodes, Cursor array) { @@ -132,7 +134,9 @@ class NodesResponse extends HttpResponse { if ( ! allFields) return; object.setString("id", node.id()); object.setString("state", NodeStateSerializer.wireNameOf(node.state())); + object.setString("type", node.type().name()); object.setString("hostname", node.hostname()); + object.setString("type", toString(node.type())); if (node.parentHostname().isPresent()) { object.setString("parentHostname", node.parentHostname().get()); } @@ -177,6 +181,15 @@ class NodesResponse extends HttpResponse { toSlime(node.history(), object.setArray("history")); } + private String toString(Node.Type type) { + switch(type) { + case tenant: return "tenant"; + case host: return "host"; + default: + throw new RuntimeException("New type added to enum, not implemented in NodesResponse: " + type.name()); + } + } + private void toSlime(ApplicationId id, Cursor object) { object.setString("tenant", id.tenant().value()); object.setString("application", id.application().value()); 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 d60e43cebed..123104a354f 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 @@ -48,22 +48,22 @@ public class MockNodeRepository extends NodeRepository { NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(this, flavors, Zone.defaultZone()); List<Node> nodes = new ArrayList<>(); - nodes.add(createNode("node1", "host1.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")))); - nodes.add(createNode("node2", "host2.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")))); - nodes.add(createNode("node3", "host3.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("expensive")))); + nodes.add(createNode("node1", "host1.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes.add(createNode("node2", "host2.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes.add(createNode("node3", "host3.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("expensive")), Node.Type.tenant)); // TODO: Use docker flavor - Node node4 = createNode("node4", "host4.yahoo.com", Optional.of("dockerhost4"), new Configuration(flavors.getFlavorOrThrow("default"))); + Node node4 = createNode("node4", "host4.yahoo.com", Optional.of("dockerhost4"), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant); node4 = node4.setStatus(node4.status().setDockerImage("image-12")); nodes.add(node4); - Node node5 = createNode("node5", "host5.yahoo.com", Optional.of("dockerhost"), new Configuration(flavors.getFlavorOrThrow("default"))); + Node node5 = createNode("node5", "host5.yahoo.com", Optional.of("dockerhost"), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant); nodes.add(node5.setStatus(node5.status().setDockerImage("image-123"))); - nodes.add(createNode("node6", "host6.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")))); - nodes.add(createNode("node7", "host7.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")))); + nodes.add(createNode("node6", "host6.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes.add(createNode("node7", "host7.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant)); // 8 and 9 are added by web service calls - Node node10 = createNode("node10", "host10.yahoo.com", Optional.of("parent.yahoo.com"), new Configuration(flavors.getFlavorOrThrow("default"))); + Node node10 = createNode("node10", "host10.yahoo.com", Optional.of("parent.yahoo.com"), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant); Status node10newStatus = node10.status(); node10newStatus = node10newStatus .setVespaVersion(Version.fromString("5.104.142")) @@ -71,6 +71,9 @@ public class MockNodeRepository extends NodeRepository { .setStateVersion("5.104.142-2.1.2408"); node10 = node10.setStatus(node10newStatus); nodes.add(node10); + + nodes.add(createNode("parent1", "parent1.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.host)); + nodes = addNodes(nodes); nodes.remove(6); setReady(nodes); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainerTest.java index 99c6c7d9294..636d56da1df 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainerTest.java @@ -49,6 +49,7 @@ public class ApplicationMaintainerTest { NodeRepository nodeRepository = new NodeRepository(nodeFlavors, curator, clock); createReadyNodes(15, nodeRepository, nodeFlavors); + createHostNodes(2, nodeRepository, nodeFlavors); Fixture fixture = new Fixture(zone, nodeRepository, nodeFlavors); @@ -63,22 +64,24 @@ public class ApplicationMaintainerTest { int failedInApp2 = 2; assertEquals(fixture.wantedNodesApp1 - failedInApp1, nodeRepository.getNodes(fixture.app1, Node.State.active).size()); assertEquals(fixture.wantedNodesApp2 - failedInApp2, nodeRepository.getNodes(fixture.app2, Node.State.active).size()); - assertEquals(failedInApp1 + failedInApp2, nodeRepository.getNodes(Node.State.failed).size()); - assertEquals(3, nodeRepository.getNodes(Node.State.ready).size()); + assertEquals(failedInApp1 + failedInApp2, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).size()); + assertEquals(3, nodeRepository.getNodes(Node.Type.tenant, Node.State.ready).size()); + assertEquals(2, nodeRepository.getNodes(Node.Type.host, Node.State.ready).size()); + // Cause maintenance deployment which will allocate replacement nodes fixture.runApplicationMaintainer(); assertEquals(fixture.wantedNodesApp1, nodeRepository.getNodes(fixture.app1, Node.State.active).size()); assertEquals(fixture.wantedNodesApp2, nodeRepository.getNodes(fixture.app2, Node.State.active).size()); - assertEquals(0, nodeRepository.getNodes(Node.State.ready).size()); + assertEquals(0, nodeRepository.getNodes(Node.Type.tenant, Node.State.ready).size()); // Unfail the previously failed nodes - nodeRepository.unfail(nodeRepository.getNodes(Node.State.failed).get(0).hostname()); - nodeRepository.unfail(nodeRepository.getNodes(Node.State.failed).get(0).hostname()); - nodeRepository.unfail(nodeRepository.getNodes(Node.State.failed).get(0).hostname()); + nodeRepository.unfail(nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).get(0).hostname()); + nodeRepository.unfail(nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).get(0).hostname()); + nodeRepository.unfail(nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).get(0).hostname()); int unfailedInApp1 = 1; int unfailedInApp2 = 2; - assertEquals(0, nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(0, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).size()); assertEquals(fixture.wantedNodesApp1 + unfailedInApp1, nodeRepository.getNodes(fixture.app1, Node.State.active).size()); assertEquals(fixture.wantedNodesApp2 + unfailedInApp2, nodeRepository.getNodes(fixture.app2, Node.State.active).size()); assertEquals("The unfailed nodes are now active but not part of the application", @@ -95,7 +98,15 @@ public class ApplicationMaintainerTest { private void createReadyNodes(int count, NodeRepository nodeRepository, NodeFlavors nodeFlavors) { List<Node> nodes = new ArrayList<>(count); for (int i = 0; i < count; i++) - nodes.add(nodeRepository.createNode("node" + i, "host" + i, Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")))); + nodes.add(nodeRepository.createNode("node" + i, "host" + i, Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes = nodeRepository.addNodes(nodes); + nodeRepository.setReady(nodes); + } + + private void createHostNodes(int count, NodeRepository nodeRepository, NodeFlavors nodeFlavors) { + List<Node> nodes = new ArrayList<>(count); + for (int i = 0; i < count; i++) + nodes.add(nodeRepository.createNode("hostNode" + i, "realHost" + i, Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.host)); nodes = nodeRepository.addNodes(nodes); nodeRepository.setReady(nodes); } @@ -140,7 +151,7 @@ public class ApplicationMaintainerTest { } NodeList getNodes(Node.State ... states) { - return new NodeList(nodeRepository.getNodes(states)); + return new NodeList(nodeRepository.getNodes(Node.Type.tenant, states)); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java index 278a9b704b9..a1d9268ee33 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java @@ -45,18 +45,18 @@ public class FailedExpirerTest { public void ensure_failed_nodes_are_deallocated_in_prod() throws InterruptedException { NodeRepository nodeRepository = failureScenarioIn(Environment.prod); - assertEquals(2, nodeRepository.getNodes(Node.State.failed).size()); - assertEquals(1, nodeRepository.getNodes(Node.State.dirty).size()); - assertEquals("node3", nodeRepository.getNodes(Node.State.dirty).get(0).hostname()); + assertEquals(2, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).size()); + assertEquals(1, nodeRepository.getNodes(Node.Type.tenant, Node.State.dirty).size()); + assertEquals("node3", nodeRepository.getNodes(Node.Type.tenant, Node.State.dirty).get(0).hostname()); } @Test public void ensure_failed_nodes_are_deallocated_in_dev() throws InterruptedException { NodeRepository nodeRepository = failureScenarioIn(Environment.dev); - assertEquals(1, nodeRepository.getNodes(Node.State.failed).size()); - assertEquals(2, nodeRepository.getNodes(Node.State.dirty).size()); - assertEquals("node2", nodeRepository.getNodes(Node.State.failed).get(0).hostname()); + assertEquals(1, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).size()); + assertEquals(2, nodeRepository.getNodes(Node.Type.tenant, Node.State.dirty).size()); + assertEquals("node2", nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).get(0).hostname()); } private NodeRepository failureScenarioIn(Environment environment) { @@ -66,11 +66,17 @@ public class FailedExpirerTest { NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, Zone.defaultZone(), clock); List<Node> nodes = new ArrayList<>(3); - nodes.add(nodeRepository.createNode("node1", "node1", Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")))); - nodes.add(nodeRepository.createNode("node2", "node2", Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")))); - nodes.add(nodeRepository.createNode("node3", "node3", Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")))); + nodes.add(nodeRepository.createNode("node1", "node1", Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes.add(nodeRepository.createNode("node2", "node2", Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes.add(nodeRepository.createNode("node3", "node3", Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.tenant)); nodeRepository.addNodes(nodes); + List<Node> hostNodes = new ArrayList<>(1); + hostNodes.add(nodeRepository.createNode("parent1", "parent1", Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.host)); + hostNodes.add(nodeRepository.createNode("parent2", "parent2", Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.host)); + nodeRepository.addNodes(hostNodes); + + // Set node1 to have failed 4 times before Node node1 = nodeRepository.getNode("node1").get(); node1 = node1.setStatus(node1.status().increaseFailCount()); @@ -85,20 +91,20 @@ public class FailedExpirerTest { nodeRepository.write(node2); // Allocate the nodes - nodeRepository.setReady(nodeRepository.getNodes(Node.State.provisioned)); + nodeRepository.setReady(nodeRepository.getNodes(Node.Type.tenant, Node.State.provisioned)); ApplicationId applicationId = ApplicationId.from(TenantName.from("foo"), ApplicationName.from("bar"), InstanceName.from("fuz")); ClusterSpec cluster = ClusterSpec.from(ClusterSpec.Type.content, ClusterSpec.Id.from("test"), Optional.empty()); provisioner.prepare(applicationId, cluster, Capacity.fromNodeCount(3), 1, null); NestedTransaction transaction = new NestedTransaction().add(new CuratorTransaction(curator)); provisioner.activate(transaction, applicationId, asHosts(nodes)); transaction.commit(); - assertEquals(3, nodeRepository.getNodes(Node.State.active).size()); + assertEquals(3, nodeRepository.getNodes(Node.Type.tenant, Node.State.active).size()); // Fail the nodes nodeRepository.fail("node1"); nodeRepository.fail("node2"); nodeRepository.fail("node3"); - assertEquals(3, nodeRepository.getNodes(Node.State.failed).size()); + assertEquals(3, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).size()); // Failure times out clock.advance(Duration.ofDays(5)); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java index 460ab3906ed..0c853e4b1dd 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java @@ -50,10 +50,15 @@ public class InactiveAndFailedExpirerTest { NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, Zone.defaultZone(), clock); List<Node> nodes = new ArrayList<>(2); - nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")))); - nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")))); + nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.tenant)); nodeRepository.addNodes(nodes); + List<Node> hostNodes = new ArrayList<>(2); + hostNodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.host)); + hostNodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.host)); + nodeRepository.addNodes(hostNodes); + // Allocate then deallocate 2 nodes nodeRepository.setReady(nodes); ApplicationId applicationId = ApplicationId.from(TenantName.from("foo"), ApplicationName.from("bar"), InstanceName.from("fuz")); @@ -62,16 +67,16 @@ public class InactiveAndFailedExpirerTest { NestedTransaction transaction = new NestedTransaction().add(new CuratorTransaction(curator)); provisioner.activate(transaction, applicationId, asHosts(nodes)); transaction.commit(); - assertEquals(2, nodeRepository.getNodes(Node.State.active).size()); + assertEquals(2, nodeRepository.getNodes(Node.Type.tenant, Node.State.active).size()); nodeRepository.deactivate(applicationId); - assertEquals(2, nodeRepository.getNodes(Node.State.inactive).size()); + assertEquals(2, nodeRepository.getNodes(Node.Type.tenant, Node.State.inactive).size()); // Inactive times out clock.advance(Duration.ofMinutes(14)); new InactiveExpirer(nodeRepository, clock, Duration.ofMinutes(10)).run(); - assertEquals(0, nodeRepository.getNodes(Node.State.inactive).size()); - List<Node> dirty = nodeRepository.getNodes(Node.State.dirty); + assertEquals(0, nodeRepository.getNodes(Node.Type.tenant, Node.State.inactive).size()); + List<Node> dirty = nodeRepository.getNodes(Node.Type.tenant, Node.State.dirty); assertEquals(2, dirty.size()); assertFalse(dirty.get(0).allocation().isPresent()); assertFalse(dirty.get(1).allocation().isPresent()); @@ -84,8 +89,8 @@ public class InactiveAndFailedExpirerTest { // Dirty times out for the other one clock.advance(Duration.ofMinutes(14)); new DirtyExpirer(nodeRepository, clock, Duration.ofMinutes(10)).run(); - assertEquals(0, nodeRepository.getNodes(Node.State.dirty).size()); - List<Node> failed = nodeRepository.getNodes(Node.State.failed); + assertEquals(0, nodeRepository.getNodes(Node.Type.tenant, Node.State.dirty).size()); + List<Node> failed = nodeRepository.getNodes(Node.Type.tenant, Node.State.failed); assertEquals(1, failed.size()); assertEquals(1, failed.get(0).status().failCount()); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java index 39a72ef16e8..c194f8f88d1 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java @@ -90,6 +90,7 @@ public class NodeFailerTest { NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, NODE_FLAVORS, ZONE); createReadyNodes(14, nodeRepository, NODE_FLAVORS); + createHostNodes(3, nodeRepository, NODE_FLAVORS); // Create applications ClusterSpec clusterApp1 = ClusterSpec.from(ClusterSpec.Type.container, ClusterSpec.Id.from("test"), Optional.empty()); @@ -139,9 +140,9 @@ public class NodeFailerTest { failer.run(); clock.advance(Duration.ofMinutes(5)); assertEquals( 0, deployer.redeployments); - assertEquals(12, nodeRepository.getNodes(Node.State.active).size()); - assertEquals( 0, nodeRepository.getNodes(Node.State.failed).size()); - assertEquals( 2, nodeRepository.getNodes(Node.State.ready).size()); + assertEquals(12, nodeRepository.getNodes(Node.Type.tenant, Node.State.active).size()); + assertEquals( 0, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).size()); + assertEquals( 2, nodeRepository.getNodes(Node.Type.tenant, Node.State.ready).size()); } String downHost1 = nodeRepository.getNodes(APP_1, Node.State.active).get(1).hostname(); @@ -153,9 +154,9 @@ public class NodeFailerTest { failer.run(); clock.advance(Duration.ofMinutes(5)); assertEquals( 0, deployer.redeployments); - assertEquals(12, nodeRepository.getNodes(Node.State.active).size()); - assertEquals( 0, nodeRepository.getNodes(Node.State.failed).size()); - assertEquals( 2, nodeRepository.getNodes(Node.State.ready).size()); + assertEquals(12, nodeRepository.getNodes(Node.Type.tenant, Node.State.active).size()); + assertEquals( 0, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).size()); + assertEquals( 2, nodeRepository.getNodes(Node.Type.tenant, Node.State.ready).size()); } serviceMonitor.setHostUp(downHost1); for (int minutes = 0; minutes < 30; minutes +=5 ) { @@ -165,10 +166,10 @@ public class NodeFailerTest { // downHost2 should now be failed and replaced, but not downHost1 assertEquals( 1, deployer.redeployments); - assertEquals(12, nodeRepository.getNodes(Node.State.active).size()); - assertEquals( 1, nodeRepository.getNodes(Node.State.failed).size()); - assertEquals( 1, nodeRepository.getNodes(Node.State.ready).size()); - assertEquals(downHost2, nodeRepository.getNodes(Node.State.failed).get(0).hostname()); + assertEquals(12, nodeRepository.getNodes(Node.Type.tenant, Node.State.active).size()); + assertEquals( 1, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).size()); + assertEquals( 1, nodeRepository.getNodes(Node.Type.tenant, Node.State.ready).size()); + assertEquals(downHost2, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).get(0).hostname()); // downHost1 fails again serviceMonitor.setHostDown(downHost1); @@ -180,17 +181,17 @@ public class NodeFailerTest { failer.run(); // due to this, nothing is failed assertEquals( 1, deployer.redeployments); - assertEquals(12, nodeRepository.getNodes(Node.State.active).size()); - assertEquals( 1, nodeRepository.getNodes(Node.State.failed).size()); - assertEquals( 1, nodeRepository.getNodes(Node.State.ready).size()); + assertEquals(12, nodeRepository.getNodes(Node.Type.tenant, Node.State.active).size()); + assertEquals( 1, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).size()); + assertEquals( 1, nodeRepository.getNodes(Node.Type.tenant, Node.State.ready).size()); // when status becomes known, and the host is still down, it is failed clock.advance(Duration.ofMinutes(5)); serviceMonitor.setStatusIsKnown(true); failer.run(); assertEquals( 2, deployer.redeployments); - assertEquals(12, nodeRepository.getNodes(Node.State.active).size()); - assertEquals( 2, nodeRepository.getNodes(Node.State.failed).size()); - assertEquals( 0, nodeRepository.getNodes(Node.State.ready).size()); + assertEquals(12, nodeRepository.getNodes(Node.Type.tenant, Node.State.active).size()); + assertEquals( 2, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).size()); + assertEquals( 0, nodeRepository.getNodes(Node.Type.tenant, Node.State.ready).size()); // the last host goes down Node lastNode = highestIndex(nodeRepository.getNodes(APP_1, Node.State.active)); @@ -200,9 +201,9 @@ public class NodeFailerTest { failer.run(); clock.advance(Duration.ofMinutes(5)); assertEquals( 2, deployer.redeployments); - assertEquals(12, nodeRepository.getNodes(Node.State.active).size()); - assertEquals( 2, nodeRepository.getNodes(Node.State.failed).size()); - assertEquals( 0, nodeRepository.getNodes(Node.State.ready).size()); + assertEquals(12, nodeRepository.getNodes(Node.Type.tenant, Node.State.active).size()); + assertEquals( 2, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).size()); + assertEquals( 0, nodeRepository.getNodes(Node.Type.tenant, Node.State.ready).size()); } // A new node is available @@ -210,9 +211,9 @@ public class NodeFailerTest { failer.run(); // The node is now failed assertEquals( 3, deployer.redeployments); - assertEquals(12, nodeRepository.getNodes(Node.State.active).size()); - assertEquals( 3, nodeRepository.getNodes(Node.State.failed).size()); - assertEquals( 0, nodeRepository.getNodes(Node.State.ready).size()); + assertEquals(12, nodeRepository.getNodes(Node.Type.tenant, Node.State.active).size()); + assertEquals( 3, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).size()); + assertEquals( 0, nodeRepository.getNodes(Node.Type.tenant, Node.State.ready).size()); assertTrue("The index of the last failed node is not reused", highestIndex(nodeRepository.getNodes(APP_1, Node.State.active)).allocation().get().membership().index() > @@ -226,7 +227,15 @@ public class NodeFailerTest { private void createReadyNodes(int count, int startIndex, NodeRepository nodeRepository, NodeFlavors nodeFlavors) { List<Node> nodes = new ArrayList<>(count); for (int i = startIndex; i < startIndex + count; i++) - nodes.add(nodeRepository.createNode("node" + i, "host" + i, Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")))); + nodes.add(nodeRepository.createNode("node" + i, "host" + i, Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes = nodeRepository.addNodes(nodes); + nodeRepository.setReady(nodes); + } + + private void createHostNodes(int count, NodeRepository nodeRepository, NodeFlavors nodeFlavors) { + List<Node> nodes = new ArrayList<>(count); + for (int i = 0; i < count; i++) + nodes.add(nodeRepository.createNode("parent" + i, "parent" + i, Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.host)); nodes = nodeRepository.addNodes(nodes); nodeRepository.setReady(nodes); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java index 10e685e3f96..8c0563e4bc8 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java @@ -41,25 +41,26 @@ public class ReservationExpirerTest { NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, flavors, Zone.defaultZone(), clock); List<Node> nodes = new ArrayList<>(2); - nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")))); - nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")))); + nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.host)); nodes = nodeRepository.addNodes(nodes); // Reserve 2 nodes - assertEquals(2, nodeRepository.getNodes(Node.State.provisioned).size()); + assertEquals(2, nodeRepository.getNodes(Node.Type.tenant, Node.State.provisioned).size()); nodeRepository.setReady(nodes); ApplicationId applicationId = new ApplicationId.Builder().tenant("foo").applicationName("bar").instanceName("fuz").build(); ClusterSpec cluster = ClusterSpec.from(ClusterSpec.Type.content, ClusterSpec.Id.from("test"), Optional.empty()); provisioner.prepare(applicationId, cluster, Capacity.fromNodeCount(2), 1, null); - assertEquals(2, nodeRepository.getNodes(Node.State.reserved).size()); + assertEquals(2, nodeRepository.getNodes(Node.Type.tenant, Node.State.reserved).size()); // Reservation times out clock.advance(Duration.ofMinutes(14)); // Reserved but not used time out new ReservationExpirer(nodeRepository, clock, Duration.ofMinutes(10)).run(); // Assert nothing is reserved - assertEquals(0, nodeRepository.getNodes(Node.State.reserved).size()); - List<Node> dirty = nodeRepository.getNodes(Node.State.dirty); + assertEquals(0, nodeRepository.getNodes(Node.Type.tenant, Node.State.reserved).size()); + List<Node> dirty = nodeRepository.getNodes(Node.Type.tenant, Node.State.dirty); assertEquals(2, dirty.size()); assertFalse(dirty.get(0).allocation().isPresent()); assertFalse(dirty.get(1).allocation().isPresent()); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java index f6f26aeced6..be80690a972 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java @@ -49,6 +49,7 @@ public class RetiredExpirerTest { NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, zone); createReadyNodes(7, nodeRepository, nodeFlavors); + createHostNodes(4, nodeRepository, nodeFlavors); ApplicationId applicationId = ApplicationId.from(TenantName.from("foo"), ApplicationName.from("bar"), InstanceName.from("fuz")); @@ -86,6 +87,7 @@ public class RetiredExpirerTest { NodeRepositoryProvisioner provisioner = new NodeRepositoryProvisioner(nodeRepository, nodeFlavors, zone); createReadyNodes(8, nodeRepository, nodeFlavors); + createHostNodes(4, nodeRepository, nodeFlavors); ApplicationId applicationId = ApplicationId.from(TenantName.from("foo"), ApplicationName.from("bar"), InstanceName.from("fuz")); @@ -120,7 +122,15 @@ public class RetiredExpirerTest { private void createReadyNodes(int count, NodeRepository nodeRepository, NodeFlavors nodeFlavors) { List<Node> nodes = new ArrayList<>(count); for (int i = 0; i < count; i++) - nodes.add(nodeRepository.createNode("node" + i, "node" + i, Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")))); + nodes.add(nodeRepository.createNode("node" + i, "node" + i, Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes = nodeRepository.addNodes(nodes); + nodeRepository.setReady(nodes); + } + + private void createHostNodes(int count, NodeRepository nodeRepository, NodeFlavors nodeFlavors) { + List<Node> nodes = new ArrayList<>(count); + for (int i = 0; i < count; i++) + nodes.add(nodeRepository.createNode("parent" + i, "parent" + i, Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.host)); nodes = nodeRepository.addNodes(nodes); nodeRepository.setReady(nodes); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/monitoring/ProvisionMetricsTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/monitoring/ProvisionMetricsTest.java index d2092e5be13..ac6532b1b4a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/monitoring/ProvisionMetricsTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/monitoring/ProvisionMetricsTest.java @@ -28,8 +28,10 @@ public class ProvisionMetricsTest { final NodeFlavors nodeFlavors = FlavorConfigBuilder.createDummies("default"); final Curator curator = new MockCurator(); final NodeRepository nodeRepository = new NodeRepository(nodeFlavors, curator); - final Node node = nodeRepository.createNode("openStackId", "hostname", Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default"))); + final Node node = nodeRepository.createNode("openStackId", "hostname", Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.tenant); nodeRepository.addNodes(Collections.singletonList(node)); + final Node hostNode = nodeRepository.createNode("openStackId2", "parent", Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.host); + nodeRepository.addNodes(Collections.singletonList(hostNode)); final Map<String, Number> expectedMetrics = new HashMap<>(); expectedMetrics.put("hostedVespa.provisionedHosts", 1); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClientTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClientTest.java index 50d0e56d999..7f80a83bef7 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClientTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClientTest.java @@ -24,7 +24,7 @@ public class CuratorDatabaseClientTest { private CuratorDatabaseClient zkClient = new CuratorDatabaseClient(FlavorConfigBuilder.createDummies("default"), curator, Clock.systemUTC()); @Test - public void ensure_can_read_stored_host_with_instance_information() throws Exception { + public void ensure_can_read_stored_host_with_instance_information_no_type() throws Exception { String zkline = "{\"hostname\":\"oxy-oxygen-0a4ae4f1.corp.bf1.yahoo.com\",\"openStackId\":\"7951bb9d-3989-4a60-a21c-13690637c8ea\",\"configuration\":{\"flavor\":\"default\"},\"created\":1421054425159,\"allocated\":1421057746687,\"instance\":{\"tenantId\":\"by_mortent\",\"applicationId\":\"music\",\"instanceId\":\"default\",\"serviceId\":\"container/default/0/0\"}}"; curator.framework().create().creatingParentsIfNeeded().forPath("/provision/v1/allocated/oxy-oxygen-0a4ae4f1.corp.bf1.yahoo.com", zkline.getBytes()); @@ -32,15 +32,17 @@ public class CuratorDatabaseClientTest { List<Node> allocatedNodes = zkClient.getNodes(Node.State.active); assertEquals(1, allocatedNodes.size()); assertEquals("container/default/0/0", allocatedNodes.get(0).allocation().get().membership().stringValue()); + assertEquals(Node.Type.tenant, allocatedNodes.get(0).type()); } @Test public void ensure_can_read_stored_host_information() throws Exception { - String zkline = "{\"hostname\":\"oxy-oxygen-0a4ae4f1.corp.bf1.yahoo.com\",\"openStackId\":\"7951bb9d-3989-4a60-a21c-13690637c8ea\",\"configuration\":{\"flavor\":\"default\"},\"created\":1421054425159}"; + String zkline = "{\"hostname\":\"oxy-oxygen-0a4ae4f1.corp.bf1.yahoo.com\",\"openStackId\":\"7951bb9d-3989-4a60-a21c-13690637c8ea\",\"configuration\":{\"flavor\":\"default\"},\"created\":1421054425159, \"type\":\"host\"}"; curator.framework().create().creatingParentsIfNeeded().forPath("/provision/v1/ready/oxy-oxygen-0a4ae4f1.corp.bf1.yahoo.com", zkline.getBytes()); List<Node> allocatedNodes = zkClient.getNodes(Node.State.ready); assertEquals(1, allocatedNodes.size()); + assertEquals(Node.Type.host, allocatedNodes.get(0).type()); } /** Test that locks can be acquired and released */ diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/SerializationTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/SerializationTest.java index 7dc52148e8b..9ba29cec588 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/SerializationTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/SerializationTest.java @@ -65,6 +65,7 @@ public class SerializationTest { node = node.setStatus(node.status().setVespaVersion(Version.fromString("1.2.3"))); node = node.setStatus(node.status().increaseFailCount().increaseFailCount()); node = node.setStatus(node.status().setHardwareFailure(true)); + node = node.setType(Node.Type.tenant); Node copy = nodeSerializer.fromJson(Node.State.provisioned, nodeSerializer.toJson(node)); assertEquals(node.id(), copy.id()); @@ -83,10 +84,22 @@ public class SerializationTest { assertEquals(node.allocation().get().removable(), copy.allocation().get().removable()); assertEquals(1, copy.history().events().size()); assertEquals(clock.instant(), copy.history().event(History.Event.Type.reserved).get().at()); + assertEquals(Node.Type.tenant, copy.type()); } @Test - public void testRebootAndRestartNoCurrentValuesSerialization() { + public void testDefaultType() { + Node node = createNode().allocate(ApplicationId.from(TenantName.from("myTenant"), + ApplicationName.from("myApplication"), + InstanceName.from("myInstance")), + ClusterMembership.from("content/myId/0/0", Optional.empty()), + clock.instant()); + Node copy = nodeSerializer.fromJson(Node.State.provisioned, nodeSerializer.toJson(node)); + assertEquals(Node.Type.host, copy.type()); + } + + @Test + public void testRebootAndRestartandTypeNoCurrentValuesSerialization() { String nodeData = "{\n" + " \"rebootGeneration\" : 0,\n" + " \"configuration\" : {\n" + @@ -116,6 +129,7 @@ public class SerializationTest { assertEquals(0, node.status().reboot().current()); assertEquals(0, node.allocation().get().restartGeneration().wanted()); assertEquals(0, node.allocation().get().restartGeneration().current()); + assertEquals(Node.Type.tenant, node.type()); } @Test @@ -194,7 +208,7 @@ public class SerializationTest { @Test public void serialize_parentHostname() { final String parentHostname = "parent.yahoo.com"; - Node node = Node.create("myId", "myHostname", Optional.of(parentHostname), new Configuration(nodeFlavors.getFlavorOrThrow("default"))); + Node node = Node.create("myId", "myHostname", Optional.of(parentHostname), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.tenant); Node deserializedNode = nodeSerializer.fromJson(State.provisioned, nodeSerializer.toJson(node)); assertEquals(parentHostname, deserializedNode.parentHostname().get()); @@ -234,7 +248,7 @@ public class SerializationTest { } private Node createNode() { - return Node.create("myId", "myHostname", Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default"))); + return Node.create("myId", "myHostname", Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.host); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java index 01d8a0eeabf..8eec59590c2 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java @@ -166,7 +166,7 @@ public class ProvisioningTester implements AutoCloseable { public void fail(HostSpec host) { int beforeFailCount = nodeRepository.getNode(Node.State.active, host.hostname()).get().status().failCount(); Node failedNode = nodeRepository.fail(host.hostname()); - assertTrue(nodeRepository.getNodes(Node.State.failed).contains(failedNode)); + assertTrue(nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).contains(failedNode)); assertEquals(beforeFailCount + 1, failedNode.status().failCount()); } @@ -205,7 +205,7 @@ public class ProvisioningTester implements AutoCloseable { nodes.add(nodeRepository.createNode(UUID.randomUUID().toString(), UUID.randomUUID().toString(), Optional.empty(), - new Configuration(nodeFlavors.getFlavorOrThrow(flavor)))); + new Configuration(nodeFlavors.getFlavorOrThrow(flavor)), Node.Type.tenant)); nodes = nodeRepository.addNodes(nodes); nodeRepository.setReady(nodes); return nodes; @@ -222,7 +222,7 @@ public class ProvisioningTester implements AutoCloseable { for (int i = 0; i < n; i++) { final String hostname = UUID.randomUUID().toString(); nodes.add(nodeRepository.createNode("openstack-id", hostname, parentHostId, - new Configuration(nodeFlavors.getFlavorOrThrow(flavor)))); + new Configuration(nodeFlavors.getFlavorOrThrow(flavor)), Node.Type.tenant)); } nodes = nodeRepository.addNodes(nodes); nodeRepository.setReady(nodes); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/legacy/ProvisionResourceTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/legacy/ProvisionResourceTest.java index 56c2e755c21..4acd748c3d0 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/legacy/ProvisionResourceTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/legacy/ProvisionResourceTest.java @@ -56,14 +56,14 @@ public class ProvisionResourceTest { List<Node> readyNodes = new ArrayList<>(); for (HostInfo hostInfo : createHostInfos(readyCount, 0)) readyNodes.add(nodeRepository.createNode(hostInfo.openStackId, hostInfo.hostname, - Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")))); + Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.tenant)); readyNodes = nodeRepository.addNodes(readyNodes); nodeRepository.setReady(readyNodes); List<Node> provisionedNodes = new ArrayList<>(); for (HostInfo hostInfo : createHostInfos(provisionedCount, readyCount)) provisionedNodes.add(nodeRepository.createNode(hostInfo.openStackId, hostInfo.hostname, - Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")))); + Optional.empty(), new Configuration(nodeFlavors.getFlavorOrThrow("default")), Node.Type.tenant)); nodeRepository.addNodes(provisionedNodes); } @@ -111,12 +111,12 @@ public class ProvisionResourceTest { assignNode(application, 2); nodeRepository.deactivate(application); List<Node> nodes = nodeRepository.deallocate(nodeRepository.getNodes(application, Node.State.inactive)); - assertEquals(0, nodeRepository.getNodes(Node.State.ready).size()); - assertEquals(2, nodeRepository.getNodes(Node.State.dirty).size()); + assertEquals(0, nodeRepository.getNodes(Node.Type.tenant, Node.State.ready).size()); + assertEquals(2, nodeRepository.getNodes(Node.Type.tenant, Node.State.dirty).size()); provisionResource.setReady(nodes.get(0).hostname()); provisionResource.setReady(nodes.get(1).hostname()); - assertEquals(2, nodeRepository.getNodes(Node.State.ready).size()); - assertEquals(0, nodeRepository.getNodes(Node.State.dirty).size()); + assertEquals(2, nodeRepository.getNodes(Node.Type.tenant, Node.State.ready).size()); + assertEquals(0, nodeRepository.getNodes(Node.Type.tenant, Node.State.dirty).size()); } @Test(expected = IllegalArgumentException.class) diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v1/RestApiTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v1/RestApiTest.java index 9afb14f632a..fe027bddae0 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v1/RestApiTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v1/RestApiTest.java @@ -85,12 +85,12 @@ public class RestApiTest { NodeFlavors flavors = FlavorConfigBuilder.createDummies("default"); List<Node> nodes = new ArrayList<>(); - nodes.add(createNode("node1", "host1.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")))); - nodes.add(createNode("node2", "host2.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")))); - nodes.add(createNode("node3", "host3.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")))); - nodes.add(createNode("node4", "host4.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")))); - nodes.add(createNode("node5", "host5.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")))); - nodes.add(createNode("node6", "host6.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")))); + nodes.add(createNode("node1", "host1.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes.add(createNode("node2", "host2.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes.add(createNode("node3", "host3.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes.add(createNode("node4", "host4.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes.add(createNode("node5", "host5.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant)); + nodes.add(createNode("node6", "host6.yahoo.com", Optional.empty(), new Configuration(flavors.getFlavorOrThrow("default")), Node.Type.tenant)); nodes = addNodes(nodes); nodes.remove(5); setReady(nodes); 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 922e0038ea5..fb7209fb308 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 @@ -60,7 +60,7 @@ public class RestApiTest { new byte[0], Request.Method.POST)); assertReboot(2, new Request("http://localhost:8080/nodes/v2/command/reboot?application=tenant2.application2.instance2", new byte[0], Request.Method.POST)); - assertReboot(8, new Request("http://localhost:8080/nodes/v2/command/reboot", + assertReboot(9, new Request("http://localhost:8080/nodes/v2/command/reboot", new byte[0], Request.Method.POST)); assertResponseContains(new Request("http://localhost:8080/nodes/v2/node/host3.yahoo.com"), "\"rebootGeneration\":3"); @@ -69,13 +69,15 @@ public class RestApiTest { assertResponse(new Request("http://localhost:8080/nodes/v2/node", ("[" + asNodeJson("host8.yahoo.com", "default") + "," + asNodeJson("host9.yahoo.com", "large-variant") + "," + + asHostJson("parent2.yahoo.com", "large-variant") + "," + asDockerNodeJson("host11.yahoo.com", "parent.host.yahoo.com") + "]"). getBytes(StandardCharsets.UTF_8), Request.Method.POST), - "{\"message\":\"Added 3 nodes to the provisioned state\"}"); + "{\"message\":\"Added 4 nodes to the provisioned state\"}"); assertFile(new Request("http://localhost:8080/nodes/v2/node/host8.yahoo.com"), "node8.json"); assertFile(new Request("http://localhost:8080/nodes/v2/node/host9.yahoo.com"), "node9.json"); assertFile(new Request("http://localhost:8080/nodes/v2/node/host11.yahoo.com"), "node11.json"); + assertFile(new Request("http://localhost:8080/nodes/v2/node/parent2.yahoo.com"), "parent2.json"); // PUT nodes ready assertResponse(new Request("http://localhost:8080/nodes/v2/state/ready/host8.yahoo.com", @@ -216,6 +218,12 @@ public class RestApiTest { return "{\"hostname\":\"" + hostname + "\", \"openStackId\":\"" + hostname + "\",\"flavor\":\"" + flavor + "\"}"; } + private String asHostJson(String hostname, String flavor) { + return "{\"hostname\":\"" + hostname + "\", \"openStackId\":\"" + hostname + "\",\"flavor\":\"" + flavor + "\"" + + ", \"type\":\"host\"}"; + } + + /** Asserts a particular response and 200 as response status */ private void assertResponse(Request request, String responseMessage) throws IOException { assertResponse(request, 200, responseMessage); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/host1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/host1.json new file mode 100644 index 00000000000..4847cf1fa9e --- /dev/null +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/host1.json @@ -0,0 +1,34 @@ +{ + "url": "http://localhost:8080/nodes/v2/node/parent1.yahoo.com", + "id": "parent1.yahoo.com", + "state": "active", + "type": "host", + "hostname": "parent1.yahoo.com", + "openStackId": "what", + "flavor": "default", + "minDiskAvailableGb":400.0, + "minMainMemoryAvailableGb":16.0, + "description":"Host node", + "minCpuCores":2.0, + "canonicalFlavor": "default", + "environment":"env", + "owner": { + "tenant": "tenant3", + "application": "application3", + "instance": "instance3" + }, + "membership": { + "clustertype": "content", + "clusterid": "id3", + "group": "0", + "index": 1, + "retired": false + }, + "restartGeneration": 0, + "currentRestartGeneration": 0, + "rebootGeneration": 0, + "currentRebootGeneration": 0, + "failCount": 0, + "hardwareFailure" : false, + "history":[{"event":"readied","at":123},{"event":"reserved","at":123},{"event":"activated","at":123}] +} diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node1.json index 734b6702c1e..eeb86038e52 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node1.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node1.json @@ -2,6 +2,7 @@ "url": "http://localhost:8080/nodes/v2/node/host1.yahoo.com", "id": "host1.yahoo.com", "state": "active", + "type": "tenant", "hostname": "host1.yahoo.com", "openStackId": "node1", "flavor": "default", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node10.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node10.json index d412e803bf5..d9efb50af66 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node10.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node10.json @@ -2,6 +2,7 @@ "url": "http://localhost:8080/nodes/v2/node/host10.yahoo.com", "id": "host10.yahoo.com", "state": "reserved", + "type": "tenant", "hostname": "host10.yahoo.com", "parentHostname": "parent.yahoo.com", "openStackId": "node10", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node11.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node11.json index 6d1922e7fc0..e74d95daf89 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node11.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node11.json @@ -2,6 +2,7 @@ "url":"http://localhost:8080/nodes/v2/node/host11.yahoo.com", "id":"host11.yahoo.com", "state":"provisioned", + "type": "tenant", "hostname":"host11.yahoo.com", "parentHostname":"parent.host.yahoo.com", "openStackId":"host11.yahoo.com", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node2.json index 830c866ae81..dddba8ccc44 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node2.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node2.json @@ -2,6 +2,7 @@ "url": "http://localhost:8080/nodes/v2/node/host2.yahoo.com", "id": "host2.yahoo.com", "state": "active", + "type": "tenant", "hostname": "host2.yahoo.com", "openStackId": "node2", "flavor": "default", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node3.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node3.json index 5bf8631797a..5f50d4b9bb1 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node3.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node3.json @@ -2,6 +2,7 @@ "url": "http://localhost:8080/nodes/v2/node/host3.yahoo.com", "id": "host3.yahoo.com", "state": "active", + "type": "tenant", "hostname": "host3.yahoo.com", "openStackId": "node3", "flavor":"expensive", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4-after-changes.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4-after-changes.json index ef88154fc5c..80b06a8056e 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4-after-changes.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4-after-changes.json @@ -2,6 +2,7 @@ "url": "http://localhost:8080/nodes/v2/node/host4.yahoo.com", "id": "host4.yahoo.com", "state": "reserved", + "type": "tenant", "hostname": "host4.yahoo.com", "parentHostname": "parent.yahoo.com", "openStackId": "node4", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4.json index a1bc67705ce..01d4b1b65d8 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4.json @@ -2,6 +2,7 @@ "url": "http://localhost:8080/nodes/v2/node/host4.yahoo.com", "id": "host4.yahoo.com", "state": "reserved", + "type": "tenant", "hostname": "host4.yahoo.com", "parentHostname":"dockerhost4", "openStackId": "node4", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node5.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node5.json index da4b49280c7..ce4ffc3ec86 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node5.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node5.json @@ -2,6 +2,7 @@ "url": "http://localhost:8080/nodes/v2/node/host5.yahoo.com", "id": "host5.yahoo.com", "state": "failed", + "type": "tenant", "hostname": "host5.yahoo.com", "parentHostname":"dockerhost", "openStackId": "node5", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node6.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node6.json index 9ef8adb1f07..378347d9ac2 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node6.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node6.json @@ -2,6 +2,7 @@ "url": "http://localhost:8080/nodes/v2/node/host6.yahoo.com", "id": "host6.yahoo.com", "state": "active", + "type": "tenant", "hostname": "host6.yahoo.com", "openStackId": "node6", "flavor": "default", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node7.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node7.json index 52f01407b2b..855450b640a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node7.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node7.json @@ -2,6 +2,7 @@ "url": "http://localhost:8080/nodes/v2/node/host7.yahoo.com", "id": "host7.yahoo.com", "state": "provisioned", + "type": "tenant", "hostname": "host7.yahoo.com", "openStackId": "node7", "flavor": "default", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node8.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node8.json index c00b6ed797c..0060c315171 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node8.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node8.json @@ -2,6 +2,7 @@ "url": "http://localhost:8080/nodes/v2/node/host8.yahoo.com", "id": "host8.yahoo.com", "state": "provisioned", + "type": "tenant", "hostname": "host8.yahoo.com", "openStackId": "host8.yahoo.com", "flavor": "default", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node9.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node9.json index 73a0eb8a266..70fa6423fe4 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node9.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node9.json @@ -2,6 +2,7 @@ "url": "http://localhost:8080/nodes/v2/node/host9.yahoo.com", "id": "host9.yahoo.com", "state": "provisioned", + "type": "tenant", "hostname": "host9.yahoo.com", "openStackId": "host9.yahoo.com", "flavor": "large-variant", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/nodes-recursive.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/nodes-recursive.json index 8ea48599f0e..ac9b247f8e0 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/nodes-recursive.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/nodes-recursive.json @@ -1,6 +1,7 @@ { "nodes": [ @include(node7.json), + @include(parent1.json), @include(node10.json), @include(node4.json), @include(node6.json), diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/nodes.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/nodes.json index 73947ded547..d9f0d9ed34a 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/nodes.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/nodes.json @@ -4,6 +4,9 @@ "url": "http://localhost:8080/nodes/v2/node/host7.yahoo.com" }, { + "url":"http://localhost:8080/nodes/v2/node/parent1.yahoo.com" + }, + { "url":"http://localhost:8080/nodes/v2/node/host10.yahoo.com" }, { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent1.json new file mode 100644 index 00000000000..d6369fa51d3 --- /dev/null +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent1.json @@ -0,0 +1 @@ +{"url":"http://localhost:8080/nodes/v2/node/parent1.yahoo.com","id":"parent1.yahoo.com","state":"ready","type":"host","hostname":"parent1.yahoo.com","openStackId":"parent1","flavor":"default","minDiskAvailableGb":400.0,"minMainMemoryAvailableGb":16.0,"description":"Flavor-name-is-default","minCpuCores":2.0,"canonicalFlavor":"default","environment":"env","rebootGeneration":0,"currentRebootGeneration":0,"failCount":0,"hardwareFailure":false,"history":[{"event":"readied","at":123}]} diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent2.json new file mode 100644 index 00000000000..9b9f1179c1c --- /dev/null +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent2.json @@ -0,0 +1,20 @@ +{ + "url": "http://localhost:8080/nodes/v2/node/parent2.yahoo.com", + "id": "parent2.yahoo.com", + "state": "provisioned", + "type": "host", + "hostname": "parent2.yahoo.com", + "openStackId": "parent2.yahoo.com", + "flavor": "large-variant", + "minDiskAvailableGb": 2000.0, + "minMainMemoryAvailableGb": 128.0, + "description": "Flavor-name-is-large-variant", + "minCpuCores": 64.0, + "canonicalFlavor": "large", + "environment": "env", + "rebootGeneration": 0, + "currentRebootGeneration": 0, + "failCount": 0, + "hardwareFailure": false, + "history": [] +}
\ No newline at end of file diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/states-recursive.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/states-recursive.json index b83616d2e0b..9dd85385f4c 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/states-recursive.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/states-recursive.json @@ -9,6 +9,7 @@ "ready": { "url": "http://localhost:8080/nodes/v2/state/ready", "nodes": [ + @include(parent1.json) ] }, "reserved": { |