Skip to content

Commit

Permalink
Allow mandrel and graalvm as values of `quarkus.native.builder-im…
Browse files Browse the repository at this point in the history
…age`

This change makes it easier for developers to choose the variant of the
builder image they want to use without having to worry about which
version is the currently supported one. Quarkus will figure that out on
their behalf.

Closes quarkusio#18129
  • Loading branch information
zakkak committed Jan 24, 2022
1 parent 350aecf commit c353844
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 9 deletions.
2 changes: 1 addition & 1 deletion build-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
<forbiddenapis-maven-plugin.version>3.1</forbiddenapis-maven-plugin.version>

<!-- platform properties - this is a floating tag -->
<platform.quarkus.native.builder-image>quay.io/quarkus/ubi-quarkus-native-image:21.3-java11</platform.quarkus.native.builder-image>
<platform.quarkus.native.builder-image>graalvm</platform.quarkus.native.builder-image>

<script.extension>sh</script.extension>
<docker-prune.location>${maven.multiModuleProjectDirectory}/.github/docker-prune.${script.extension}</docker-prune.location>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
public class NativeConfig {

public static final String DEFAULT_GRAALVM_BUILDER_IMAGE = "quay.io/quarkus/ubi-quarkus-native-image:21.3-java11";
public static final String DEFAULT_MANDREL_BUILDER_IMAGE = "quay.io/quarkus/ubi-quarkus-mandrel:21.3-java11";

/**
* Comma-separated, additional arguments to pass to the build process.
* If an argument includes the {@code ,} symbol, it needs to be escaped, e.g. {@code \\,}
Expand Down Expand Up @@ -195,11 +198,23 @@ public boolean isContainerBuild() {
}

/**
* The docker image to use to do the image build
* The docker image to use to do the image build. It can be one of `graalvm`, `mandrel`, or the full image path, e.g.
* {@code quay.io/quarkus/ubi-quarkus-mandrel:21.3-java17}.
*/
@ConfigItem(defaultValue = "${platform.quarkus.native.builder-image}")
public String builderImage;

public String getEffectiveBuilderImage() {
final String builderImageName = this.builderImage.toUpperCase();
if (builderImageName.equals(BuilderImageProvider.GRAALVM.name())) {
return DEFAULT_GRAALVM_BUILDER_IMAGE;
} else if (builderImageName.equals(BuilderImageProvider.MANDREL.name())) {
return DEFAULT_MANDREL_BUILDER_IMAGE;
} else {
return this.builderImage;
}
}

/**
* The container runtime (e.g. docker) that is used to do an image based build. If this is set then
* a container build is always done.
Expand Down Expand Up @@ -429,4 +444,12 @@ public String getExecutableName() {
return this.name().toLowerCase();
}
}

/**
* Supported Builder Image providers/distributions
*/
public static enum BuilderImageProvider {
GRAALVM,
MANDREL;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ public void setup(boolean processInheritIODisabled) {
// we pull the docker image in order to give users an indication of which step the process is at
// it's not strictly necessary we do this, however if we don't the subsequent version command
// will appear to block and no output will be shown
log.info("Checking image status " + nativeConfig.builderImage);
log.info("Checking image status " + nativeConfig.getEffectiveBuilderImage());
Process pullProcess = null;
try {
final ProcessBuilder pb = new ProcessBuilder(
Arrays.asList(containerRuntime.getExecutableName(), "pull", nativeConfig.builderImage));
Arrays.asList(containerRuntime.getExecutableName(), "pull", nativeConfig.getEffectiveBuilderImage()));
pullProcess = ProcessUtil.launchProcess(pb, processInheritIODisabled);
pullProcess.waitFor();
} catch (IOException | InterruptedException e) {
throw new RuntimeException("Failed to pull builder image " + nativeConfig.builderImage, e);
throw new RuntimeException("Failed to pull builder image " + nativeConfig.getEffectiveBuilderImage(), e);
} finally {
if (pullProcess != null) {
pullProcess.destroy();
Expand Down Expand Up @@ -121,7 +121,7 @@ protected List<String> getContainerRuntimeBuildArgs() {
protected String[] buildCommand(String dockerCmd, List<String> containerRuntimeArgs, List<String> command) {
return Stream
.of(Stream.of(containerRuntime.getExecutableName()), Stream.of(dockerCmd), Stream.of(baseContainerRuntimeArgs),
containerRuntimeArgs.stream(), Stream.of(nativeConfig.builderImage), command.stream())
containerRuntimeArgs.stream(), Stream.of(nativeConfig.getEffectiveBuilderImage()), command.stream())
.flatMap(Function.identity()).toArray(String[]::new);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void compress(NativeConfig nativeConfig, NativeImageBuildItem image,
throw new IllegalStateException("Unable to compress the native executable");
}
} else if (nativeConfig.isContainerBuild()) {
log.infof("Running UPX from a container using the builder image: " + nativeConfig.builderImage);
log.infof("Running UPX from a container using the builder image: " + nativeConfig.getEffectiveBuilderImage());
if (!runUpxInContainer(image, nativeConfig)) {
throw new IllegalStateException("Unable to compress the native executable");
}
Expand Down Expand Up @@ -131,7 +131,7 @@ private boolean runUpxInContainer(NativeImageBuildItem nativeImage, NativeConfig
Collections.addAll(commandLine, "-v",
volumeOutputPath + ":" + NativeImageBuildStep.CONTAINER_BUILD_VOLUME_PATH + ":z");

commandLine.add(nativeConfig.builderImage);
commandLine.add(nativeConfig.getEffectiveBuilderImage());
commandLine.add(level);
commandLine.addAll(extraArgs);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.quarkus.deployment.pkg;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;

class NativeConfigTest {

@Test
public void testBuilderImageProperlyDetected() {
NativeConfig nativeConfig = new NativeConfig();
nativeConfig.builderImage = "graalvm";
assertThat(nativeConfig.getEffectiveBuilderImage().contains("ubi-quarkus-native-image")).isTrue();
nativeConfig.builderImage = "GraalVM";
assertThat(nativeConfig.getEffectiveBuilderImage().contains("ubi-quarkus-native-image")).isTrue();
nativeConfig.builderImage = "GRAALVM";
assertThat(nativeConfig.getEffectiveBuilderImage().contains("ubi-quarkus-native-image")).isTrue();
nativeConfig.builderImage = "mandrel";
assertThat(nativeConfig.getEffectiveBuilderImage().contains("ubi-quarkus-mandrel")).isTrue();
nativeConfig.builderImage = "Mandrel";
assertThat(nativeConfig.getEffectiveBuilderImage().contains("ubi-quarkus-mandrel")).isTrue();
nativeConfig.builderImage = "MANDREL";
assertThat(nativeConfig.getEffectiveBuilderImage().contains("ubi-quarkus-mandrel")).isTrue();
nativeConfig.builderImage = "aRandomString";
assertThat(nativeConfig.getEffectiveBuilderImage().contains("aRandomString")).isTrue();
nativeConfig.builderImage = "aRandomStr32ng";
assertThat(nativeConfig.getEffectiveBuilderImage().contains("aRandomString")).isFalse();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.quarkus.deployment.pkg.steps;

import static org.assertj.core.api.Assertions.assertThat;

import java.nio.file.Path;
import java.util.Collections;
import java.util.Optional;

import org.junit.jupiter.api.Test;

import io.quarkus.deployment.pkg.NativeConfig;

class NativeImageBuildContainerRunnerTest {

@Test
void testBuilderImageBeingPickedUp() {
NativeConfig nativeConfig = new NativeConfig();
nativeConfig.containerRuntime = Optional.empty();
boolean found;
NativeImageBuildLocalContainerRunner localRunner;
String[] command;

nativeConfig.builderImage = "graalvm";
localRunner = new NativeImageBuildLocalContainerRunner(nativeConfig, Path.of("/tmp"));
command = localRunner.buildCommand("docker", Collections.emptyList(), Collections.emptyList());
found = false;
for (String part : command) {
if (part.contains("ubi-quarkus-native-image")) {
found = true;
}
}
assertThat(found).isTrue();

nativeConfig.builderImage = "mandrel";
localRunner = new NativeImageBuildLocalContainerRunner(nativeConfig, Path.of("/tmp"));
command = localRunner.buildCommand("docker", Collections.emptyList(), Collections.emptyList());
found = false;
for (String part : command) {
if (part.contains("ubi-quarkus-mandrel")) {
found = true;
}
}
assertThat(found).isTrue();

nativeConfig.builderImage = "RandomString";
localRunner = new NativeImageBuildLocalContainerRunner(nativeConfig, Path.of("/tmp"));
command = localRunner.buildCommand("docker", Collections.emptyList(), Collections.emptyList());
found = false;
for (String part : command) {
if (part.equals("RandomString")) {
found = true;
}
}
assertThat(found).isTrue();
}
}
2 changes: 1 addition & 1 deletion docs/src/main/asciidoc/platform.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public class NativeConfig {
----

In this case the default value for `quarkus.native.builder-image` will be provided by the platform. The user will still be able to set the desired value for `quarkus.native.builder-image` in its `application.properties`, of course. But in case it's not customized by the user, the default value will be coming from the platform properties.
A platform properties file for the example above would contain (the actual value is provided as an example):
A platform properties file for the example above would contain:

[source,text,subs=attributes+]
----
Expand Down

0 comments on commit c353844

Please sign in to comment.