From 656d8a95662db5f491fa4a90f62e4caeb50954cf Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 8 Jun 2021 09:05:01 +0300 Subject: [PATCH] Pull docker image when necessary for @QuarkusIntegrationTest Fixes: #17730 --- .../docker/deployment/DockerProcessor.java | 10 +++++-- .../image/jib/deployment/JibProcessor.java | 16 +++++++---- .../test/common/DockerContainerLauncher.java | 28 +++++++++++++++---- .../QuarkusIntegrationTestExtension.java | 4 ++- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerProcessor.java b/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerProcessor.java index 183064e35b7de..e2afb940d65e5 100644 --- a/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerProcessor.java +++ b/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerProcessor.java @@ -13,7 +13,6 @@ import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -87,8 +86,10 @@ public void dockerBuildFromJar(DockerConfig dockerConfig, false, pushRequest.isPresent(), packageConfig); + // a pull is not required when using this image locally because the docker strategy always builds the container image + // locally before pushing it to the registry artifactResultProducer.produce(new ArtifactResultBuildItem(null, "jar-container", - Collections.singletonMap("container-image", builtContainerImage))); + Map.of("container-image", builtContainerImage, "pull-required", "false"))); } @BuildStep(onlyIf = { IsNormalNotRemoteDev.class, NativeBuild.class, DockerBuild.class }) @@ -122,8 +123,11 @@ public void dockerBuildFromNativeImage(DockerConfig dockerConfig, ImageIdReader reader = new ImageIdReader(); String builtContainerImage = createContainerImage(containerImageConfig, dockerConfig, containerImage, out, reader, true, pushRequest.isPresent(), packageConfig); + + // a pull is not required when using this image locally because the docker strategy always builds the container image + // locally before pushing it to the registry artifactResultProducer.produce(new ArtifactResultBuildItem(null, "native-container", - Collections.singletonMap("container-image", builtContainerImage))); + Map.of("container-image", builtContainerImage, "pull-required", "false"))); } private String createContainerImage(ContainerImageConfig containerImageConfig, DockerConfig dockerConfig, diff --git a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java index 7a61648d0afb6..674e74cb59e59 100644 --- a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java +++ b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java @@ -108,8 +108,9 @@ public void buildFromJar(ContainerImageConfig containerImageConfig, JibConfig ji Optional appCDSResult, BuildProducer artifactResultProducer) { - if (!containerImageConfig.build && !containerImageConfig.push && !buildRequest.isPresent() - && !pushRequest.isPresent()) { + Boolean buildContainerImage = containerImageConfig.build || buildRequest.isPresent(); + Boolean pushContainerImage = containerImageConfig.push || pushRequest.isPresent(); + if (!buildContainerImage && !pushContainerImage) { return; } @@ -132,7 +133,8 @@ public void buildFromJar(ContainerImageConfig containerImageConfig, JibConfig ji pushRequest.isPresent()); artifactResultProducer.produce(new ArtifactResultBuildItem(null, "jar-container", - Collections.singletonMap("container-image", container.getTargetImage().toString()))); + Map.of("container-image", container.getTargetImage().toString(), "pull-required", + pushContainerImage.toString()))); } @BuildStep(onlyIf = { IsNormalNotRemoteDev.class, JibBuild.class, NativeBuild.class }) @@ -145,8 +147,9 @@ public void buildFromNative(ContainerImageConfig containerImageConfig, JibConfig List containerImageLabels, BuildProducer artifactResultProducer) { - if (!containerImageConfig.build && !containerImageConfig.push && !buildRequest.isPresent() - && !pushRequest.isPresent()) { + Boolean buildContainerImage = containerImageConfig.build || buildRequest.isPresent(); + Boolean pushContainerImage = containerImageConfig.push || pushRequest.isPresent(); + if (!buildContainerImage && !pushContainerImage) { return; } @@ -164,7 +167,8 @@ public void buildFromNative(ContainerImageConfig containerImageConfig, JibConfig pushRequest.isPresent()); artifactResultProducer.produce(new ArtifactResultBuildItem(null, "native-container", - Collections.singletonMap("container-image", container.getTargetImage().toString()))); + Map.of("container-image", container.getTargetImage().toString(), "pull-required", + pushContainerImage.toString()))); } private JibContainer containerize(ContainerImageConfig containerImageConfig, diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/DockerContainerLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/DockerContainerLauncher.java index 1fbbea9606cc7..1ea7aa07e82d6 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/DockerContainerLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/DockerContainerLauncher.java @@ -3,6 +3,7 @@ import static io.quarkus.test.common.LauncherUtil.installAndGetSomeConfig; import static io.quarkus.test.common.LauncherUtil.updateConfigForPort; import static io.quarkus.test.common.LauncherUtil.waitForCapturedListeningData; +import static java.lang.ProcessBuilder.Redirect.DISCARD; import java.io.IOException; import java.net.ServerSocket; @@ -33,32 +34,49 @@ public class DockerContainerLauncher implements ArtifactLauncher { private int httpsPort; private final long jarWaitTime; private final Map systemProps = new HashMap<>(); + private final boolean pullRequired; private boolean isSsl; - private DockerContainerLauncher(String containerImage, Config config) { + private DockerContainerLauncher(String containerImage, Config config, boolean pullRequired) { this(containerImage, config.getValue("quarkus.http.test-port", OptionalInt.class).orElse(DEFAULT_PORT), config.getValue("quarkus.http.test-ssl-port", OptionalInt.class).orElse(DEFAULT_HTTPS_PORT), config.getValue("quarkus.test.jar-wait-time", OptionalLong.class).orElse(DEFAULT_WAIT_TIME), config.getOptionalValue("quarkus.test.native-image-profile", String.class) - .orElse(null)); + .orElse(null), + pullRequired); } - public DockerContainerLauncher(String containerImage) { - this(containerImage, installAndGetSomeConfig()); + public DockerContainerLauncher(String containerImage, boolean pullRequired) { + this(containerImage, installAndGetSomeConfig(), pullRequired); } - public DockerContainerLauncher(String containerImage, int httpPort, int httpsPort, long jarWaitTime, String profile) { + private DockerContainerLauncher(String containerImage, int httpPort, int httpsPort, long jarWaitTime, String profile, + boolean pullRequired) { this.containerImage = containerImage; this.httpPort = httpPort; this.httpsPort = httpsPort; this.jarWaitTime = jarWaitTime; this.profile = profile; + this.pullRequired = pullRequired; } public void start() throws IOException { + if (pullRequired) { + System.out.println("Pulling container image '" + containerImage + "'"); + try { + int pullResult = new ProcessBuilder().redirectError(DISCARD).redirectOutput(DISCARD) + .command(List.of("docker", "pull", containerImage).toArray(new String[0])).start().waitFor(); + if (pullResult > 0) { + throw new RuntimeException("Pulling container image '" + containerImage + "' completed unsuccessfully"); + } + } catch (InterruptedException e) { + throw new RuntimeException("Unable to pull container image '" + containerImage + "'", e); + } + } + System.setProperty("test.url", TestHTTPResourceManager.getUri()); if (httpPort == 0) { diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java index adf045e38354f..28f5da132306f 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java @@ -177,8 +177,10 @@ public void close() throws Throwable { case "jar-container": case "native-container": String containerImage = quarkusArtifactProperties.getProperty("metadata.container-image"); + boolean pullRequired = Boolean + .parseBoolean(quarkusArtifactProperties.getProperty("metadata.pull-required", "false")); if ((containerImage != null) && !containerImage.isEmpty()) { - launcher = new DockerContainerLauncher(containerImage); + launcher = new DockerContainerLauncher(containerImage, pullRequired); } else { throw new IllegalStateException("The container image to be launched could not be determined"); }