-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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 image digest to <target>/jib-image.digest #1155
Conversation
I'm not enamoured by this solution which has a lot of repetition. I'll look into instead leveraging the eventing system. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can just refactor the writing of the digest out to BuildStepsRunner
or somewhere else in jib-plugins-common
?
} | ||
|
||
/** | ||
* Returns the output directory for the image digest. By default, it is {@code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
output file
jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/BuildTarTask.java
Show resolved
Hide resolved
@@ -117,6 +132,8 @@ private static String buildAndRunAdditionalTag( | |||
verifier.executeGoals(Arrays.asList("clean", "compile", "jib:build")); | |||
verifier.verifyErrorFreeLog(); | |||
|
|||
assertImageDigest(projectRoot); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the test, we can actually pull and build using the digest that was generated to assert that the image was actually pushed with that digest.
So I tried various other approaches and creating an |
Hmm, what was the reason for this extra |
The additional information is what I'd want from the library. From my experience, the image digest is only useful for the build to registry case: I can't use it to access the created image In the build to docker case (nor build to tar). I can't look up a container by the image digest if I haven't pushed it to a registry. I can't use the image digest to run the image. An alternative is to change the return results from a Why an event? It allowed me to separate my action (write the digest to a file) from when that information was available. I could have modified
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's a good point that the image digest is only able to reference the image in the build to registry case. However, I'm not sure about the necessity of an event handler to write the file. I think adding the event might be redundant (compared to just adding more information to JibContainer
) since then both JibContainer
and the ImageCreatedEvent
would essentially have the same information. Also, event handling is a bit limited in what can be actually done since, for one, it doesn't currently have a good way of throwing an exception since it is executed asynchronously, whereas if we used JibContainer
to get the information after the build executes, we could write out the digest file synchronously and throw an exception if it did not succeed. The current way the eventing system is designed is more suited for tracking what is actually being done by the asynchronous steps rather than performing any costly operations or file I/O, but we could potentially change that (such as allowing checked exceptions to be thrown by event handlers).
} | ||
|
||
/** @return the created image */ | ||
public Image<? extends Layer> getImage() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can remove this since Image
is more of an internal representation rather than something we want to expose to a user.
} | ||
|
||
/** | ||
* Return the <em>image digest</em>, the digest of the registry image manifest. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right, maybe we should use <strong>
and <em>
in our other javadocs as well.
String digest = new String(Files.readAllBytes(digestPath), StandardCharsets.UTF_8); | ||
DescriptorDigest.fromDigest(digest); | ||
} catch (IOException | DigestException ex) { | ||
throw new AssertionError("Invalid jib-image.digest", ex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think since this is a test we can just have this method throw the exceptions directly?
new TimerEventHandler(message -> logEventHandler.accept(LogEvent.debug(message)))); | ||
|
||
Path buildOutputPath = project.getBuildDir().toPath(); | ||
Path digestOutputPath = buildOutputPath.resolve("jib-image.digest"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should make this configurable like jib-image.tar
is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh interesting, I thought we had that as configurable - nevermind then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted back and modified BuildStepsRunner and friends to return a JibContainer. Augmented the JibContainer with both image digest and ID. Added support for writing out the imageDigest to BuildStepsRunner.
new TimerEventHandler(message -> logEventHandler.accept(LogEvent.debug(message)))); | ||
|
||
Path buildOutputPath = project.getBuildDir().toPath(); | ||
Path digestOutputPath = buildOutputPath.resolve("jib-image.digest"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @param imageId digest of the container configuration | ||
* @return the new container | ||
*/ | ||
public static JibContainer create(DescriptorDigest imageDigest, DescriptorDigest imageId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, minor API thing, but since JibContainer
is the user-facing API for representing the build results, it might be better to not include a public factory method to create a JibContainer
. I think we should still keep the package-private constructor (or a package-private factory method) to only allow JibContainerBuilder#containerize
to instantiate it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't disagree, but it's created from the build steps in .build.steps
, not .api
.
I've moved the method on JibContainerBuilder and added a note that it is for internal consumption. I could mark it with Guava's com.google.common.annotations.Beta
annotation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should keep the package-hierarchy free of cyclical dependencies such that .api
depends on .build.steps
and there isn't a reference in the other direction - so an alternative here would be to have the build steps return the image digest and id (via some class like BuildSteps.Result
or something) and have JibContainerBuilder
create the JibContainer
using those return values.
jib-core/src/main/java/com/google/cloud/tools/jib/api/JibContainer.java
Outdated
Show resolved
Hide resolved
jib-core/src/main/java/com/google/cloud/tools/jib/api/JibContainer.java
Outdated
Show resolved
Hide resolved
jib-core/src/main/java/com/google/cloud/tools/jib/api/JibContainer.java
Outdated
Show resolved
Hide resolved
jib-core/src/test/java/com/google/cloud/tools/jib/api/JibContainerTest.java
Outdated
Show resolved
Hide resolved
@@ -130,15 +130,11 @@ static void assertCreationTimeEpoch(String imageReference) | |||
new Command("docker", "inspect", "-f", "{{.Created}}", imageReference).run().trim()); | |||
} | |||
|
|||
static void assertImageDigest(Path projectRoot) { | |||
static String assertImageDigest(Path projectRoot) throws IOException, DigestException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the String
return used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm no. We're testing the result in the maven tests, so I'll drop it from here.
BuildStepsRunner.forBuildImage(targetImageReference, getTargetImageAdditionalTags()) | ||
.imageDigestOutputPath(imageDigestOutputPath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, rather than a nullable with a setter, could this just be writeImageDigest(path)
method on either a separate class (like ImageDigestWriter
?) or chained onto BuildStepsRunner#build
?
Like
BuildStepsRunner...
.build(...)
.writeImageDigest(imageDigestOutputPath);
jib-core/src/main/java/com/google/cloud/tools/jib/api/JibContainer.java
Outdated
Show resolved
Hide resolved
jib-core/src/main/java/com/google/cloud/tools/jib/api/JibContainerBuilder.java
Outdated
Show resolved
Hide resolved
jib-core/src/main/java/com/google/cloud/tools/jib/api/JibContainerBuilder.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aside from Q's comments/a few javadoc nits, seems good to me.
} | ||
|
||
/** | ||
* Gets the digest of the container image built by Jib. | ||
* Gets the image digest, the digest of the registry image manifest built by Jib. This digest can |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First sentence seems a bit redundant, maybe just "Gets the digest of the registry image manifest built by Jib."
* | ||
* @return the image digest | ||
*/ | ||
public DescriptorDigest getDigest() { | ||
return imageDigest; | ||
} | ||
|
||
/** | ||
* Gets the image ID, the digest of the container configuration built by Jib. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, "Gets the digest of the container configuration built by Jib."
@@ -35,13 +35,13 @@ | |||
private interface ImageBuildRunnable { | |||
|
|||
/** | |||
* Builds an image and returns its digest. | |||
* Build an image. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should still be "Builds" with an 's', shouldn't it?
Let's add a CHANGLOG entry as well. |
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (this == obj) return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think we generally still use brackets for single-line if-statements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, just some merge conflicts to resolve.
public boolean equals(Object obj) { | ||
if (this == obj) return true; | ||
if (obj == null) return false; | ||
if (getClass() != obj.getClass()) return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we generally use instanceof
even though we don't use inheritance, but it does save the extra null check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant to look up Bloch previously and he discusses at length in Effective Java how .equals()
is required to be symmetric and thus instanceof
should never be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed #1202
Fixed #933