diff --git a/extensions/kubernetes/spi/src/main/java/io/quarkus/kubernetes/spi/GeneratedKubernetesResourceBuildItem.java b/extensions/kubernetes/spi/src/main/java/io/quarkus/kubernetes/spi/GeneratedKubernetesResourceBuildItem.java new file mode 100644 index 0000000000000..dc1435449dc29 --- /dev/null +++ b/extensions/kubernetes/spi/src/main/java/io/quarkus/kubernetes/spi/GeneratedKubernetesResourceBuildItem.java @@ -0,0 +1,25 @@ +package io.quarkus.kubernetes.spi; + +import io.quarkus.builder.item.MultiBuildItem; + +/** + * Represents a resource generated by the quarkus-kubernetes extension + */ +public final class GeneratedKubernetesResourceBuildItem extends MultiBuildItem { + + private final String name; + private final byte[] content; + + public GeneratedKubernetesResourceBuildItem(String name, byte[] content) { + this.name = name; + this.content = content; + } + + public String getName() { + return name; + } + + public byte[] getContent() { + return content; + } +} 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 d9b05f5a4123a..9ef24d7a3a4c8 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 @@ -45,6 +45,7 @@ import io.quarkus.kubernetes.spi.ConfiguratorBuildItem; import io.quarkus.kubernetes.spi.CustomProjectRootBuildItem; import io.quarkus.kubernetes.spi.DecoratorBuildItem; +import io.quarkus.kubernetes.spi.GeneratedKubernetesResourceBuildItem; import io.quarkus.kubernetes.spi.KubernetesDeploymentTargetBuildItem; import io.quarkus.kubernetes.spi.KubernetesPortBuildItem; import io.quarkus.runtime.LaunchMode; @@ -91,7 +92,8 @@ public void build(ApplicationInfoBuildItem applicationInfo, List configurators, List decorators, Optional customProjectRoot, - BuildProducer generatedResourceProducer) { + BuildProducer generatedResourceProducer, + BuildProducer generatedKubernetesResourceProducer) { List allConfigurationRegistry = new ArrayList<>(configurators); List allDecorators = new ArrayList<>(decorators); @@ -169,6 +171,9 @@ public void build(ApplicationInfoBuildItem applicationInfo, Path targetPath = outputTarget.getOutputDirectory().resolve(KUBERNETES).resolve(fileName); String relativePath = targetPath.toAbsolutePath().toString().replace(root.toAbsolutePath().toString(), ""); + generatedKubernetesResourceProducer.produce(new GeneratedKubernetesResourceBuildItem(fileName, + resourceEntry.getValue().getBytes(StandardCharsets.UTF_8))); + if (fileName.endsWith(".yml") || fileName.endsWith(".json")) { String target = fileName.substring(0, fileName.lastIndexOf(".")); if (!deploymentTargets.contains(target)) { diff --git a/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/GeneratedKubernetesResourcesBuildItemTest.java b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/GeneratedKubernetesResourcesBuildItemTest.java new file mode 100644 index 0000000000000..13a08e3538c99 --- /dev/null +++ b/integration-tests/kubernetes/quarkus-standard-way/src/test/java/io/quarkus/it/kubernetes/GeneratedKubernetesResourcesBuildItemTest.java @@ -0,0 +1,86 @@ +package io.quarkus.it.kubernetes; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +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.quarkus.builder.BuildContext; +import io.quarkus.deployment.builditem.GeneratedResourceBuildItem; +import io.quarkus.kubernetes.spi.GeneratedKubernetesResourceBuildItem; +import io.quarkus.test.ProdBuildResults; +import io.quarkus.test.ProdModeTestBuildStep; +import io.quarkus.test.ProdModeTestResults; +import io.quarkus.test.QuarkusProdModeTest; + +public class GeneratedKubernetesResourcesBuildItemTest { + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClasses(GreetingResource.class)) + .setApplicationName("basic") + .setApplicationVersion("0.1-SNAPSHOT") + .addBuildChainCustomizerEntries(new QuarkusProdModeTest.BuildChainCustomizerEntry( + CustomGeneratedKubernetesResourcesHandler.class, + Collections.singletonList(GeneratedResourceBuildItem.class), + Collections.singletonList(GeneratedKubernetesResourceBuildItem.class))); + + @ProdBuildResults + private ProdModeTestResults prodModeTestResults; + + @Test + public void test() { + Path buildDir = prodModeTestResults.getBuildDir(); + assertThat(buildDir).isDirectory(); + Path quarkusAppDir = buildDir.resolve("quarkus-app"); + assertThat(quarkusAppDir).isDirectory(); + Path quarkusDir = quarkusAppDir.resolve("quarkus"); + assertThat(quarkusDir).isDirectory(); + Path generatedBytecodeJar = quarkusDir.resolve("generated-bytecode.jar"); + assertThat(generatedBytecodeJar).isRegularFile(); + try (JarFile jarFile = new JarFile(generatedBytecodeJar.toFile())) { + assertEntry(jarFile, "dummy-kubernetes.json"); + assertEntry(jarFile, "dummy-kubernetes.yml"); + } catch (IOException e) { + fail("Unable to verify contents of generated-bytecode jar file: " + e.getMessage()); + } + } + + private void assertEntry(JarFile jarFile, String name) { + JarEntry jarEntry = jarFile.getJarEntry(name); + if (jarEntry == null) { + fail(String.format("Unable to locate expected entry '%s' in generated-bytecode jar", name)); + } + } + + /** + * This simulates an extension using {@link GeneratedKubernetesResourceBuildItem}. + * It's testable because it writes the contents of each build item to the generate-bytecode jar. + */ + public static class CustomGeneratedKubernetesResourcesHandler extends ProdModeTestBuildStep { + + public CustomGeneratedKubernetesResourcesHandler(Map testContext) { + super(testContext); + } + + @Override + public void execute(BuildContext context) { + List k8sResources = context + .consumeMulti(GeneratedKubernetesResourceBuildItem.class); + for (GeneratedKubernetesResourceBuildItem bi : k8sResources) { + context.produce(new GeneratedResourceBuildItem("dummy-" + bi.getName(), bi.getContent())); + } + } + } +}