Add runImage option for image building
This commit adds a runImage property to the Maven plugin build-image goal and the Gradle bootBuildImage task. The property allows the user to override the run image reference provided in the builder metadata with an alternate run image. The runImage property can be specified in the build file or on the command line. Fixes gh-21534
This commit is contained in:
@@ -82,7 +82,6 @@ public class BuildRequestTests {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> BuildRequest.forJarFile(new File(this.tempDir, "missing.jar")))
|
||||
.withMessage("JarFile must exist");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -106,6 +105,21 @@ public class BuildRequestTests {
|
||||
"docker.io/spring/builder:@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withRunImageUpdatesRunImage() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"))
|
||||
.withRunImage(ImageReference.of("example.com/custom/run-image:latest"));
|
||||
assertThat(request.getRunImage().toString()).isEqualTo("example.com/custom/run-image:latest");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withRunImageWhenHasDigestUpdatesRunImage() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar")).withRunImage(ImageReference
|
||||
.of("example.com/custom/run-image:@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d"));
|
||||
assertThat(request.getRunImage().toString()).isEqualTo(
|
||||
"example.com/custom/run-image:@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withCreatorUpdatesCreator() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
|
||||
|
||||
@@ -106,6 +106,47 @@ class BuilderTests {
|
||||
verify(docker.image()).remove(archive.getValue().getTag(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildInvokesBuilderWithRunImageInDigestForm() throws Exception {
|
||||
TestPrintStream out = new TestPrintStream();
|
||||
DockerApi docker = mockDockerApi();
|
||||
Image builderImage = loadImage("image-with-run-image-digest.json");
|
||||
Image runImage = loadImage("run-image.json");
|
||||
given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any()))
|
||||
.willAnswer(withPulledImage(builderImage));
|
||||
given(docker.image().pull(eq(ImageReference.of(
|
||||
"docker.io/cloudfoundry/run:@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d")),
|
||||
any())).willAnswer(withPulledImage(runImage));
|
||||
Builder builder = new Builder(BuildLog.to(out), docker);
|
||||
BuildRequest request = getTestRequest();
|
||||
builder.build(request);
|
||||
assertThat(out.toString()).contains("Running creator");
|
||||
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
|
||||
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
|
||||
verify(docker.image()).load(archive.capture(), any());
|
||||
verify(docker.image()).remove(archive.getValue().getTag(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildInvokesBuilderWithRunImageFromRequest() throws Exception {
|
||||
TestPrintStream out = new TestPrintStream();
|
||||
DockerApi docker = mockDockerApi();
|
||||
Image builderImage = loadImage("image.json");
|
||||
Image runImage = loadImage("run-image.json");
|
||||
given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any()))
|
||||
.willAnswer(withPulledImage(builderImage));
|
||||
given(docker.image().pull(eq(ImageReference.of("example.com/custom/run:latest")), any()))
|
||||
.willAnswer(withPulledImage(runImage));
|
||||
Builder builder = new Builder(BuildLog.to(out), docker);
|
||||
BuildRequest request = getTestRequest().withRunImage(ImageReference.of("example.com/custom/run:latest"));
|
||||
builder.build(request);
|
||||
assertThat(out.toString()).contains("Running creator");
|
||||
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
|
||||
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
|
||||
verify(docker.image()).load(archive.capture(), any());
|
||||
verify(docker.image()).remove(archive.getValue().getTag(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWhenStackIdDoesNotMatchThrowsException() throws Exception {
|
||||
TestPrintStream out = new TestPrintStream();
|
||||
@@ -175,8 +216,7 @@ class BuilderTests {
|
||||
private BuildRequest getTestRequest() {
|
||||
TarArchive content = mock(TarArchive.class);
|
||||
ImageReference name = ImageReference.of("my-application");
|
||||
BuildRequest request = BuildRequest.of(name, (owner) -> content);
|
||||
return request;
|
||||
return BuildRequest.of(name, (owner) -> content);
|
||||
}
|
||||
|
||||
private Image loadImage(String name) throws IOException {
|
||||
|
||||
@@ -150,7 +150,7 @@ class LifecycleTests {
|
||||
private BuildRequest getTestRequest() {
|
||||
TarArchive content = mock(TarArchive.class);
|
||||
ImageReference name = ImageReference.of("my-application");
|
||||
return BuildRequest.of(name, (owner) -> content);
|
||||
return BuildRequest.of(name, (owner) -> content).withRunImage(ImageReference.of("cloudfoundry/run"));
|
||||
}
|
||||
|
||||
private Lifecycle createLifecycle() throws IOException {
|
||||
@@ -159,8 +159,7 @@ class LifecycleTests {
|
||||
|
||||
private Lifecycle createLifecycle(BuildRequest request) throws IOException {
|
||||
EphemeralBuilder builder = mockEphemeralBuilder();
|
||||
return new TestLifecycle(BuildLog.to(this.out), this.docker, request, ImageReference.of("cloudfoundry/run"),
|
||||
builder);
|
||||
return new TestLifecycle(BuildLog.to(this.out), this.docker, request, builder);
|
||||
}
|
||||
|
||||
private EphemeralBuilder mockEphemeralBuilder() throws IOException {
|
||||
@@ -208,9 +207,8 @@ class LifecycleTests {
|
||||
|
||||
static class TestLifecycle extends Lifecycle {
|
||||
|
||||
TestLifecycle(BuildLog log, DockerApi docker, BuildRequest request, ImageReference runImageReference,
|
||||
EphemeralBuilder builder) {
|
||||
super(log, docker, request, runImageReference, builder);
|
||||
TestLifecycle(BuildLog log, DockerApi docker, BuildRequest request, EphemeralBuilder builder) {
|
||||
super(log, docker, request, builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,6 +28,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
* Tests for {@link ImageReference}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class ImageReferenceTests {
|
||||
|
||||
@@ -223,6 +224,26 @@ class ImageReferenceTests {
|
||||
assertThat(reference.inTaggedForm().toString()).isEqualTo("docker.io/library/ubuntu:bionic");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inTaggedOrDigestFormWhenHasDigestUsesDigest() {
|
||||
ImageReference reference = ImageReference
|
||||
.of("ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d");
|
||||
assertThat(reference.inTaggedOrDigestForm().toString()).isEqualTo(
|
||||
"docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inTaggedOrDigestFormWhenHasTagUsesTag() {
|
||||
ImageReference reference = ImageReference.of("ubuntu:bionic");
|
||||
assertThat(reference.inTaggedOrDigestForm().toString()).isEqualTo("docker.io/library/ubuntu:bionic");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inTaggedOrDigestFormWhenHasNoTagOrDigestUsesLatest() {
|
||||
ImageReference reference = ImageReference.of("ubuntu");
|
||||
assertThat(reference.inTaggedOrDigestForm().toString()).isEqualTo("docker.io/library/ubuntu:latest");
|
||||
}
|
||||
|
||||
@Test
|
||||
void equalsAndHashCode() {
|
||||
ImageReference r1 = ImageReference.of("ubuntu:bionic");
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"User" : "root",
|
||||
"Image" : "pack.local/ephemeral-builder",
|
||||
"Cmd" : [ "/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "-skip-restore", "docker.io/library/my-application:latest" ],
|
||||
"Cmd" : [ "/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run:latest", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "-skip-restore", "docker.io/library/my-application:latest" ],
|
||||
"Labels" : {
|
||||
"author" : "spring-boot"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"User" : "root",
|
||||
"Image" : "pack.local/ephemeral-builder",
|
||||
"Cmd" : [ "/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "docker.io/library/my-application:latest" ],
|
||||
"Cmd" : [ "/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run:latest", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "docker.io/library/my-application:latest" ],
|
||||
"Labels" : {
|
||||
"author" : "spring-boot"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user