diff --git a/extensions/kubernetes/vanilla/deployment/pom.xml b/extensions/kubernetes/vanilla/deployment/pom.xml index 73a0f7b24f3c24..b5d2048385d7a5 100644 --- a/extensions/kubernetes/vanilla/deployment/pom.xml +++ b/extensions/kubernetes/vanilla/deployment/pom.xml @@ -29,6 +29,10 @@ io.quarkus quarkus-kubernetes-client-deployment-internal + + io.quarkus + quarkus-smallrye-metrics-spi + io.dekorate kubernetes-annotations diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/Annotations.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/Annotations.java new file mode 100644 index 00000000000000..8a4844a13a8727 --- /dev/null +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/Annotations.java @@ -0,0 +1,19 @@ +package io.quarkus.kubernetes.deployment; + +final class Annotations { + + private Annotations() { + } + + static class Prometheus { + + private Prometheus() { + } + + private static final String PREFIX = "prometheus.io/"; + + static final String SCRAPE = PREFIX + "scrape"; + static final String PATH = PREFIX + "path"; + static final String PORT = PREFIX + "port"; + } +} diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesProcessor.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesProcessor.java index 81e47753c16453..15d1339ef95698 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesProcessor.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesProcessor.java @@ -55,7 +55,17 @@ import io.quarkus.deployment.pkg.PackageConfig; import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem; import io.quarkus.deployment.util.FileUtil; -import io.quarkus.kubernetes.spi.*; +import io.quarkus.kubernetes.deployment.Annotations.Prometheus; +import io.quarkus.kubernetes.spi.KubernetesAnnotationBuildItem; +import io.quarkus.kubernetes.spi.KubernetesCommandBuildItem; +import io.quarkus.kubernetes.spi.KubernetesDeploymentTargetBuildItem; +import io.quarkus.kubernetes.spi.KubernetesEnvBuildItem; +import io.quarkus.kubernetes.spi.KubernetesHealthLivenessPathBuildItem; +import io.quarkus.kubernetes.spi.KubernetesHealthReadinessPathBuildItem; +import io.quarkus.kubernetes.spi.KubernetesLabelBuildItem; +import io.quarkus.kubernetes.spi.KubernetesPortBuildItem; +import io.quarkus.kubernetes.spi.KubernetesRoleBuildItem; +import io.quarkus.smallrye.metrics.deployment.spi.MetricsConfigurationBuildItem; class KubernetesProcessor { @@ -118,12 +128,28 @@ public EnabledKubernetesDeploymentTargetsBuildItem enabledKubernetesDeploymentTa @BuildStep public List createAnnotations(KubernetesConfig kubernetesConfig, - OpenshiftConfig openshiftConfig, KnativeConfig knativeConfig) { - List items = new ArrayList(); - kubernetesConfig.annotations.forEach((k, v) -> items.add(new KubernetesAnnotationBuildItem(k, v, KUBERNETES))); - openshiftConfig.annotations.forEach((k, v) -> items.add(new KubernetesAnnotationBuildItem(k, v, OPENSHIFT))); - knativeConfig.annotations.forEach((k, v) -> items.add(new KubernetesAnnotationBuildItem(k, v, KNATIVE))); - return items; + OpenshiftConfig openshiftConfig, KnativeConfig knativeConfig, + Optional metricsConfiguration, List kubernetesPorts) { + List result = new ArrayList(); + addAnnotations(kubernetesConfig, KUBERNETES, metricsConfiguration, kubernetesPorts, result); + addAnnotations(openshiftConfig, OPENSHIFT, metricsConfiguration, kubernetesPorts, result); + addAnnotations(knativeConfig, KNATIVE, metricsConfiguration, kubernetesPorts, result); + return result; + } + + private void addAnnotations(PlatformConfiguration config, String target, + Optional metricsConfigurationBuildItem, + List kubernetesPorts, + List result) { + for (Map.Entry entry : config.getAnnotations().entrySet()) { + result.add(new KubernetesAnnotationBuildItem(entry.getKey(), entry.getValue(), target)); + } + if (metricsConfigurationBuildItem.isPresent() && !kubernetesPorts.isEmpty()) { + result.add(new KubernetesAnnotationBuildItem(Prometheus.SCRAPE, "true", target)); + result.add(new KubernetesAnnotationBuildItem(Prometheus.PATH, metricsConfigurationBuildItem.get().getPath(), + target)); + result.add(new KubernetesAnnotationBuildItem(Prometheus.PORT, "" + kubernetesPorts.get(0).getPort(), target)); + } } @BuildStep diff --git a/extensions/smallrye-metrics/deployment/src/main/java/io/quarkus/smallrye/metrics/deployment/SmallRyeMetricsProcessor.java b/extensions/smallrye-metrics/deployment/src/main/java/io/quarkus/smallrye/metrics/deployment/SmallRyeMetricsProcessor.java index a2701061f6fc85..0e36f87a851ddd 100644 --- a/extensions/smallrye-metrics/deployment/src/main/java/io/quarkus/smallrye/metrics/deployment/SmallRyeMetricsProcessor.java +++ b/extensions/smallrye-metrics/deployment/src/main/java/io/quarkus/smallrye/metrics/deployment/SmallRyeMetricsProcessor.java @@ -70,6 +70,7 @@ import io.quarkus.smallrye.metrics.deployment.jandex.JandexBeanInfoAdapter; import io.quarkus.smallrye.metrics.deployment.jandex.JandexMemberInfoAdapter; import io.quarkus.smallrye.metrics.deployment.spi.MetricBuildItem; +import io.quarkus.smallrye.metrics.deployment.spi.MetricsConfigurationBuildItem; import io.quarkus.smallrye.metrics.runtime.MetadataHolder; import io.quarkus.smallrye.metrics.runtime.SmallRyeMetricsRecorder; import io.quarkus.smallrye.metrics.runtime.TagHolder; @@ -123,6 +124,11 @@ static final class SmallRyeMetricsConfig { SmallRyeMetricsConfig metrics; + @BuildStep + MetricsConfigurationBuildItem metricsConfigurationBuildItem() { + return new MetricsConfigurationBuildItem(metrics.path); + } + @BuildStep @Record(STATIC_INIT) void createRoute(BuildProducer routes, diff --git a/extensions/smallrye-metrics/spi/src/main/java/io/quarkus/smallrye/metrics/deployment/spi/MetricsConfigurationBuildItem.java b/extensions/smallrye-metrics/spi/src/main/java/io/quarkus/smallrye/metrics/deployment/spi/MetricsConfigurationBuildItem.java new file mode 100644 index 00000000000000..7c8f434871cb0a --- /dev/null +++ b/extensions/smallrye-metrics/spi/src/main/java/io/quarkus/smallrye/metrics/deployment/spi/MetricsConfigurationBuildItem.java @@ -0,0 +1,19 @@ +package io.quarkus.smallrye.metrics.deployment.spi; + +import io.quarkus.builder.item.SimpleBuildItem; + +/** + * A build item that can be used by build steps that need to know the metrics configuration + */ +public final class MetricsConfigurationBuildItem extends SimpleBuildItem { + + private final String path; + + public MetricsConfigurationBuildItem(String path) { + this.path = path; + } + + public String getPath() { + return path; + } +} diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithMetricsTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithMetricsTest.java new file mode 100644 index 00000000000000..794ba83f501e0e --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithMetricsTest.java @@ -0,0 +1,83 @@ +package io.quarkus.it.kubernetes; + +import static io.restassured.RestAssured.given; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.quarkus.bootstrap.model.AppArtifact; +import io.quarkus.builder.Version; +import io.quarkus.test.LogFile; +import io.quarkus.test.ProdBuildResults; +import io.quarkus.test.ProdModeTestResults; +import io.quarkus.test.QuarkusProdModeTest; + +public class KubernetesWithMetricsTest { + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClasses(GreetingResource.class)) + .setApplicationName("health") + .setApplicationVersion("0.1-SNAPSHOT") + .setRun(true) + .setLogFileName("k8s.log") + .withConfigurationResource("kubernetes-with-metrics.properties") + .setForcedDependencies( + Collections.singletonList( + new AppArtifact("io.quarkus", "quarkus-smallrye-metrics", Version.getVersion()))); + + @ProdBuildResults + private ProdModeTestResults prodModeTestResults; + + @LogFile + private Path logfile; + + @Test + public void assertApplicationRuns() { + assertThat(logfile).isRegularFile().hasFileName("k8s.log"); + TestUtil.assertLogFileContents(logfile, "kubernetes", "metrics"); + + given() + .when().get("/greeting") + .then() + .statusCode(200) + .body(is("hello")); + } + + @Test + public void assertGeneratedResources() throws IOException { + final Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes"); + assertThat(kubernetesDir) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.json")) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.yml")); + List kubernetesList = DeserializationUtil + .deserializeAsList(kubernetesDir.resolve("kubernetes.yml")); + assertThat(kubernetesList.get(0)).isInstanceOfSatisfying(Deployment.class, d -> { + assertThat(d.getMetadata()).satisfies(m -> { + assertThat(m.getName()).isEqualTo("health"); + }); + + assertThat(d.getSpec()).satisfies(deploymentSpec -> { + assertThat(deploymentSpec.getTemplate()).satisfies(t -> { + assertThat(t.getMetadata()).satisfies(meta -> { + assertThat(meta.getAnnotations()).contains(entry("prometheus.io/scrape", "true"), + entry("prometheus.io/path", "/met"), entry("prometheus.io/port", "9090")); + }); + }); + }); + }); + } + +} diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-metrics.properties b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-metrics.properties new file mode 100644 index 00000000000000..a6e7232a4984b4 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/resources/kubernetes-with-metrics.properties @@ -0,0 +1,2 @@ +quarkus.http.port=9090 +quarkus.smallrye-metrics.path=/met