This is an automated email from the ASF dual-hosted git repository.
jbonofre pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/karaf.git
The following commit(s) were added to refs/heads/main by this push:
new e637cf5232 Allow configuring base docker image in DockerfileMojo
(#2785) (#2839)
e637cf5232 is described below
commit e637cf523263542619a84ac56f0d4a505226e6cb
Author: gaurav kumar pandey <[email protected]>
AuthorDate: Sat Sep 12 23:01:54 2026 +0530
Allow configuring base docker image in DockerfileMojo (#2785) (#2839)
* Allow configuring base docker image in DockerfileMojo (#2785)
- Add configurable 'image' parameter to DockerfileMojo defaulting to
eclipse-temurin:11-jre
- Validate 'image' and 'command' parameters, falling back to defaults on
blank values and rejecting newlines
- Add DockerfileMojoTest covering default, custom, blank fallback, and
validation scenarios
- Strengthen test-dockerfile IT verification
- Update developer documentation with image and command parameters and fix
XML typo
* Address review feedback: bind command property and update docker example
---
examples/karaf-docker-example/README.md | 4 +-
.../karaf-docker-example-dynamic-dist/pom.xml | 1 +
.../karaf-docker-example-static-dist/pom.xml | 3 +
.../developer-guide/karaf-maven-plugin.adoc | 10 +-
.../src/it/test-dockerfile/verify.bsh | 8 +-
.../org/apache/karaf/tooling/DockerfileMojo.java | 23 ++-
.../apache/karaf/tooling/DockerfileMojoTest.java | 175 +++++++++++++++++++++
7 files changed, 217 insertions(+), 7 deletions(-)
diff --git a/examples/karaf-docker-example/README.md
b/examples/karaf-docker-example/README.md
index a57b3169e1..322e665423 100644
--- a/examples/karaf-docker-example/README.md
+++ b/examples/karaf-docker-example/README.md
@@ -123,7 +123,7 @@ You can build the docker image using the generated
`Dockerfile`:
$ cd karaf-docker-example-static-dist/target
$ docker build -t mykaraf .
Sending build context to Docker daemon 78.08MB
-Step 1/7 : FROM openjdk:8-jre
+Step 1/7 : FROM eclipse-temurin:17-jre
---> d60154a7d9b2
Step 2/7 : ENV KARAF_INSTALL_PATH /opt
---> Using cache
@@ -259,7 +259,7 @@ You can build the docker image using the generated
`Dockerfile`:
$ cd karaf-docker-example-dynamic-dist/target
$ docker build -t mykaraf .
Sending build context to Docker daemon 102.5MB
-Step 1/7 : FROM openjdk:8-jre
+Step 1/7 : FROM eclipse-temurin:17-jre
---> 19c48cc84cc6
Step 2/7 : ENV KARAF_INSTALL_PATH /opt
---> Running in 8a9a42db2395
diff --git
a/examples/karaf-docker-example/karaf-docker-example-dynamic-dist/pom.xml
b/examples/karaf-docker-example/karaf-docker-example-dynamic-dist/pom.xml
index 0d444b96cf..737f04e70c 100644
--- a/examples/karaf-docker-example/karaf-docker-example-dynamic-dist/pom.xml
+++ b/examples/karaf-docker-example/karaf-docker-example-dynamic-dist/pom.xml
@@ -101,6 +101,7 @@
<goal>dockerfile</goal>
</goals>
<configuration>
+ <image>eclipse-temurin:17-jre</image>
<command>["karaf"]</command>
</configuration>
</execution>
diff --git
a/examples/karaf-docker-example/karaf-docker-example-static-dist/pom.xml
b/examples/karaf-docker-example/karaf-docker-example-static-dist/pom.xml
index 6113f13009..962cb65914 100644
--- a/examples/karaf-docker-example/karaf-docker-example-static-dist/pom.xml
+++ b/examples/karaf-docker-example/karaf-docker-example-static-dist/pom.xml
@@ -96,6 +96,9 @@
<goals>
<goal>dockerfile</goal>
</goals>
+ <configuration>
+ <image>eclipse-temurin:17-jre</image>
+ </configuration>
</execution>
</executions>
<configuration>
diff --git a/manual/src/main/asciidoc/developer-guide/karaf-maven-plugin.adoc
b/manual/src/main/asciidoc/developer-guide/karaf-maven-plugin.adoc
index 47090ee60a..5b62598185 100644
--- a/manual/src/main/asciidoc/developer-guide/karaf-maven-plugin.adoc
+++ b/manual/src/main/asciidoc/developer-guide/karaf-maven-plugin.adoc
@@ -991,6 +991,14 @@ The `karaf:dockerfile` goal creates a ready to use
Dockerfile for a given Karaf
|`assembly`
|`File`
|The directory containing the Karaf assembly (as generated by
`karaf:assembly`). Default value: ${project.build.directory}/assembly
+
+|`command`
+|`String`
+|The CMD command instruction to include in the generated Dockerfile. Default
value: `["karaf", "run"]`
+
+|`image`
+|`String`
+|The base Docker image (FROM instruction) to use. Default value:
`eclipse-temurin:11-jre`
|===
===== Docker
@@ -1008,7 +1016,7 @@ This goal requires a local Docker daemon and runs only on
Unix. The `docker` com
<execution>
<id>docker</id>
<goals>
- <goal>docker</docker>
+ <goal>docker</goal>
</goals>
</execution>
----
diff --git a/tooling/karaf-maven-plugin/src/it/test-dockerfile/verify.bsh
b/tooling/karaf-maven-plugin/src/it/test-dockerfile/verify.bsh
index f42d4205c9..e96f658702 100644
--- a/tooling/karaf-maven-plugin/src/it/test-dockerfile/verify.bsh
+++ b/tooling/karaf-maven-plugin/src/it/test-dockerfile/verify.bsh
@@ -22,4 +22,10 @@ import java.lang.*;
import java.util.*;
File generated = new File(basedir, "target/Dockerfile");
-return generated.exists();
\ No newline at end of file
+if (!generated.exists()) {
+ return false;
+}
+BufferedReader reader = new BufferedReader(new FileReader(generated));
+String line = reader.readLine();
+reader.close();
+return line != null && line.startsWith("FROM eclipse-temurin:11-jre");
\ No newline at end of file
diff --git
a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/DockerfileMojo.java
b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/DockerfileMojo.java
index 83fa290cb7..b8d809e97f 100644
---
a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/DockerfileMojo.java
+++
b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/DockerfileMojo.java
@@ -31,29 +31,46 @@ import java.io.FileWriter;
@Mojo(name = "dockerfile", defaultPhase = LifecyclePhase.PACKAGE)
public class DockerfileMojo extends MojoSupport {
+ private static final String DEFAULT_IMAGE = "eclipse-temurin:11-jre";
+ private static final String DEFAULT_COMMAND = "[\"karaf\", \"run\"]";
+
@Parameter(defaultValue = "${project.build.directory}")
private File destDir;
@Parameter(defaultValue = "${project.build.directory}/assembly")
private File assembly;
- @Parameter(defaultValue = "[\"karaf\", \"run\"]")
+ @Parameter(defaultValue = DEFAULT_COMMAND, property = "command")
private String command;
+ @Parameter(defaultValue = DEFAULT_IMAGE, property = "image")
+ private String image;
+
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
getLog().info("Creating Dockerfile");
+
+ String baseImage = (image == null || image.trim().isEmpty()) ?
DEFAULT_IMAGE : image.trim();
+ String cmd = (command == null || command.trim().isEmpty()) ?
DEFAULT_COMMAND : command.trim();
+
+ if (baseImage.contains("\n") || baseImage.contains("\r")) {
+ throw new MojoExecutionException("Invalid image: base image cannot
contain newline characters");
+ }
+ if (cmd.contains("\n") || cmd.contains("\r")) {
+ throw new MojoExecutionException("Invalid command: command cannot
contain newline characters");
+ }
+
File dockerFile = new File(destDir, "Dockerfile");
try {
StringBuilder buffer = new StringBuilder();
- buffer.append("FROM eclipse-temurin:11-jre").append("\n");
+ buffer.append("FROM ").append(baseImage).append("\n");
buffer.append("ENV KARAF_INSTALL_PATH /opt").append("\n");
buffer.append("ENV KARAF_HOME
$KARAF_INSTALL_PATH/apache-karaf").append("\n");
buffer.append("ENV KARAF_EXEC exec").append("\n");
buffer.append("ENV PATH $PATH:$KARAF_HOME/bin").append("\n");
buffer.append("COPY ").append(assembly.getName()).append("
$KARAF_HOME").append("\n");
buffer.append("EXPOSE 8101 1099 44444 8181").append("\n");
- buffer.append("CMD ").append(command).append("\n");
+ buffer.append("CMD ").append(cmd).append("\n");
try (FileWriter writer = new FileWriter(dockerFile)) {
writer.write(buffer.toString());
}
diff --git
a/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/DockerfileMojoTest.java
b/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/DockerfileMojoTest.java
new file mode 100644
index 0000000000..15e52b7c1e
--- /dev/null
+++
b/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/DockerfileMojoTest.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.tooling;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.nio.file.Files;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class DockerfileMojoTest {
+
+ @Rule
+ public final TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Test
+ public void testDefaultDockerfileGeneration() throws Exception {
+ DockerfileMojo mojo = new DockerfileMojo();
+ File destDir = temporaryFolder.newFolder("target");
+ File assembly = new File(destDir, "assembly");
+
+ setPrivateField(mojo, "destDir", destDir);
+ setPrivateField(mojo, "assembly", assembly);
+ setPrivateField(mojo, "command", "[\"karaf\", \"run\"]");
+ setPrivateField(mojo, "image", "eclipse-temurin:11-jre");
+
+ mojo.execute();
+
+ File dockerfile = new File(destDir, "Dockerfile");
+ assertTrue("Dockerfile should be created", dockerfile.exists());
+
+ List<String> lines = Files.readAllLines(dockerfile.toPath());
+ assertEquals("FROM eclipse-temurin:11-jre", lines.get(0));
+ assertEquals("ENV KARAF_INSTALL_PATH /opt", lines.get(1));
+ assertEquals("ENV KARAF_HOME $KARAF_INSTALL_PATH/apache-karaf",
lines.get(2));
+ assertEquals("ENV KARAF_EXEC exec", lines.get(3));
+ assertEquals("ENV PATH $PATH:$KARAF_HOME/bin", lines.get(4));
+ assertEquals("COPY assembly $KARAF_HOME", lines.get(5));
+ assertEquals("EXPOSE 8101 1099 44444 8181", lines.get(6));
+ assertEquals("CMD [\"karaf\", \"run\"]", lines.get(7));
+ }
+
+ @Test
+ public void testCustomImageAndCommand() throws Exception {
+ DockerfileMojo mojo = new DockerfileMojo();
+ File destDir = temporaryFolder.newFolder("target-custom");
+ File assembly = new File(destDir, "custom-dist");
+
+ setPrivateField(mojo, "destDir", destDir);
+ setPrivateField(mojo, "assembly", assembly);
+ setPrivateField(mojo, "command", "[\"karaf\", \"server\"]");
+ setPrivateField(mojo, "image", "eclipse-temurin:17-jre");
+
+ mojo.execute();
+
+ File dockerfile = new File(destDir, "Dockerfile");
+ assertTrue("Dockerfile should be created", dockerfile.exists());
+
+ List<String> lines = Files.readAllLines(dockerfile.toPath());
+ assertEquals("FROM eclipse-temurin:17-jre", lines.get(0));
+ assertEquals("COPY custom-dist $KARAF_HOME", lines.get(5));
+ assertEquals("CMD [\"karaf\", \"server\"]", lines.get(7));
+ }
+
+ @Test
+ public void testBlankOrNullImageFallsBackToDefault() throws Exception {
+ String[] blankImages = new String[]{null, "", " "};
+ for (int i = 0; i < blankImages.length; i++) {
+ DockerfileMojo mojo = new DockerfileMojo();
+ File destDir = temporaryFolder.newFolder("target-blank-image-" +
i);
+ File assembly = new File(destDir, "assembly");
+
+ setPrivateField(mojo, "destDir", destDir);
+ setPrivateField(mojo, "assembly", assembly);
+ setPrivateField(mojo, "command", "[\"karaf\", \"run\"]");
+ setPrivateField(mojo, "image", blankImages[i]);
+
+ mojo.execute();
+
+ File dockerfile = new File(destDir, "Dockerfile");
+ assertTrue("Dockerfile should be created", dockerfile.exists());
+
+ List<String> lines = Files.readAllLines(dockerfile.toPath());
+ assertEquals("FROM eclipse-temurin:11-jre", lines.get(0));
+ }
+ }
+
+ @Test
+ public void testBlankOrNullCommandFallsBackToDefault() throws Exception {
+ String[] blankCommands = new String[]{null, "", " "};
+ for (int i = 0; i < blankCommands.length; i++) {
+ DockerfileMojo mojo = new DockerfileMojo();
+ File destDir = temporaryFolder.newFolder("target-blank-cmd-" + i);
+ File assembly = new File(destDir, "assembly");
+
+ setPrivateField(mojo, "destDir", destDir);
+ setPrivateField(mojo, "assembly", assembly);
+ setPrivateField(mojo, "command", blankCommands[i]);
+ setPrivateField(mojo, "image", "eclipse-temurin:11-jre");
+
+ mojo.execute();
+
+ File dockerfile = new File(destDir, "Dockerfile");
+ assertTrue("Dockerfile should be created", dockerfile.exists());
+
+ List<String> lines = Files.readAllLines(dockerfile.toPath());
+ assertEquals("CMD [\"karaf\", \"run\"]", lines.get(7));
+ }
+ }
+
+ @Test(expected = MojoExecutionException.class)
+ public void testImageWithNewlineThrowsException() throws Exception {
+ DockerfileMojo mojo = new DockerfileMojo();
+ File destDir = temporaryFolder.newFolder("target-nl-image");
+ File assembly = new File(destDir, "assembly");
+
+ setPrivateField(mojo, "destDir", destDir);
+ setPrivateField(mojo, "assembly", assembly);
+ setPrivateField(mojo, "command", "[\"karaf\", \"run\"]");
+ setPrivateField(mojo, "image", "eclipse-temurin:11-jre\nRUN rm -rf /");
+
+ mojo.execute();
+ }
+
+ @Test(expected = MojoExecutionException.class)
+ public void testCommandWithNewlineThrowsException() throws Exception {
+ DockerfileMojo mojo = new DockerfileMojo();
+ File destDir = temporaryFolder.newFolder("target-nl-cmd");
+ File assembly = new File(destDir, "assembly");
+
+ setPrivateField(mojo, "destDir", destDir);
+ setPrivateField(mojo, "assembly", assembly);
+ setPrivateField(mojo, "command", "[\"karaf\", \"run\"]\nRUN rm -rf /");
+ setPrivateField(mojo, "image", "eclipse-temurin:11-jre");
+
+ mojo.execute();
+ }
+
+ private void setPrivateField(Object obj, String fieldName, Object value)
throws Exception {
+ Class<?> aClass = obj.getClass();
+ while (aClass != null) {
+ try {
+ Field field = aClass.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ field.set(obj, value);
+ return;
+ } catch (final NoSuchFieldException nsfe) {
+ aClass = aClass.getSuperclass();
+ }
+ }
+ fail("cant set " + fieldName);
+ }
+}