diff --git a/docs/src/main/asciidoc/http-reference.adoc b/docs/src/main/asciidoc/http-reference.adoc index 4a98d84efe846..b1243e582b80b 100644 --- a/docs/src/main/asciidoc/http-reference.adoc +++ b/docs/src/main/asciidoc/http-reference.adoc @@ -261,7 +261,7 @@ include::{generated-dir}/config/quarkus-vertx-http-config-group-filter-config.ad == Support 100-Continue in vert.x In order to support `100-continue`, the `quarkus.http.handle-100-continue-automatically` option needs to be enabled explicitly -For additional information check https://datatracker.ietf.org/doc/html/rfc7231#section-5.1.1[100-continue= and the related +For additional information check https://datatracker.ietf.org/doc/html/rfc7231#section-5.1.1[100-continue] and the related https://vertx.io/docs/apidocs/io/vertx/core/http/HttpServerOptions.html#DEFAULT_HANDLE_100_CONTINE_AUTOMATICALLY[Vert.x documentation]. [source,properties] diff --git a/docs/src/main/asciidoc/management-interface-reference.adoc b/docs/src/main/asciidoc/management-interface-reference.adoc new file mode 100644 index 0000000000000..5260574376e8c --- /dev/null +++ b/docs/src/main/asciidoc/management-interface-reference.adoc @@ -0,0 +1,162 @@ +//// +This guide is maintained in the main Quarkus repository +and pull requests should be submitted there: +https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc +//// += HTTP Reference +include::_attributes.adoc[] +:categories: observability +:summary: Learn how you can use a separated management interface +:numbered: +:sectnums: +:sectnumlevels: 4 + +:numbered: +:sectnums: +:sectnumlevels: 4 + + +By default, Quarkus exposes the _management_ endpoints under `/q` on the main HTTP server. +The same HTTP server provides the application endpoints and the management endpoints. + +This document presents how you can use a separate HTTP server (bound to a different network interface and port) for the management endpoints. +It avoids exposing these endpoints on the main server and, thus, prevents undesired accesses. + +== Enabling the management interface + +To enable the management interface, use the following **build-time** property: + +[source, properties] +---- +quarkus.management.enabled=true +---- + +Management endpoints will be exposed on: `http://0.0.0.0:8999/q`. +For example, `http://0.0.0.0:8998/q/health/ready` for the readiness probe. + +== Configure the host, port and scheme + +By default, the management interface is exposed on the interface: `0.0.0.0` (all interfaces) and on the port `8999` (`8998` in test mode). +It does not use TLS (`https`) by default. + +You can configure the host, ports and TLS certificates using the following properties: + +* `quarkus.management.host` - the interface / host +* `quarkus.management.port` - the port +* `quarkus.management.test-port` - the port to use in test mode +* `quarkus.management.ssl` - the TLS configuration, xref:http-reference#ssl[same as for the main HTTP server]. + +Here is an example for properties exposing the management interface on _https://localhost:9000_: + +[source, properties] +---- +quarkus.management.enabled=true +quarkus.management.host=localhost +quarkus.management.port=9000 +quarkus.management.ssl.certificate.key-store-file=server-keystore.jks +quarkus.management.ssl.certificate.key-store-password=secret +---- + +IMPORTANT: Unlike the main HTTP server, the management interface does not handle _http_ and _https_ at the same time. +If _https_ is configured, plain HTTP requests will be rejected. + +== Configure the root path + +By default, management endpoints are exposed under `/q`. +This _root path_ can be configured using the `quarkus.management.root-path` property. +For example, if you want to expose the management endpoints under `/management` use: + +[source, properties] +---- +quarkus.management.enabled=true +quarkus.management.root-path=/management +---- + +The mounting rules of the management endpoints are slightly different than the ones used when using the main HTTP server: + +* Management endpoints configured using a _relative_ path (not starting with `/`) will be served from the configured root path. +For example, if the endpoint path is `health` and the root path is `management`, the resulting path is `/management/health` +* Management endpoints configured using an _absolute_ path (starting with `/`) will be served from the root. +For example, if the endpoint path is `/health`, the resulting path is `/health`, regardless of the root path +* The management interface does not use the HTTP root path from the main HTTP server. + +== Management endpoints + +SmallRye Health Checks, SmallRye Metrics and Prometheus are declared as management endpoints. +Note that if you do not enable the management interface, these endpoints will be served using the main HTTP server (under `/q` by default). + +To declare a management endpoint, an extension must produce a _non application_ route and call the `management()` method: + +[source, java] +---- +@BuildStep +void createManagementRoute(BuildProducer routes, + NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem, + MyRecorder recorder) { + + routes.produce(nonApplicationRootPathBuildItem.routeBuilder() + .management() // Must be called BEFORE the routeFunction method + .routeFunction("my-path", recorder.route()) + .handler(recorder.getHandler()) + .blockingRoute() + .build()); + //... +} +---- + +If the management interface is enabled, the endpoint will be exposed on: `http://0.0.0.0:8999/q/my-path`. +Otherwise, it will be exposed on: `http://localhost:8080/q/my-path`. + +IMPORTANT: Management endpoints can only be declared by extensions and not from the application code. + +== Management Interface Configuration + +include::{generated-dir}/config/quarkus-management-management-management-interface-build-time-config.adoc[leveloffset=+1, opts=optional] + +include::{generated-dir}/config/quarkus-management-management-management-interface-configuration.adoc[leveloffset=+1, opts=optional] + + +[[reverse-proxy]] +== Running behind a reverse proxy + +Quarkus could be accessed through proxies that additionally generate headers (e.g. `X-Forwarded-Host`) to keep +information from the client-facing side of the proxy servers that is altered or lost when they are involved. +In those scenarios, Quarkus can be configured to automatically update information like protocol, host, port and URI +reflecting the values in these headers. + +IMPORTANT: Activating this feature leaves the server exposed to several security issues (i.e. information spoofing). +Consider activate it only when running behind a reverse proxy. + +To set up this feature for the management interface, include the following lines in `src/main/resources/application.properties`: +[source,properties] +---- +quarkus.management.proxy.proxy-address-forwarding=true +---- + +To consider only de-facto standard header (`Forwarded` header), please include the following lines in `src/main/resources/application.properties`: +[source,properties] +---- +quarkus.management.proxy.allow-forwarded=true +---- + +To consider only non-standard headers, please include the following lines instead in `src/main/resources/application.properties`: + +[source,properties] +---- +quarkus.management.proxy.proxy-address-forwarding=true +quarkus.management.proxy.allow-x-forwarded=true +quarkus.management.proxy.enable-forwarded-host=true +quarkus.management.proxy.enable-forwarded-prefix=true +---- + +Both configurations related to standard and non-standard headers can be combined, although the standard headers configuration will have precedence. However, combining them has security implications as clients can forge requests with a forwarded header that is not overwritten by the proxy. +Therefore, proxies should strip unexpected `X-Forwarded` or `X-Forwarded-*` headers from the client. + +Supported forwarding address headers are: + +* `Forwarded` +* `X-Forwarded-Proto` +* `X-Forwarded-Host` +* `X-Forwarded-Port` +* `X-Forwarded-Ssl` +* `X-Forwarded-Prefix` diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/management/ManagementWithMainServerDisabledTest.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/management/ManagementWithMainServerDisabledTest.java new file mode 100644 index 0000000000000..800697c37779a --- /dev/null +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/management/ManagementWithMainServerDisabledTest.java @@ -0,0 +1,80 @@ +package io.quarkus.vertx.http.management; + +import java.util.function.Consumer; + +import javax.enterprise.event.Observes; +import javax.inject.Singleton; + +import org.hamcrest.Matchers; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.builder.BuildChainBuilder; +import io.quarkus.builder.BuildContext; +import io.quarkus.builder.BuildStep; +import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem; +import io.quarkus.vertx.http.deployment.RouteBuildItem; +import io.restassured.RestAssured; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; + +public class ManagementWithMainServerDisabledTest { + private static final String APP_PROPS = "" + + "quarkus.management.enabled=true\n" + + "quarkus.management.root-path=/management\n" + + "quarkus.http.host-enabled=false\n"; + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addAsResource(new StringAsset(APP_PROPS), "application.properties") + .addClasses(MyObserver.class)) + .addBuildChainCustomizer(buildCustomizer()); + + static Consumer buildCustomizer() { + return new Consumer() { + @Override + public void accept(BuildChainBuilder builder) { + builder.addBuildStep(new BuildStep() { + @Override + public void execute(BuildContext context) { + NonApplicationRootPathBuildItem buildItem = context.consume(NonApplicationRootPathBuildItem.class); + context.produce(buildItem.routeBuilder() + .management() + .route("my-route") + .handler(new MyHandler()) + .blockingRoute() + .build()); + } + }).produces(RouteBuildItem.class) + .consumes(NonApplicationRootPathBuildItem.class) + .build(); + } + }; + } + + public static class MyHandler implements Handler { + @Override + public void handle(RoutingContext rc) { + rc.response().end("ok"); + } + } + + @Test + public void testManagementWithoutMain() { + RestAssured.given() + .get("http://0.0.0.0:8998/management/my-route") + .then().statusCode(200).body(Matchers.equalTo("ok")); + } + + @Singleton + static class MyObserver { + + void test(@Observes String event) { + //Do Nothing + } + + } +} diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/management/ManagementWithP12Test.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/management/ManagementWithP12Test.java index 3814290d5363b..eec3f8caf765d 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/management/ManagementWithP12Test.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/management/ManagementWithP12Test.java @@ -70,7 +70,7 @@ public void handle(RoutingContext rc) { } @Test - public void testSslWithJks() { + public void testSslWithP12() { RestAssured.given() .relaxedHTTPSValidation() .get("https://0.0.0.0:8998/management/my-route") diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/management/ManagementWithPemTest.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/management/ManagementWithPemTest.java index 796df20c07e7a..c8b38dea9f42a 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/management/ManagementWithPemTest.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/management/ManagementWithPemTest.java @@ -71,7 +71,7 @@ public void handle(RoutingContext rc) { } @Test - public void testSslWithJks() { + public void testSslWithPem() { RestAssured.given() .relaxedHTTPSValidation() .get("https://0.0.0.0:8998/management/my-route") diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java index ed5ccab2a959d..bb9c3a3a0fe69 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java @@ -195,6 +195,10 @@ private boolean uriValid(HttpServerRequest httpServerRequest) { } } }; + private static HttpServerOptions httpMainSslServerOptions; + private static HttpServerOptions httpMainServerOptions; + private static HttpServerOptions httpMainDomainSocketOptions; + private static HttpServerOptions httpManagementServerOptions; final HttpBuildTimeConfig httpBuildTimeConfig; final ManagementInterfaceBuildTimeConfig managementBuildTimeConfig; final RuntimeValue httpConfiguration; @@ -320,7 +324,8 @@ public void startServer(Supplier vertx, ShutdownContext shutdown, HttpConfiguration httpConfiguration = this.httpConfiguration.getValue(); ManagementInterfaceConfiguration managementConfig = this.managementConfiguration == null ? null : this.managementConfiguration.getValue(); - if (startSocket && (httpConfiguration.hostEnabled || httpConfiguration.domainSocketEnabled)) { + if (startSocket && (httpConfiguration.hostEnabled || httpConfiguration.domainSocketEnabled + || managementConfig.hostEnabled || managementConfig.domainSocketEnabled)) { // Start the server if (closeTask == null) { doServerStart(vertx.get(), httpBuildTimeConfig, managementBuildTimeConfig, managementRouter, @@ -562,16 +567,92 @@ private void warnIfProxyAddressForwardingAllowedWithMultipleHeaders(ProxyConfig } } - private static void doServerStart(Vertx vertx, HttpBuildTimeConfig httpBuildTimeConfig, + private static CompletableFuture initializeManagementInterfaceWithDomainSocket(Vertx vertx, ManagementInterfaceBuildTimeConfig managementBuildTimeConfig, Handler managementRouter, - HttpConfiguration httpConfiguration, ManagementInterfaceConfiguration managementConfig, + ManagementInterfaceConfiguration managementConfig, + List websocketSubProtocols) { + CompletableFuture managementInterfaceDomainSocketFuture = new CompletableFuture<>(); + if (!managementBuildTimeConfig.enabled || managementRouter == null || managementConfig == null) { + managementInterfaceDomainSocketFuture.complete(null); + return managementInterfaceDomainSocketFuture; + } + + HttpServerOptions domainSocketOptionsForManagement = createDomainSocketOptionsForManagementInterface( + managementBuildTimeConfig, managementConfig, + websocketSubProtocols); + if (domainSocketOptionsForManagement != null) { + vertx.createHttpServer(domainSocketOptionsForManagement) + .requestHandler(managementRouter) + .listen(ar -> { + if (ar.failed()) { + managementInterfaceDomainSocketFuture.completeExceptionally( + new IllegalStateException( + "Unable to start the management interface on the " + + domainSocketOptionsForManagement.getHost() + " domain socket", + ar.cause())); + } else { + managementInterfaceDomainSocketFuture.complete(ar.result()); + } + }); + } else { + managementInterfaceDomainSocketFuture.complete(null); + } + return managementInterfaceDomainSocketFuture; + } + + private static CompletableFuture initializeManagementInterface(Vertx vertx, + ManagementInterfaceBuildTimeConfig managementBuildTimeConfig, Handler managementRouter, + ManagementInterfaceConfiguration managementConfig, LaunchMode launchMode, - Supplier eventLoops, List websocketSubProtocols, boolean auxiliaryApplication) throws IOException { + List websocketSubProtocols) throws IOException { + httpManagementServerOptions = null; + CompletableFuture managementInterfaceFuture = new CompletableFuture<>(); + if (!managementBuildTimeConfig.enabled || managementRouter == null || managementConfig == null) { + managementInterfaceFuture.complete(null); + return managementInterfaceFuture; + } + + HttpServerOptions httpServerOptionsForManagement = createHttpServerOptionsForManagementInterface( + managementBuildTimeConfig, managementConfig, launchMode, + websocketSubProtocols); + httpManagementServerOptions = HttpServerOptionsUtils.createSslOptionsForManagementInterface( + managementBuildTimeConfig, managementConfig, launchMode, + websocketSubProtocols); + if (httpManagementServerOptions != null && httpManagementServerOptions.getKeyCertOptions() == null) { + httpManagementServerOptions = httpServerOptionsForManagement; + } + + if (httpManagementServerOptions != null) { + vertx.createHttpServer(httpManagementServerOptions) + .requestHandler(managementRouter) + .listen(ar -> { + if (ar.failed()) { + managementInterfaceFuture.completeExceptionally( + new IllegalStateException("Unable to start the management interface", ar.cause())); + } else { + actualManagementPort = ar.result().actualPort(); + managementInterfaceFuture.complete(ar.result()); + } + }); + } else { + managementInterfaceFuture.complete(null); + } + return managementInterfaceFuture; + } + + private static CompletableFuture initializeMainHttpServer(Vertx vertx, HttpBuildTimeConfig httpBuildTimeConfig, + HttpConfiguration httpConfiguration, + LaunchMode launchMode, + Supplier eventLoops, List websocketSubProtocols) throws IOException { + + if (!httpConfiguration.hostEnabled) { + return CompletableFuture.completedFuture(null); + } // Http server configuration - HttpServerOptions httpServerOptions = createHttpServerOptions(httpBuildTimeConfig, httpConfiguration, launchMode, + httpMainServerOptions = createHttpServerOptions(httpBuildTimeConfig, httpConfiguration, launchMode, websocketSubProtocols); - HttpServerOptions domainSocketOptions = createDomainSocketOptions(httpBuildTimeConfig, httpConfiguration, + httpMainDomainSocketOptions = createDomainSocketOptions(httpBuildTimeConfig, httpConfiguration, websocketSubProtocols); HttpServerOptions tmpSslConfig = HttpServerOptionsUtils.createSslOptions(httpBuildTimeConfig, httpConfiguration, launchMode, @@ -583,14 +664,14 @@ private static void doServerStart(Vertx vertx, HttpBuildTimeConfig httpBuildTime .listAll(HttpServerOptionsCustomizer.class); for (InstanceHandle instance : instances) { HttpServerOptionsCustomizer customizer = instance.get(); - if (httpServerOptions != null) { - customizer.customizeHttpServer(httpServerOptions); + if (httpMainServerOptions != null) { + customizer.customizeHttpServer(httpMainServerOptions); } if (tmpSslConfig != null) { customizer.customizeHttpsServer(tmpSslConfig); } - if (domainSocketOptions != null) { - customizer.customizeDomainSocketServer(domainSocketOptions); + if (httpMainDomainSocketOptions != null) { + customizer.customizeDomainSocketServer(httpMainDomainSocketOptions); } } } @@ -599,61 +680,13 @@ private static void doServerStart(Vertx vertx, HttpBuildTimeConfig httpBuildTime if (tmpSslConfig != null && tmpSslConfig.getKeyCertOptions() == null) { tmpSslConfig = null; } - final HttpServerOptions sslConfig = tmpSslConfig; + httpMainSslServerOptions = tmpSslConfig; - if (httpConfiguration.insecureRequests != HttpConfiguration.InsecureRequests.ENABLED && sslConfig == null) { + if (httpConfiguration.insecureRequests != HttpConfiguration.InsecureRequests.ENABLED + && httpMainSslServerOptions == null) { throw new IllegalStateException("Cannot set quarkus.http.redirect-insecure-requests without enabling SSL."); } - HttpServerOptions managementServerOptions = null; - CompletableFuture managementInterfaceFuture = new CompletableFuture<>(); - CompletableFuture managementInterfaceDomainSocketFuture = new CompletableFuture<>(); - if (managementBuildTimeConfig.enabled && managementRouter != null && managementConfig != null) { - HttpServerOptions httpServerOptionsForManagement = createHttpServerOptionsForManagementInterface( - managementBuildTimeConfig, managementConfig, launchMode, - websocketSubProtocols); - HttpServerOptions domainSocketOptionsForManagement = createDomainSocketOptionsForManagementInterface( - managementBuildTimeConfig, managementConfig, - websocketSubProtocols); - managementServerOptions = HttpServerOptionsUtils.createSslOptionsForManagementInterface( - managementBuildTimeConfig, managementConfig, launchMode, - websocketSubProtocols); - if (managementServerOptions != null && managementServerOptions.getKeyCertOptions() == null) { - managementServerOptions = httpServerOptionsForManagement; - } - - if (managementServerOptions != null) { - vertx.createHttpServer(managementServerOptions) - .requestHandler(managementRouter) - .listen(ar -> { - if (ar.failed()) { - managementInterfaceFuture.completeExceptionally( - new IllegalStateException("Unable to start the management interface", ar.cause())); - } else { - actualManagementPort = ar.result().actualPort(); - managementInterfaceFuture.complete(ar.result()); - } - }); - } else { - managementInterfaceFuture.complete(null); - } - - if (domainSocketOptionsForManagement != null) { - vertx.createHttpServer(domainSocketOptions) - .requestHandler(managementRouter) - .listen(ar -> { - if (ar.failed()) { - managementInterfaceFuture.completeExceptionally( - new IllegalStateException("Unable to start the management interface", ar.cause())); - } else { - managementInterfaceFuture.complete(ar.result()); - } - }); - } else { - managementInterfaceDomainSocketFuture.complete(null); - } - } - int eventLoopCount = eventLoops.get(); final int ioThreads; if (httpConfiguration.ioThreads.isPresent()) { @@ -664,11 +697,13 @@ private static void doServerStart(Vertx vertx, HttpBuildTimeConfig httpBuildTime ioThreads = eventLoopCount; } CompletableFuture futureResult = new CompletableFuture<>(); + AtomicInteger connectionCount = new AtomicInteger(); vertx.deployVerticle(new Supplier() { @Override public Verticle get() { - return new WebDeploymentVerticle(httpServerOptions, sslConfig, domainSocketOptions, launchMode, + return new WebDeploymentVerticle(httpMainServerOptions, httpMainSslServerOptions, httpMainDomainSocketOptions, + launchMode, httpConfiguration.insecureRequests, httpConfiguration, connectionCount); } }, new DeploymentOptions().setInstances(ioThreads), new Handler>() { @@ -679,13 +714,15 @@ public void handle(AsyncResult event) { if (effectiveCause instanceof BindException) { List portsUsed = Collections.emptyList(); - if ((sslConfig == null) && (httpServerOptions != null)) { - portsUsed = List.of(httpServerOptions.getPort()); - } else if ((httpConfiguration.insecureRequests == InsecureRequests.DISABLED) && (sslConfig != null)) { - portsUsed = List.of(sslConfig.getPort()); - } else if ((sslConfig != null) && (httpConfiguration.insecureRequests == InsecureRequests.ENABLED) - && (httpServerOptions != null)) { - portsUsed = List.of(httpServerOptions.getPort(), sslConfig.getPort()); + if ((httpMainSslServerOptions == null) && (httpMainServerOptions != null)) { + portsUsed = List.of(httpMainServerOptions.getPort()); + } else if ((httpConfiguration.insecureRequests == InsecureRequests.DISABLED) + && (httpMainSslServerOptions != null)) { + portsUsed = List.of(httpMainSslServerOptions.getPort()); + } else if ((httpMainSslServerOptions != null) + && (httpConfiguration.insecureRequests == InsecureRequests.ENABLED) + && (httpMainServerOptions != null)) { + portsUsed = List.of(httpMainServerOptions.getPort(), httpMainSslServerOptions.getPort()); } effectiveCause = new QuarkusBindException((BindException) effectiveCause, portsUsed); @@ -696,80 +733,102 @@ public void handle(AsyncResult event) { } } }); + + return futureResult; + } + + private static void doServerStart(Vertx vertx, HttpBuildTimeConfig httpBuildTimeConfig, + ManagementInterfaceBuildTimeConfig managementBuildTimeConfig, Handler managementRouter, + HttpConfiguration httpConfiguration, ManagementInterfaceConfiguration managementConfig, + LaunchMode launchMode, + Supplier eventLoops, List websocketSubProtocols, boolean auxiliaryApplication) throws IOException { + + var mainServerFuture = initializeMainHttpServer(vertx, httpBuildTimeConfig, httpConfiguration, launchMode, eventLoops, + websocketSubProtocols); + var managementInterfaceFuture = initializeManagementInterface(vertx, managementBuildTimeConfig, managementRouter, + managementConfig, launchMode, websocketSubProtocols); + var managementInterfaceDomainSocketFuture = initializeManagementInterfaceWithDomainSocket(vertx, + managementBuildTimeConfig, managementRouter, managementConfig, websocketSubProtocols); + try { - String deploymentId = futureResult.get(); + String deploymentIdIfAny = mainServerFuture.get(); - HttpServer ms = null; - HttpServer ms2 = null; + HttpServer tmpManagementServer = null; + HttpServer tmpManagementServerUsingDomainSocket = null; if (managementRouter != null) { - ms = managementInterfaceFuture.get(); - ms2 = managementInterfaceDomainSocketFuture.get(); + tmpManagementServer = managementInterfaceFuture.get(); + tmpManagementServerUsingDomainSocket = managementInterfaceDomainSocketFuture.get(); + } + HttpServer managementServer = tmpManagementServer; + HttpServer managementServerDomainSocket = tmpManagementServerUsingDomainSocket; + if (deploymentIdIfAny != null) { + VertxCoreRecorder.setWebDeploymentId(deploymentIdIfAny); } - HttpServer managementServer = ms; - HttpServer managementServerDomainSocket = ms2; - - VertxCoreRecorder.setWebDeploymentId(deploymentId); closeTask = new Runnable() { @Override public synchronized void run() { //guard against this being run twice if (closeTask == this) { - if (vertx.deploymentIDs().contains(deploymentId)) { - int count = 1; // main server - if (managementServer != null) { - count++; - } - if (managementServerDomainSocket != null) { - count++; - } + int count = 0; + if (deploymentIdIfAny != null && vertx.deploymentIDs().contains(deploymentIdIfAny)) { + count++; + } + if (managementServer != null) { + count++; + } + if (managementServerDomainSocket != null) { + count++; + } - CountDownLatch latch = new CountDownLatch(count); - var handler = new Handler>() { - @Override - public void handle(AsyncResult event) { - latch.countDown(); - } - }; + CountDownLatch latch = new CountDownLatch(count); + var handler = new Handler>() { + @Override + public void handle(AsyncResult event) { + latch.countDown(); + } + }; - // shutdown main HTTP server + // shutdown main HTTP server + if (deploymentIdIfAny != null) { try { - vertx.undeploy(deploymentId, handler); + vertx.undeploy(deploymentIdIfAny, handler); } catch (Exception e) { LOGGER.warn("Failed to undeploy deployment ", e); } + } - // shutdown the management interface - try { - if (managementServer != null) { - managementServer.close(handler); - } - if (managementServerDomainSocket != null) { - managementServerDomainSocket.close(handler); - } - } catch (Exception e) { - LOGGER.warn("Unable to shutdown the management interface quietly", e); + // shutdown the management interface + try { + if (managementServer != null) { + managementServer.close(handler); } - - try { - latch.await(); - } catch (InterruptedException e) { - throw new RuntimeException(e); + if (managementServerDomainSocket != null) { + managementServerDomainSocket.close(handler); } + } catch (Exception e) { + LOGGER.warn("Unable to shutdown the management interface quietly", e); } - closeTask = null; - if (remoteSyncHandler != null) { - remoteSyncHandler.close(); - remoteSyncHandler = null; + + try { + latch.await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); } } + closeTask = null; + if (remoteSyncHandler != null) { + remoteSyncHandler.close(); + remoteSyncHandler = null; + } } }; } catch (InterruptedException | ExecutionException e) { throw new RuntimeException("Unable to start HTTP server", e); } - setHttpServerTiming(httpConfiguration.insecureRequests, httpServerOptions, sslConfig, domainSocketOptions, - auxiliaryApplication, managementServerOptions); + setHttpServerTiming(httpConfiguration.insecureRequests, httpMainServerOptions, httpMainSslServerOptions, + httpMainDomainSocketOptions, + auxiliaryApplication, httpManagementServerOptions); } private static void setHttpServerTiming(InsecureRequests insecureRequests, HttpServerOptions httpServerOptions, @@ -1220,6 +1279,7 @@ public void afterRestore(org.crac.Context context) throws Ex p.future().onComplete(event -> latch.countDown()); latch.await(); } + } protected static ServerBootstrap virtualBootstrap;