aboutsummaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2020-02-14 16:03:00 +0100
committerMartin Polden <mpolden@mpolden.no>2020-02-17 11:13:46 +0100
commit3a88329b8e68804c82a229e73608e441b49be15c (patch)
treead87edcb7131d19d0f5e1c001fc7db502774467a /controller-server
parent3a538c64845c6ff42847483b3ad84b2afd1b5c97 (diff)
Make /routing/v1 discoverable
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiHandler.java89
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiTest.java41
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/application.json7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/environment.json43
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/instance.json10
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/root.json10
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/tenant.json7
7 files changed, 199 insertions, 8 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiHandler.java
index 1815628a1ee..745316826cd 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiHandler.java
@@ -2,6 +2,9 @@
package com.yahoo.vespa.hosted.controller.restapi.routing;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.ApplicationName;
+import com.yahoo.config.provision.InstanceName;
+import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.zone.RoutingMethod;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.container.jdisc.HttpRequest;
@@ -9,21 +12,26 @@ import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.restapi.ErrorResponse;
import com.yahoo.restapi.MessageResponse;
import com.yahoo.restapi.Path;
+import com.yahoo.restapi.ResourceResponse;
import com.yahoo.restapi.SlimeJsonResponse;
import com.yahoo.slime.Cursor;
import com.yahoo.slime.Slime;
+import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.Instance;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.EndpointStatus;
import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
+import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId;
import com.yahoo.vespa.hosted.controller.auditlog.AuditLoggingRequestHandler;
import com.yahoo.vespa.hosted.controller.routing.GlobalRouting;
import com.yahoo.vespa.hosted.controller.routing.RoutingPolicy;
import com.yahoo.yolean.Exceptions;
+import java.net.URI;
import java.time.Instant;
import java.util.Objects;
import java.util.logging.Level;
+import java.util.stream.Collectors;
/**
* This implements the /routing/v1 API, which provides operator with global routing control at both zone- and
@@ -45,7 +53,7 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler {
try {
var path = new Path(request.getUri());
switch (request.getMethod()) {
- case GET: return get(path);
+ case GET: return get(path, request.getUri());
case POST: return post(path);
case DELETE: return delete(path);
default: return ErrorResponse.methodNotAllowed("Method '" + request.getMethod() + "' is not supported");
@@ -70,12 +78,62 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler {
return ErrorResponse.notFoundError("Nothing at " + path);
}
- private HttpResponse get(Path path) {
- if (path.matches("/routing/v1/status/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}")) return deploymentStatus(path);
- if (path.matches("/routing/v1/status/environment/{environment}/region/{region}")) return zoneStatus(path);
+ private HttpResponse get(Path path, URI requestUrl) {
+ if (path.matches("/routing/v1/")) return status(requestUrl);
+ if (path.matches("/routing/v1/status/tenant/{tenant}")) return tenant(path, requestUrl);
+ if (path.matches("/routing/v1/status/tenant/{tenant}/application/{application}")) return application(path, requestUrl);
+ if (path.matches("/routing/v1/status/tenant/{tenant}/application/{application}/instance/{instance}")) return instance(path, requestUrl);
+ if (path.matches("/routing/v1/status/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}")) return deployment(path);
+ if (path.matches("/routing/v1/status/environment")) return environment(requestUrl);
+ if (path.matches("/routing/v1/status/environment/{environment}/region/{region}")) return zone(path);
return ErrorResponse.notFoundError("Nothing at " + path);
}
+ private HttpResponse environment(URI requestUrl) {
+ var resources = controller.zoneRegistry().zones().all().ids().stream()
+ .map(zone -> zone.environment().value() +
+ "/region/" + zone.region().value())
+ .sorted()
+ .collect(Collectors.toList());
+ return new ResourceResponse(requestUrl, resources);
+ }
+
+ private HttpResponse status(URI requestUrl) {
+ return new ResourceResponse(requestUrl, "status/tenant", "status/environment");
+ }
+
+ private HttpResponse tenant(Path path, URI requestUrl) {
+ var tenantName = tenantFrom(path);
+ var resources = controller.applications().asList(tenantName).stream()
+ .map(Application::id)
+ .map(TenantAndApplicationId::application)
+ .map(ApplicationName::value)
+ .map(application -> "application/" + application)
+ .sorted()
+ .collect(Collectors.toList());
+ return new ResourceResponse(requestUrl, resources);
+ }
+
+ private HttpResponse application(Path path, URI requestUrl) {
+ var tenantAndApplicationId = tenantAndApplicationIdFrom(path);
+ var resources = controller.applications().requireApplication(tenantAndApplicationId).instances().keySet().stream()
+ .map(InstanceName::value)
+ .map(instance -> "instance/" + instance)
+ .sorted()
+ .collect(Collectors.toList());
+ return new ResourceResponse(requestUrl, resources);
+ }
+
+ private HttpResponse instance(Path path, URI requestUrl) {
+ var instanceId = instanceFrom(path);
+ var resources = controller.applications().requireInstance(instanceId).deployments().keySet().stream()
+ .map(zone -> "environment/" + zone.environment().value() +
+ "/region/" + zone.region().value())
+ .sorted()
+ .collect(Collectors.toList());
+ return new ResourceResponse(requestUrl, resources);
+ }
+
private HttpResponse setZoneStatus(Path path, boolean in) {
var zone = zoneFrom(path);
if (controller.zoneRegistry().zones().directlyRouted().ids().contains(zone)) {
@@ -88,7 +146,7 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler {
(in ? "IN" : "OUT"));
}
- private HttpResponse zoneStatus(Path path) {
+ private HttpResponse zone(Path path) {
var zone = zoneFrom(path);
var slime = new Slime();
var root = slime.setObject();
@@ -124,7 +182,7 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler {
return new MessageResponse("Set global routing status for " + deployment + " to " + (in ? "IN" : "OUT"));
}
- private HttpResponse deploymentStatus(Path path) {
+ private HttpResponse deployment(Path path) {
var deployment = deploymentFrom(path);
var instance = controller.applications().requireInstance(deployment.applicationId());
var slime = new Slime();
@@ -190,9 +248,24 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler {
policy.status().globalRouting(), RoutingMethod.exclusive);
}
+ private TenantName tenantFrom(Path path) {
+ return TenantName.from(path.get("tenant"));
+ }
+
+ private ApplicationName applicationFrom(Path path) {
+ return ApplicationName.from(path.get("application"));
+ }
+
+ private TenantAndApplicationId tenantAndApplicationIdFrom(Path path) {
+ return TenantAndApplicationId.from(tenantFrom(path), applicationFrom(path));
+ }
+
+ private ApplicationId instanceFrom(Path path) {
+ return ApplicationId.from(tenantFrom(path), applicationFrom(path), InstanceName.from(path.get("instance")));
+ }
+
private DeploymentId deploymentFrom(Path path) {
- return new DeploymentId(ApplicationId.from(path.get("tenant"), path.get("application"), path.get("instance")),
- zoneFrom(path));
+ return new DeploymentId(instanceFrom(path), zoneFrom(path));
}
private ZoneId zoneFrom(Path path) {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiTest.java
index 635adc73d1d..b368cb6dd5e 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiTest.java
@@ -35,6 +35,47 @@ public class RoutingApiTest extends ControllerContainerTest {
}
@Test
+ public void discovery() {
+ // Deploy
+ var context = deploymentTester.newDeploymentContext("t1", "a1", "default");
+ var westZone = ZoneId.from("prod", "us-west-1");
+ var eastZone = ZoneId.from("prod", "us-east-3");
+ var applicationPackage = new ApplicationPackageBuilder()
+ .region(westZone.region())
+ .region(eastZone.region())
+ .endpoint("default", "default", eastZone.region().value(), westZone.region().value())
+ .build();
+ context.submit(applicationPackage).deploy();
+
+ // GET root
+ tester.assertResponse(operatorRequest("http://localhost:8080/routing/v1/", "",
+ Request.Method.GET),
+ new File("discovery/root.json"));
+
+ // GET tenant
+ tester.assertResponse(operatorRequest("http://localhost:8080/routing/v1/status/tenant/t1", "",
+ Request.Method.GET),
+ new File("discovery/tenant.json"));
+
+ // GET application
+ tester.assertResponse(operatorRequest("http://localhost:8080/routing/v1/status/tenant/t1/application/a1/",
+ "",
+ Request.Method.GET),
+ new File("discovery/application.json"));
+
+ // GET instance
+ tester.assertResponse(operatorRequest("http://localhost:8080/routing/v1/status/tenant/t1/application/a1/instance/default/",
+ "",
+ Request.Method.GET),
+ new File("discovery/instance.json"));
+
+ // GET environment
+ tester.assertResponse(operatorRequest("http://localhost:8080/routing/v1/status/environment/", "",
+ Request.Method.GET),
+ new File("discovery/environment.json"));
+ }
+
+ @Test
public void exclusive_routing() {
var context = deploymentTester.newDeploymentContext();
// Zones support direct routing
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/application.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/application.json
new file mode 100644
index 00000000000..deda734cbbf
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/application.json
@@ -0,0 +1,7 @@
+{
+ "resources": [
+ {
+ "url": "http://localhost:8080/routing/v1/status/tenant/t1/application/a1/instance/default/"
+ }
+ ]
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/environment.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/environment.json
new file mode 100644
index 00000000000..1e06b279873
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/environment.json
@@ -0,0 +1,43 @@
+{
+ "resources": [
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/dev/region/aws-us-east-2a/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/dev/region/us-east-1/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/perf/region/us-east-3/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/prod/region/ap-northeast-1/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/prod/region/ap-northeast-2/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/prod/region/ap-southeast-1/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/prod/region/aws-us-east-1a/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/prod/region/eu-west-1/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/prod/region/us-central-1/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/prod/region/us-east-3/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/prod/region/us-west-1/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/staging/region/us-east-3/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/test/region/us-east-1/"
+ }
+ ]
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/instance.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/instance.json
new file mode 100644
index 00000000000..1a3ad823e14
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/instance.json
@@ -0,0 +1,10 @@
+{
+ "resources": [
+ {
+ "url": "http://localhost:8080/routing/v1/status/tenant/t1/application/a1/instance/default/environment/prod/region/us-east-3/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/tenant/t1/application/a1/instance/default/environment/prod/region/us-west-1/"
+ }
+ ]
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/root.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/root.json
new file mode 100644
index 00000000000..9b5630335aa
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/root.json
@@ -0,0 +1,10 @@
+{
+ "resources": [
+ {
+ "url": "http://localhost:8080/routing/v1/status/tenant/"
+ },
+ {
+ "url": "http://localhost:8080/routing/v1/status/environment/"
+ }
+ ]
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/tenant.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/tenant.json
new file mode 100644
index 00000000000..acd05d35c8d
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/tenant.json
@@ -0,0 +1,7 @@
+{
+ "resources": [
+ {
+ "url": "http://localhost:8080/routing/v1/status/tenant/t1/application/a1/"
+ }
+ ]
+}