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 93600e49e0e..8b2e822cfb3 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 c6adc770964..f67470445b5 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 234592afd4a..fab5bb48457 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 da945f6848b..1df69c312ea 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 92115cc0a59..c75e5155cf5 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 8e5b26187cb..03234771e29 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 ffddb464480..e2cc1bc47b2 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 cc94d2d7aed..a0b9292345c 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 00000000000..ae6ab807d12 --- /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 2c034b77671..51780616f10 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 65f0f4cc6db..888d1524c9d 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 bdd8cdb2e23..831987fa720 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 31d2d10dd8a..082a2b59543 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 24de20aaa1a..2a58ca004d9 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 33b9891b780..95f2ecee4f9 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 0ce0afd83b4..e648f556bc8 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 15ee4db4105..7c0d24921f9 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 8b2e822cfb3..b7feaa52777 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 f67470445b5..ae372bc71ed 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 fab5bb48457..8c0264f836c 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 1df69c312ea..a411b49f287 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 e2cc1bc47b2..6bed915d450 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 888d1524c9d..0d1677aac28 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 a8517e11ef6..8f5d4691afc 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 00000000000..d5b5b0113e6 --- /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 2a58ca004d9..df8aa32b50d 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 6bc3d567702..0d75a99e44a 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 00000000000..1f0ca34f925 --- /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 00000000000..27259ff01ad --- /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 a9317aa0c6b..8c1dce7774a 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"