From 8e6d03b22105fcad469fe498ccee2b0983212ed3 Mon Sep 17 00:00:00 2001 From: Jeroen Meijer Date: Sat, 24 Jul 2021 15:47:01 +0200 Subject: [PATCH 1/2] Add network option for image building This commit adds configuration to the Maven and Gradle plugins to allow specifying the network mode to be provided to the image building goal and task. See gh-27486 --- .../platform/build/BuildRequest.java | 46 ++++++++++++++----- .../buildpack/platform/build/Lifecycle.java | 2 + .../boot/buildpack/platform/build/Phase.java | 8 ++++ .../platform/docker/type/ContainerConfig.java | 14 +++++- .../platform/build/BuildRequestTests.java | 7 +++ .../platform/build/LifecycleTests.java | 12 +++++ .../buildpack/platform/build/PhaseTests.java | 20 ++++++++ .../docker/type/ContainerConfigTests.java | 2 + .../build/lifecycle-creator-network.json | 13 ++++++ .../docker/type/container-config.json | 3 +- .../docs/asciidoc/packaging-oci-image.adoc | 8 ++++ .../gradle/tasks/bundling/BootBuildImage.java | 23 ++++++++++ .../tasks/bundling/BootBuildImageTests.java | 7 +++ .../docs/asciidoc/packaging-oci-image.adoc | 8 ++++ .../boot/maven/BuildImageMojo.java | 11 +++++ .../org/springframework/boot/maven/Image.java | 16 +++++++ .../boot/maven/ImageTests.java | 10 ++++ 17 files changed, 195 insertions(+), 15 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-network.json diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java index 93600e49e0..8b2e822cfb 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java @@ -36,6 +36,7 @@ import org.springframework.util.Assert; * @author Phillip Webb * @author Scott Frederick * @author Andrey Shlykov + * @author Jeroen Meijer * @since 2.3.0 */ public class BuildRequest { @@ -68,6 +69,8 @@ public class BuildRequest { private final List bindings; + private final String network; + BuildRequest(ImageReference name, Function applicationContent) { Assert.notNull(name, "Name must not be null"); Assert.notNull(applicationContent, "ApplicationContent must not be null"); @@ -83,12 +86,13 @@ public class BuildRequest { this.creator = Creator.withVersion(""); this.buildpacks = Collections.emptyList(); this.bindings = Collections.emptyList(); + this.network = null; } BuildRequest(ImageReference name, Function applicationContent, ImageReference builder, ImageReference runImage, Creator creator, Map env, boolean cleanCache, boolean verboseLogging, PullPolicy pullPolicy, boolean publish, List buildpacks, - List bindings) { + List bindings, String network) { this.name = name; this.applicationContent = applicationContent; this.builder = builder; @@ -101,6 +105,7 @@ public class BuildRequest { this.publish = publish; this.buildpacks = buildpacks; this.bindings = bindings; + this.network = network; } /** @@ -112,7 +117,7 @@ public class BuildRequest { Assert.notNull(builder, "Builder must not be null"); return new BuildRequest(this.name, this.applicationContent, builder.inTaggedOrDigestForm(), this.runImage, this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, - this.buildpacks, this.bindings); + this.buildpacks, this.bindings, this.network); } /** @@ -123,7 +128,7 @@ public class BuildRequest { public BuildRequest withRunImage(ImageReference runImageName) { return new BuildRequest(this.name, this.applicationContent, this.builder, runImageName.inTaggedOrDigestForm(), this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, - this.buildpacks, this.bindings); + this.buildpacks, this.bindings, this.network); } /** @@ -134,7 +139,8 @@ public class BuildRequest { public BuildRequest withCreator(Creator creator) { Assert.notNull(creator, "Creator must not be null"); return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, creator, this.env, - this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings); + this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings, + this.network); } /** @@ -150,7 +156,7 @@ public class BuildRequest { env.put(name, value); return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, Collections.unmodifiableMap(env), this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, - this.buildpacks, this.bindings); + this.buildpacks, this.bindings, this.network); } /** @@ -164,7 +170,7 @@ public class BuildRequest { updatedEnv.putAll(env); return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, Collections.unmodifiableMap(updatedEnv), this.cleanCache, this.verboseLogging, this.pullPolicy, - this.publish, this.buildpacks, this.bindings); + this.publish, this.buildpacks, this.bindings, this.network); } /** @@ -174,7 +180,8 @@ public class BuildRequest { */ public BuildRequest withCleanCache(boolean cleanCache) { return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env, - cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings); + cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings, + this.network); } /** @@ -184,7 +191,8 @@ public class BuildRequest { */ public BuildRequest withVerboseLogging(boolean verboseLogging) { return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env, - this.cleanCache, verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings); + this.cleanCache, verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings, + this.network); } /** @@ -194,7 +202,8 @@ public class BuildRequest { */ public BuildRequest withPullPolicy(PullPolicy pullPolicy) { return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env, - this.cleanCache, this.verboseLogging, pullPolicy, this.publish, this.buildpacks, this.bindings); + this.cleanCache, this.verboseLogging, pullPolicy, this.publish, this.buildpacks, this.bindings, + this.network); } /** @@ -204,7 +213,8 @@ public class BuildRequest { */ public BuildRequest withPublish(boolean publish) { return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env, - this.cleanCache, this.verboseLogging, this.pullPolicy, publish, this.buildpacks, this.bindings); + this.cleanCache, this.verboseLogging, this.pullPolicy, publish, this.buildpacks, this.bindings, + this.network); } /** @@ -227,7 +237,8 @@ public class BuildRequest { public BuildRequest withBuildpacks(List buildpacks) { Assert.notNull(buildpacks, "Buildpacks must not be null"); return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env, - this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, buildpacks, this.bindings); + this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, buildpacks, this.bindings, + this.network); } /** @@ -250,7 +261,14 @@ public class BuildRequest { public BuildRequest withBindings(List bindings) { Assert.notNull(bindings, "Bindings must not be null"); return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env, - this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, bindings); + this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, bindings, + this.network); + } + + public BuildRequest withNetwork(String network) { + return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env, + this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings, + network); } /** @@ -353,6 +371,10 @@ public class BuildRequest { return this.bindings; } + public String getNetwork() { + return this.network; + } + /** * Factory method to create a new {@link BuildRequest} from a JAR file. * @param jarFile the source jar file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java index c6adc77096..f67470445b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java @@ -38,6 +38,7 @@ import org.springframework.util.Assert; * * @author Phillip Webb * @author Scott Frederick + * @author Jeroen Meijer */ class Lifecycle implements Closeable { @@ -147,6 +148,7 @@ class Lifecycle implements Closeable { this.request.getBindings().forEach(phase::withBinding); } phase.withEnv(PLATFORM_API_VERSION_KEY, this.platformVersion.toString()); + phase.withNetworkMode(this.request.getNetwork()); return phase; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java index 234592afd4..fab5bb4845 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java @@ -31,6 +31,7 @@ import org.springframework.util.StringUtils; * * @author Phillip Webb * @author Scott Frederick + * @author Jeroen Meijer */ class Phase { @@ -48,6 +49,8 @@ class Phase { private final Map env = new LinkedHashMap<>(); + private String networkMode; + /** * Create a new {@link Phase} instance. * @param name the name of the phase @@ -101,6 +104,10 @@ class Phase { this.env.put(name, value); } + void withNetworkMode(String networkMode) { + this.networkMode = networkMode; + } + /** * Return the name of the phase. * @return the phase name @@ -127,6 +134,7 @@ class Phase { update.withLabel("author", "spring-boot"); this.bindings.forEach(update::withBinding); this.env.forEach(update::withEnv); + update.withNetworkMode(this.networkMode); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfig.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfig.java index da945f6848..1df69c312e 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfig.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfig.java @@ -40,6 +40,7 @@ import org.springframework.util.StringUtils; * * @author Phillip Webb * @author Scott Frederick + * @author Jeroen Meijer * @since 2.3.0 */ public class ContainerConfig { @@ -47,7 +48,7 @@ public class ContainerConfig { private final String json; ContainerConfig(String user, ImageReference image, String command, List args, Map labels, - List bindings, Map env) throws IOException { + List bindings, Map env, String networkMode) throws IOException { Assert.notNull(image, "Image must not be null"); Assert.hasText(command, "Command must not be empty"); ObjectMapper objectMapper = SharedObjectMapper.get(); @@ -64,6 +65,9 @@ public class ContainerConfig { ObjectNode labelsNode = node.putObject("Labels"); labels.forEach(labelsNode::put); ObjectNode hostConfigNode = node.putObject("HostConfig"); + if (networkMode != null) { + hostConfigNode.put("NetworkMode", networkMode); + } ArrayNode bindsNode = hostConfigNode.putArray("Binds"); bindings.forEach((binding) -> bindsNode.add(binding.toString())); this.json = objectMapper.writeValueAsString(node); @@ -114,6 +118,8 @@ public class ContainerConfig { private final Map env = new LinkedHashMap<>(); + private String networkMode; + Update(ImageReference image) { this.image = image; } @@ -122,7 +128,7 @@ public class ContainerConfig { update.accept(this); try { return new ContainerConfig(this.user, this.image, this.command, this.args, this.labels, this.bindings, - this.env); + this.env, this.networkMode); } catch (IOException ex) { throw new IllegalStateException(ex); @@ -182,6 +188,10 @@ public class ContainerConfig { this.env.put(name, value); } + public void withNetworkMode(String networkMode) { + this.networkMode = networkMode; + } + } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java index 92115cc0a5..c75e5155cf 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java @@ -45,6 +45,7 @@ import static org.assertj.core.api.Assertions.entry; * * @author Phillip Webb * @author Scott Frederick + * @author Jeroen Meijer */ public class BuildRequestTests { @@ -199,6 +200,12 @@ public class BuildRequestTests { .withMessage("Bindings must not be null"); } + @Test + void withNetworkUpdatesNetwork() throws IOException { + BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar")).withNetwork("test"); + assertThat(request.getNetwork()).isEqualTo("test"); + } + private void hasExpectedJarContent(TarArchive archive) { try { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java index 8e5b26187c..03234771e2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java @@ -62,6 +62,7 @@ import static org.mockito.Mockito.verify; * * @author Phillip Webb * @author Scott Frederick + * @author Jeroen Meijer */ class LifecycleTests { @@ -188,6 +189,17 @@ class LifecycleTests { verify(this.docker.volume()).delete(VolumeName.of("pack-app-aaaaaaaaaa"), true); } + @Test + void executeWithNetworkExecutesPhases() throws Exception { + given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId()); + given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId()); + given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null)); + BuildRequest request = getTestRequest().withNetwork("test"); + createLifecycle(request).execute(); + assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-network.json")); + assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); + } + private DockerApi mockDockerApi() { DockerApi docker = mock(DockerApi.class); ImageApi imageApi = mock(ImageApi.class); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java index ffddb46448..e2cc1bc47b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java @@ -32,6 +32,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; * * @author Phillip Webb * @author Scott Frederick + * @author Jeroen Meijer */ class PhaseTests { @@ -56,6 +57,7 @@ class PhaseTests { phase.apply(update); verify(update).withCommand("/cnb/lifecycle/test", NO_ARGS); verify(update).withLabel("author", "spring-boot"); + verify(update).withNetworkMode(null); verifyNoMoreInteractions(update); } @@ -69,6 +71,7 @@ class PhaseTests { verify(update).withBinding(Binding.from("/var/run/docker.sock", "/var/run/docker.sock")); verify(update).withCommand("/cnb/lifecycle/test", NO_ARGS); verify(update).withLabel("author", "spring-boot"); + verify(update).withNetworkMode(null); verifyNoMoreInteractions(update); } @@ -80,6 +83,7 @@ class PhaseTests { phase.apply(update); verify(update).withCommand("/cnb/lifecycle/test", "-log-level", "debug"); verify(update).withLabel("author", "spring-boot"); + verify(update).withNetworkMode(null); verifyNoMoreInteractions(update); } @@ -91,6 +95,7 @@ class PhaseTests { phase.apply(update); verify(update).withCommand("/cnb/lifecycle/test"); verify(update).withLabel("author", "spring-boot"); + verify(update).withNetworkMode(null); verifyNoMoreInteractions(update); } @@ -102,6 +107,7 @@ class PhaseTests { phase.apply(update); verify(update).withCommand("/cnb/lifecycle/test", "a", "b", "c"); verify(update).withLabel("author", "spring-boot"); + verify(update).withNetworkMode(null); verifyNoMoreInteractions(update); } @@ -115,6 +121,7 @@ class PhaseTests { verify(update).withCommand("/cnb/lifecycle/test"); verify(update).withLabel("author", "spring-boot"); verify(update).withBinding(Binding.from(volumeName, "/test")); + verify(update).withNetworkMode(null); verifyNoMoreInteractions(update); } @@ -129,6 +136,19 @@ class PhaseTests { verify(update).withLabel("author", "spring-boot"); verify(update).withEnv("name1", "value1"); verify(update).withEnv("name2", "value2"); + verify(update).withNetworkMode(null); + verifyNoMoreInteractions(update); + } + + @Test + void applyWhenWithNetworkModeUpdatesConfigurationWithNetworkMode() { + Phase phase = new Phase("test", true); + phase.withNetworkMode("test"); + Update update = mock(Update.class); + phase.apply(update); + verify(update).withCommand("/cnb/lifecycle/test"); + verify(update).withNetworkMode("test"); + verify(update).withLabel("author", "spring-boot"); verifyNoMoreInteractions(update); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfigTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfigTests.java index cc94d2d7ae..a0b9292345 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfigTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfigTests.java @@ -32,6 +32,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException * * @author Phillip Webb * @author Scott Frederick + * @author Jeroen Meijer */ class ContainerConfigTests extends AbstractJsonTests { @@ -59,6 +60,7 @@ class ContainerConfigTests extends AbstractJsonTests { update.withBinding(Binding.from("bind-source", "bind-dest")); update.withEnv("name1", "value1"); update.withEnv("name2", "value2"); + update.withNetworkMode("test"); }); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); containerConfig.writeTo(outputStream); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-network.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-network.json new file mode 100644 index 0000000000..ae6ab807d1 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-network.json @@ -0,0 +1,13 @@ +{ + "User" : "root", + "Image" : "pack.local/ephemeral-builder", + "Cmd" : [ "/cnb/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run:latest", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "-process-type=web", "docker.io/library/my-application:latest" ], + "Env" : [ "CNB_PLATFORM_API=0.4" ], + "Labels" : { + "author" : "spring-boot" + }, + "HostConfig" : { + "NetworkMode" : "test", + "Binds" : [ "/var/run/docker.sock:/var/run/docker.sock", "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache", "pack-cache-b35197ac41ea.launch:/launch-cache" ] + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/container-config.json b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/container-config.json index 2c034b7767..51780616f1 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/container-config.json +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/container-config.json @@ -16,6 +16,7 @@ "HostConfig": { "Binds": [ "bind-source:bind-dest" - ] + ], + "NetworkMode": "test" } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging-oci-image.adoc b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging-oci-image.adoc index 65f0f4cc6d..888d1524c9 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging-oci-image.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging-oci-image.adoc @@ -169,6 +169,14 @@ Where `` can contain: | `--publishImage` | Whether to publish the generated image to a Docker registry. | `false` + +| `network` +| `--network` +| The network the build container will connect to. The value supplied for this option will be passed +unvalidated as `HostConfig.NetworkMode` to the configuration which creates the build container, +see https://docs.docker.com/engine/api/v1.41/#operation/ContainerCreate[Docker's engine API]. +Using this option is similar to running `docker build --network ...`. +| |=== NOTE: The plugin detects the target Java compatibility of the project using the JavaPlugin's `targetCompatibility` property. diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java index bdd8cdb2e2..831987fa72 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java @@ -58,6 +58,7 @@ import org.springframework.util.StringUtils; * * @author Andy Wilkinson * @author Scott Frederick + * @author Jeroen Meijer * @since 2.3.0 */ public class BootBuildImage extends DefaultTask { @@ -92,6 +93,8 @@ public class BootBuildImage extends DefaultTask { private final ListProperty bindings; + private String network; + private final DockerSpec docker = new DockerSpec(); public BootBuildImage() { @@ -376,6 +379,25 @@ public class BootBuildImage extends DefaultTask { this.bindings.addAll(bindings); } + /** + * Returns the network the build container will connect to. + * @return the network + */ + @Input + @Optional + public String getNetwork() { + return this.network; + } + + /** + * Sets the network the build container will connect to. + * @param network the network + */ + @Option(option = "network", description = "Connect detect and build containers to network") + public void setNetwork(String network) { + this.network = network; + } + /** * Returns the Docker configuration the builder will use. * @return docker configuration. @@ -438,6 +460,7 @@ public class BootBuildImage extends DefaultTask { request = customizePublish(request); request = customizeBuildpacks(request); request = customizeBindings(request); + request = request.withNetwork(this.network); return request; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageTests.java index 31d2d10dd8..082a2b5954 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageTests.java @@ -42,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; * @author Andy Wilkinson * @author Scott Frederick * @author Andrey Shlykov + * @author Jeroen Meijer */ class BootBuildImageTests { @@ -278,4 +279,10 @@ class BootBuildImageTests { .containsExactly(Binding.of("host-src:container-dest:ro"), Binding.of("volume-name:container-dest:rw")); } + @Test + void whenNetworkIsConfiguredThenRequestHasNetwork() { + this.buildImage.setNetwork("test"); + assertThat(this.buildImage.createRequest().getNetwork()).isEqualTo("test"); + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc index 24de20aaa1..2a58ca004d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc @@ -176,6 +176,14 @@ Where `` can contain: (`spring-boot.build-image.publish`) | Whether to publish the generated image to a Docker registry. | `false` + +| `network` + +(`spring-boot.build-image.network`) +| The network the build container will connect to. The value supplied for this option will be passed +unvalidated as `HostConfig.NetworkMode` to the configuration which creates the build container, +see https://docs.docker.com/engine/api/v1.41/#operation/ContainerCreate[Docker's engine API]. +Using this option is similar to running `docker build --network ...`. +| |=== NOTE: The plugin detects the target Java compatibility of the project using the compiler's plugin configuration or the `maven.compiler.target` property. diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java index 33b9891b78..95f2ecee4f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java @@ -59,6 +59,7 @@ import org.springframework.util.StringUtils; * * @author Phillip Webb * @author Scott Frederick + * @author Jeroen Meijer * @since 2.3.0 */ @Mojo(name = "build-image", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true, threadSafe = true, @@ -153,6 +154,13 @@ public class BuildImageMojo extends AbstractPackagerMojo { @Parameter(property = "spring-boot.build-image.publish", readonly = true) Boolean publish; + /** + * Alias for {@link Image#network} to support configuration via command-line property. + * @since 2.6.0 + */ + @Parameter(property = "spring-boot.build-image.network", readonly = true) + String network; + /** * Docker configuration options. * @since 2.4.0 @@ -248,6 +256,9 @@ public class BuildImageMojo extends AbstractPackagerMojo { if (image.publish == null && this.publish != null) { image.setPublish(this.publish); } + if (image.network == null && this.network != null) { + image.setNetwork(this.network); + } if (image.publish != null && image.publish && publishRegistryNotConfigured()) { throw new MojoExecutionException("Publishing an image requires docker.publishRegistry to be configured"); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java index 0ce0afd83b..e648f556bc 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java @@ -39,6 +39,7 @@ import org.springframework.util.StringUtils; * * @author Phillip Webb * @author Scott Frederick + * @author Jeroen Meijer * @since 2.3.0 */ public class Image { @@ -63,6 +64,8 @@ public class Image { List bindings; + String network; + /** * The name of the created image. * @return the image name @@ -151,6 +154,18 @@ public class Image { this.publish = publish; } + /** + * Returns the network the build container will connect to. + * @return the network + */ + public String getNetwork() { + return this.network; + } + + public void setNetwork(String network) { + this.network = network; + } + BuildRequest getBuildRequest(Artifact artifact, Function applicationContent) { return customize(BuildRequest.of(getOrDeduceName(artifact), applicationContent)); } @@ -190,6 +205,7 @@ public class Image { if (!CollectionUtils.isEmpty(this.bindings)) { request = request.withBindings(this.bindings.stream().map(Binding::of).collect(Collectors.toList())); } + request = request.withNetwork(this.network); return request; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java index 15ee4db410..7c0d24921f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java @@ -41,6 +41,7 @@ import static org.assertj.core.api.Assertions.entry; * * @author Phillip Webb * @author Scott Frederick + * @author Jeroen Meijer */ class ImageTests { @@ -70,6 +71,7 @@ class ImageTests { assertThat(request.getPullPolicy()).isEqualTo(PullPolicy.ALWAYS); assertThat(request.getBuildpacks()).isEmpty(); assertThat(request.getBindings()).isEmpty(); + assertThat(request.getNetwork()).isNull(); } @Test @@ -146,6 +148,14 @@ class ImageTests { Binding.of("volume-name:container-dest:rw")); } + @Test + void getBuildRequestWhenNetworkUsesNetwork() { + Image image = new Image(); + image.network = "test"; + BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent()); + assertThat(request.getNetwork()).isEqualTo("test"); + } + private Artifact createArtifact() { return new DefaultArtifact("com.example", "my-app", VersionRange.createFromVersion("0.0.1-SNAPSHOT"), "compile", "jar", null, new DefaultArtifactHandler()); From 2178c281e9bad4d58f9bcc6d4296c928cff04d1d Mon Sep 17 00:00:00 2001 From: Scott Frederick Date: Thu, 12 Aug 2021 17:07:49 -0500 Subject: [PATCH 2/2] Polish "Add network option for image building" See gh-27486 --- .../platform/build/BuildRequest.java | 11 ++++++ .../buildpack/platform/build/Lifecycle.java | 4 ++- .../boot/buildpack/platform/build/Phase.java | 8 ++++- .../platform/docker/type/ContainerConfig.java | 5 +++ .../buildpack/platform/build/PhaseTests.java | 7 ---- .../docs/asciidoc/packaging-oci-image.adoc | 13 ++++--- .../BootBuildImageIntegrationTests.java | 15 ++++++++ ...ests-buildsImageWithNetworkModeNone.gradle | 16 +++++++++ .../docs/asciidoc/packaging-oci-image.adoc | 13 ++++--- .../boot/maven/BuildImageTests.java | 11 ++++++ .../projects/build-image-network/pom.xml | 35 +++++++++++++++++++ .../main/java/org/test/SampleApplication.java | 28 +++++++++++++++ .../buildpacks/test-info/bin/build | 2 ++ 13 files changed, 145 insertions(+), 23 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithNetworkModeNone.gradle create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-network/pom.xml create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-network/src/main/java/org/test/SampleApplication.java diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java index 8b2e822cfb..b7feaa5277 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java @@ -265,6 +265,12 @@ public class BuildRequest { this.network); } + /** + * Return a new {@link BuildRequest} with an updated network setting. + * @param network the network the build container will connect to + * @return an updated build request + * @since 2.6.0 + */ public BuildRequest withNetwork(String network) { return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings, @@ -371,6 +377,11 @@ public class BuildRequest { return this.bindings; } + /** + * Return the network the build container will connect to. + * @return the network + * @since 2.6.0 + */ public String getNetwork() { return this.network; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java index f67470445b..ae372bc71e 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java @@ -148,7 +148,9 @@ class Lifecycle implements Closeable { this.request.getBindings().forEach(phase::withBinding); } phase.withEnv(PLATFORM_API_VERSION_KEY, this.platformVersion.toString()); - phase.withNetworkMode(this.request.getNetwork()); + if (this.request.getNetwork() != null) { + phase.withNetworkMode(this.request.getNetwork()); + } return phase; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java index fab5bb4845..8c0264f836 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java @@ -104,6 +104,10 @@ class Phase { this.env.put(name, value); } + /** + * Update this phase with the network the build container will connect to. + * @param networkMode the network + */ void withNetworkMode(String networkMode) { this.networkMode = networkMode; } @@ -134,7 +138,9 @@ class Phase { update.withLabel("author", "spring-boot"); this.bindings.forEach(update::withBinding); this.env.forEach(update::withEnv); - update.withNetworkMode(this.networkMode); + if (this.networkMode != null) { + update.withNetworkMode(this.networkMode); + } } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfig.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfig.java index 1df69c312e..a411b49f28 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfig.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfig.java @@ -188,6 +188,11 @@ public class ContainerConfig { this.env.put(name, value); } + /** + * Update the container config with the network that the build container will + * connect to. + * @param networkMode the network + */ public void withNetworkMode(String networkMode) { this.networkMode = networkMode; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java index e2cc1bc47b..6bed915d45 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java @@ -57,7 +57,6 @@ class PhaseTests { phase.apply(update); verify(update).withCommand("/cnb/lifecycle/test", NO_ARGS); verify(update).withLabel("author", "spring-boot"); - verify(update).withNetworkMode(null); verifyNoMoreInteractions(update); } @@ -71,7 +70,6 @@ class PhaseTests { verify(update).withBinding(Binding.from("/var/run/docker.sock", "/var/run/docker.sock")); verify(update).withCommand("/cnb/lifecycle/test", NO_ARGS); verify(update).withLabel("author", "spring-boot"); - verify(update).withNetworkMode(null); verifyNoMoreInteractions(update); } @@ -83,7 +81,6 @@ class PhaseTests { phase.apply(update); verify(update).withCommand("/cnb/lifecycle/test", "-log-level", "debug"); verify(update).withLabel("author", "spring-boot"); - verify(update).withNetworkMode(null); verifyNoMoreInteractions(update); } @@ -95,7 +92,6 @@ class PhaseTests { phase.apply(update); verify(update).withCommand("/cnb/lifecycle/test"); verify(update).withLabel("author", "spring-boot"); - verify(update).withNetworkMode(null); verifyNoMoreInteractions(update); } @@ -107,7 +103,6 @@ class PhaseTests { phase.apply(update); verify(update).withCommand("/cnb/lifecycle/test", "a", "b", "c"); verify(update).withLabel("author", "spring-boot"); - verify(update).withNetworkMode(null); verifyNoMoreInteractions(update); } @@ -121,7 +116,6 @@ class PhaseTests { verify(update).withCommand("/cnb/lifecycle/test"); verify(update).withLabel("author", "spring-boot"); verify(update).withBinding(Binding.from(volumeName, "/test")); - verify(update).withNetworkMode(null); verifyNoMoreInteractions(update); } @@ -136,7 +130,6 @@ class PhaseTests { verify(update).withLabel("author", "spring-boot"); verify(update).withEnv("name1", "value1"); verify(update).withEnv("name2", "value2"); - verify(update).withNetworkMode(null); verifyNoMoreInteractions(update); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging-oci-image.adoc b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging-oci-image.adoc index 888d1524c9..0d1677aac2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging-oci-image.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging-oci-image.adoc @@ -155,6 +155,12 @@ Where `` can contain: * `volume-opt=key=value` to specify key-value pairs consisting of an option name and its value | +| `network` +| `--network` +| The https://docs.docker.com/network/#network-drivers[network driver] the builder container will be configured to use. +The value supplied will be passed unvalidated to Docker when creating the builder container. +| + | `cleanCache` | `--cleanCache` | Whether to clean the cache before building. @@ -170,13 +176,6 @@ Where `` can contain: | Whether to publish the generated image to a Docker registry. | `false` -| `network` -| `--network` -| The network the build container will connect to. The value supplied for this option will be passed -unvalidated as `HostConfig.NetworkMode` to the configuration which creates the build container, -see https://docs.docker.com/engine/api/v1.41/#operation/ContainerCreate[Docker's engine API]. -Using this option is similar to running `docker build --network ...`. -| |=== NOTE: The plugin detects the target Java compatibility of the project using the JavaPlugin's `targetCompatibility` property. diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java index a8517e11ef..8f5d4691af 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java @@ -71,6 +71,7 @@ class BootBuildImageIntegrationTests { assertThat(result.getOutput()).contains("docker.io/library/" + projectName); assertThat(result.getOutput()).contains("---> Test Info buildpack building"); assertThat(result.getOutput()).contains("env: BP_JVM_VERSION=8.*"); + assertThat(result.getOutput()).contains("Network status: HTTP/2 200"); assertThat(result.getOutput()).contains("---> Test Info buildpack done"); removeImage(projectName); } @@ -247,6 +248,20 @@ class BootBuildImageIntegrationTests { removeImage(projectName); } + @TestTemplate + void buildsImageWithNetworkModeNone() throws IOException { + writeMainClass(); + writeLongNameResource(); + BuildResult result = this.gradleBuild.build("bootBuildImage", "--pullPolicy=IF_NOT_PRESENT"); + String projectName = this.gradleBuild.getProjectDir().getName(); + assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(result.getOutput()).contains("docker.io/library/" + projectName); + assertThat(result.getOutput()).contains("---> Test Info buildpack building"); + assertThat(result.getOutput()).contains("Network status: curl failed"); + assertThat(result.getOutput()).contains("---> Test Info buildpack done"); + removeImage(projectName); + } + @TestTemplate void failsWithBuilderError() throws IOException { writeMainClass(); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithNetworkModeNone.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithNetworkModeNone.gradle new file mode 100644 index 0000000000..d5b5b0113e --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithNetworkModeNone.gradle @@ -0,0 +1,16 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '{version}' +} + +if (project.hasProperty('applyWarPlugin')) { + apply plugin: 'war' +} + +sourceCompatibility = '1.8' +targetCompatibility = '1.8' + +bootBuildImage { + builder = "projects.registry.vmware.com/springboot/spring-boot-cnb-builder:0.0.1" + network = "none" +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc index 2a58ca004d..df8aa32b50 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc @@ -163,6 +163,12 @@ Where `` can contain: * `volume-opt=key=value` to specify key-value pairs consisting of an option name and its value | +| `network` + +(`spring-boot.build-image.network`) +| The https://docs.docker.com/network/#network-drivers[network driver] the builder container will be configured to use. +The value supplied will be passed unvalidated to Docker when creating the builder container. +| + | `cleanCache` + (`spring-boot.build-image.cleanCache`) | Whether to clean the cache before building. @@ -177,13 +183,6 @@ Where `` can contain: | Whether to publish the generated image to a Docker registry. | `false` -| `network` + -(`spring-boot.build-image.network`) -| The network the build container will connect to. The value supplied for this option will be passed -unvalidated as `HostConfig.NetworkMode` to the configuration which creates the build container, -see https://docs.docker.com/engine/api/v1.41/#operation/ContainerCreate[Docker's engine API]. -Using this option is similar to running `docker build --network ...`. -| |=== NOTE: The plugin detects the target Java compatibility of the project using the compiler's plugin configuration or the `maven.compiler.target` property. diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java index 6bc3d56770..0d75a99e44 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java @@ -270,6 +270,17 @@ public class BuildImageTests extends AbstractArchiveIntegrationTests { }); } + @TestTemplate + void whenBuildImageIsInvokedWithNetworkModeNone(MavenBuild mavenBuild) { + mavenBuild.project("build-image-network").goals("package") + .systemProperty("spring-boot.build-image.pullPolicy", "IF_NOT_PRESENT").execute((project) -> { + assertThat(buildLog(project)).contains("Building image") + .contains("docker.io/library/build-image-network:0.0.1.BUILD-SNAPSHOT") + .contains("Network status: curl failed").contains("Successfully built image"); + removeImage("build-image-network", "0.0.1.BUILD-SNAPSHOT"); + }); + } + @TestTemplate void whenBuildImageIsInvokedOnMultiModuleProjectWithPackageGoal(MavenBuild mavenBuild) { mavenBuild.project("build-image-multi-module").goals("package") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-network/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-network/pom.xml new file mode 100644 index 0000000000..1f0ca34f92 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-network/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + org.springframework.boot.maven.it + build-image-network + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + build-image + + + + projects.registry.vmware.com/springboot/spring-boot-cnb-builder:0.0.1 + none + + + + + + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-network/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-network/src/main/java/org/test/SampleApplication.java new file mode 100644 index 0000000000..27259ff01a --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-network/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * 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 + * + * https://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 org.test; + +public class SampleApplication { + + public static void main(String[] args) throws Exception { + System.out.println("Launched"); + synchronized(args) { + args.wait(); // Prevent exit" + } + } + +} diff --git a/src/spring-boot-builder/buildpacks/test-info/bin/build b/src/spring-boot-builder/buildpacks/test-info/bin/build index a9317aa0c6..8c1dce7774 100755 --- a/src/spring-boot-builder/buildpacks/test-info/bin/build +++ b/src/spring-boot-builder/buildpacks/test-info/bin/build @@ -32,4 +32,6 @@ if [[ -f META-INF/MANIFEST.MF ]]; then cat META-INF/MANIFEST.MF fi +echo "Network status: $(curl --silent --head https://spring.io | grep -E '^HTTP' || echo "curl failed")" + echo "---> Test Info buildpack done"