diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/api/Containerizer.java b/jib-core/src/main/java/com/google/cloud/tools/jib/api/Containerizer.java index 8ebbb4d957..96442a5135 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/api/Containerizer.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/api/Containerizer.java @@ -20,7 +20,8 @@ import com.google.cloud.tools.jib.builder.steps.StepsRunner; import com.google.cloud.tools.jib.configuration.BuildContext; import com.google.cloud.tools.jib.configuration.ImageConfiguration; -import com.google.cloud.tools.jib.docker.DockerClient; +import com.google.cloud.tools.jib.docker.CliDockerClient; +import com.google.cloud.tools.jib.docker.DockerClientResolver; import com.google.cloud.tools.jib.event.EventHandlers; import com.google.cloud.tools.jib.filesystem.XdgDirectories; import com.google.common.base.Preconditions; @@ -90,17 +91,14 @@ public static Containerizer to(RegistryImage registryImage) { * @return a new {@link Containerizer} */ public static Containerizer to(DockerDaemonImage dockerDaemonImage) { - ImageConfiguration imageConfiguration = - ImageConfiguration.builder(dockerDaemonImage.getImageReference()).build(); - DockerClient dockerClient = - new DockerClient( - dockerDaemonImage.getDockerExecutable(), dockerDaemonImage.getDockerEnvironment()); - Function stepsRunnerFactory = - buildContext -> StepsRunner.begin(buildContext).dockerLoadSteps(dockerClient); + DockerClientResolver.resolve(dockerDaemonImage.getDockerEnvironment()) + .orElse( + new CliDockerClient( + dockerDaemonImage.getDockerExecutable(), + dockerDaemonImage.getDockerEnvironment())); - return new Containerizer( - DESCRIPTION_FOR_DOCKER_DAEMON, imageConfiguration, stepsRunnerFactory, false); + return to(dockerClient, dockerDaemonImage); } /** @@ -127,6 +125,24 @@ public static Containerizer to(TarImage tarImage) { DESCRIPTION_FOR_TARBALL, imageConfiguration, stepsRunnerFactory, false); } + /** + * Gets a new {@link Containerizer} that containerizes to a Docker daemon. + * + * @param dockerClient the {@link DockerClient} to connect + * @param dockerDaemonImage the {@link DockerDaemonImage} that defines target Docker daemon + * @return a new {@link Containerizer} + */ + public static Containerizer to(DockerClient dockerClient, DockerDaemonImage dockerDaemonImage) { + ImageConfiguration imageConfiguration = + ImageConfiguration.builder(dockerDaemonImage.getImageReference()).build(); + + Function stepsRunnerFactory = + buildContext -> StepsRunner.begin(buildContext).dockerLoadSteps(dockerClient); + + return new Containerizer( + DESCRIPTION_FOR_DOCKER_DAEMON, imageConfiguration, stepsRunnerFactory, false); + } + private final String description; private final ImageConfiguration imageConfiguration; private final Function stepsRunnerFactory; diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/api/DockerClient.java b/jib-core/src/main/java/com/google/cloud/tools/jib/api/DockerClient.java new file mode 100644 index 0000000000..50ce2f463f --- /dev/null +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/api/DockerClient.java @@ -0,0 +1,72 @@ +/* + * Copyright 2022 Google LLC. + * + * Licensed 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 com.google.cloud.tools.jib.api; + +import com.google.cloud.tools.jib.image.ImageTarball; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Map; +import java.util.function.Consumer; + +public interface DockerClient { + + /** + * Validate if the DockerClient is supported. + * + * @param parameters to be used by the docker client + * @return true if conditions are met + */ + boolean supported(Map parameters); + + /** + * Loads an image tarball into the Docker daemon. + * + * @see https://docs.docker.com/engine/reference/commandline/load + * @param imageTarball the built container tarball + * @param writtenByteCountListener callback to call when bytes are loaded + * @return stdout from {@code docker} + * @throws InterruptedException if the 'docker load' process is interrupted + * @throws IOException if streaming the blob to 'docker load' fails + */ + String load(ImageTarball imageTarball, Consumer writtenByteCountListener) + throws InterruptedException, IOException; + + /** + * Saves an image tarball from the Docker daemon. + * + * @see https://docs.docker.com/engine/reference/commandline/save + * @param imageReference the image to save + * @param outputPath the destination path to save the output tarball + * @param writtenByteCountListener callback to call when bytes are saved + * @throws InterruptedException if the 'docker save' process is interrupted + * @throws IOException if creating the tarball fails + */ + void save(ImageReference imageReference, Path outputPath, Consumer writtenByteCountListener) + throws InterruptedException, IOException; + + /** + * Gets the size, image ID, and diff IDs of an image in the Docker daemon. + * + * @param imageReference the image to inspect + * @return the size, image ID, and diff IDs of the image + * @throws IOException if an I/O exception occurs or {@code docker inspect} failed + * @throws InterruptedException if the {@code docker inspect} process was interrupted + */ + ImageDetails inspect(ImageReference imageReference) throws IOException, InterruptedException; +} diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/api/DockerDaemonImage.java b/jib-core/src/main/java/com/google/cloud/tools/jib/api/DockerDaemonImage.java index a97e5afbad..d6fcde1864 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/api/DockerDaemonImage.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/api/DockerDaemonImage.java @@ -16,7 +16,7 @@ package com.google.cloud.tools.jib.api; -import com.google.cloud.tools.jib.docker.DockerClient; +import com.google.cloud.tools.jib.docker.CliDockerClient; import java.nio.file.Path; import java.util.Collections; import java.util.Map; @@ -49,7 +49,7 @@ public static DockerDaemonImage named(String imageReference) } private final ImageReference imageReference; - private Path dockerExecutable = DockerClient.DEFAULT_DOCKER_CLIENT; + private Path dockerExecutable = CliDockerClient.DEFAULT_DOCKER_CLIENT; private Map dockerEnvironment = Collections.emptyMap(); /** Instantiate with {@link #named}. */ diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/api/ImageDetails.java b/jib-core/src/main/java/com/google/cloud/tools/jib/api/ImageDetails.java new file mode 100644 index 0000000000..c1c90766e1 --- /dev/null +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/api/ImageDetails.java @@ -0,0 +1,29 @@ +/* + * Copyright 2022 Google LLC. + * + * Licensed 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 com.google.cloud.tools.jib.api; + +import java.security.DigestException; +import java.util.List; + +public interface ImageDetails { + + long getSize(); + + DescriptorDigest getImageId() throws DigestException; + + List getDiffIds() throws DigestException; +} diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/api/Jib.java b/jib-core/src/main/java/com/google/cloud/tools/jib/api/Jib.java index 20e70bb638..a8387df0e6 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/api/Jib.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/api/Jib.java @@ -106,5 +106,19 @@ public static JibContainerBuilder fromScratch() { return from(ImageReference.scratch()); } + /** + * Starts building the container from a base image stored in the Docker cache. Requires a running + * Docker daemon. + * + * @param dockerClient the {@link DockerClient} to connect + * @param dockerDaemonImage the {@link DockerDaemonImage} that defines the base image and Docker + * client + * @return a new {@link JibContainerBuilder} to continue building the container + */ + public static JibContainerBuilder from( + DockerClient dockerClient, DockerDaemonImage dockerDaemonImage) { + return new JibContainerBuilder(dockerClient, dockerDaemonImage); + } + private Jib() {} } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/api/JibContainerBuilder.java b/jib-core/src/main/java/com/google/cloud/tools/jib/api/JibContainerBuilder.java index 3946603418..9a809ef798 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/api/JibContainerBuilder.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/api/JibContainerBuilder.java @@ -29,7 +29,8 @@ import com.google.cloud.tools.jib.configuration.BuildContext; import com.google.cloud.tools.jib.configuration.ContainerConfiguration; import com.google.cloud.tools.jib.configuration.ImageConfiguration; -import com.google.cloud.tools.jib.docker.DockerClient; +import com.google.cloud.tools.jib.docker.CliDockerClient; +import com.google.cloud.tools.jib.docker.DockerClientResolver; import com.google.cloud.tools.jib.event.EventHandlers; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Verify; @@ -100,7 +101,10 @@ private static String capitalizeFirstLetter(String string) { this( ImageConfiguration.builder(baseImage.getImageReference()) .setDockerClient( - new DockerClient(baseImage.getDockerExecutable(), baseImage.getDockerEnvironment())) + DockerClientResolver.resolve(baseImage.getDockerEnvironment()) + .orElse( + new CliDockerClient( + baseImage.getDockerExecutable(), baseImage.getDockerEnvironment()))) .build(), BuildContext.builder()); } @@ -115,6 +119,15 @@ private static String capitalizeFirstLetter(String string) { BuildContext.builder()); } + /** Instantiate with {@link Jib#from}. */ + JibContainerBuilder(DockerClient dockerClient, DockerDaemonImage baseImage) { + this( + ImageConfiguration.builder(baseImage.getImageReference()) + .setDockerClient(dockerClient) + .build(), + BuildContext.builder()); + } + @VisibleForTesting JibContainerBuilder( ImageConfiguration imageConfiguration, BuildContext.Builder buildContextBuilder) { diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/LoadDockerStep.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/LoadDockerStep.java index 8e3b941981..5e2d11cb54 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/LoadDockerStep.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/LoadDockerStep.java @@ -16,11 +16,11 @@ package com.google.cloud.tools.jib.builder.steps; +import com.google.cloud.tools.jib.api.DockerClient; import com.google.cloud.tools.jib.api.LogEvent; import com.google.cloud.tools.jib.builder.ProgressEventDispatcher; import com.google.cloud.tools.jib.builder.TimerEventDispatcher; import com.google.cloud.tools.jib.configuration.BuildContext; -import com.google.cloud.tools.jib.docker.DockerClient; import com.google.cloud.tools.jib.event.EventHandlers; import com.google.cloud.tools.jib.event.progress.ThrottledAccumulatingConsumer; import com.google.cloud.tools.jib.image.Image; diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/LocalBaseImageSteps.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/LocalBaseImageSteps.java index 916c579fea..93b03d2d50 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/LocalBaseImageSteps.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/LocalBaseImageSteps.java @@ -19,6 +19,8 @@ import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.cloud.tools.jib.api.DescriptorDigest; +import com.google.cloud.tools.jib.api.DockerClient; +import com.google.cloud.tools.jib.api.ImageDetails; import com.google.cloud.tools.jib.api.ImageReference; import com.google.cloud.tools.jib.blob.Blob; import com.google.cloud.tools.jib.blob.BlobDescriptor; @@ -30,8 +32,6 @@ import com.google.cloud.tools.jib.cache.CacheCorruptedException; import com.google.cloud.tools.jib.cache.CachedLayer; import com.google.cloud.tools.jib.configuration.BuildContext; -import com.google.cloud.tools.jib.docker.DockerClient; -import com.google.cloud.tools.jib.docker.DockerClient.DockerImageDetails; import com.google.cloud.tools.jib.docker.json.DockerManifestEntryTemplate; import com.google.cloud.tools.jib.event.progress.ThrottledAccumulatingConsumer; import com.google.cloud.tools.jib.filesystem.TempDirectoryProvider; @@ -109,7 +109,7 @@ static Callable retrieveDockerDaemonLayersStep( new TimerEventDispatcher( buildContext.getEventHandlers(), "Saving " + imageReference + " from Docker daemon")) { - DockerClient.DockerImageDetails dockerImageDetails = dockerClient.inspect(imageReference); + ImageDetails dockerImageDetails = dockerClient.inspect(imageReference); Optional cachedImage = getCachedDockerImage(buildContext.getBaseImageLayersCache(), dockerImageDetails); if (cachedImage.isPresent()) { @@ -176,8 +176,7 @@ static Callable returnImageAndRegistryClientStep( } @VisibleForTesting - static Optional getCachedDockerImage( - Cache cache, DockerImageDetails dockerImageDetails) + static Optional getCachedDockerImage(Cache cache, ImageDetails dockerImageDetails) throws DigestException, IOException, CacheCorruptedException { // Get config Optional cachedConfig = diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/StepsRunner.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/StepsRunner.java index ae7c2b95f8..46c63bfc9d 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/StepsRunner.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/StepsRunner.java @@ -17,13 +17,13 @@ package com.google.cloud.tools.jib.builder.steps; import com.google.cloud.tools.jib.api.DescriptorDigest; +import com.google.cloud.tools.jib.api.DockerClient; import com.google.cloud.tools.jib.blob.BlobDescriptor; import com.google.cloud.tools.jib.builder.ProgressEventDispatcher; import com.google.cloud.tools.jib.builder.steps.LocalBaseImageSteps.LocalImage; import com.google.cloud.tools.jib.builder.steps.PullBaseImageStep.ImagesAndRegistryClient; import com.google.cloud.tools.jib.configuration.BuildContext; import com.google.cloud.tools.jib.configuration.ImageConfiguration; -import com.google.cloud.tools.jib.docker.DockerClient; import com.google.cloud.tools.jib.filesystem.TempDirectoryProvider; import com.google.cloud.tools.jib.global.JibSystemProperties; import com.google.cloud.tools.jib.image.Image; diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/ImageConfiguration.java b/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/ImageConfiguration.java index d561401325..91e8818713 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/ImageConfiguration.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/ImageConfiguration.java @@ -17,8 +17,8 @@ package com.google.cloud.tools.jib.configuration; import com.google.cloud.tools.jib.api.CredentialRetriever; +import com.google.cloud.tools.jib.api.DockerClient; import com.google.cloud.tools.jib.api.ImageReference; -import com.google.cloud.tools.jib.docker.DockerClient; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import java.nio.file.Path; diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerClient.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/CliDockerClient.java similarity index 84% rename from jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerClient.java rename to jib-core/src/main/java/com/google/cloud/tools/jib/docker/CliDockerClient.java index ac17fc8935..c62ff819a1 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerClient.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/CliDockerClient.java @@ -19,6 +19,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.cloud.tools.jib.api.DescriptorDigest; +import com.google.cloud.tools.jib.api.DockerClient; +import com.google.cloud.tools.jib.api.ImageDetails; import com.google.cloud.tools.jib.api.ImageReference; import com.google.cloud.tools.jib.http.NotifyingOutputStream; import com.google.cloud.tools.jib.image.ImageTarball; @@ -48,13 +50,13 @@ import java.util.function.Function; /** Calls out to the {@code docker} CLI. */ -public class DockerClient { +public class CliDockerClient implements DockerClient { /** * Contains the size, image ID, and diff IDs of an image inspected with {@code docker inspect}. */ @JsonIgnoreProperties(ignoreUnknown = true) - public static class DockerImageDetails implements JsonTemplate { + public static class DockerImageDetails implements JsonTemplate, ImageDetails { @JsonIgnoreProperties(ignoreUnknown = true) private static class RootFsTemplate implements JsonTemplate { @@ -71,10 +73,12 @@ private static class RootFsTemplate implements JsonTemplate { @JsonProperty("RootFS") private final RootFsTemplate rootFs = new RootFsTemplate(); + @Override public long getSize() { return size; } + @Override public DescriptorDigest getImageId() throws DigestException { return DescriptorDigest.fromDigest(imageId); } @@ -85,6 +89,7 @@ public DescriptorDigest getImageId() throws DigestException { * @return a list of diff ids * @throws DigestException if a digest is invalid */ + @Override public List getDiffIds() throws DigestException { List processedDiffIds = new ArrayList<>(rootFs.layers.size()); for (String diffId : rootFs.layers) { @@ -165,28 +170,23 @@ private static String getStderrOutput(Process process) { * @param dockerExecutable path to {@code docker} * @param dockerEnvironment environment variables for {@code docker} */ - public DockerClient(Path dockerExecutable, Map dockerEnvironment) { + public CliDockerClient(Path dockerExecutable, Map dockerEnvironment) { this( defaultProcessBuilderFactory( dockerExecutable.toString(), ImmutableMap.copyOf(dockerEnvironment))); } @VisibleForTesting - DockerClient(Function, ProcessBuilder> processBuilderFactory) { + CliDockerClient(Function, ProcessBuilder> processBuilderFactory) { this.processBuilderFactory = processBuilderFactory; } - /** - * Loads an image tarball into the Docker daemon. - * - * @see https://docs.docker.com/engine/reference/commandline/load - * @param imageTarball the built container tarball - * @param writtenByteCountListener callback to call when bytes are loaded - * @return stdout from {@code docker} - * @throws InterruptedException if the 'docker load' process is interrupted - * @throws IOException if streaming the blob to 'docker load' fails - */ + @Override + public boolean supported(Map parameters) { + return true; + } + + @Override public String load(ImageTarball imageTarball, Consumer writtenByteCountListener) throws InterruptedException, IOException { // Runs 'docker load'. @@ -224,17 +224,7 @@ public String load(ImageTarball imageTarball, Consumer writtenByteCountLis } } - /** - * Saves an image tarball from the Docker daemon. - * - * @see https://docs.docker.com/engine/reference/commandline/save - * @param imageReference the image to save - * @param outputPath the destination path to save the output tarball - * @param writtenByteCountListener callback to call when bytes are saved - * @throws InterruptedException if the 'docker save' process is interrupted - * @throws IOException if creating the tarball fails - */ + @Override public void save( ImageReference imageReference, Path outputPath, Consumer writtenByteCountListener) throws InterruptedException, IOException { @@ -253,14 +243,7 @@ public void save( } } - /** - * Gets the size, image ID, and diff IDs of an image in the Docker daemon. - * - * @param imageReference the image to inspect - * @return the size, image ID, and diff IDs of the image - * @throws IOException if an I/O exception occurs or {@code docker inspect} failed - * @throws InterruptedException if the {@code docker inspect} process was interrupted - */ + @Override public DockerImageDetails inspect(ImageReference imageReference) throws IOException, InterruptedException { Process inspectProcess = diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerClientResolver.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerClientResolver.java new file mode 100644 index 0000000000..c8b3135d1f --- /dev/null +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerClientResolver.java @@ -0,0 +1,45 @@ +/* + * Copyright 2022 Google LLC. + * + * Licensed 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 com.google.cloud.tools.jib.docker; + +import com.google.cloud.tools.jib.api.DockerClient; +import java.util.Map; +import java.util.Optional; +import java.util.ServiceLoader; + +public class DockerClientResolver { + + private static final ServiceLoader dockerClients = + ServiceLoader.load(DockerClient.class); + + private DockerClientResolver() {} + + /** + * Look for supported DockerClient. + * + * @param parameters needed by the dockerClient + * @return dockerClient if any is found + */ + public static Optional resolve(Map parameters) { + for (DockerClient dockerClient : dockerClients) { + if (dockerClient.supported(parameters)) { + return Optional.of(dockerClient); + } + } + return Optional.empty(); + } +} diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/api/ContainerizerTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/api/ContainerizerTest.java index bda882cb44..f6a4432c62 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/api/ContainerizerTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/api/ContainerizerTest.java @@ -17,6 +17,7 @@ package com.google.cloud.tools.jib.api; import com.google.cloud.tools.jib.configuration.ImageConfiguration; +import com.google.cloud.tools.jib.docker.AnotherDockerClient; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.MoreExecutors; import java.io.IOException; @@ -37,10 +38,12 @@ public void testTo() throws CacheDirectoryCreationException, InvalidImageReferen RegistryImage registryImage = RegistryImage.named("registry/image"); DockerDaemonImage dockerDaemonImage = DockerDaemonImage.named("daemon/image"); TarImage tarImage = TarImage.at(Paths.get("ignored")).named("tar/iamge"); + DockerClient dockerClient = new AnotherDockerClient(); verifyTo(Containerizer.to(registryImage)); verifyTo(Containerizer.to(dockerDaemonImage)); verifyTo(Containerizer.to(tarImage)); + verifyTo(Containerizer.to(dockerClient, dockerDaemonImage)); } private void verifyTo(Containerizer containerizer) throws CacheDirectoryCreationException { diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/api/DockerClientResolverTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/api/DockerClientResolverTest.java new file mode 100644 index 0000000000..17c6dc6ad0 --- /dev/null +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/api/DockerClientResolverTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2022 Google LLC. + * + * Licensed 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 com.google.cloud.tools.jib.api; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.cloud.tools.jib.docker.AnotherDockerClient; +import com.google.cloud.tools.jib.docker.DockerClientResolver; +import java.util.Collections; +import java.util.Optional; +import org.junit.Test; + +/** Tests for {@link DockerClientResolver}. */ +public class DockerClientResolverTest { + + @Test + public void testDockerClientIsReturned() { + Optional dockerClient = + DockerClientResolver.resolve(Collections.singletonMap("test", "true")); + assertThat(dockerClient.get()).isInstanceOf(AnotherDockerClient.class); + } +} diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/api/DockerDaemonImageTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/api/DockerDaemonImageTest.java index 52ae1db7d8..0ffd4dd078 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/api/DockerDaemonImageTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/api/DockerDaemonImageTest.java @@ -16,7 +16,7 @@ package com.google.cloud.tools.jib.api; -import com.google.cloud.tools.jib.docker.DockerClient; +import com.google.cloud.tools.jib.docker.CliDockerClient; import com.google.common.collect.ImmutableMap; import java.nio.file.Paths; import org.junit.Assert; @@ -31,7 +31,7 @@ public void testGetters_default() throws InvalidImageReferenceException { Assert.assertEquals("docker/daemon/image", dockerDaemonImage.getImageReference().toString()); Assert.assertEquals( - DockerClient.DEFAULT_DOCKER_CLIENT, dockerDaemonImage.getDockerExecutable()); + CliDockerClient.DEFAULT_DOCKER_CLIENT, dockerDaemonImage.getDockerExecutable()); Assert.assertEquals(0, dockerDaemonImage.getDockerEnvironment().size()); } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/LocalBaseImageStepsTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/LocalBaseImageStepsTest.java index 1d68926631..97bd9f1217 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/LocalBaseImageStepsTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/LocalBaseImageStepsTest.java @@ -17,12 +17,13 @@ package com.google.cloud.tools.jib.builder.steps; import com.google.cloud.tools.jib.api.CacheDirectoryCreationException; +import com.google.cloud.tools.jib.api.ImageDetails; import com.google.cloud.tools.jib.builder.ProgressEventDispatcher; import com.google.cloud.tools.jib.builder.steps.LocalBaseImageSteps.LocalImage; import com.google.cloud.tools.jib.cache.Cache; import com.google.cloud.tools.jib.cache.CacheCorruptedException; import com.google.cloud.tools.jib.configuration.BuildContext; -import com.google.cloud.tools.jib.docker.DockerClient.DockerImageDetails; +import com.google.cloud.tools.jib.docker.CliDockerClient; import com.google.cloud.tools.jib.event.EventHandlers; import com.google.cloud.tools.jib.filesystem.TempDirectoryProvider; import com.google.cloud.tools.jib.json.JsonTemplateMapper; @@ -141,8 +142,8 @@ public void testGetCachedDockerImage() + "\"RootFS\": { \"Layers\": [" + " \"sha256:5e701122d3347fae0758cd5b7f0692c686fcd07b0e7fd9c4a125fbdbbedc04dd\"," + " \"sha256:f1ac3015bcbf0ada4750d728626eb10f0f585199e2b667dcd79e49f0e926178e\" ] } }"; - DockerImageDetails dockerImageDetails = - JsonTemplateMapper.readJson(dockerInspectJson, DockerImageDetails.class); + ImageDetails dockerImageDetails = + JsonTemplateMapper.readJson(dockerInspectJson, CliDockerClient.DockerImageDetails.class); Path cachePath = temporaryFolder.newFolder("cache").toPath(); Files.createDirectories(cachePath.resolve("local/config")); Cache cache = Cache.withDirectory(cachePath); diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/AnotherDockerClient.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/AnotherDockerClient.java new file mode 100644 index 0000000000..64926306ec --- /dev/null +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/AnotherDockerClient.java @@ -0,0 +1,50 @@ +/* + * Copyright 2022 Google LLC. + * + * Licensed 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 com.google.cloud.tools.jib.docker; + +import com.google.cloud.tools.jib.api.DockerClient; +import com.google.cloud.tools.jib.api.ImageDetails; +import com.google.cloud.tools.jib.api.ImageReference; +import com.google.cloud.tools.jib.image.ImageTarball; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Map; +import java.util.function.Consumer; + +public class AnotherDockerClient implements DockerClient { + @Override + public boolean supported(Map parameters) { + return parameters.containsKey("test"); + } + + @Override + public String load(ImageTarball imageTarball, Consumer writtenByteCountListener) + throws InterruptedException, IOException { + return null; + } + + @Override + public void save( + ImageReference imageReference, Path outputPath, Consumer writtenByteCountListener) + throws InterruptedException, IOException {} + + @Override + public ImageDetails inspect(ImageReference imageReference) + throws IOException, InterruptedException { + return null; + } +} diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerClientTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/CliDockerClientTest.java similarity index 93% rename from jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerClientTest.java rename to jib-core/src/test/java/com/google/cloud/tools/jib/docker/CliDockerClientTest.java index 8f4c57b85d..4d1f37f6ce 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerClientTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/CliDockerClientTest.java @@ -17,8 +17,9 @@ package com.google.cloud.tools.jib.docker; import com.google.cloud.tools.jib.api.DescriptorDigest; +import com.google.cloud.tools.jib.api.DockerClient; import com.google.cloud.tools.jib.api.ImageReference; -import com.google.cloud.tools.jib.docker.DockerClient.DockerImageDetails; +import com.google.cloud.tools.jib.docker.CliDockerClient.DockerImageDetails; import com.google.cloud.tools.jib.image.ImageTarball; import com.google.cloud.tools.jib.json.JsonTemplateMapper; import com.google.common.collect.ImmutableMap; @@ -47,9 +48,9 @@ import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.VoidAnswer1; -/** Tests for {@link DockerClient}. */ +/** Tests for {@link CliDockerClient}. */ @RunWith(MockitoJUnitRunner.class) -public class DockerClientTest { +public class CliDockerClientTest { @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -70,13 +71,13 @@ public void setUp() throws IOException { @Test public void testIsDockerInstalled_fail() { - Assert.assertFalse(DockerClient.isDockerInstalled(Paths.get("path/to/nonexistent/file"))); + Assert.assertFalse(CliDockerClient.isDockerInstalled(Paths.get("path/to/nonexistent/file"))); } @Test public void testLoad() throws IOException, InterruptedException { DockerClient testDockerClient = - new DockerClient( + new CliDockerClient( subcommand -> { Assert.assertEquals(Collections.singletonList("load"), subcommand); return mockProcessBuilder; @@ -100,7 +101,7 @@ public void testLoad() throws IOException, InterruptedException { @Test public void testLoad_stdinFail() throws InterruptedException { - DockerClient testDockerClient = new DockerClient(ignored -> mockProcessBuilder); + DockerClient testDockerClient = new CliDockerClient(ignored -> mockProcessBuilder); Mockito.when(mockProcess.getOutputStream()) .thenReturn( @@ -125,7 +126,7 @@ public void write(int b) throws IOException { @Test public void testLoad_stdinFail_stderrFail() throws InterruptedException { - DockerClient testDockerClient = new DockerClient(ignored -> mockProcessBuilder); + DockerClient testDockerClient = new CliDockerClient(ignored -> mockProcessBuilder); Mockito.when(mockProcess.getOutputStream()) .thenReturn( @@ -157,7 +158,7 @@ public int read() throws IOException { @Test public void testLoad_stdoutFail() throws InterruptedException { - DockerClient testDockerClient = new DockerClient(ignored -> mockProcessBuilder); + DockerClient testDockerClient = new CliDockerClient(ignored -> mockProcessBuilder); Mockito.when(mockProcess.waitFor()).thenReturn(1); Mockito.when(mockProcess.getOutputStream()).thenReturn(ByteStreams.nullOutputStream()); @@ -213,7 +214,7 @@ public void testSave_fail() throws InterruptedException { @Test public void testDefaultProcessorBuilderFactory_customExecutable() { ProcessBuilder processBuilder = - DockerClient.defaultProcessBuilderFactory("docker-executable", ImmutableMap.of()) + CliDockerClient.defaultProcessBuilderFactory("docker-executable", ImmutableMap.of()) .apply(Arrays.asList("sub", "command")); Assert.assertEquals( @@ -229,7 +230,7 @@ public void testDefaultProcessorBuilderFactory_customEnvironment() { expectedEnvironment.putAll(environment); ProcessBuilder processBuilder = - DockerClient.defaultProcessBuilderFactory("docker", environment) + CliDockerClient.defaultProcessBuilderFactory("docker", environment) .apply(Collections.emptyList()); Assert.assertEquals(expectedEnvironment, processBuilder.environment()); @@ -238,7 +239,7 @@ public void testDefaultProcessorBuilderFactory_customEnvironment() { @Test public void testSize_fail() throws InterruptedException { DockerClient testDockerClient = - new DockerClient( + new CliDockerClient( subcommand -> { Assert.assertEquals("inspect", subcommand.get(0)); return mockProcessBuilder; @@ -317,7 +318,7 @@ public void testDockerImageDetails_emptyJson() throws IOException, DigestExcepti } private DockerClient makeDockerSaveClient() { - return new DockerClient( + return new CliDockerClient( subcommand -> { try { if (subcommand.contains("{{.Size}}")) { diff --git a/jib-core/src/test/resources/META-INF/services/com.google.cloud.tools.jib.api.DockerClient b/jib-core/src/test/resources/META-INF/services/com.google.cloud.tools.jib.api.DockerClient new file mode 100644 index 0000000000..597997356e --- /dev/null +++ b/jib-core/src/test/resources/META-INF/services/com.google.cloud.tools.jib.api.DockerClient @@ -0,0 +1 @@ +com.google.cloud.tools.jib.docker.AnotherDockerClient \ No newline at end of file diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildDockerTask.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildDockerTask.java index fc6a469fee..692449db03 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildDockerTask.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildDockerTask.java @@ -18,7 +18,7 @@ import com.google.cloud.tools.jib.api.CacheDirectoryCreationException; import com.google.cloud.tools.jib.api.InvalidImageReferenceException; -import com.google.cloud.tools.jib.docker.DockerClient; +import com.google.cloud.tools.jib.docker.CliDockerClient; import com.google.cloud.tools.jib.filesystem.TempDirectoryProvider; import com.google.cloud.tools.jib.plugins.common.BuildStepsExecutionException; import com.google.cloud.tools.jib.plugins.common.ExtraDirectoryNotFoundException; @@ -96,8 +96,8 @@ public void buildDocker() Path dockerExecutable = jibExtension.getDockerClient().getExecutablePath(); boolean isDockerInstalled = dockerExecutable == null - ? DockerClient.isDefaultDockerInstalled() - : DockerClient.isDockerInstalled(dockerExecutable); + ? CliDockerClient.isDefaultDockerInstalled() + : CliDockerClient.isDockerInstalled(dockerExecutable); if (!isDockerInstalled) { throw new GradleException( HelpfulSuggestions.forDockerNotInstalled(HELPFUL_SUGGESTIONS_PREFIX)); diff --git a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/BuildDockerMojo.java b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/BuildDockerMojo.java index 8665dc97d8..d7a739a2a8 100644 --- a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/BuildDockerMojo.java +++ b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/BuildDockerMojo.java @@ -18,7 +18,7 @@ import com.google.cloud.tools.jib.api.CacheDirectoryCreationException; import com.google.cloud.tools.jib.api.InvalidImageReferenceException; -import com.google.cloud.tools.jib.docker.DockerClient; +import com.google.cloud.tools.jib.docker.CliDockerClient; import com.google.cloud.tools.jib.filesystem.TempDirectoryProvider; import com.google.cloud.tools.jib.plugins.common.BuildStepsExecutionException; import com.google.cloud.tools.jib.plugins.common.ExtraDirectoryNotFoundException; @@ -68,8 +68,8 @@ public void execute() throws MojoExecutionException, MojoFailureException { Path dockerExecutable = getDockerClientExecutable(); boolean isDockerInstalled = dockerExecutable == null - ? DockerClient.isDefaultDockerInstalled() - : DockerClient.isDockerInstalled(dockerExecutable); + ? CliDockerClient.isDefaultDockerInstalled() + : CliDockerClient.isDockerInstalled(dockerExecutable); if (!isDockerInstalled) { throw new MojoExecutionException( HelpfulSuggestions.forDockerNotInstalled(HELPFUL_SUGGESTIONS_PREFIX));