From 9d633e48670bccd87b258095e60d6e0117c33f01 Mon Sep 17 00:00:00 2001 From: Phillip Kruger Date: Tue, 11 Jul 2023 16:37:49 +1000 Subject: [PATCH] Add OpenAPI to management interface if enabled, with option to exclude Signed-off-by: Phillip Kruger --- .../devui/SmallRyeGraphQLDevUIProcessor.java | 7 +- .../deployment/SmallRyeHealthConfig.java | 7 ++ .../SmallRyeHealthDevUiProcessor.java | 11 ++- .../deployment/SmallRyeHealthProcessor.java | 18 +++-- .../deployment/SmallRyeOpenApiConfig.java | 7 ++ .../deployment/SmallRyeOpenApiProcessor.java | 74 +++++++++++++++++-- .../devui/OpenApiDevUIProcessor.java | 23 ++++-- .../deployment/filter/AutoServerFilter.java | 9 ++- .../deployment/SwaggerUiProcessor.java | 3 + .../deployment/HttpRootPathBuildItem.java | 6 ++ .../NonApplicationRootPathBuildItem.java | 22 ++++-- .../vertx/http/deployment/RouteBuildItem.java | 18 ++++- .../resources/dev-ui/qwc/qwc-external-page.js | 2 +- .../devui/spi/page/ExternalPageBuilder.java | 8 ++ 14 files changed, 173 insertions(+), 42 deletions(-) diff --git a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/devui/SmallRyeGraphQLDevUIProcessor.java b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/devui/SmallRyeGraphQLDevUIProcessor.java index fc960b8ffeba0..495a617a5cf23 100644 --- a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/devui/SmallRyeGraphQLDevUIProcessor.java +++ b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/devui/SmallRyeGraphQLDevUIProcessor.java @@ -18,17 +18,16 @@ CardPageBuildItem createCard(NonApplicationRootPathBuildItem nonApplicationRootP CardPageBuildItem cardPageBuildItem = new CardPageBuildItem(); // Generated GraphQL Schema + String schemaPath = "/" + graphQLConfig.rootPath + "/schema.graphql"; PageBuilder schemaPage = Page.externalPageBuilder("GraphQL Schema") .icon("font-awesome-solid:diagram-project") - .url("/" + graphQLConfig.rootPath + "/schema.graphql"); + .url(schemaPath, schemaPath); // GraphiQL UI String uiPath = nonApplicationRootPathBuildItem.resolvePath(graphQLConfig.ui.rootPath); PageBuilder uiPage = Page.externalPageBuilder("GraphQL UI") .icon("font-awesome-solid:table-columns") - .staticLabel("") - .url(uiPath + "/index.html?embed=true"); + .url(uiPath + "/index.html?embed=true", uiPath); // Learn PageBuilder learnLink = Page.externalPageBuilder("Learn more about GraphQL") diff --git a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthConfig.java b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthConfig.java index ee1f47b536bab..79a941fa3e3ce 100644 --- a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthConfig.java +++ b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthConfig.java @@ -72,6 +72,13 @@ public class SmallRyeHealthConfig { @ConfigItem Optional defaultHealthGroup; + /** + * If management interface is turned on the health endpoints and ui will be published under the management interface. This + * allows you to exclude Health from management by setting the value to false + */ + @ConfigItem(name = "management.enabled", defaultValue = "true") + public boolean managementEnabled; + /** * SmallRye Health UI configuration */ diff --git a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthDevUiProcessor.java b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthDevUiProcessor.java index c6909315a1a8d..4a9f5b2f79d92 100644 --- a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthDevUiProcessor.java +++ b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthDevUiProcessor.java @@ -25,16 +25,19 @@ CardPageBuildItem create(NonApplicationRootPathBuildItem nonApplicationRootPathB SmallRyeHealthRecorder unused) { CardPageBuildItem pageBuildItem = new CardPageBuildItem(); - var path = nonApplicationRootPathBuildItem.resolveManagementPath(config.rootPath, - managementInterfaceBuildTimeConfig, launchModeBuildItem); + String path = nonApplicationRootPathBuildItem.resolveManagementPath(config.rootPath, + managementInterfaceBuildTimeConfig, launchModeBuildItem, config.managementEnabled); + pageBuildItem.addPage(Page.externalPageBuilder("Health") .icon("font-awesome-solid:heart-circle-bolt") - .url(path) + .url(path, path) .isJsonContent()); + String uipath = nonApplicationRootPathBuildItem.resolveManagementPath(config.ui.rootPath, + managementInterfaceBuildTimeConfig, launchModeBuildItem, config.managementEnabled); pageBuildItem.addPage(Page.externalPageBuilder("Health UI") .icon("font-awesome-solid:stethoscope") - .url(nonApplicationRootPathBuildItem.resolvePath(config.ui.rootPath)) + .url(uipath, uipath) .isHtmlContent()); return pageBuildItem; diff --git a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java index 8b8a35a6ba640..1281337f62a5f 100644 --- a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java +++ b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java @@ -208,7 +208,7 @@ public void defineHealthRoutes(BuildProducer routes, // Register the health handler routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management() + .management("quarkus.smallrye-health.management.enabled") .route(healthConfig.rootPath) .routeConfigKey("quarkus.smallrye-health.root-path") .handler(new SmallRyeHealthHandler()) @@ -218,7 +218,7 @@ public void defineHealthRoutes(BuildProducer routes, // Register the liveness handler routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management() + .management("quarkus.smallrye-health.management.enabled") .nestedRoute(healthConfig.rootPath, healthConfig.livenessPath) .handler(new SmallRyeLivenessHandler()) .displayOnNotFoundPage() @@ -227,7 +227,7 @@ public void defineHealthRoutes(BuildProducer routes, // Register the readiness handler routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management() + .management("quarkus.smallrye-health.management.enabled") .nestedRoute(healthConfig.rootPath, healthConfig.readinessPath) .handler(new SmallRyeReadinessHandler()) .displayOnNotFoundPage() @@ -249,7 +249,7 @@ public void defineHealthRoutes(BuildProducer routes, // Register the health group handlers routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management() + .management("quarkus.smallrye-health.management.enabled") .nestedRoute(healthConfig.rootPath, healthConfig.groupPath) .handler(new SmallRyeHealthGroupHandler()) .displayOnNotFoundPage() @@ -258,7 +258,7 @@ public void defineHealthRoutes(BuildProducer routes, SmallRyeIndividualHealthGroupHandler handler = new SmallRyeIndividualHealthGroupHandler(); routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management() + .management("quarkus.smallrye-health.management.enabled") .nestedRoute(healthConfig.rootPath, healthConfig.groupPath + "/*") .handler(handler) .displayOnNotFoundPage() @@ -267,7 +267,7 @@ public void defineHealthRoutes(BuildProducer routes, // Register the wellness handler routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management() + .management("quarkus.smallrye-health.management.enabled") .nestedRoute(healthConfig.rootPath, healthConfig.wellnessPath) .handler(new SmallRyeWellnessHandler()) .displayOnNotFoundPage() @@ -276,7 +276,7 @@ public void defineHealthRoutes(BuildProducer routes, // Register the startup handler routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management() + .management("quarkus.smallrye-health.management.enabled") .nestedRoute(healthConfig.rootPath, healthConfig.startupPath) .handler(new SmallRyeStartupHandler()) .displayOnNotFoundPage() @@ -443,8 +443,9 @@ void registerHealthUiHandler( Handler handler = recorder.uiHandler(result.getFinalDestination(), healthUiPath, result.getWebRootConfigurations(), runtimeConfig, shutdownContext); - // The health ui is not a management route. + routeProducer.produce(nonApplicationRootPathBuildItem.routeBuilder() + .management("quarkus.smallrye-health.management.enabled") .route(healthConfig.ui.rootPath) .displayOnNotFoundPage("Health UI") .routeConfigKey("quarkus.smallrye-health.ui.root-path") @@ -452,6 +453,7 @@ void registerHealthUiHandler( .build()); routeProducer.produce(nonApplicationRootPathBuildItem.routeBuilder() + .management("quarkus.smallrye-health.management.enabled") .route(healthConfig.ui.rootPath + "*") .handler(handler) .build()); diff --git a/extensions/smallrye-openapi-common/deployment/src/main/java/io/quarkus/smallrye/openapi/common/deployment/SmallRyeOpenApiConfig.java b/extensions/smallrye-openapi-common/deployment/src/main/java/io/quarkus/smallrye/openapi/common/deployment/SmallRyeOpenApiConfig.java index 9e9f11f99cc0d..59c333fc96e20 100644 --- a/extensions/smallrye-openapi-common/deployment/src/main/java/io/quarkus/smallrye/openapi/common/deployment/SmallRyeOpenApiConfig.java +++ b/extensions/smallrye-openapi-common/deployment/src/main/java/io/quarkus/smallrye/openapi/common/deployment/SmallRyeOpenApiConfig.java @@ -37,6 +37,13 @@ public final class SmallRyeOpenApiConfig { @ConfigItem(defaultValue = "false") public boolean ignoreStaticDocument; + /** + * If management interface is turned on the openapi schema document will be published under the management interface. This + * allows you to exclude OpenAPI from management by setting the value to false + */ + @ConfigItem(name = "management.enabled", defaultValue = "true") + public boolean managementEnabled; + /** * A list of local directories that should be scanned for yaml and/or json files to be included in the static model. * Example: `META-INF/openapi/` diff --git a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java index 5d9e6b6a220e1..8f9e945bbf6bd 100644 --- a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java +++ b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java @@ -23,6 +23,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.regex.Matcher; @@ -70,6 +71,7 @@ import io.quarkus.deployment.builditem.LaunchModeBuildItem; import io.quarkus.deployment.builditem.RunTimeConfigBuilderBuildItem; import io.quarkus.deployment.builditem.ShutdownContextBuildItem; +import io.quarkus.deployment.builditem.SystemPropertyBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveHierarchyBuildItem; @@ -105,6 +107,8 @@ import io.quarkus.vertx.http.deployment.RouteBuildItem; import io.quarkus.vertx.http.deployment.SecurityInformationBuildItem; import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem; +import io.quarkus.vertx.http.runtime.management.ManagementInterfaceBuildTimeConfig; +import io.quarkus.vertx.http.runtime.management.ManagementInterfaceConfiguration; import io.smallrye.openapi.api.OpenApiConfig; import io.smallrye.openapi.api.OpenApiConfigImpl; import io.smallrye.openapi.api.OpenApiDocument; @@ -235,12 +239,15 @@ void registerAutoSecurityFilter(BuildProducer syntheticB void handler(LaunchModeBuildItem launch, BuildProducer displayableEndpoints, BuildProducer routes, + BuildProducer systemProperties, OpenApiRecorder recorder, NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem, OpenApiRuntimeConfig openApiRuntimeConfig, ShutdownContextBuildItem shutdownContext, SmallRyeOpenApiConfig openApiConfig, - List filterBuildItems) { + List filterBuildItems, + ManagementInterfaceBuildTimeConfig managementInterfaceBuildTimeConfig, + ManagementInterfaceConfiguration managementInterfaceConfiguration) { /* * Ugly Hack * In dev mode, we pass a classloader to load the up to date OpenAPI document. @@ -271,6 +278,7 @@ void handler(LaunchModeBuildItem launch, } routes.produce(nonApplicationRootPathBuildItem.routeBuilder() + .management("quarkus.smallrye-openapi.management.enabled") .routeFunction(openApiConfig.path, corsFilter) .routeConfigKey("quarkus.smallrye-openapi.path") .handler(handler) @@ -279,19 +287,59 @@ void handler(LaunchModeBuildItem launch, .build()); routes.produce(nonApplicationRootPathBuildItem.routeBuilder() + .management("quarkus.smallrye-openapi.management.enabled") .routeFunction(openApiConfig.path + ".json", corsFilter) .handler(handler) .build()); routes.produce(nonApplicationRootPathBuildItem.routeBuilder() + .management("quarkus.smallrye-openapi.management.enabled") .routeFunction(openApiConfig.path + ".yaml", corsFilter) .handler(handler) .build()); routes.produce(nonApplicationRootPathBuildItem.routeBuilder() + .management("quarkus.smallrye-openapi.management.enabled") .routeFunction(openApiConfig.path + ".yml", corsFilter) .handler(handler) .build()); + + // If management is enabled and swagger-ui is part of management, we need to add CORS so that swagger can hit the endpoint + if (isManagement(managementInterfaceBuildTimeConfig, openApiConfig, launch)) { + Config c = ConfigProvider.getConfig(); + + // quarkus.http.cors=true + // quarkus.http.cors.origins + Optional maybeCors = c.getOptionalValue("quarkus.http.cors", Boolean.class); + if (!maybeCors.isPresent() || !maybeCors.get().booleanValue()) { + // We need to set quarkus.http.cors=true + systemProperties.produce(new SystemPropertyBuildItem("quarkus.http.cors", "true")); + } + + String managementUrl = getManagementRoot(launch, nonApplicationRootPathBuildItem, openApiConfig, + managementInterfaceBuildTimeConfig, managementInterfaceConfiguration); + + List origins = c.getOptionalValues("quarkus.http.cors.origins", String.class).orElse(new ArrayList<>()); + if (!origins.contains(managementUrl)) { + // We need to set quarkus.http.cors.origins + origins.add(managementUrl); + String originConfigValue = String.join(",", origins); + systemProperties.produce(new SystemPropertyBuildItem("quarkus.http.cors.origins", originConfigValue)); + } + + } + } + + private String getManagementRoot(LaunchModeBuildItem launch, + NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem, + SmallRyeOpenApiConfig openApiConfig, + ManagementInterfaceBuildTimeConfig managementInterfaceBuildTimeConfig, + ManagementInterfaceConfiguration managementInterfaceConfiguration) { + String managementRoot = nonApplicationRootPathBuildItem.resolveManagementPath("/", + managementInterfaceBuildTimeConfig, launch, openApiConfig.managementEnabled); + + return managementRoot.split(managementInterfaceBuildTimeConfig.rootPath)[0]; + } @BuildStep @@ -340,7 +388,9 @@ public boolean accepts(DotName className) { void addAutoFilters(BuildProducer addToOpenAPIDefinitionProducer, List securityInformationBuildItems, OpenApiFilteredIndexViewBuildItem apiFilteredIndexViewBuildItem, - SmallRyeOpenApiConfig config) { + SmallRyeOpenApiConfig config, + LaunchModeBuildItem launchModeBuildItem, + ManagementInterfaceBuildTimeConfig managementInterfaceBuildTimeConfig) { // Add a security scheme from config if (config.securityScheme.isPresent()) { @@ -371,12 +421,24 @@ void addAutoFilters(BuildProducer addToOpenAPID } // Add Auto Server based on the current server details - OASFilter autoServerFilter = getAutoServerFilter(config, false); + OASFilter autoServerFilter = getAutoServerFilter(config, false, "Auto generated value"); if (autoServerFilter != null) { addToOpenAPIDefinitionProducer.produce(new AddToOpenAPIDefinitionBuildItem(autoServerFilter)); + } else if (isManagement(managementInterfaceBuildTimeConfig, config, launchModeBuildItem)) { // Add server if management is enabled + OASFilter serverFilter = getAutoServerFilter(config, true, "Auto-added by management interface"); + if (serverFilter != null) { + addToOpenAPIDefinitionProducer.produce(new AddToOpenAPIDefinitionBuildItem(serverFilter)); + } } } + private boolean isManagement(ManagementInterfaceBuildTimeConfig managementInterfaceBuildTimeConfig, + SmallRyeOpenApiConfig smallRyeOpenApiConfig, + LaunchModeBuildItem launchModeBuildItem) { + return managementInterfaceBuildTimeConfig.enabled && smallRyeOpenApiConfig.managementEnabled + && launchModeBuildItem.getLaunchMode().equals(LaunchMode.DEVELOPMENT); + } + private OASFilter getAutoSecurityFilter(List securityInformationBuildItems, SmallRyeOpenApiConfig config) { @@ -467,7 +529,7 @@ private OASFilter getAutoTagFilter(OpenApiFilteredIndexViewBuildItem apiFiltered return null; } - private OASFilter getAutoServerFilter(SmallRyeOpenApiConfig config, boolean defaultFlag) { + private OASFilter getAutoServerFilter(SmallRyeOpenApiConfig config, boolean defaultFlag, String description) { if (config.autoAddServer.orElse(defaultFlag)) { Config c = ConfigProvider.getConfig(); @@ -483,7 +545,7 @@ private OASFilter getAutoServerFilter(SmallRyeOpenApiConfig config, boolean defa port = c.getOptionalValue("quarkus.http.ssl-port", Integer.class).orElse(8443); } - return new AutoServerFilter(scheme, host, port); + return new AutoServerFilter(scheme, host, port, description); } return null; } @@ -1040,7 +1102,7 @@ private OpenApiDocument storeDocument(OutputTargetBuildItem out, } // By default, also add the auto generated server - OASFilter autoServerFilter = getAutoServerFilter(smallRyeOpenApiConfig, true); + OASFilter autoServerFilter = getAutoServerFilter(smallRyeOpenApiConfig, true, "Auto generated value"); if (autoServerFilter != null) { document.filter(autoServerFilter); } diff --git a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/devui/OpenApiDevUIProcessor.java b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/devui/OpenApiDevUIProcessor.java index 3e5cc8b608051..52602cfb894dc 100644 --- a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/devui/OpenApiDevUIProcessor.java +++ b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/devui/OpenApiDevUIProcessor.java @@ -2,37 +2,44 @@ import io.quarkus.deployment.IsDevelopment; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.LaunchModeBuildItem; import io.quarkus.devui.spi.page.CardPageBuildItem; import io.quarkus.devui.spi.page.Page; import io.quarkus.smallrye.openapi.common.deployment.SmallRyeOpenApiConfig; import io.quarkus.swaggerui.deployment.SwaggerUiConfig; import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem; +import io.quarkus.vertx.http.runtime.management.ManagementInterfaceBuildTimeConfig; public class OpenApiDevUIProcessor { @BuildStep(onlyIf = IsDevelopment.class) public CardPageBuildItem pages(NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem, - SwaggerUiConfig swaggerUiConfig, SmallRyeOpenApiConfig openApiConfig) { + ManagementInterfaceBuildTimeConfig managementInterfaceBuildTimeConfig, + LaunchModeBuildItem launchModeBuildItem, + SwaggerUiConfig swaggerUiConfig, + SmallRyeOpenApiConfig openApiConfig) { - String uiPath = nonApplicationRootPathBuildItem.resolvePath(swaggerUiConfig.path); - String schemaPath = nonApplicationRootPathBuildItem.resolvePath(openApiConfig.path); + String uiPath = nonApplicationRootPathBuildItem.resolveManagementPath(swaggerUiConfig.path, + managementInterfaceBuildTimeConfig, launchModeBuildItem, openApiConfig.managementEnabled); + + String schemaPath = nonApplicationRootPathBuildItem.resolveManagementPath(openApiConfig.path, + managementInterfaceBuildTimeConfig, launchModeBuildItem, openApiConfig.managementEnabled); CardPageBuildItem cardPageBuildItem = new CardPageBuildItem(); cardPageBuildItem.addPage(Page.externalPageBuilder("Schema yaml") - .url(nonApplicationRootPathBuildItem.resolvePath(schemaPath)) + .url(schemaPath, schemaPath) .isYamlContent() .icon("font-awesome-solid:file-lines")); + String jsonSchema = schemaPath + "?format=json"; cardPageBuildItem.addPage(Page.externalPageBuilder("Schema json") - .url(nonApplicationRootPathBuildItem.resolvePath(schemaPath) + "?format=json") + .url(jsonSchema, jsonSchema) .isJsonContent() .icon("font-awesome-solid:file-code")); cardPageBuildItem.addPage(Page.externalPageBuilder("Swagger UI") - .url(uiPath + "/index.html?embed=true") - .staticLabel("") + .url(uiPath + "/index.html?embed=true", uiPath) .isHtmlContent() .icon("font-awesome-solid:signs-post")); diff --git a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/AutoServerFilter.java b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/AutoServerFilter.java index e7068f72a6e26..0519a91303139 100644 --- a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/AutoServerFilter.java +++ b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/filter/AutoServerFilter.java @@ -14,7 +14,6 @@ */ public class AutoServerFilter implements OASFilter { - private static final String DESCRIPTION = "Auto generated value"; private static final String HTTP = "http"; private static final String ZEROS = "0.0.0.0"; private static final String LOCALHOST = "localhost"; @@ -23,8 +22,9 @@ public class AutoServerFilter implements OASFilter { private final String defaultScheme; private final String defaultHost; private final int defaultPort; + private final String description; - public AutoServerFilter(String defaultScheme, String defaultHost, int defaultPort) { + public AutoServerFilter(String defaultScheme, String defaultHost, int defaultPort, String description) { if (defaultScheme == null) { defaultScheme = HTTP; } @@ -34,6 +34,7 @@ public AutoServerFilter(String defaultScheme, String defaultHost, int defaultPor this.defaultScheme = defaultScheme; this.defaultHost = defaultHost; this.defaultPort = defaultPort; + this.description = description; } @Override @@ -47,13 +48,13 @@ public void filterOpenAPI(OpenAPI openAPI) { if (this.defaultHost.equals(ZEROS)) { ServerImpl localhost = new ServerImpl(); localhost.setUrl(getUrl(this.defaultScheme, LOCALHOST, this.defaultPort)); - localhost.setDescription(DESCRIPTION); + localhost.setDescription(this.description); servers.add(localhost); } ServerImpl serverImpl = new ServerImpl(); serverImpl.setUrl(getUrl(this.defaultScheme, this.defaultHost, this.defaultPort)); - serverImpl.setDescription(DESCRIPTION); + serverImpl.setDescription(this.description); servers.add(serverImpl); openAPI.setServers(servers); diff --git a/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiProcessor.java b/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiProcessor.java index e04a0abb8e18d..46d7bc6a03dd3 100644 --- a/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiProcessor.java +++ b/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiProcessor.java @@ -120,6 +120,7 @@ public void getSwaggerUiFinalDestination( } String openApiPath = nonApplicationRootPathBuildItem.resolvePath(openapi.path); + String swaggerUiPath = nonApplicationRootPathBuildItem.resolvePath(swaggerUiConfig.path); ThemeHref theme = swaggerUiConfig.theme.orElse(ThemeHref.feeling_blue); @@ -180,6 +181,7 @@ public void registerSwaggerUiHandler(SwaggerUiRecorder recorder, runtimeConfig, shutdownContext); routes.produce(nonApplicationRootPathBuildItem.routeBuilder() + .management("quarkus.smallrye-openapi.management.enabled") .route(swaggerUiConfig.path) .displayOnNotFoundPage("Open API UI") .routeConfigKey("quarkus.swagger-ui.path") @@ -187,6 +189,7 @@ public void registerSwaggerUiHandler(SwaggerUiRecorder recorder, .build()); routes.produce(nonApplicationRootPathBuildItem.routeBuilder() + .management("quarkus.smallrye-openapi.management.enabled") .route(swaggerUiConfig.path + "*") .handler(handler) .build()); diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java index 451c50593da56..b5219b0166461 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpRootPathBuildItem.java @@ -224,6 +224,12 @@ public Builder management() { return this; } + @Override + public Builder management(String managementConfigKey) { + super.management(managementConfigKey); + return this; + } + @Override protected NotFoundPageDisplayableEndpointBuildItem getNotFoundEndpoint() { return super.getNotFoundEndpoint(); diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/NonApplicationRootPathBuildItem.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/NonApplicationRootPathBuildItem.java index 67ecf5846ef9a..1eea2aa28a267 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/NonApplicationRootPathBuildItem.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/NonApplicationRootPathBuildItem.java @@ -169,15 +169,15 @@ public String resolvePath(String path) { public String resolveManagementPath(String path, ManagementInterfaceBuildTimeConfig managementInterfaceBuildTimeConfig, LaunchModeBuildItem mode) { + return resolveManagementPath(path, managementInterfaceBuildTimeConfig, mode, true); + } + + public String resolveManagementPath(String path, ManagementInterfaceBuildTimeConfig managementInterfaceBuildTimeConfig, + LaunchModeBuildItem mode, boolean extensionOverride) { if (path == null || path.trim().isEmpty()) { throw new IllegalArgumentException("Specified path can not be empty"); } - if (!managementInterfaceBuildTimeConfig.enabled) { - if (managementRootPath != null) { - return UriNormalizationUtil.normalizeWithBase(managementRootPath, path, false).getPath(); - } - return UriNormalizationUtil.normalizeWithBase(nonApplicationRootPath, path, false).getPath(); - } else { + if (managementInterfaceBuildTimeConfig.enabled && extensionOverride) { // Best effort String prefix = getManagementUrlPrefix(mode); if (managementRootPath != null) { @@ -185,6 +185,11 @@ public String resolveManagementPath(String path, ManagementInterfaceBuildTimeCon } else { return prefix + path; } + } else { + if (managementRootPath != null) { + return UriNormalizationUtil.normalizeWithBase(managementRootPath, path, false).getPath(); + } + return UriNormalizationUtil.normalizeWithBase(nonApplicationRootPath, path, false).getPath(); } } @@ -411,6 +416,11 @@ public Builder management() { return this; } + @Override + public Builder management(String managementConfigKey) { + super.management(managementConfigKey); + return this; + } } /** diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RouteBuildItem.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RouteBuildItem.java index f4f985baee246..2fc29dad31396 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RouteBuildItem.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RouteBuildItem.java @@ -5,6 +5,9 @@ import java.util.function.Consumer; import java.util.function.Function; +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; + import io.quarkus.builder.item.MultiBuildItem; import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem; import io.quarkus.vertx.http.deployment.devmode.console.ConfiguredPathInfo; @@ -210,10 +213,23 @@ public Builder routeConfigKey(String attributeName) { } public Builder management() { - this.isManagement = true; + return management(null); + } + + public Builder management(String managementConfigKey) { + if (managementConfigKey == null || shouldInclude(managementConfigKey)) { + this.isManagement = true; + } else { + this.isManagement = false; + } return this; } + private boolean shouldInclude(String managementConfigKey) { + Config config = ConfigProvider.getConfig(); + return config.getValue(managementConfigKey, boolean.class); + } + public RouteBuildItem build() { if (routeFunction == null) { throw new IllegalStateException( diff --git a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-external-page.js b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-external-page.js index c0f99a61d2754..a0baff193e6c5 100644 --- a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-external-page.js +++ b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-external-page.js @@ -109,7 +109,7 @@ export class QwcExternalPage extends LitElement { let currentPath = window.location.pathname; currentPath = currentPath.substring(0, currentPath.indexOf('/dev')); return html`
- + Download diff --git a/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/ExternalPageBuilder.java b/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/ExternalPageBuilder.java index aad52ee93d1cb..cd778b554a81c 100644 --- a/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/ExternalPageBuilder.java +++ b/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/ExternalPageBuilder.java @@ -21,10 +21,18 @@ protected ExternalPageBuilder(String title) { } public ExternalPageBuilder url(String url) { + return url(url, null); + } + + public ExternalPageBuilder url(String url, String externalLink) { if (url == null || url.isEmpty()) { throw new RuntimeException("Invalid external URL, can not be empty"); } super.metadata.put(EXTERNAL_URL, url); + if (externalLink != null) { + return staticLabel(""); + } return this; }