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 5 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
2 changes: 1 addition & 1 deletion config/checkstyle/copyright-java.header
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
^/\*$
^ \* Copyright 20(17|18|19) Google LLC\.$
^ \* Copyright 20(17|18|19|20) 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$
Expand Down
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 Path getImageJsonOutputPath() {
return jibExtension.getOutputPaths().getImageJsonPath();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ public class OutputPathsParameters {
private Path digest;
private Path tar;
private Path imageId;
private Path imageJson;

@Inject
public OutputPathsParameters(Project project) {
this.project = project;
digest = project.getBuildDir().toPath().resolve("jib-image.digest");
imageId = project.getBuildDir().toPath().resolve("jib-image.id");
imageJson = project.getBuildDir().toPath().resolve("jib-image.json");
tar = project.getBuildDir().toPath().resolve("jib-image.tar");
}

Expand Down Expand Up @@ -69,6 +71,20 @@ public void setImageId(String id) {
this.imageId = Paths.get(id);
}

@Input
public String getImageJson() {
return getRelativeToProjectRoot(imageJson, PropertyNames.OUTPUT_PATHS_IMAGE_JSON).toString();
}

@Internal
Path getImageJsonPath() {
return getRelativeToProjectRoot(imageJson, PropertyNames.OUTPUT_PATHS_IMAGE_JSON);
}

public void setImageJson(String imageJson) {
this.imageJson = Paths.get(imageJson);
}

@Input
public String getTar() {
return getRelativeToProjectRoot(tar, PropertyNames.OUTPUT_PATHS_TAR).toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public void testGetters() {

Mockito.when(outputPathsParameters.getDigestPath()).thenReturn(Paths.get("digest/path"));
Mockito.when(outputPathsParameters.getImageIdPath()).thenReturn(Paths.get("id/path"));
Mockito.when(outputPathsParameters.getImageJsonPath()).thenReturn(Paths.get("json/path"));
Mockito.when(outputPathsParameters.getTarPath()).thenReturn(Paths.get("tar/path"));

GradleRawConfiguration rawConfiguration = new GradleRawConfiguration(jibExtension);
Expand Down Expand Up @@ -115,6 +116,7 @@ public void testGetters() {
rawConfiguration.getDockerEnvironment());
Assert.assertEquals(Paths.get("digest/path"), rawConfiguration.getDigestOutputPath());
Assert.assertEquals(Paths.get("id/path"), rawConfiguration.getImageIdOutputPath());
Assert.assertEquals(Paths.get("json/path"), rawConfiguration.getImageJsonOutputPath());
Assert.assertEquals(Paths.get("tar/path"), rawConfiguration.getTarOutputPath());
}
}
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.
`imageJson` | string | `(project-dir)/target/jib-image.json` | The path of the image metadata json file 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 imageJson;
}

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

Path getImageJsonOutputPath() {
Path configuredPath =
outputPaths.imageJson == null
? Paths.get(getProject().getBuild().getDirectory()).resolve("jib-image.json")
: outputPaths.imageJson.toPath();
return getRelativeToProjectRoot(configuredPath, PropertyNames.OUTPUT_PATHS_IMAGE_JSON);
}

private Path getRelativeToProjectRoot(Path configuration, String propertyName) {
String property = getProperty(propertyName);
Path path = property != null ? Paths.get(property) : configuration;
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 Path getImageJsonOutputPath() {
return jibPluginConfiguration.getImageJsonOutputPath();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ public void testSystemProperties() {
sessionProperties.put("jib.outputPaths.imageId", "id/path");
Assert.assertEquals(
Paths.get("/repository/project/id/path"), testPluginConfiguration.getImageIdOutputPath());
sessionProperties.put("jib.outputPaths.imageJson", "json/path");
Assert.assertEquals(
Paths.get("/repository/project/json/path"),
testPluginConfiguration.getImageJsonOutputPath());
sessionProperties.put("jib.outputPaths.tar", "tar/path");
Assert.assertEquals(
Paths.get("/repository/project/tar/path"), testPluginConfiguration.getTarOutputPath());
Expand Down Expand Up @@ -258,6 +262,8 @@ public void testPomProperties() {
Assert.assertEquals(Paths.get("/digest/path"), testPluginConfiguration.getDigestOutputPath());
project.getProperties().setProperty("jib.outputPaths.imageId", "/id/path");
Assert.assertEquals(Paths.get("/id/path"), testPluginConfiguration.getImageIdOutputPath());
project.getProperties().setProperty("jib.outputPaths.imageJson", "/json/path");
Assert.assertEquals(Paths.get("/json/path"), testPluginConfiguration.getImageJsonOutputPath());
project.getProperties().setProperty("jib.outputPaths.tar", "tar/path");
Assert.assertEquals(
Paths.get("/repository/project/tar/path"), testPluginConfiguration.getTarOutputPath());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ public void testGetters() {
.thenReturn(new HashMap<>(ImmutableMap.of("docker", "client")));
Mockito.when(jibPluginConfiguration.getDigestOutputPath()).thenReturn(Paths.get("digest/path"));
Mockito.when(jibPluginConfiguration.getImageIdOutputPath()).thenReturn(Paths.get("id/path"));
Mockito.when(jibPluginConfiguration.getImageJsonOutputPath())
.thenReturn(Paths.get("json/path"));
Mockito.when(jibPluginConfiguration.getTarOutputPath()).thenReturn(Paths.get("tar/path"));

MavenRawConfiguration rawConfiguration = new MavenRawConfiguration(jibPluginConfiguration);
Expand Down Expand Up @@ -118,6 +120,7 @@ public void testGetters() {
rawConfiguration.getDockerEnvironment());
Assert.assertEquals(Paths.get("digest/path"), jibPluginConfiguration.getDigestOutputPath());
Assert.assertEquals(Paths.get("id/path"), jibPluginConfiguration.getImageIdOutputPath());
Assert.assertEquals(Paths.get("json/path"), jibPluginConfiguration.getImageJsonOutputPath());
Assert.assertEquals(Paths.get("tar/path"), jibPluginConfiguration.getTarOutputPath());

Mockito.verifyNoMoreInteractions(eventHandlers);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright 2020 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.plugins.common;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.cloud.tools.jib.api.JibContainer;
import com.google.cloud.tools.jib.json.JsonTemplate;
import com.google.cloud.tools.jib.json.JsonTemplateMapper;
import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;

/**
* Builds a JSON string containing metadata about a {@link JibContainer} from a build.
*
* <p>Example:
*
* <pre>{@code
* {
* "image":"gcr.io/project/image:tag",
mbruggmann marked this conversation as resolved.
Show resolved Hide resolved
* "imageId": "sha256:61bb3ec31a47cb730eb58a38bbfa813761a51dca69d10e39c24c3d00a7b2c7a9",
* "imageDigest": "sha256:3f1be7e19129edb202c071a659a4db35280ab2bb1a16f223bfd5d1948657b6f"
* }
* }</pre>
*/
public class ImageMetadataOutput implements JsonTemplate {

private final String image;
private final String imageId;
private final String imageDigest;

@JsonCreator
ImageMetadataOutput(
@JsonProperty(value = "image", required = true) String image,
@JsonProperty(value = "imageId", required = true) String imageId,
@JsonProperty(value = "imageDigest", required = true) String imageDigest) {
this.image = image;
this.imageId = imageId;
this.imageDigest = imageDigest;
}

@VisibleForTesting
static ImageMetadataOutput fromJson(String json) throws IOException {
return JsonTemplateMapper.readJson(json, ImageMetadataOutput.class);
}

public static ImageMetadataOutput fromJibContainer(JibContainer jibContainer) {
String image = jibContainer.getTargetImage().toString();
String imageId = jibContainer.getImageId().toString();
String imageDigest = jibContainer.getDigest().toString();
return new ImageMetadataOutput(image, imageId, imageDigest);
}

public String getImage() {
return image;
}

public String getImageId() {
return imageId;
}

public String getImageDigest() {
return imageDigest;
}

public String toJson() throws IOException {
return JsonTemplateMapper.toUtf8String(this);
}
}
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 imageJsonOutputPath;

@VisibleForTesting
JibBuildRunner(
Expand Down Expand Up @@ -237,6 +238,11 @@ public JibContainer runBuild()
String imageId = jibContainer.getImageId().toString();
Files.write(imageIdOutputPath, imageId.getBytes(StandardCharsets.UTF_8));
}
if (imageJsonOutputPath != null) {
ImageMetadataOutput metadataOutput = ImageMetadataOutput.fromJibContainer(jibContainer);
String imageJson = metadataOutput.toJson();
Files.write(imageJsonOutputPath, imageJson.getBytes(StandardCharsets.UTF_8));
}

return jibContainer;

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

/**
* Set the location where the image metadata json will be saved. If {@code null} then the metadata
* is not saved.
*
* @param imageJsonOutputPath the location to write the image metadata, or {@code null} to skip
* @return this
*/
public JibBuildRunner writeImageJson(@Nullable Path imageJsonOutputPath) {
this.imageJsonOutputPath = imageJsonOutputPath;
return this;
}
}
Loading