summaryrefslogtreecommitdiffstats
path: root/node-repository
diff options
context:
space:
mode:
authorMartin Polden <martin.polden@gmail.com>2017-08-08 11:33:37 +0200
committerMartin Polden <martin.polden@gmail.com>2017-08-08 12:06:10 +0200
commitabc6ff167b22fe3fae82d6ec369ddfd0ba7260af (patch)
tree42078775d9d144d76e7415c1a5b27caa8ec6a0c6 /node-repository
parenta69f61901d6a243eec05d7a8d60eecbf28d70931 (diff)
Add hardware divergence field to nodes API
Diffstat (limited to 'node-repository')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Status.java42
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/NodeSerializer.java13
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodePatcher.java5
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodesResponse.java1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java24
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node6-after-changes.json42
6 files changed, 116 insertions, 11 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Status.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Status.java
index 16ce1c2f1d5..35e2a102737 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Status.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Status.java
@@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.provision.node;
import com.yahoo.component.Version;
import javax.annotation.concurrent.Immutable;
+import java.util.Objects;
import java.util.Optional;
/**
@@ -20,6 +21,7 @@ public class Status {
private final Optional<HardwareFailureType> hardwareFailure;
private final boolean wantToRetire;
private final boolean wantToDeprovision;
+ private final Optional<String> hardwareDivergence;
public enum HardwareFailureType {
@@ -37,44 +39,51 @@ public class Status {
int failCount,
Optional<HardwareFailureType> hardwareFailure,
boolean wantToRetire,
- boolean wantToDeprovision) {
+ boolean wantToDeprovision,
+ Optional<String> hardwareDivergence) {
+ Objects.requireNonNull(generation, "Generation must be non-null");
+ Objects.requireNonNull(vespaVersion, "Vespa version must be non-null");
+ Objects.requireNonNull(hardwareFailure, "Hardware failure must be non-null");
+ Objects.requireNonNull(hardwareDivergence, "Hardware divergence must be non-null");
+ hardwareDivergence.ifPresent(s -> requireNonEmptyString(s, "Hardware divergence must be non-empty"));
this.reboot = generation;
this.vespaVersion = vespaVersion;
this.failCount = failCount;
this.hardwareFailure = hardwareFailure;
this.wantToRetire = wantToRetire;
this.wantToDeprovision = wantToDeprovision;
+ this.hardwareDivergence = hardwareDivergence;
}
/** Returns a copy of this with the reboot generation changed */
- public Status withReboot(Generation reboot) { return new Status(reboot, vespaVersion, failCount, hardwareFailure, wantToRetire, wantToDeprovision); }
+ public Status withReboot(Generation reboot) { return new Status(reboot, vespaVersion, failCount, hardwareFailure, wantToRetire, wantToDeprovision, hardwareDivergence); }
/** Returns the reboot generation of this node */
public Generation reboot() { return reboot; }
/** Returns a copy of this with the vespa version changed */
- public Status withVespaVersion(Version version) { return new Status(reboot, Optional.of(version), failCount, hardwareFailure, wantToRetire, wantToDeprovision); }
+ public Status withVespaVersion(Version version) { return new Status(reboot, Optional.of(version), failCount, hardwareFailure, wantToRetire, wantToDeprovision, hardwareDivergence); }
/** Returns the Vespa version installed on the node, if known */
public Optional<Version> vespaVersion() { return vespaVersion; }
- public Status withIncreasedFailCount() { return new Status(reboot, vespaVersion, failCount + 1, hardwareFailure, wantToRetire, wantToDeprovision); }
+ public Status withIncreasedFailCount() { return new Status(reboot, vespaVersion, failCount + 1, hardwareFailure, wantToRetire, wantToDeprovision, hardwareDivergence); }
- public Status withDecreasedFailCount() { return new Status(reboot, vespaVersion, failCount - 1, hardwareFailure, wantToRetire, wantToDeprovision); }
+ public Status withDecreasedFailCount() { return new Status(reboot, vespaVersion, failCount - 1, hardwareFailure, wantToRetire, wantToDeprovision, hardwareDivergence); }
- public Status setFailCount(Integer value) { return new Status(reboot, vespaVersion, value, hardwareFailure, wantToRetire, wantToDeprovision); }
+ public Status setFailCount(Integer value) { return new Status(reboot, vespaVersion, value, hardwareFailure, wantToRetire, wantToDeprovision, hardwareDivergence); }
/** Returns how many times this node has been moved to the failed state. */
public int failCount() { return failCount; }
- public Status withHardwareFailure(Optional<HardwareFailureType> hardwareFailure) { return new Status(reboot, vespaVersion, failCount, hardwareFailure, wantToRetire, wantToDeprovision); }
+ public Status withHardwareFailure(Optional<HardwareFailureType> hardwareFailure) { return new Status(reboot, vespaVersion, failCount, hardwareFailure, wantToRetire, wantToDeprovision, hardwareDivergence); }
/** Returns the type of the last hardware failure detected on this node, or empty if none */
public Optional<HardwareFailureType> hardwareFailure() { return hardwareFailure; }
/** Returns a copy of this with the want to retire flag changed */
public Status withWantToRetire(boolean wantToRetire) {
- return new Status(reboot, vespaVersion, failCount, hardwareFailure, wantToRetire, wantToDeprovision);
+ return new Status(reboot, vespaVersion, failCount, hardwareFailure, wantToRetire, wantToDeprovision, hardwareDivergence);
}
/**
@@ -87,7 +96,7 @@ public class Status {
/** Returns a copy of this with the want to de-provision flag changed */
public Status withWantToDeprovision(boolean wantToDeprovision) {
- return new Status(reboot, vespaVersion, failCount, hardwareFailure, wantToRetire, wantToDeprovision);
+ return new Status(reboot, vespaVersion, failCount, hardwareFailure, wantToRetire, wantToDeprovision, hardwareDivergence);
}
/**
@@ -97,7 +106,20 @@ public class Status {
return wantToDeprovision;
}
+ public Status withHardwareDivergence(Optional<String> hardwareDivergence) {
+ return new Status(reboot, vespaVersion, failCount, hardwareFailure, wantToRetire, wantToDeprovision, hardwareDivergence);
+ }
+
+ /** Returns hardware divergence report as JSON string, if any */
+ public Optional<String> hardwareDivergence() { return hardwareDivergence; }
+
/** Returns the initial status of a newly provisioned node */
- public static Status initial() { return new Status(Generation.inital(), Optional.empty(), 0, Optional.empty(), false, false); }
+ public static Status initial() { return new Status(Generation.inital(), Optional.empty(), 0, Optional.empty(), false, false, Optional.empty()); }
+
+ private void requireNonEmptyString(String value, String message) {
+ Objects.requireNonNull(value, message);
+ if (value.trim().isEmpty())
+ throw new IllegalArgumentException(message + ", but was '" + value + "'");
+ }
}
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 c1541f00a66..9f876cf5b14 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
@@ -57,6 +57,7 @@ public class NodeSerializer {
private static final String nodeTypeKey = "type";
private static final String wantToRetireKey = "wantToRetire";
private static final String wantToDeprovisionKey = "wantToDeprovision";
+ private static final String hardwareDivergenceKey = "hardwareDivergence";
// Configuration fields
private static final String flavorKey = "flavor";
@@ -111,6 +112,8 @@ public class NodeSerializer {
node.allocation().ifPresent(allocation -> toSlime(allocation, object.setObject(instanceKey)));
toSlime(node.history(), object.setArray(historyKey));
object.setString(nodeTypeKey, toString(node.type()));
+ node.status().hardwareDivergence().ifPresent(hardwareDivergence -> object.setString(hardwareDivergenceKey,
+ hardwareDivergence));
}
private void toSlime(Allocation allocation, Cursor object) {
@@ -167,7 +170,8 @@ public class NodeSerializer {
(int)object.field(failCountKey).asLong(),
hardwareFailureFromSlime(object.field(hardwareFailureKey)),
object.field(wantToRetireKey).asBool(),
- wantToDeprovision);
+ wantToDeprovision,
+ hardwareDivergenceFromSlime(object));
}
private Flavor flavorFromSlime(Inspector object) {
@@ -228,6 +232,13 @@ public class NodeSerializer {
return Optional.empty();
}
+ private Optional<String> hardwareDivergenceFromSlime(Inspector object) {
+ if (object.field(hardwareDivergenceKey).valid()) {
+ return Optional.of(object.field(hardwareDivergenceKey).asString());
+ }
+ return Optional.empty();
+ }
+
private Set<String> ipAddressesFromSlime(Inspector object, String key) {
ImmutableSet.Builder<String> ipAddresses = ImmutableSet.builder();
object.field(key).traverse((ArrayTraverser) (i, item) -> ipAddresses.add(item.asString()));
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodePatcher.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodePatcher.java
index 9e7b178c2bc..07e005a3601 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodePatcher.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/NodePatcher.java
@@ -124,6 +124,11 @@ public class NodePatcher {
return node.with(node.status().withWantToRetire(asBoolean(value)));
case "wantToDeprovision" :
return node.with(node.status().withWantToDeprovision(asBoolean(value)));
+ case "hardwareDivergence" :
+ if (value.type().equals(Type.NIX)) {
+ return node.with(node.status().withHardwareDivergence(Optional.empty()));
+ }
+ return node.with(node.status().withHardwareDivergence(Optional.of(asString(value))));
default :
throw new IllegalArgumentException("Could not apply field '" + name + "' on a node: No such modifiable field");
}
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 2a844bdc21b..699782e3a93 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
@@ -178,6 +178,7 @@ class NodesResponse extends HttpResponse {
toSlime(node.history(), object.setArray("history"));
ipAddressesToSlime(node.ipAddresses(), object.setArray("ipAddresses"));
ipAddressesToSlime(node.additionalIpAddresses(), object.setArray("additionalIpAddresses"));
+ node.status().hardwareDivergence().ifPresent(hardwareDivergence -> object.setString("hardwareDivergence", hardwareDivergence));
}
private String toString(NodeType type) {
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 53b14c2e1ec..dd2b64a7854 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
@@ -471,6 +471,30 @@ public class RestApiTest {
assertFile(new Request("http://localhost:8080/nodes/v2/node/host5.yahoo.com"), "node5-after-changes.json");
}
+ @Test
+ public void test_hardware_divergence_patching() throws Exception {
+ // Add report
+ assertResponse(new Request("http://localhost:8080/nodes/v2/node/host6.yahoo.com",
+ Utf8.toBytes("{\"hardwareDivergence\": \"{\\\"actualCpuCores\\\":2}\"}"),
+ Request.Method.PATCH),
+ "{\"message\":\"Updated host6.yahoo.com\"}");
+ assertFile(new Request("http://localhost:8080/nodes/v2/node/host6.yahoo.com"), "node6-after-changes.json");
+
+ // Empty report is rejected
+ assertResponse(new Request("http://localhost:8080/nodes/v2/node/host6.yahoo.com",
+ Utf8.toBytes("{\"hardwareDivergence\": \"\"}"),
+ Request.Method.PATCH),
+ 400,
+ "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Could not set field 'hardwareDivergence': Hardware divergence must be non-empty, but was ''\"}");
+
+ // Clear report
+ assertResponse(new Request("http://localhost:8080/nodes/v2/node/host6.yahoo.com",
+ Utf8.toBytes("{\"hardwareDivergence\": null}"),
+ Request.Method.PATCH),
+ "{\"message\":\"Updated host6.yahoo.com\"}");
+ assertFile(new Request("http://localhost:8080/nodes/v2/node/host6.yahoo.com"), "node6.json");
+ }
+
/** Tests the rendering of each node separately to make it easier to find errors */
@Test
public void test_single_node_rendering() throws Exception {
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node6-after-changes.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node6-after-changes.json
new file mode 100644
index 00000000000..7177567011a
--- /dev/null
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/node6-after-changes.json
@@ -0,0 +1,42 @@
+{
+ "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",
+ "canonicalFlavor": "default",
+ "minDiskAvailableGb":400.0,
+ "minMainMemoryAvailableGb":16.0,
+ "description":"Flavor-name-is-default",
+ "minCpuCores":2.0,
+ "fastDisk":true,
+ "environment":"BARE_METAL",
+ "owner": {
+ "tenant": "tenant3",
+ "application": "application3",
+ "instance": "instance3"
+ },
+ "membership": {
+ "clustertype": "content",
+ "clusterid": "id3",
+ "group": "0",
+ "index": 0,
+ "retired": false
+ },
+ "restartGeneration": 0,
+ "currentRestartGeneration": 0,
+ "wantedDockerImage":"docker-registry.domain.tld:8080/dist/vespa:6.42.0",
+ "wantedVespaVersion":"6.42.0",
+ "rebootGeneration": 1,
+ "currentRebootGeneration": 0,
+ "failCount": 0,
+ "hardwareFailure" : false,
+ "wantToRetire" : false,
+ "wantToDeprovision" : false,
+ "history":[{"event":"readied","at":123,"agent":"system"},{"event":"reserved","at":123,"agent":"application"},{"event":"activated","at":123,"agent":"application"}],
+ "ipAddresses":["::1", "127.0.0.1"],
+ "additionalIpAddresses":[],
+ "hardwareDivergence":"{\"actualCpuCores\":2}"
+}