summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java43
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java9
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/assimilate/PopulateClient.java15
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Expirer.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/monitoring/ProvisionMetrics.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java3
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java32
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/legacy/ProvisionResource.java7
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v1/NodesApiHandler.java14
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesApiHandler.java19
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesResponse.java25
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java19
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainerTest.java29
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirerTest.java30
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java21
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailerTest.java55
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ReservationExpirerTest.java13
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirerTest.java12
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/monitoring/ProvisionMetricsTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClientTest.java6
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/SerializationTest.java20
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java6
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/legacy/ProvisionResourceTest.java12
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v1/RestApiTest.java12
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java12
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/host1.json34
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node1.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node10.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node11.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node2.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node3.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4-after-changes.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node4.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node5.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node6.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node7.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node8.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node9.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/nodes-recursive.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/nodes.json3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent1.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent2.json20
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/states-recursive.json1
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": {