Skip to content

Commit

Permalink
Container Image Docker: uses Core autodetection too
Browse files Browse the repository at this point in the history
  • Loading branch information
Karm committed Mar 16, 2023
1 parent 781eb53 commit ea1728b
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.stream.Collectors;

Expand All @@ -16,7 +17,7 @@
public final class ContainerRuntimeUtil {

private static final Logger log = Logger.getLogger(ContainerRuntimeUtil.class);
private static final String DOCKER_EXECUTABLE = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class)
private static final String CONTAINER_EXECUTABLE = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class)
.getOptionalValue("quarkus.native.container-runtime", String.class).orElse(null);

/**
Expand Down Expand Up @@ -51,16 +52,16 @@ public static ContainerRuntime detectContainerRuntime(boolean required) {
// podman version 2.1.1
String podmanVersionOutput;
boolean podmanAvailable;
if (DOCKER_EXECUTABLE != null) {
if (DOCKER_EXECUTABLE.trim().equalsIgnoreCase("docker")) {
if (CONTAINER_EXECUTABLE != null) {
if (CONTAINER_EXECUTABLE.trim().equalsIgnoreCase("docker")) {
dockerVersionOutput = getVersionOutputFor(ContainerRuntime.DOCKER);
dockerAvailable = dockerVersionOutput.contains("Docker version");
if (dockerAvailable) {
storeConfig(ContainerRuntime.DOCKER);
return ContainerRuntime.DOCKER;
}
}
if (DOCKER_EXECUTABLE.trim().equalsIgnoreCase("podman")) {
if (CONTAINER_EXECUTABLE.trim().equalsIgnoreCase("podman")) {
podmanVersionOutput = getVersionOutputFor(ContainerRuntime.PODMAN);
podmanAvailable = podmanVersionOutput.startsWith("podman version");
if (podmanAvailable) {
Expand Down Expand Up @@ -125,8 +126,14 @@ private static String getVersionOutputFor(ContainerRuntime containerRuntime) {
final ProcessBuilder pb = new ProcessBuilder(containerRuntime.getExecutableName(), "--version")
.redirectErrorStream(true);
versionProcess = pb.start();
versionProcess.waitFor();
return new String(versionProcess.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
final int timeoutS = 10;
if (versionProcess.waitFor(timeoutS, TimeUnit.SECONDS)) {
return new String(versionProcess.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
} else {
log.debugf("Failure. It took command %s more than %d seconds to execute.", containerRuntime.getExecutableName(),
timeoutS);
return "";
}
} catch (IOException | InterruptedException e) {
// If an exception is thrown in the process, just return an empty String
log.debugf(e, "Failure to read version output from %s", containerRuntime.getExecutableName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ public class DockerConfig {

/**
* Name of binary used to execute the docker commands.
* This setting can override the global container runtime detection.
*/
@ConfigItem(defaultValue = "docker")
public String executableName;
@ConfigItem
public Optional<String> executableName;

/**
* Configuration for Docker Buildx options
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static io.quarkus.container.image.deployment.util.EnablementUtil.buildContainerImageNeeded;
import static io.quarkus.container.image.deployment.util.EnablementUtil.pushContainerImageNeeded;
import static io.quarkus.container.util.PathsUtil.findMainSourcesRoot;
import static io.quarkus.runtime.util.ContainerRuntimeUtil.detectContainerRuntime;

import java.io.BufferedReader;
import java.io.IOException;
Expand Down Expand Up @@ -87,9 +88,10 @@ public void dockerBuildFromJar(DockerConfig dockerConfig,
throw new RuntimeException("Unable to build docker image. Please check your docker installation");
}

var dockerfilePaths = getDockerfilePaths(dockerConfig, false, packageConfig, out);
var dockerFileBaseInformationProvider = DockerFileBaseInformationProvider.impl();
var dockerFileBaseInformation = dockerFileBaseInformationProvider.determine(dockerfilePaths.getDockerfilePath());
DockerfilePaths dockerfilePaths = getDockerfilePaths(dockerConfig, false, packageConfig, out);
DockerFileBaseInformationProvider dockerFileBaseInformationProvider = DockerFileBaseInformationProvider.impl();
Optional<DockerFileBaseInformationProvider.DockerFileBaseInformation> dockerFileBaseInformation = dockerFileBaseInformationProvider
.determine(dockerfilePaths.getDockerfilePath());

if ((compiledJavaVersion.getJavaVersion().isJava17OrHigher() == CompiledJavaVersionBuildItem.JavaVersion.Status.TRUE)
&& dockerFileBaseInformation.isPresent() && (dockerFileBaseInformation.get().getJavaVersion() < 17)) {
Expand Down Expand Up @@ -168,11 +170,11 @@ private String createContainerImage(ContainerImageConfig containerImageConfig, D
boolean pushContainerImage,
PackageConfig packageConfig) {

var useBuildx = dockerConfig.buildx.useBuildx();
boolean useBuildx = dockerConfig.buildx.useBuildx();

// useBuildx: Whether or not any of the buildx parameters are set
// useBuildx: Whether any of the buildx parameters are set
//
// pushImages: Whether or not the user requested the built images to be pushed to a registry
// pushImages: Whether the user requested the built images to be pushed to a registry
// Pushing images is different based on if you're using buildx or not.
// If not using any of the buildx params (useBuildx == false), then the flow is as it was before:
//
Expand All @@ -196,9 +198,10 @@ private String createContainerImage(ContainerImageConfig containerImageConfig, D
}

if (buildContainerImage) {
log.infof("Executing the following command to build docker image: '%s %s'", dockerConfig.executableName,
final String executableName = dockerConfig.executableName.orElse(detectContainerRuntime(true).getExecutableName());
log.infof("Executing the following command to build docker image: '%s %s'", executableName,
String.join(" ", dockerArgs));
boolean buildSuccessful = ExecUtil.exec(out.getOutputDirectory().toFile(), reader, dockerConfig.executableName,
boolean buildSuccessful = ExecUtil.exec(out.getOutputDirectory().toFile(), reader, executableName,
dockerArgs);
if (!buildSuccessful) {
throw dockerException(dockerArgs);
Expand Down Expand Up @@ -234,15 +237,16 @@ private String createContainerImage(ContainerImageConfig containerImageConfig, D

private void loginToRegistryIfNeeded(ContainerImageConfig containerImageConfig,
ContainerImageInfoBuildItem containerImageInfo, DockerConfig dockerConfig) {
var registry = containerImageInfo.getRegistry()
String registry = containerImageInfo.getRegistry()
.orElseGet(() -> {
log.info("No container image registry was set, so 'docker.io' will be used");
return "docker.io";
});

// Check if we need to login first
if (containerImageConfig.username.isPresent() && containerImageConfig.password.isPresent()) {
boolean loginSuccessful = ExecUtil.exec(dockerConfig.executableName, "login", registry, "-u",
final String executableName = dockerConfig.executableName.orElse(detectContainerRuntime(true).getExecutableName());
boolean loginSuccessful = ExecUtil.exec(executableName, "login", registry, "-u",
containerImageConfig.username.get(),
"-p" + containerImageConfig.password.get());
if (!loginSuccessful) {
Expand All @@ -254,15 +258,17 @@ private void loginToRegistryIfNeeded(ContainerImageConfig containerImageConfig,
private String[] getDockerArgs(String image, DockerfilePaths dockerfilePaths, ContainerImageConfig containerImageConfig,
DockerConfig dockerConfig, ContainerImageInfoBuildItem containerImageInfo, boolean pushImages) {
List<String> dockerArgs = new ArrayList<>(6 + dockerConfig.buildArgs.size());
var useBuildx = dockerConfig.buildx.useBuildx();
boolean useBuildx = dockerConfig.buildx.useBuildx();

if (useBuildx) {
final String executableName = dockerConfig.executableName.orElse(detectContainerRuntime(true).getExecutableName());
// Check the executable. If not 'docker', then fail the build
if (!DOCKER.equals(dockerConfig.executableName)) {
if (!DOCKER.equals(executableName)) {
throw new IllegalArgumentException(
String.format(
"The 'buildx' properties are specific to 'executable-name=docker' and can not be used with the '%s' executable name. Either remove the `buildx` properties or the `executable-name` property.",
dockerConfig.executableName));
"The 'buildx' properties are specific to 'executable-name=docker' and can not be used with " +
"the '%s' executable name. Either remove the `buildx` properties or the `executable-name` property.",
executableName));
}

dockerArgs.add("buildx");
Expand Down Expand Up @@ -315,18 +321,20 @@ private String[] getDockerArgs(String image, DockerfilePaths dockerfilePaths, Co
}

private void createAdditionalTags(String image, List<String> additionalImageTags, DockerConfig dockerConfig) {
final String executableName = dockerConfig.executableName.orElse(detectContainerRuntime(true).getExecutableName());
for (String additionalTag : additionalImageTags) {
String[] tagArgs = { "tag", image, additionalTag };
boolean tagSuccessful = ExecUtil.exec(dockerConfig.executableName, tagArgs);
boolean tagSuccessful = ExecUtil.exec(executableName, tagArgs);
if (!tagSuccessful) {
throw dockerException(tagArgs);
}
}
}

private void pushImage(String image, DockerConfig dockerConfig) {
final String executableName = dockerConfig.executableName.orElse(detectContainerRuntime(true).getExecutableName());
String[] pushArgs = { "push", image };
boolean pushSuccessful = ExecUtil.exec(dockerConfig.executableName, pushArgs);
boolean pushSuccessful = ExecUtil.exec(executableName, pushArgs);
if (!pushSuccessful) {
throw dockerException(pushArgs);
}
Expand Down Expand Up @@ -464,7 +472,7 @@ public static ProvidedDockerfile get(Path dockerfilePath, Path outputDirectory)
: mainSourcesRoot.getValue().resolve(dockerfilePath);
if (!effectiveDockerfilePath.toFile().exists()) {
throw new IllegalArgumentException(
"Specified Dockerfile path " + effectiveDockerfilePath.toAbsolutePath().toString() + " does not exist");
"Specified Dockerfile path " + effectiveDockerfilePath.toAbsolutePath() + " does not exist");
}
return new ProvidedDockerfile(
effectiveDockerfilePath,
Expand Down

0 comments on commit ea1728b

Please sign in to comment.