From 3d3e4bf63f427a641aa385325f53ee7759ac0e71 Mon Sep 17 00:00:00 2001 From: Robert Macaulay Date: Tue, 8 Oct 2019 14:37:03 -0500 Subject: [PATCH] Make admin interfaces streamable --- .../hotels/styx/admin/AdminServerBuilder.java | 66 +++++++++---------- .../hotels/styx/server/AdminHttpRouter.java | 54 +++++++++++++++ 2 files changed, 87 insertions(+), 33 deletions(-) create mode 100644 components/server/src/main/java/com/hotels/styx/server/AdminHttpRouter.java diff --git a/components/proxy/src/main/java/com/hotels/styx/admin/AdminServerBuilder.java b/components/proxy/src/main/java/com/hotels/styx/admin/AdminServerBuilder.java index 9194b38f93..c37e129f3f 100644 --- a/components/proxy/src/main/java/com/hotels/styx/admin/AdminServerBuilder.java +++ b/components/proxy/src/main/java/com/hotels/styx/admin/AdminServerBuilder.java @@ -53,8 +53,8 @@ import com.hotels.styx.routing.RoutingObjectRecord; import com.hotels.styx.routing.config.RoutingObjectFactory; import com.hotels.styx.routing.db.StyxObjectStore; +import com.hotels.styx.server.AdminHttpRouter; import com.hotels.styx.server.HttpServer; -import com.hotels.styx.server.StandardHttpRouter; import com.hotels.styx.server.handlers.ClassPathResourceHandler; import com.hotels.styx.server.netty.NettyServerBuilderSpec; import com.hotels.styx.server.netty.WebServerConnectorFactory; @@ -114,42 +114,42 @@ public HttpServer build() { return new NettyServerBuilderSpec("Admin", environment.serverEnvironment(), new WebServerConnectorFactory()) .toNettyServerBuilder(adminServerConfig) - .handlerFactory(() -> new HttpAggregator(adminEndpoints(styxConfig, startupConfig))) + .handlerFactory(() -> adminEndpoints(styxConfig, startupConfig)) .build(); } - private WebServiceHandler adminEndpoints(StyxConfig styxConfig, StartupConfig startupConfig) { + private HttpHandler adminEndpoints(StyxConfig styxConfig, StartupConfig startupConfig) { Optional metricsCacheExpiration = styxConfig.adminServerConfig().metricsCacheExpiration(); - StandardHttpRouter httpRouter = new StandardHttpRouter(); - httpRouter.add("/", new IndexHandler(indexLinkPaths())); - httpRouter.add("/version.txt", new VersionTextHandler(styxConfig.versionFiles(startupConfig))); - httpRouter.add("/admin", new IndexHandler(indexLinkPaths())); - httpRouter.add("/admin/ping", new PingHandler()); - httpRouter.add("/admin/threads", new ThreadsHandler()); - httpRouter.add("/admin/current_requests", new CurrentRequestsHandler(CurrentRequestTracker.INSTANCE)); + AdminHttpRouter httpRouter = new AdminHttpRouter(); + httpRouter.aggregate("/", new IndexHandler(indexLinkPaths())); + httpRouter.aggregate("/version.txt", new VersionTextHandler(styxConfig.versionFiles(startupConfig))); + httpRouter.aggregate("/admin", new IndexHandler(indexLinkPaths())); + httpRouter.aggregate("/admin/ping", new PingHandler()); + httpRouter.aggregate("/admin/threads", new ThreadsHandler()); + httpRouter.aggregate("/admin/current_requests", new CurrentRequestsHandler(CurrentRequestTracker.INSTANCE)); MetricsHandler metricsHandler = new MetricsHandler(environment.metricRegistry(), metricsCacheExpiration); - httpRouter.add("/admin/metrics", metricsHandler); - httpRouter.add("/admin/metrics/", metricsHandler); - httpRouter.add("/admin/configuration", new StyxConfigurationHandler(configuration)); - httpRouter.add("/admin/configuration/origins", new OriginsHandler(backendServicesRegistry)); - httpRouter.add("/admin/jvm", new JVMMetricsHandler(environment.metricRegistry(), metricsCacheExpiration)); - httpRouter.add("/admin/origins/status", new OriginsInventoryHandler(environment.eventBus())); - httpRouter.add("/admin/configuration/logging", new LoggingConfigurationHandler(startupConfig.logConfigLocation())); - httpRouter.add("/admin/configuration/startup", new StartupConfigHandler(startupConfig)); + httpRouter.aggregate("/admin/metrics", metricsHandler); + httpRouter.aggregate("/admin/metrics/", metricsHandler); + httpRouter.aggregate("/admin/configuration", new StyxConfigurationHandler(configuration)); + httpRouter.aggregate("/admin/configuration/origins", new OriginsHandler(backendServicesRegistry)); + httpRouter.aggregate("/admin/jvm", new JVMMetricsHandler(environment.metricRegistry(), metricsCacheExpiration)); + httpRouter.aggregate("/admin/origins/status", new OriginsInventoryHandler(environment.eventBus())); + httpRouter.aggregate("/admin/configuration/logging", new LoggingConfigurationHandler(startupConfig.logConfigLocation())); + httpRouter.aggregate("/admin/configuration/startup", new StartupConfigHandler(startupConfig)); RoutingObjectHandler routingObjectHandler = new RoutingObjectHandler(routeDatabase, routingObjectFactoryContext); - httpRouter.add("/admin/routing", routingObjectHandler); - httpRouter.add("/admin/routing/", routingObjectHandler); + httpRouter.aggregate("/admin/routing", routingObjectHandler); + httpRouter.aggregate("/admin/routing/", routingObjectHandler); // Dashboard - httpRouter.add("/admin/dashboard/data.json", dashboardDataHandler(styxConfig)); - httpRouter.add("/admin/dashboard/", new ClassPathResourceHandler("/admin/dashboard/")); + httpRouter.aggregate("/admin/dashboard/data.json", dashboardDataHandler(styxConfig)); + httpRouter.aggregate("/admin/dashboard/", new ClassPathResourceHandler("/admin/dashboard/")); // Tasks - httpRouter.add("/admin/tasks/origins/reload", new HttpMethodFilteringHandler(POST, new OriginsReloadCommandHandler(backendServicesRegistry))); - httpRouter.add("/admin/tasks/origins", new HttpMethodFilteringHandler(POST, new OriginsCommandHandler(environment.eventBus()))); - httpRouter.add("/admin/tasks/plugin/", new PluginToggleHandler(environment.configStore())); + httpRouter.aggregate("/admin/tasks/origins/reload", new HttpMethodFilteringHandler(POST, new OriginsReloadCommandHandler(backendServicesRegistry))); + httpRouter.aggregate("/admin/tasks/origins", new HttpMethodFilteringHandler(POST, new OriginsCommandHandler(environment.eventBus()))); + httpRouter.aggregate("/admin/tasks/plugin/", new PluginToggleHandler(environment.configStore())); // Plugins Handler @@ -158,10 +158,10 @@ private WebServiceHandler adminEndpoints(StyxConfig styxConfig, StartupConfig st NamedPlugin namedPlugin = entry.value(); routesForPlugin(namedPlugin).forEach(route -> - httpRouter.add(route.path(), route.handler())); + httpRouter.stream(route.path(), route.handler())); }); - httpRouter.add("/admin/plugins", new PluginListHandler(environment.configStore())); + httpRouter.aggregate("/admin/plugins", new PluginListHandler(environment.configStore())); return httpRouter; } @@ -199,7 +199,7 @@ private static List routesForPlugin(NamedPlugin namedPlugin) { ? new StaticBodyHttpHandler(HTML_UTF_8, format("This plugin (%s) does not expose any admin interfaces", namedPlugin.name())) : new IndexHandler(endpointLinks); - Route indexRoute = new Route(pluginPath(namedPlugin), handler); + Route indexRoute = new Route(pluginPath(namedPlugin), new HttpAggregator(MEGABYTE, handler)); return concatenate(indexRoute, routes); } @@ -219,7 +219,7 @@ private static List pluginAdminEndpointRoutes(NamedPlu Map adminInterfaceHandlers = namedPlugin.adminInterfaceHandlers(); return mapToList(adminInterfaceHandlers, (relativePath, handler) -> - new PluginAdminEndpointRoute(namedPlugin, relativePath, new HttpStreamer(MEGABYTE, handler))); + new PluginAdminEndpointRoute(namedPlugin, relativePath, handler)); } // allows key and value to be labelled in lambda instead of having to use Entry.getKey, Entry.getValue @@ -231,9 +231,9 @@ private static List mapToList(Map map, BiFunction fu private static class Route { private final String path; - private final WebServiceHandler handler; + private final HttpHandler handler; - Route(String path, WebServiceHandler handler) { + Route(String path, HttpHandler handler) { this.path = path; this.handler = handler; } @@ -242,7 +242,7 @@ String path() { return path; } - WebServiceHandler handler() { + HttpHandler handler() { return handler; } } @@ -250,7 +250,7 @@ WebServiceHandler handler() { private static class PluginAdminEndpointRoute extends Route { private final NamedPlugin namedPlugin; - PluginAdminEndpointRoute(NamedPlugin namedPlugin, String relativePath, WebServiceHandler handler) { + PluginAdminEndpointRoute(NamedPlugin namedPlugin, String relativePath, HttpHandler handler) { super(pluginAdminEndpointPath(namedPlugin, relativePath), handler); this.namedPlugin = namedPlugin; diff --git a/components/server/src/main/java/com/hotels/styx/server/AdminHttpRouter.java b/components/server/src/main/java/com/hotels/styx/server/AdminHttpRouter.java new file mode 100644 index 0000000000..7590862d94 --- /dev/null +++ b/components/server/src/main/java/com/hotels/styx/server/AdminHttpRouter.java @@ -0,0 +1,54 @@ +/* + Copyright (C) 2013-2019 Expedia Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +package com.hotels.styx.server; + +import com.hotels.styx.api.Eventual; +import com.hotels.styx.api.HttpHandler; +import com.hotels.styx.api.HttpInterceptor; +import com.hotels.styx.api.LiveHttpRequest; +import com.hotels.styx.api.LiveHttpResponse; +import com.hotels.styx.api.WebServiceHandler; +import com.hotels.styx.common.http.handler.HttpAggregator; + +import static com.hotels.styx.api.HttpResponse.response; +import static com.hotels.styx.api.HttpResponseStatus.NOT_FOUND; + +/** + * Simple Http Router. + */ +public class AdminHttpRouter implements HttpHandler { + private static final int MEGABYTE = 1024 * 1024; + private static final HttpHandler NOT_FOUND_HANDLER = (request, context) -> Eventual.of(response(NOT_FOUND).build().stream()); + + private final PathTrie routes = new PathTrie<>(); + + @Override + public Eventual handle(LiveHttpRequest request, HttpInterceptor.Context context) { + return routes.get(request.path()) + .orElse(NOT_FOUND_HANDLER) + .handle(request, context); + } + + public AdminHttpRouter aggregate(String path, WebServiceHandler httpHandler) { + routes.put(path, new HttpAggregator(MEGABYTE, httpHandler)); + return this; + } + + public AdminHttpRouter stream(String path, HttpHandler httpHandler) { + routes.put(path, httpHandler); + return this; + } +}