From 03cf527daa5b5d88a501d14fbf8b621a41b06512 Mon Sep 17 00:00:00 2001 From: Jon Marius Venstad Date: Wed, 10 Apr 2019 15:47:06 +0200 Subject: Support a few more fields in controller's Node --- .../api/integration/configserver/Node.java | 31 ++++++++++++++++++++-- .../controller/integration/NodeRepositoryMock.java | 25 +++++++++++++---- .../controller/maintenance/OsUpgraderTest.java | 2 +- .../hosted/controller/restapi/os/OsApiTest.java | 2 +- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java index d166bb0d3fb..d618464fc2a 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/Node.java @@ -31,10 +31,14 @@ public class Node { private final long wantedRestartGeneration; private final long rebootGeneration; private final long wantedRebootGeneration; + private final String canonicalFlavor; + private final String clusterId; + private final ClusterType clusterType; public Node(HostName hostname, State state, NodeType type, Optional owner, Version currentVersion, Version wantedVersion, Version currentOsVersion, Version wantedOsVersion, ServiceState serviceState, - long restartGeneration, long wantedRestartGeneration, long rebootGeneration, long wantedRebootGeneration) { + long restartGeneration, long wantedRestartGeneration, long rebootGeneration, long wantedRebootGeneration, + String canonicalFlavor, String clusterId, ClusterType clusterType) { this.hostname = hostname; this.state = state; this.type = type; @@ -48,13 +52,17 @@ public class Node { this.wantedRestartGeneration = wantedRestartGeneration; this.rebootGeneration = rebootGeneration; this.wantedRebootGeneration = wantedRebootGeneration; + this.canonicalFlavor = canonicalFlavor; + this.clusterId = clusterId; + this.clusterType = clusterType; } @TestOnly public Node(HostName hostname, State state, NodeType type, Optional owner, Version currentVersion, Version wantedVersion) { this(hostname, state, type, owner, currentVersion, wantedVersion, - Version.emptyVersion, Version.emptyVersion, ServiceState.unorchestrated, 0, 0, 0, 0); + Version.emptyVersion, Version.emptyVersion, ServiceState.unorchestrated, 0, 0, 0, 0, + "d-2-8-50", "cluster", ClusterType.container); } public HostName hostname() { @@ -107,6 +115,18 @@ public class Node { return wantedRebootGeneration; } + public String canonicalFlavor() { + return canonicalFlavor; + } + + public String clusterId() { + return clusterId; + } + + public ClusterType clusterType() { + return clusterType; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -139,4 +159,11 @@ public class Node { unorchestrated } + /** Known cluster types. */ + public enum ClusterType { + admin, + container, + content + } + } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java index ac15ab046c3..49bc910ac33 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java @@ -89,7 +89,10 @@ public class NodeRepositoryMock implements NodeRepository { node.restartGeneration(), node.wantedRestartGeneration(), node.rebootGeneration(), - node.wantedRebootGeneration())) + node.wantedRebootGeneration(), + node.canonicalFlavor(), + node.clusterId(), + node.clusterType())) .forEach(node -> putByHostname(zone, node)); } @@ -131,7 +134,10 @@ public class NodeRepositoryMock implements NodeRepository { node.restartGeneration(), node.wantedRestartGeneration() + 1, node.rebootGeneration(), - node.wantedRebootGeneration())); + node.wantedRebootGeneration(), + node.canonicalFlavor(), + node.clusterId(), + node.clusterType())); } public void doRestart(DeploymentId deployment, Optional hostname) { @@ -147,7 +153,10 @@ public class NodeRepositoryMock implements NodeRepository { node.restartGeneration() + 1, node.wantedRestartGeneration(), node.rebootGeneration(), - node.wantedRebootGeneration())); + node.wantedRebootGeneration(), + node.canonicalFlavor(), + node.clusterId(), + node.clusterType())); } public void requestReboot(DeploymentId deployment, Optional hostname) { @@ -163,7 +172,10 @@ public class NodeRepositoryMock implements NodeRepository { node.restartGeneration(), node.wantedRestartGeneration(), node.rebootGeneration(), - node.wantedRebootGeneration() + 1)); + node.wantedRebootGeneration() + 1, + node.canonicalFlavor(), + node.clusterId(), + node.clusterType())); } public void doReboot(DeploymentId deployment, Optional hostname) { @@ -179,7 +191,10 @@ public class NodeRepositoryMock implements NodeRepository { node.restartGeneration(), node.wantedRestartGeneration(), node.rebootGeneration() + 1, - node.wantedRebootGeneration())); + node.wantedRebootGeneration(), + node.canonicalFlavor(), + node.clusterId(), + node.clusterType())); } } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgraderTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgraderTest.java index b053bfa1bfe..7a008d1f478 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgraderTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgraderTest.java @@ -168,7 +168,7 @@ public class OsUpgraderTest { node.hostname(), node.state(), node.type(), node.owner(), node.currentVersion(), node.wantedVersion(), node.wantedOsVersion(), node.wantedOsVersion(), node.serviceState(), node.restartGeneration(), node.wantedRestartGeneration(), node.rebootGeneration(), - node.wantedRebootGeneration())); + node.wantedRebootGeneration(), node.canonicalFlavor(), node.clusterId(), node.clusterType())); } assertCurrent(version, application, zone); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java index 1eb3316a33e..bc8dd8d4479 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/os/OsApiTest.java @@ -149,7 +149,7 @@ public class OsApiTest extends ControllerContainerTest { node.hostname(), node.state(), node.type(), node.owner(), node.currentVersion(), node.wantedVersion(), node.wantedOsVersion(), node.wantedOsVersion(), node.serviceState(), node.restartGeneration(), node.wantedRestartGeneration(), node.rebootGeneration(), - node.wantedRebootGeneration())); + node.wantedRebootGeneration(), node.canonicalFlavor(), node.clusterId(), node.clusterType())); } } } -- cgit v1.2.3 From 26558c5b69f98ce460811050e7d223a4642d051a Mon Sep 17 00:00:00 2001 From: Jon Marius Venstad Date: Wed, 10 Apr 2019 15:47:26 +0200 Subject: Make ConfigServerMock actiavte nodes on deployment (nit) --- .../yahoo/vespa/hosted/controller/integration/ConfigServerMock.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java index 61c397d893a..927596ca9ab 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java @@ -248,7 +248,8 @@ public class ConfigServerMock extends AbstractComponent implements ConfigServer List nodes = nodeRepository.list(deployment.zoneId(), deployment.applicationId()); for (Node node : nodes) { nodeRepository.putByHostname(deployment.zoneId(), new Node(node.hostname(), - node.state(), node.type(), + Node.State.active, + node.type(), node.owner(), node.currentVersion(), application.version().get())); -- cgit v1.2.3 From 5769a20f4b4c98bfab9ba8e5caaddd1fd41f37d1 Mon Sep 17 00:00:00 2001 From: Jon Marius Venstad Date: Wed, 10 Apr 2019 15:48:16 +0200 Subject: Expose application nodes in application/v4 --- .../hosted/controller/api/role/PathGroup.java | 1 + .../restapi/application/ApplicationApiHandler.java | 54 ++++++++++++++++++++++ .../restapi/application/ApplicationApiTest.java | 5 ++ .../application/responses/application-nodes.json | 13 ++++++ 4 files changed, 73 insertions(+) create mode 100644 controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-nodes.json diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java index 797ca10ed3d..8209e5d3568 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java @@ -57,6 +57,7 @@ public enum PathGroup { Matcher.application, "/application/v4/tenant/{tenant}/application/{application}/deploying/{*}", "/application/v4/tenant/{tenant}/application/{application}/instance/{*}", + "/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/nodes", "/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/logs", "/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/suspended", "/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/service/{*}", diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java index 44794600551..1bfd75bae6e 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java @@ -44,6 +44,7 @@ import com.yahoo.vespa.hosted.controller.api.identifiers.TenantId; import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException; import com.yahoo.vespa.hosted.controller.api.integration.configserver.Log; import com.yahoo.vespa.hosted.controller.api.integration.configserver.Logs; +import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; @@ -173,6 +174,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { if (path.matches("/application/v4/tenant/{tenant}/application/{application}")) return application(path.get("tenant"), path.get("application"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/deploying")) return deploying(path.get("tenant"), path.get("application"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/deploying/pin")) return deploying(path.get("tenant"), path.get("application"), request); + if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/nodes")) return nodes(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region")); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/logs")) return logs(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request.propertyMap()); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/job")) return JobControllerApiHandlerHelper.jobTypeResponse(controller, appIdFromPath(path), request.getUri()); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/job/{jobtype}")) return JobControllerApiHandlerHelper.runResponse(controller.jobController().runs(appIdFromPath(path), jobTypeFromPath(path)), request.getUri()); @@ -328,6 +330,58 @@ public class ApplicationApiHandler extends LoggingRequestHandler { .orElseThrow(() -> new NotExistsException(applicationId + " not found")); } + private HttpResponse nodes(String tenantName, String applicationName, String instanceName, String environment, String region) { + ApplicationId id = ApplicationId.from(tenantName, applicationName, instanceName); + ZoneId zone = ZoneId.from(environment, region); + List nodes = controller.configServer().nodeRepository().list(zone, id); + + Slime slime = new Slime(); + Cursor nodesArray = slime.setObject().setArray("nodes"); + for (Node node : nodes) { + Cursor nodeObject = nodesArray.addObject(); + nodeObject.setString("hostname", node.hostname().value()); + nodeObject.setString("state", valueOf(node.state())); + nodeObject.setString("orchestration", valueOf(node.serviceState())); + nodeObject.setString("version", node.currentVersion().toString()); + nodeObject.setString("flavor", node.canonicalFlavor()); + nodeObject.setString("clusterId", node.clusterId()); + nodeObject.setString("clusterType", valueOf(node.clusterType())); + } + return new SlimeJsonResponse(slime); + } + + private static String valueOf(Node.State state) { + switch (state) { + case failed: return "failed"; + case parked: return "parked"; + case dirty: return "dirty"; + case ready: return "ready"; + case active: return "active"; + case inactive: return "inactive"; + case reserved: return "reserved"; + case provisioned: return "provisioned"; + default: throw new IllegalArgumentException("Unexpected node state '" + state + "'."); + } + } + + private static String valueOf(Node.ServiceState state) { + switch (state) { + case expectedUp: return "expectedUp"; + case allowedDown: return "allowedDown"; + case unorchestrated: return "unorchestrated"; + default: throw new IllegalArgumentException("Unexpected node state '" + state + "'."); + } + } + + private static String valueOf(Node.ClusterType type) { + switch (type) { + case admin: return "admin"; + case content: return "content"; + case container: return "container"; + default: throw new IllegalArgumentException("Unexpected node cluster type '" + type + "'."); + } + } + private HttpResponse logs(String tenantName, String applicationName, String instanceName, String environment, String region, Map queryParameters) { ApplicationId application = ApplicationId.from(tenantName, applicationName, instanceName); ZoneId zone = ZoneId.from(environment, region); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java index ec17e26d867..e60bbdc4d84 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java @@ -380,6 +380,11 @@ public class ApplicationApiTest extends ControllerContainerTest { .recursive("true"), new File("application1-recursive.json")); + // GET nodes + tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-central-1/instance/default/nodes", GET) + .userIdentity(USER_ID), + new File("application-nodes.json")); + // GET logs tester.assertResponse(request("/application/v4/tenant/tenant2/application/application1/environment/prod/region/us-central-1/instance/default/logs?from=1233&to=3214", GET) .userIdentity(USER_ID), diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-nodes.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-nodes.json new file mode 100644 index 00000000000..eb53ff7161e --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-nodes.json @@ -0,0 +1,13 @@ +{ + "nodes": [ + { + "hostname": "host-tenant1:application1:default-prod.us-central-1", + "state": "active", + "orchestration": "unorchestrated", + "version": "6.1", + "flavor": "d-2-8-50", + "clusterId": "cluster", + "clusterType": "container" + } + ] +} -- cgit v1.2.3