diff options
author | Øyvind Grønnesby <oyving@verizonmedia.com> | 2021-09-10 10:41:13 +0200 |
---|---|---|
committer | Øyvind Grønnesby <oyving@verizonmedia.com> | 2021-09-10 10:41:13 +0200 |
commit | a8c616b18803e2e3a959b9ba987deb64fabf252a (patch) | |
tree | 3a4997d150defdee909c800e3169dcd720ea2cc0 /controller-server | |
parent | 0bd1f4da69f10cfe5f4de2585a7973240e9b42f5 (diff) |
Expose all endpoints for a given instance
Diffstat (limited to 'controller-server')
3 files changed, 80 insertions, 0 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 828e7e63483..2d7e4f3f29e 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 @@ -21,6 +21,7 @@ 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.Endpoint; import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId; import com.yahoo.vespa.hosted.controller.auditlog.AuditLoggingRequestHandler; import com.yahoo.vespa.hosted.controller.routing.GlobalRouting; @@ -85,11 +86,38 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler { if (path.matches("/routing/v1/status/tenant/{tenant}/application/{application}")) return application(path, request); if (path.matches("/routing/v1/status/tenant/{tenant}/application/{application}/instance/{instance}")) return instance(path, request); 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/tenant/{tenant}/application/{application}/instance/{instance}/endpoint")) return endpoints(path); if (path.matches("/routing/v1/status/environment")) return environment(request); if (path.matches("/routing/v1/status/environment/{environment}/region/{region}")) return zone(path); return ErrorResponse.notFoundError("Nothing at " + path); } + private HttpResponse endpoints(Path path) { + var instanceId = instanceFrom(path); + var endpoints = controller.routing().endpointsOf(instanceId); + var zoneStatus = endpoints.asList().stream() + .flatMap(e -> e.zones().stream()) + .distinct() + .collect(Collectors.toMap( + zone -> zone, + zone -> controller.routing().globalRotationStatus(new DeploymentId(instanceId, zone)) + )); + + var slime = new Slime(); + var root = slime.setObject(); + var endpointsRoot = root.setArray("endpoints"); + endpoints.forEach(endpoint -> { + var endpointRoot = endpointsRoot.addObject(); + endpointToSlime(endpointRoot, endpoint); + var zonesRoot = endpointRoot.setArray("zones"); + zoneStatus.forEach((zone, status) -> { + endpointStatusToSlime(zonesRoot.addObject(), zone, status.get(endpoint)); + }); + }); + + return new SlimeJsonResponse(slime); + } + private HttpResponse environment(HttpRequest request) { var zones = controller.zoneRegistry().zones().all().ids(); if (isRecursive(request)) { @@ -304,6 +332,20 @@ public class RoutingApiHandler extends AuditLoggingRequestHandler { object.setLong("changedAt", globalRouting.changedAt().toEpochMilli()); } + private static void endpointToSlime(Cursor object, Endpoint endpoint) { + object.setString("endpoint", endpoint.name()); + object.setString("dns", endpoint.dnsName()); + object.setString("routingMethod", endpoint.routingMethod().name()); + object.setString("cluster", endpoint.cluster().value()); + object.setString("scope", endpoint.scope().name()); + } + + private static void endpointStatusToSlime(Cursor object, ZoneId zone, EndpointStatus status) { + object.setString("zone", zone.value()); + object.setString("status", status.getStatus().name()); + object.setString("reason", status.getReason()); + } + private TenantName tenantFrom(Path path) { return TenantName.from(path.get("tenant")); } 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 b1bd7df059c..42c9b5bdf4f 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 @@ -362,4 +362,19 @@ public class RoutingApiTest extends ControllerContainerTest { 400); } + @Test + public void endpoints_list() { + 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(); + + tester.assertResponse(operatorRequest("http://localhost:8080/routing/v1/status/tenant/t1/application/a1/instance/default/endpoint", "", Request.Method.GET), + new File("endpoint/endpoints.json")); + } } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/endpoint/endpoints.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/endpoint/endpoints.json new file mode 100644 index 00000000000..a3a5e3d8236 --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/endpoint/endpoints.json @@ -0,0 +1,23 @@ +{ + "endpoints": [ + { + "endpoint": "default", + "dns": "a1--t1.global.vespa.oath.cloud", + "routingMethod": "shared", + "cluster": "default", + "scope": "global", + "zones": [ + { + "zone": "prod.us-east-3", + "status": "in", + "reason": "" + }, + { + "zone": "prod.us-west-1", + "status": "in", + "reason": "" + } + ] + } + ] +}
\ No newline at end of file |