Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write out the image metadata to a file after build. #2227

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,41 @@

package com.google.cloud.tools.jib.api;

import com.google.cloud.tools.jib.builder.steps.BuildResult;
import com.google.cloud.tools.jib.configuration.BuildContext;
import com.google.common.annotations.VisibleForTesting;
import java.util.Objects;

/** The container built by Jib. */
public class JibContainer {

private final ImageReference targetImage;
private final DescriptorDigest imageDigest;
private final DescriptorDigest imageId;

JibContainer(DescriptorDigest imageDigest, DescriptorDigest imageId) {
@VisibleForTesting
JibContainer(ImageReference targetImage, DescriptorDigest imageDigest, DescriptorDigest imageId) {
this.targetImage = targetImage;
this.imageDigest = imageDigest;
this.imageId = imageId;
}

static JibContainer from(BuildContext buildContext, BuildResult buildResult) {
ImageReference targetImage = buildContext.getTargetImageConfiguration().getImage();
DescriptorDigest imageDigest = buildResult.getImageDigest();
DescriptorDigest imageId = buildResult.getImageId();
return new JibContainer(targetImage, imageDigest, imageId);
}

/**
* Get the target image that was built.
*
* @return the target image reference.
*/
public ImageReference getTargetImage() {
return targetImage;
}

/**
* Gets the digest of the registry image manifest built by Jib. This digest can be used to fetch a
* specific image from the registry in the form {@code myregistry/myimage@digest}.
Expand All @@ -50,7 +72,7 @@ public DescriptorDigest getImageId() {

@Override
public int hashCode() {
return Objects.hash(imageDigest, imageId);
return Objects.hash(targetImage, imageDigest, imageId);
}

@Override
Expand All @@ -62,6 +84,8 @@ public boolean equals(Object other) {
return false;
}
JibContainer otherContainer = (JibContainer) other;
return imageDigest.equals(otherContainer.imageDigest) && imageId.equals(otherContainer.imageId);
return targetImage.equals(otherContainer.targetImage)
&& imageDigest.equals(otherContainer.imageDigest)
&& imageId.equals(otherContainer.imageId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,8 @@ public JibContainer containerize(Containerizer containerizer)
buildContext.getEventHandlers(), containerizer.getDescription())) {
logSources(buildContext.getEventHandlers());

BuildResult result = containerizer.run(buildContext);
return new JibContainer(result.getImageDigest(), result.getImageId());
BuildResult buildResult = containerizer.run(buildContext);
return JibContainer.from(buildContext, buildResult);

} catch (ExecutionException ex) {
// If an ExecutionException occurs, re-throw the cause to be more easily handled by the user
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ public class JibContainerTest {

@Rule public TemporaryFolder temporaryDirectory = new TemporaryFolder();

private ImageReference targetImage1;
private ImageReference targetImage2;
private DescriptorDigest digest1;
private DescriptorDigest digest2;
private DescriptorDigest digest3;

@Before
public void setUp() throws DigestException {
public void setUp() throws DigestException, InvalidImageReferenceException {
targetImage1 = ImageReference.parse("gcr.io/project/image:tag");
targetImage2 = ImageReference.parse("gcr.io/project/image:tag2");
digest1 =
DescriptorDigest.fromDigest(
"sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789");
Expand All @@ -47,20 +51,27 @@ public void setUp() throws DigestException {

@Test
public void testCreation() {
JibContainer container = new JibContainer(digest1, digest2);
JibContainer container = new JibContainer(targetImage1, digest1, digest2);

Assert.assertEquals(targetImage1, container.getTargetImage());
Assert.assertEquals(digest1, container.getDigest());
Assert.assertEquals(digest2, container.getImageId());
}

@Test
public void testEquality() {
JibContainer container1 = new JibContainer(digest1, digest2);
JibContainer container2 = new JibContainer(digest1, digest2);
JibContainer container3 = new JibContainer(digest2, digest3);
JibContainer container1 = new JibContainer(targetImage1, digest1, digest2);
JibContainer container2 = new JibContainer(targetImage1, digest1, digest2);
JibContainer container3 = new JibContainer(targetImage1, digest2, digest3);
JibContainer container4 = new JibContainer(targetImage2, digest2, digest3);

Assert.assertEquals(container1, container2);
Assert.assertEquals(container1.hashCode(), container2.hashCode());

Assert.assertNotEquals(container1, container3);
Assert.assertNotEquals(container1.hashCode(), container3.hashCode());

Assert.assertNotEquals(container3, container4);
Assert.assertNotEquals(container3.hashCode(), container4.hashCode());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,9 @@ public Path getDigestOutputPath() {
public Path getImageIdOutputPath() {
return jibExtension.getOutputPaths().getImageIdPath();
}

@Override
public Optional<Path> getImageNameOutputPath() {
return Optional.empty();
}
}
1 change: 1 addition & 0 deletions jib-maven-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ Property | Type | Default | Description
`tar` | string | `(project-dir)/target/jib-image.tar` | The path of the tarball generated by `jib:buildTar`. Relative paths are resolved relative to the project root.
`digest` | string | `(project-dir)/target/jib-image.digest` | The path of the image digest written out during the build. Relative paths are resolved relative to the project root.
`imageId` | string | `(project-dir)/target/jib-image.id` | The path of the image ID written out during the build. Relative paths are resolved relative to the project root.
`imageName` | string | *None* | The path of the image name written out during the build. Relative paths are resolved relative to the project root.

<a name="dockerclient-object"></a>`dockerClient` is an object used to configure Docker when building to/from the Docker daemon. It has the following properties:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ public static class OutputPathsParameters {
@Nullable @Parameter private File digest;

@Nullable @Parameter private File imageId;

@Nullable @Parameter private File imageName;
}

@Nullable
Expand Down Expand Up @@ -625,9 +627,29 @@ Path getImageIdOutputPath() {
return getRelativeToProjectRoot(configuredPath, PropertyNames.OUTPUT_PATHS_IMAGE_ID);
}

Optional<Path> getImageNameOutputPath() {
String propertyValue = getProperty(PropertyNames.OUTPUT_PATHS_IMAGE_NAME);
File pomValue = outputPaths.imageName;

final Path configuredPath;
if (propertyValue != null) {
configuredPath = Paths.get(propertyValue);
} else if (pomValue != null) {
configuredPath = pomValue.toPath();
} else {
configuredPath = null;
}

return Optional.ofNullable(configuredPath).map(this::getRelativeToProjectRoot);
}

private Path getRelativeToProjectRoot(Path configuration, String propertyName) {
String property = getProperty(propertyName);
Path path = property != null ? Paths.get(property) : configuration;
return getRelativeToProjectRoot(path);
}

private Path getRelativeToProjectRoot(Path path) {
return path.isAbsolute() ? path : getProject().getBasedir().toPath().resolve(path);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,9 @@ public Path getDigestOutputPath() {
public Path getImageIdOutputPath() {
return jibPluginConfiguration.getImageIdOutputPath();
}

@Override
public Optional<Path> getImageNameOutputPath() {
return jibPluginConfiguration.getImageNameOutputPath();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Build;
Expand Down Expand Up @@ -325,4 +326,16 @@ public void testIsContainerizable_directory() {
projectProperties.setProperty("jib.containerize", "project2");
Assert.assertFalse(testPluginConfiguration.isContainerizable());
}

@Test
public void testImageName_emptyByDefault() {
Assert.assertEquals(Optional.empty(), testPluginConfiguration.getImageNameOutputPath());
}

@Test
public void testImageName_setFromProperty() {
project.getProperties().setProperty("jib.outputPaths.imageName", "/image/path");
Assert.assertEquals(
Paths.get("/image/path"), testPluginConfiguration.getImageNameOutputPath().get());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ private static void handleRegistryUnauthorizedException(
private final HelpfulSuggestions helpfulSuggestions;
@Nullable private Path imageDigestOutputPath;
@Nullable private Path imageIdOutputPath;
@Nullable private Path imageNameOutputPath;

@VisibleForTesting
JibBuildRunner(
Expand Down Expand Up @@ -237,6 +238,10 @@ public JibContainer runBuild()
String imageId = jibContainer.getImageId().toString();
Files.write(imageIdOutputPath, imageId.getBytes(StandardCharsets.UTF_8));
}
if (imageNameOutputPath != null) {
String imageName = jibContainer.getTargetImage().toString();
Files.write(imageNameOutputPath, imageName.getBytes(StandardCharsets.UTF_8));
}

return jibContainer;

Expand Down Expand Up @@ -304,4 +309,16 @@ public JibBuildRunner writeImageId(@Nullable Path imageIdOutputPath) {
this.imageIdOutputPath = imageIdOutputPath;
return this;
}

/**
* Set the location where the image name will be saved. If {@code null} then the name is not
* saved.
*
* @param imageNameOutputPath the location to write the image name or {@code null} to skip
* @return this
*/
public JibBuildRunner writeImageName(@Nullable Path imageNameOutputPath) {
this.imageNameOutputPath = imageNameOutputPath;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ public static JibBuildRunner createJibBuildRunnerForDockerDaemonImage(
targetImageReference,
rawConfiguration.getToTags())
.writeImageDigest(rawConfiguration.getDigestOutputPath())
.writeImageId(rawConfiguration.getImageIdOutputPath());
.writeImageId(rawConfiguration.getImageIdOutputPath())
.writeImageName(rawConfiguration.getImageNameOutputPath().orElse(null));
}

public static JibBuildRunner createJibBuildRunnerForTarImage(
Expand Down Expand Up @@ -188,7 +189,8 @@ public static JibBuildRunner createJibBuildRunnerForRegistryImage(
targetImageReference,
rawConfiguration.getToTags())
.writeImageDigest(rawConfiguration.getDigestOutputPath())
.writeImageId(rawConfiguration.getImageIdOutputPath());
.writeImageId(rawConfiguration.getImageIdOutputPath())
.writeImageName(rawConfiguration.getImageNameOutputPath().orElse(null));
}

public static String getSkaffoldSyncMap(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public class PropertyNames {
public static final String DOCKER_CLIENT_ENVIRONMENT = "jib.dockerClient.environment";
public static final String OUTPUT_PATHS_DIGEST = "jib.outputPaths.digest";
public static final String OUTPUT_PATHS_IMAGE_ID = "jib.outputPaths.imageId";
public static final String OUTPUT_PATHS_IMAGE_NAME = "jib.outputPaths.imageName";
public static final String OUTPUT_PATHS_TAR = "jib.outputPaths.tar";
public static final String CONTAINERIZING_MODE = "jib.containerizingMode";
public static final String SKIP = "jib.skip";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,6 @@ public interface RawConfiguration {
Path getDigestOutputPath();

Path getImageIdOutputPath();

Optional<Path> getImageNameOutputPath();
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,18 @@
import com.google.api.client.http.HttpStatusCodes;
import com.google.cloud.tools.jib.api.CacheDirectoryCreationException;
import com.google.cloud.tools.jib.api.Containerizer;
import com.google.cloud.tools.jib.api.ImageReference;
import com.google.cloud.tools.jib.api.InsecureRegistryException;
import com.google.cloud.tools.jib.api.JibContainer;
import com.google.cloud.tools.jib.api.JibContainerBuilder;
import com.google.cloud.tools.jib.api.RegistryException;
import com.google.cloud.tools.jib.api.RegistryUnauthorizedException;
import com.google.cloud.tools.jib.registry.RegistryCredentialsNotSentException;
import java.io.IOException;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.ExecutionException;
import org.apache.http.conn.HttpHostConnectException;
import org.junit.Assert;
Expand All @@ -50,6 +55,7 @@ public class JibBuildRunnerTest {
@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();

@Mock private JibContainerBuilder mockJibContainerBuilder;
@Mock private JibContainer mockJibContainer;
@Mock private Containerizer mockContainerizer;
@Mock private RegistryUnauthorizedException mockRegistryUnauthorizedException;
@Mock private RegistryCredentialsNotSentException mockRegistryCredentialsNotSentException;
Expand Down Expand Up @@ -215,4 +221,18 @@ public void testBuildImage_other()
Assert.assertEquals(TEST_HELPFUL_SUGGESTIONS.none(), ex.getMessage());
}
}

@Test
public void testBuildImage_writesImageName() throws Exception {
final ImageReference targetImageReference = ImageReference.parse("gcr.io/distroless/java:11");
final Path outputPath = temporaryFolder.newFile("jib-image.name").toPath();

Mockito.when(mockJibContainer.getTargetImage()).thenReturn(targetImageReference);
Mockito.when(mockJibContainerBuilder.containerize(mockContainerizer))
.thenReturn(mockJibContainer);
testJibBuildRunner.writeImageName(outputPath).runBuild();

final String output = new String(Files.readAllBytes(outputPath), StandardCharsets.UTF_8);
Assert.assertEquals(targetImageReference.toString(), output);
}
}