From 9453a08f94a4c427271b519fb28a738b50251795 Mon Sep 17 00:00:00 2001 From: jtama Date: Thu, 4 Jan 2024 14:43:32 +0100 Subject: [PATCH] Allow applications using quakus-info to contribute data to the /info at runtime --- docs/src/main/asciidoc/getting-started.adoc | 2 + .../info/deployment/InfoProcessor.java | 3 + .../src/main/resources/dev-ui/qwc-info.js | 48 ++++++++++++--- .../ExternalInfoContributorTest.java | 61 +++++++++++++++++++ .../io/quarkus/info/runtime/InfoRecorder.java | 6 ++ 5 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 extensions/info/deployment/src/test/java/io/quarkus/info/deployment/ExternalInfoContributorTest.java diff --git a/docs/src/main/asciidoc/getting-started.adoc b/docs/src/main/asciidoc/getting-started.adoc index 357fdafa2aeb5..83b5d1f3955d3 100644 --- a/docs/src/main/asciidoc/getting-started.adoc +++ b/docs/src/main/asciidoc/getting-started.adoc @@ -481,6 +481,8 @@ but users can also choose to expose one that might present a security risk under If the application contains the `quarkus-info` extension, then Quarkus will by default expose the `/q/info` endpoint which provides information about the build, java version, version control, and operating system. The level of detail of the exposed information is configurable. +All CDI beans implementing the `InfoContributor` will be picked up and their data will be append to the endpoint. + ==== Configuration Reference include::{generated-dir}/config/quarkus-info.adoc[opts=optional, leveloffset=+2] diff --git a/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java index 32762ff7f36ca..b87f5c19a4029 100644 --- a/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java +++ b/extensions/info/deployment/src/main/java/io/quarkus/info/deployment/InfoProcessor.java @@ -26,6 +26,7 @@ import org.jboss.logging.Logger; import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.arc.deployment.UnremovableBeanBuildItem; import io.quarkus.bootstrap.model.ApplicationModel; import io.quarkus.bootstrap.workspace.WorkspaceModule; import io.quarkus.builder.Version; @@ -274,6 +275,7 @@ RouteBuildItem defineRoute(InfoBuildTimeConfig buildTimeConfig, List buildTimeValues, List contributors, NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem, + BuildProducer unremovableBeanBuildItemBuildProducer, InfoRecorder recorder) { Map buildTimeInfo = buildTimeValues.stream().collect( Collectors.toMap(InfoBuildTimeValuesBuildItem::getName, InfoBuildTimeValuesBuildItem::getValue, (x, y) -> y, @@ -281,6 +283,7 @@ RouteBuildItem defineRoute(InfoBuildTimeConfig buildTimeConfig, List infoContributors = contributors.stream() .map(InfoBuildTimeContributorBuildItem::getInfoContributor) .collect(Collectors.toList()); + unremovableBeanBuildItemBuildProducer.produce(UnremovableBeanBuildItem.beanTypes(InfoContributor.class)); return nonApplicationRootPathBuildItem.routeBuilder() .management() .route(buildTimeConfig.path()) diff --git a/extensions/info/deployment/src/main/resources/dev-ui/qwc-info.js b/extensions/info/deployment/src/main/resources/dev-ui/qwc-info.js index a3f8d21476686..5ba4c71f05d00 100644 --- a/extensions/info/deployment/src/main/resources/dev-ui/qwc-info.js +++ b/extensions/info/deployment/src/main/resources/dev-ui/qwc-info.js @@ -54,7 +54,7 @@ export class QwcInfo extends LitElement { super.connectedCallback(); await this.load(); } - + async load() { const response = await fetch(this._infoUrl); const data = await response.json(); @@ -68,6 +68,7 @@ export class QwcInfo extends LitElement { ${this._renderJavaInfo(this._info)} ${this._renderBuildInfo(this._info)} ${this._renderGitInfo(this._info)} + ${this._renderExternalContributedInfo(this._info)} `; }else{ return html` @@ -78,7 +79,7 @@ export class QwcInfo extends LitElement { `; } } - + _renderOsInfo(info){ if(info.os){ let os = info.os; @@ -94,7 +95,7 @@ export class QwcInfo extends LitElement { `; } } - + _renderJavaInfo(info){ if(info.java){ let java = info.java; @@ -108,9 +109,9 @@ export class QwcInfo extends LitElement { `; } } - + _renderOsIcon(osname){ - + if(osname){ if(osname.toLowerCase().startsWith("linux")){ return html``; @@ -121,7 +122,7 @@ export class QwcInfo extends LitElement { } } } - + _renderGitInfo(info){ if(info.git){ let git = info.git; @@ -138,7 +139,7 @@ export class QwcInfo extends LitElement { `; } } - + _renderCommitId(git){ if(typeof git.commit.id === "string"){ return html`${git.commit.id}`; @@ -146,18 +147,18 @@ export class QwcInfo extends LitElement { return html`${git.commit.id.full}`; } } - + _renderOptionalData(git){ if(typeof git.commit.id !== "string"){ return html`Commit User${git.commit.user.name} <${git.commit.user.email}> Commit Message${unsafeHTML(this._replaceNewLine(git.commit.id.message.full))}` } } - + _replaceNewLine(line){ return line.replace(new RegExp('\r?\n','g'), '
'); } - + _renderBuildInfo(info){ if(info.build){ let build = info.build; @@ -173,5 +174,32 @@ export class QwcInfo extends LitElement { `; } } + + _renderExternalContributedInfo(info){ + const externalConstributors = Object.keys(info) + .filter(key => key !== 'build') + .filter(key => key !== 'os') + .filter(key => key !== 'git') + .filter(key => key !== 'java') + if(externalConstributors.length > 0){ + const cards = []; + externalConstributors.map(key => { + const extInfo = info[key]; + const rows = []; + for (const property of Object.keys(extInfo)){ + rows.push(html`${property}${extInfo[property]}`); + } + cards.push(html` +
+ + + ${rows} +
+
+
`); + }) + return html`${cards}`; + } + } } customElements.define('qwc-info', QwcInfo); \ No newline at end of file diff --git a/extensions/info/deployment/src/test/java/io/quarkus/info/deployment/ExternalInfoContributorTest.java b/extensions/info/deployment/src/test/java/io/quarkus/info/deployment/ExternalInfoContributorTest.java new file mode 100644 index 0000000000000..003c776304e72 --- /dev/null +++ b/extensions/info/deployment/src/test/java/io/quarkus/info/deployment/ExternalInfoContributorTest.java @@ -0,0 +1,61 @@ +package io.quarkus.info.deployment; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +import java.util.Map; + +import jakarta.enterprise.context.ApplicationScoped; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.deployment.AdditionalBeanBuildItem; +import io.quarkus.info.runtime.spi.InfoContributor; +import io.quarkus.test.QuarkusUnitTest; + +public class ExternalInfoContributorTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .addBuildChainCustomizer( + buildChainBuilder -> buildChainBuilder.addBuildStep( + context -> new AdditionalBeanBuildItem(TestInfoContributor.class)) + .produces(AdditionalBeanBuildItem.class) + .build()) + .withApplicationRoot((jar) -> jar + .addClasses(TestInfoContributor.class)); + + @Test + public void test() { + when().get("/q/info") + .then() + .statusCode(200) + .body("os", is(notNullValue())) + .body("os.name", is(notNullValue())) + .body("java", is(notNullValue())) + .body("java.version", is(notNullValue())) + .body("build", is(notNullValue())) + .body("build.time", is(notNullValue())) + .body("git", is(notNullValue())) + .body("git.branch", is(notNullValue())) + .body("test", is(notNullValue())) + .body("test.foo", is("bar")); + + } + + @ApplicationScoped + public static class TestInfoContributor implements InfoContributor { + + @Override + public String name() { + return "test"; + } + + @Override + public Map data() { + return Map.of("foo", "bar"); + } + } +} diff --git a/extensions/info/runtime/src/main/java/io/quarkus/info/runtime/InfoRecorder.java b/extensions/info/runtime/src/main/java/io/quarkus/info/runtime/InfoRecorder.java index 0cb67207f89a9..e589f7f341fa0 100644 --- a/extensions/info/runtime/src/main/java/io/quarkus/info/runtime/InfoRecorder.java +++ b/extensions/info/runtime/src/main/java/io/quarkus/info/runtime/InfoRecorder.java @@ -8,6 +8,8 @@ import java.util.Map; import java.util.function.Supplier; +import io.quarkus.arc.Arc; +import io.quarkus.arc.InstanceHandle; import io.quarkus.info.BuildInfo; import io.quarkus.info.GitInfo; import io.quarkus.info.JavaInfo; @@ -143,6 +145,10 @@ public InfoHandler(Map buildTimeInfo, List know // also, do we want to merge information or simply replace like we are doing here? finalBuildInfo.put(contributor.name(), contributor.data()); } + for (InstanceHandle handler : Arc.container().listAll(InfoContributor.class)) { + InfoContributor contributor = handler.get(); + finalBuildInfo.put(contributor.name(), contributor.data()); + } } @Override