summaryrefslogtreecommitdiffstats
path: root/node-repository
diff options
context:
space:
mode:
authorHarald Musum <musum@yahoo-inc.com>2016-06-23 18:25:11 +0200
committerGitHub <noreply@github.com>2016-06-23 18:25:11 +0200
commit521f3b8266a1386c44550ceac93a8a41a5ba4f4d (patch)
treeb6f78c468d97d3873956cad1b703e6307d96374e /node-repository
parent1e4ce065ccc1e5fe1656757fce0489524cda6982 (diff)
parent9cbefa5a54efef287888226b6ab8cf38d8fe22a8 (diff)
Merge pull request #191 from yahoo/bratseth/add-parked-node-state
Add support for parking nodes
Diffstat (limited to 'node-repository')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/Node.java11
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java34
-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/NodeFailer.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/filter/StateFilter.java1
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java9
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodeStateSerializer.java1
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesApiHandler.java13
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainerTest.java33
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/monitoring/ProvisionMetricsTest.java1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java38
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent-nodes.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent1.json26
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/states-recursive.json5
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/states.json3
16 files changed, 140 insertions, 43 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 d4a955cf746..a88fb016e23 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
@@ -244,11 +244,18 @@ public final class Node {
dirty,
/** This node has failed and must be repaired or removed. The node retains any allocation data for diagnosis. */
- failed;
+ failed,
+
+ /**
+ * This node should not currently be used.
+ * This state follows the same rules as failed except that it will never be automatically moved out of
+ * this state.
+ */
+ parked;
/** Returns whether this is a state where the node is assigned to an application */
public boolean isAllocated() {
- return this == reserved || this == active || this == inactive || this == failed;
+ return this == reserved || this == active || this == inactive || this == failed || this == parked;
}
}
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 aff65652399..11892c69c1c 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
@@ -49,7 +49,7 @@ import java.util.stream.Collectors;
// 1) (new) - > provisioned -> ready -> reserved -> active -> inactive -> dirty -> ready
// 2) inactive -> reserved
// 3) reserved -> dirty
-// 3) * -> failed -> dirty | active | (removed)
+// 3) * -> failed | parked -> dirty | active | (removed)
// Nodes have an application assigned when in states reserved, active and inactive.
// Nodes might have an application assigned in dirty.
public class NodeRepository extends AbstractComponent {
@@ -180,11 +180,16 @@ public class NodeRepository extends AbstractComponent {
return performOn(NodeListFilter.from(nodes), node -> zkClient.writeTo(Node.State.dirty, node));
}
- /** Deallocate a node which is in the failed state. Use this to recycle failed nodes which have been repaired. */
+ /**
+ * Deallocate a node which is in the failed or parked state.
+ * Use this to recycle failed nodes which have been repaired or put on hold.
+ */
public Node deallocate(String hostname) {
Optional<Node> nodeToDeallocate = getNode(Node.State.failed, hostname);
if ( ! nodeToDeallocate.isPresent())
- throw new IllegalArgumentException("Could not deallocate " + hostname + ": Node not found in the failed state");
+ nodeToDeallocate = getNode(Node.State.parked, hostname);
+ if ( ! nodeToDeallocate.isPresent())
+ throw new IllegalArgumentException("Could not deallocate " + hostname + ": No such node in the failed or parked state");
return deallocate(Collections.singletonList(nodeToDeallocate.get())).get(0);
}
@@ -199,12 +204,22 @@ public class NodeRepository extends AbstractComponent {
}
/**
- * Moves a previously failed node back to the active state.
+ * Parks this node and returns it in its new state.
+ *
+ * @return the node in its new state
+ * @throws IllegalArgumentException if the node is not found
+ */
+ public Node park(String hostname) {
+ return move(hostname, Node.State.parked);
+ }
+
+ /**
+ * Moves a previously failed or parked node back to the active state.
*
* @return the node in its new state
* @throws IllegalArgumentException if the node is not found
*/
- public Node unfail(String hostname) {
+ public Node reactivate(String hostname) {
return move(hostname, Node.State.active);
}
@@ -218,15 +233,18 @@ public class NodeRepository extends AbstractComponent {
}
/**
- * Removes a node. A node must be in the failed state before it can be removed.
+ * Removes a node. A node must be in the failed or parked state before it can be removed.
*
* @return true if the node was removed, false if it was not found
*/
public boolean remove(String hostname) {
Optional<Node> nodeToRemove = getNode(Node.State.failed, hostname);
- if ( ! nodeToRemove.isPresent()) return false;
+ if ( ! nodeToRemove.isPresent())
+ nodeToRemove = getNode(Node.State.parked, hostname);
+ if ( ! nodeToRemove.isPresent())
+ return false;
try (Mutex lock = lock(nodeToRemove.get())) {
- return zkClient.removeNode(Node.State.failed, hostname);
+ return zkClient.removeNode(nodeToRemove.get().state(), hostname);
}
}
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 d12c7f2a5ae..ce7ae429c40 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
@@ -18,7 +18,7 @@ import java.util.stream.Collectors;
* The application maintainer regularly redeploys all applications.
* This is necessary because applications may gain and lose active nodes due to nodes being moved to and from the
* failed state. This is corrected by redeploying the applications periodically.
- * It can not (at this point) be done reliably synchronously as part of the fail/unfail call due to the need for this
+ * It can not (at this point) be done reliably synchronously as part of the fail/reactivate call due to the need for this
* to happen at a node having the deployer.
*
* @author bratseth
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
index 9a1a9291c13..ba2586a95fd 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
@@ -153,7 +153,7 @@ public class NodeFailer extends Maintainer {
catch (RuntimeException e) {
// The expected reason for deployment to fail here is that there is no capacity available to redeploy.
// In that case we should leave the node in the active state to avoid failing additional nodes.
- nodeRepository().unfail(node.hostname());
+ nodeRepository().reactivate(node.hostname());
log.log(Level.WARNING, "Attempted to fail " + node + " for " + node.allocation().get().owner() +
", but redeploying without the node failed", e);
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/filter/StateFilter.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/filter/StateFilter.java
index a605835c11c..e7368e7770c 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/filter/StateFilter.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/filter/StateFilter.java
@@ -48,5 +48,4 @@ public class StateFilter extends NodeFilter {
return new StateFilter(HostFilter.split(states).stream().map(Node.State::valueOf).collect(Collectors.toSet()), next);
}
-
}
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 6805862baf3..813941de1eb 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
@@ -228,13 +228,14 @@ public class CuratorDatabaseClient {
private String toDir(Node.State state) {
switch (state) {
- case provisioned: return "provisioned";
- case ready: return "ready";
- case reserved: return "reserved";
case active: return "allocated"; // legacy name
- case inactive: return "deallocated"; // legacy name
case dirty: return "dirty";
case failed: return "failed";
+ case inactive: return "deallocated"; // legacy name
+ case parked : return "parked";
+ case provisioned: return "provisioned";
+ case ready: return "ready";
+ case reserved: return "reserved";
default: throw new RuntimeException("Node state " + state + " does not map to a directory name");
}
}
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 004cceee7cb..e4b745bcfd2 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
@@ -212,7 +212,7 @@ public class NodeSerializer {
switch (typeString) {
case nodeTypeTenant : return Node.Type.tenant;
case nodeTypeHost : return Node.Type.host;
- // TODO: Remove this when all data is converted
+ // TODO: Remove this when 6.13 is released everywhere
case "" : return Node.Type.tenant;
}
throw new IllegalArgumentException("Unknown node type '" + typeString + "'");
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodeStateSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodeStateSerializer.java
index 321a75421a2..fa74605b32f 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodeStateSerializer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodeStateSerializer.java
@@ -28,6 +28,7 @@ public class NodeStateSerializer {
addMapping(Node.State.dirty, "dirty");
addMapping(Node.State.failed, "failed");
addMapping(Node.State.inactive, "inactive");
+ addMapping(Node.State.parked, "parked");
addMapping(Node.State.provisioned, "provisioned");
addMapping(Node.State.ready, "ready");
addMapping(Node.State.reserved, "reserved");
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 575d1e69f5f..2ce682a36af 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
@@ -99,12 +99,16 @@ public class NodesApiHandler extends LoggingRequestHandler {
nodeRepository.fail(lastElement(path));
return new MessageResponse("Moved " + lastElement(path) + " to failed");
}
+ else if (path.startsWith("/nodes/v2/state/parked/")) {
+ nodeRepository.park(lastElement(path));
+ return new MessageResponse("Moved " + lastElement(path) + " to parked");
+ }
else if (path.startsWith("/nodes/v2/state/dirty/")) {
nodeRepository.deallocate(lastElement(path));
return new MessageResponse("Moved " + lastElement(path) + " to dirty");
}
else if (path.startsWith("/nodes/v2/state/active/")) {
- nodeRepository.unfail(lastElement(path));
+ nodeRepository.reactivate(lastElement(path));
return new MessageResponse("Moved " + lastElement(path) + " to active");
}
else {
@@ -221,7 +225,12 @@ public class NodesApiHandler extends LoggingRequestHandler {
if ( ! node.isPresent())
node = nodeRepository.getNode(Node.State.failed, hostname);
if ( ! node.isPresent())
- throw new IllegalArgumentException("Could not set " + hostname + " ready: Not registered as provisioned, dirty or failed");
+ node = nodeRepository.getNode(Node.State.parked, hostname);
+ if ( ! node.isPresent())
+ throw new IllegalArgumentException("Could not set " + hostname + " ready: Not registered as provisioned, dirty, failed or parked");
+
+ if (node.get().allocation().isPresent())
+ throw new IllegalArgumentException("Could not set " + hostname + " ready: Node is allocated and must be moved to dirty instead");
nodeRepository.setReady(Collections.singletonList(node.get()));
return "Moved " + hostname + " to ready";
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 636d56da1df..e034b185a02 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
@@ -56,43 +56,42 @@ public class ApplicationMaintainerTest {
// Create applications
fixture.activate();
- // Fail some nodes
+ // Fail and park some nodes
nodeRepository.fail(nodeRepository.getNodes(fixture.app1).get(3).hostname());
nodeRepository.fail(nodeRepository.getNodes(fixture.app2).get(0).hostname());
- nodeRepository.fail(nodeRepository.getNodes(fixture.app2).get(4).hostname());
+ nodeRepository.park(nodeRepository.getNodes(fixture.app2).get(4).hostname());
int failedInApp1 = 1;
- int failedInApp2 = 2;
+ int failedOrParkedInApp2 = 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.Type.tenant, Node.State.failed).size());
+ assertEquals(fixture.wantedNodesApp2 - failedOrParkedInApp2, nodeRepository.getNodes(fixture.app2, Node.State.active).size());
+ assertEquals(failedInApp1 + failedOrParkedInApp2, nodeRepository.getNodes(Node.Type.tenant, Node.State.failed, Node.State.parked).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.Type.tenant, Node.State.ready).size());
- // Unfail the previously failed nodes
- 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;
+ // Reactivate the previously failed nodes
+ nodeRepository.reactivate(nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).get(0).hostname());
+ nodeRepository.reactivate(nodeRepository.getNodes(Node.Type.tenant, Node.State.failed).get(0).hostname());
+ nodeRepository.reactivate(nodeRepository.getNodes(Node.Type.tenant, Node.State.parked).get(0).hostname());
+ int reactivatedInApp1 = 1;
+ int reactivatedInApp2 = 2;
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",
+ assertEquals(fixture.wantedNodesApp1 + reactivatedInApp1, nodeRepository.getNodes(fixture.app1, Node.State.active).size());
+ assertEquals(fixture.wantedNodesApp2 + reactivatedInApp2, nodeRepository.getNodes(fixture.app2, Node.State.active).size());
+ assertEquals("The reactivated nodes are now active but not part of the application",
0, fixture.getNodes(Node.State.active).retired().size());
// Cause maintenance deployment which will update the applications with the re-activated nodes
fixture.runApplicationMaintainer();
assertEquals("Superflous content nodes are retired",
- unfailedInApp2, fixture.getNodes(Node.State.active).retired().size());
+ reactivatedInApp2, fixture.getNodes(Node.State.active).retired().size());
assertEquals("Superflous container nodes are deactivated (this makes little point for container nodes)",
- unfailedInApp1, fixture.getNodes(Node.State.inactive).size());
+ reactivatedInApp1, fixture.getNodes(Node.State.inactive).size());
}
private void createReadyNodes(int count, NodeRepository nodeRepository, NodeFlavors nodeFlavors) {
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 ac6532b1b4a..0fe507edbe5 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
@@ -35,6 +35,7 @@ public class ProvisionMetricsTest {
final Map<String, Number> expectedMetrics = new HashMap<>();
expectedMetrics.put("hostedVespa.provisionedHosts", 1);
+ expectedMetrics.put("hostedVespa.parkedHosts", 0);
expectedMetrics.put("hostedVespa.readyHosts", 0);
expectedMetrics.put("hostedVespa.reservedHosts", 0);
expectedMetrics.put("hostedVespa.activeHosts", 0);
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 2721e5cced7..3992e808830 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
@@ -101,12 +101,12 @@ public class RestApiTest {
new byte[0], Request.Method.PUT),
"{\"message\":\"Moved host8.yahoo.com to active\"}");
- // PUT a node in failed ...
- assertResponse(new Request("http://localhost:8080/nodes/v2/state/failed/host8.yahoo.com",
+ // PUT a node in parked ...
+ assertResponse(new Request("http://localhost:8080/nodes/v2/state/parked/host8.yahoo.com",
new byte[0], Request.Method.PUT),
- "{\"message\":\"Moved host8.yahoo.com to failed\"}");
+ "{\"message\":\"Moved host8.yahoo.com to parked\"}");
assertResponseContains(new Request("http://localhost:8080()/nodes/v2/node/host8.yahoo.com"),
- "\"state\":\"failed\"");
+ "\"state\":\"parked\"");
// ... and delete it
assertResponse(new Request("http://localhost:8080/nodes/v2/node/host8.yahoo.com",
new byte[0], Request.Method.DELETE),
@@ -170,6 +170,36 @@ public class RestApiTest {
@Test
public void testInvalidRequests() throws IOException {
+ // Attempt to fail and ready an allocated node without going through dirty
+ assertResponse(new Request("http://localhost:8080/nodes/v2/state/failed/host1.yahoo.com",
+ new byte[0], Request.Method.PUT),
+ "{\"message\":\"Moved host1.yahoo.com to failed\"}");
+ assertResponse(new Request("http://localhost:8080/nodes/v2/state/ready/host1.yahoo.com",
+ new byte[0], Request.Method.PUT),
+ 400, "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Could not set host1.yahoo.com ready: Node is allocated and must be moved to dirty instead\"}");
+ // (... while dirty then ready works (the ready move will be initiated by node maintenance))
+ assertResponse(new Request("http://localhost:8080/nodes/v2/state/dirty/host1.yahoo.com",
+ new byte[0], Request.Method.PUT),
+ "{\"message\":\"Moved host1.yahoo.com to dirty\"}");
+ assertResponse(new Request("http://localhost:8080/nodes/v2/state/ready/host1.yahoo.com",
+ new byte[0], Request.Method.PUT),
+ "{\"message\":\"Moved host1.yahoo.com to ready\"}");
+
+ // Attempt to park and ready an allocated node without going through dirty
+ assertResponse(new Request("http://localhost:8080/nodes/v2/state/parked/host2.yahoo.com",
+ new byte[0], Request.Method.PUT),
+ "{\"message\":\"Moved host2.yahoo.com to parked\"}");
+ assertResponse(new Request("http://localhost:8080/nodes/v2/state/ready/host2.yahoo.com",
+ new byte[0], Request.Method.PUT),
+ 400, "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Could not set host2.yahoo.com ready: Node is allocated and must be moved to dirty instead\"}");
+ // (... while dirty then ready works (the ready move will be initiated by node maintenance))
+ assertResponse(new Request("http://localhost:8080/nodes/v2/state/dirty/host2.yahoo.com",
+ new byte[0], Request.Method.PUT),
+ "{\"message\":\"Moved host2.yahoo.com to dirty\"}");
+ assertResponse(new Request("http://localhost:8080/nodes/v2/state/ready/host2.yahoo.com",
+ new byte[0], Request.Method.PUT),
+ "{\"message\":\"Moved host2.yahoo.com to ready\"}");
+
// Attempt to DELETE a node which is not put in failed first
assertResponse(new Request("http://localhost:8080/nodes/v2/node/host8.yahoo.com",
new byte[0], Request.Method.DELETE),
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent-nodes.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent-nodes.json
index 28a17b03cc6..7352c4f4455 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent-nodes.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/parent-nodes.json
@@ -1,5 +1,5 @@
{
"nodes": [
@include(node10.json)
-]
+ ]
} \ No newline at end of file
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
index d6369fa51d3..c2d663fcb15 100644
--- 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
@@ -1 +1,25 @@
-{"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}]}
+{
+ "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/states-recursive.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/states-recursive.json
index 9dd85385f4c..02d8e473f27 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
@@ -43,6 +43,11 @@
"nodes": [
@include(node5.json)
]
+ },
+ "parked": {
+ "url": "http://localhost:8080/nodes/v2/state/parked",
+ "nodes": [
+ ]
}
}
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/states.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/states.json
index b2d7354a6c9..4b2de7532dd 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/states.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/states.json
@@ -20,6 +20,9 @@
},
"failed": {
"url": "http://localhost:8080/nodes/v2/state/failed"
+ },
+ "parked": {
+ "url": "http://localhost:8080/nodes/v2/state/parked"
}
}
} \ No newline at end of file