Skip to content

Commit

Permalink
Create DockerClient interface (#3703)
Browse files Browse the repository at this point in the history
Extract `DockerClient` into an interface to allow providing non-CLI implementations.
Old `DockerClient` renamed to `CliDockerClient` and used as default implementation.
  • Loading branch information
eddumelendez authored Jul 27, 2022
1 parent a789a11 commit 9027c8d
Show file tree
Hide file tree
Showing 21 changed files with 342 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<BuildContext, StepsRunner> 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);
}

/**
Expand All @@ -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<BuildContext, StepsRunner> 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<BuildContext, StepsRunner> stepsRunnerFactory;
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String, String> parameters);

/**
* Loads an image tarball into the Docker daemon.
*
* @see <a
* href="https://docs.docker.com/engine/reference/commandline/load/">https://docs.docker.com/engine/reference/commandline/load</a>
* @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<Long> writtenByteCountListener)
throws InterruptedException, IOException;

/**
* Saves an image tarball from the Docker daemon.
*
* @see <a
* href="https://docs.docker.com/engine/reference/commandline/save/">https://docs.docker.com/engine/reference/commandline/save</a>
* @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<Long> 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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String, String> dockerEnvironment = Collections.emptyMap();

/** Instantiate with {@link #named}. */
Expand Down
Original file line number Diff line number Diff line change
@@ -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<DescriptorDigest> getDiffIds() throws DigestException;
}
14 changes: 14 additions & 0 deletions jib-core/src/main/java/com/google/cloud/tools/jib/api/Jib.java
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
}
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -109,7 +109,7 @@ static Callable<LocalImage> retrieveDockerDaemonLayersStep(
new TimerEventDispatcher(
buildContext.getEventHandlers(),
"Saving " + imageReference + " from Docker daemon")) {
DockerClient.DockerImageDetails dockerImageDetails = dockerClient.inspect(imageReference);
ImageDetails dockerImageDetails = dockerClient.inspect(imageReference);
Optional<LocalImage> cachedImage =
getCachedDockerImage(buildContext.getBaseImageLayersCache(), dockerImageDetails);
if (cachedImage.isPresent()) {
Expand Down Expand Up @@ -176,8 +176,7 @@ static Callable<ImagesAndRegistryClient> returnImageAndRegistryClientStep(
}

@VisibleForTesting
static Optional<LocalImage> getCachedDockerImage(
Cache cache, DockerImageDetails dockerImageDetails)
static Optional<LocalImage> getCachedDockerImage(Cache cache, ImageDetails dockerImageDetails)
throws DigestException, IOException, CacheCorruptedException {
// Get config
Optional<ContainerConfigurationTemplate> cachedConfig =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 9027c8d

Please sign in to comment.