From e8f555e13dba5a29ecde34875aed737b8bee878c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A7=9C=E4=B8=BA?= Date: Sun, 16 Aug 2020 08:51:55 +0800 Subject: [PATCH] Support authentication to private docker registry This commit adds the ability to configure Docker image registry authentication credentials in the Maven and Gradle plugins. The authentication credentials are passed to the Docker daemon with all daemon API calls, and the daemon forwards the credentials to the image registry when necessary. This makes it possible to use builder and run images stored in a private Docker registry. See gh-22972 --- .../buildpack/platform/build/Builder.java | 11 +- .../buildpack/platform/docker/DockerApi.java | 30 +++- .../configuration/DockerConfiguration.java | 49 +++++++ .../DockerRegistryConfiguration.java | 129 ++++++++++++++++++ .../docker/configuration/package-info.java | 20 +++ .../docker/transport/HttpTransport.java | 33 ++++- .../transport/LocalHttpClientTransport.java | 9 +- .../transport/RemoteHttpClientTransport.java | 23 +++- .../platform/build/BuilderTests.java | 10 +- .../platform/docker/DockerApiTests.java | 45 ++++++ .../DockerConfigurationTests.java | 35 +++++ .../DockerRegistryConfigurationTests.java | 79 +++++++++++ .../docker/transport/HttpTransportTests.java | 12 ++ .../RemoteHttpClientTransportTests.java | 14 ++ .../gradle/tasks/bundling/BootBuildImage.java | 27 +++- .../boot/gradle/tasks/bundling/Docker.java | 53 +++++++ .../gradle/tasks/bundling/DockerRegistry.java | 98 +++++++++++++ .../tasks/bundling/DockerRegistryTests.java | 47 +++++++ .../boot/maven/BuildImageMojo.java | 12 +- .../springframework/boot/maven/Docker.java | 53 +++++++ .../boot/maven/DockerRegistry.java | 98 +++++++++++++ .../boot/maven/DockerRegistryTests.java | 47 +++++++ 22 files changed, 922 insertions(+), 12 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfiguration.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryConfiguration.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/package-info.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/Docker.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/DockerRegistry.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/DockerRegistryTests.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Docker.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/DockerRegistry.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DockerRegistryTests.java diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Builder.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Builder.java index de06b36523..0f3b69bb8d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Builder.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Builder.java @@ -24,6 +24,7 @@ import org.springframework.boot.buildpack.platform.docker.DockerApi; import org.springframework.boot.buildpack.platform.docker.TotalProgressEvent; import org.springframework.boot.buildpack.platform.docker.TotalProgressPullListener; import org.springframework.boot.buildpack.platform.docker.UpdateListener; +import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration; import org.springframework.boot.buildpack.platform.docker.transport.DockerEngineException; import org.springframework.boot.buildpack.platform.docker.type.Image; import org.springframework.boot.buildpack.platform.docker.type.ImageReference; @@ -48,8 +49,16 @@ public class Builder { this(BuildLog.toSystemOut()); } + public Builder(DockerConfiguration dockerConfiguration) { + this(BuildLog.toSystemOut(), dockerConfiguration); + } + public Builder(BuildLog log) { - this(log, new DockerApi()); + this(log, new DockerApi(new DockerConfiguration())); + } + + public Builder(BuildLog log, DockerConfiguration dockerConfiguration) { + this(log, new DockerApi(dockerConfiguration)); } Builder(BuildLog log, DockerApi docker) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java index 7e9aa49776..79a9237773 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java @@ -24,8 +24,12 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import org.apache.http.Header; import org.apache.http.client.utils.URIBuilder; +import org.apache.http.message.BasicHeader; +import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration; +import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryConfiguration; import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport; import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport.Response; import org.springframework.boot.buildpack.platform.docker.type.ContainerConfig; @@ -68,7 +72,15 @@ public class DockerApi { * Create a new {@link DockerApi} instance. */ public DockerApi() { - this(HttpTransport.create()); + this(new DockerConfiguration()); + } + + /** + * Create a new {@link DockerApi} instance. + * @param dockerConfiguration the Docker configuration options. + */ + public DockerApi(DockerConfiguration dockerConfiguration) { + this(HttpTransport.create(createDockerEngineAuthenticationHeaders(dockerConfiguration))); } /** @@ -84,6 +96,22 @@ public class DockerApi { this.volume = new VolumeApi(); } + static Collection
createDockerEngineAuthenticationHeaders(DockerConfiguration dockerConfiguration) { + Assert.notNull(dockerConfiguration, "Docker configuration must not be null"); + + DockerRegistryConfiguration dockerRegistryConfiguration = dockerConfiguration.getDockerRegistryConfiguration(); + if (dockerRegistryConfiguration == null) { + return Collections.emptyList(); + } + + String dockerRegistryAuthToken = dockerRegistryConfiguration.createDockerRegistryAuthToken(); + if (StringUtils.isEmpty(dockerRegistryAuthToken)) { + return Collections.emptyList(); + } + + return Arrays.asList(new BasicHeader("X-Registry-Auth", dockerRegistryAuthToken)); + } + private HttpTransport http() { return this.http; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfiguration.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfiguration.java new file mode 100644 index 0000000000..fbffe6cb83 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfiguration.java @@ -0,0 +1,49 @@ +/* + * 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.springframework.boot.buildpack.platform.docker.configuration; + +/** + * Docker configuration options. + * + * @author Wei Jiang + * @since 2.4.0 + */ +public class DockerConfiguration { + + /** + * The docker registry configuration. + */ + private DockerRegistryConfiguration dockerRegistryConfiguration; + + public DockerConfiguration() { + super(); + } + + public DockerConfiguration(DockerRegistryConfiguration dockerRegistryConfiguration) { + super(); + this.dockerRegistryConfiguration = dockerRegistryConfiguration; + } + + public DockerRegistryConfiguration getDockerRegistryConfiguration() { + return this.dockerRegistryConfiguration; + } + + public void setDockerRegistryConfiguration(DockerRegistryConfiguration dockerRegistryConfiguration) { + this.dockerRegistryConfiguration = dockerRegistryConfiguration; + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryConfiguration.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryConfiguration.java new file mode 100644 index 0000000000..5699f2b2e6 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryConfiguration.java @@ -0,0 +1,129 @@ +/* + * 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.springframework.boot.buildpack.platform.docker.configuration; + +import java.io.IOException; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.springframework.boot.buildpack.platform.json.SharedObjectMapper; +import org.springframework.util.Base64Utils; +import org.springframework.util.StringUtils; + +/** + * Docker registry configuration options. + * + * @author Wei Jiang + * @since 2.4.0 + */ +public class DockerRegistryConfiguration { + + /** + * Docker registry server address. + */ + @JsonProperty("serveraddress") + private String url; + + /** + * Docker registry authentication username. + */ + private String username; + + /** + * Docker registry authentication password. + */ + private String password; + + /** + * Docker registry authentication email. + */ + private String email; + + /** + * Docker registry authentication identity token. + */ + @JsonIgnore + private String token; + + public DockerRegistryConfiguration() { + super(); + } + + public DockerRegistryConfiguration(String url, String username, String password, String email, String token) { + super(); + this.url = url; + this.username = username; + this.password = password; + this.email = email; + this.token = token; + } + + public String createDockerRegistryAuthToken() { + if (!StringUtils.isEmpty(this.getToken())) { + return this.getToken(); + } + + try { + return Base64Utils.encodeToString(SharedObjectMapper.get().writeValueAsBytes(this)); + } + catch (IOException ex) { + throw new IllegalStateException("create docker registry authentication token failed.", ex); + } + } + + public String getUrl() { + return this.url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getEmail() { + return this.email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getToken() { + return this.token; + } + + public void setToken(String token) { + this.token = token; + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/package-info.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/package-info.java new file mode 100644 index 0000000000..d5c3fe8a3c --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/package-info.java @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/** + * Docker configuration options. + */ +package org.springframework.boot.buildpack.platform.docker.configuration; diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransport.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransport.java index 07b581e426..f374a23b96 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransport.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransport.java @@ -21,6 +21,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; +import java.util.Collection; +import java.util.Collections; + +import org.apache.http.Header; import org.springframework.boot.buildpack.platform.io.IOConsumer; import org.springframework.boot.buildpack.platform.system.Environment; @@ -84,7 +88,17 @@ public interface HttpTransport { * @return a {@link HttpTransport} instance */ static HttpTransport create() { - return create(Environment.SYSTEM); + return create(Collections.emptyList()); + } + + /** + * Create the most suitable {@link HttpTransport} based on the + * {@link Environment#SYSTEM system environment}. + * @param dockerEngineAuthenticationHeaders authentication headerS for Docker engine. + * @return a {@link HttpTransport} instance + */ + static HttpTransport create(Collection
dockerEngineAuthenticationHeaders) { + return create(Environment.SYSTEM, dockerEngineAuthenticationHeaders); } /** @@ -94,8 +108,21 @@ public interface HttpTransport { * @return a {@link HttpTransport} instance */ static HttpTransport create(Environment environment) { - HttpTransport remote = RemoteHttpClientTransport.createIfPossible(environment); - return (remote != null) ? remote : LocalHttpClientTransport.create(environment); + return create(environment, Collections.emptyList()); + } + + /** + * Create the most suitable {@link HttpTransport} based on the given + * {@link Environment}. + * @param environment the source environment + * @param dockerEngineAuthenticationHeaders authentication headerS for Docker engine. + * @return a {@link HttpTransport} instance + */ + static HttpTransport create(Environment environment, Collection
dockerEngineAuthenticationHeaders) { + HttpTransport remote = RemoteHttpClientTransport.createIfPossible(environment, + dockerEngineAuthenticationHeaders); + return (remote != null) ? remote + : LocalHttpClientTransport.create(environment, dockerEngineAuthenticationHeaders); } /** diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java index 9861f4d45a..6c4b2a99a9 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java @@ -21,8 +21,10 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; +import java.util.Collection; import com.sun.jna.Platform; +import org.apache.http.Header; import org.apache.http.HttpHost; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; @@ -41,6 +43,7 @@ import org.apache.http.util.Args; import org.springframework.boot.buildpack.platform.socket.DomainSocket; import org.springframework.boot.buildpack.platform.socket.NamedPipeSocket; import org.springframework.boot.buildpack.platform.system.Environment; +import org.springframework.util.CollectionUtils; /** * {@link HttpClientTransport} that talks to local Docker. @@ -60,10 +63,14 @@ final class LocalHttpClientTransport extends HttpClientTransport { super(client, LOCAL_DOCKER_HOST); } - static LocalHttpClientTransport create(Environment environment) { + static LocalHttpClientTransport create(Environment environment, + Collection
dockerEngineAuthenticationHeaders) { HttpClientBuilder builder = HttpClients.custom(); builder.setConnectionManager(new LocalConnectionManager(socketFilePath(environment))); builder.setSchemePortResolver(new LocalSchemePortResolver()); + if (!CollectionUtils.isEmpty(dockerEngineAuthenticationHeaders)) { + builder.setDefaultHeaders(dockerEngineAuthenticationHeaders); + } return new LocalHttpClientTransport(builder.build()); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransport.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransport.java index 1b4df90b38..8ccc7fcc85 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransport.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransport.java @@ -18,9 +18,12 @@ package org.springframework.boot.buildpack.platform.docker.transport; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.Collection; +import java.util.Collections; import javax.net.ssl.SSLContext; +import org.apache.http.Header; import org.apache.http.HttpHost; import org.apache.http.conn.socket.LayeredConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; @@ -31,6 +34,7 @@ import org.apache.http.impl.client.HttpClients; import org.springframework.boot.buildpack.platform.docker.ssl.SslContextFactory; import org.springframework.boot.buildpack.platform.system.Environment; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; /** * {@link HttpClientTransport} that talks to a remote Docker. @@ -53,15 +57,25 @@ final class RemoteHttpClientTransport extends HttpClientTransport { } static RemoteHttpClientTransport createIfPossible(Environment environment) { - return createIfPossible(environment, new SslContextFactory()); + return createIfPossible(environment, Collections.emptyList()); + } + + static RemoteHttpClientTransport createIfPossible(Environment environment, + Collection
dockerEngineAuthenticationHeaders) { + return createIfPossible(environment, new SslContextFactory(), dockerEngineAuthenticationHeaders); } static RemoteHttpClientTransport createIfPossible(Environment environment, SslContextFactory sslContextFactory) { + return createIfPossible(environment, sslContextFactory, Collections.emptyList()); + } + + static RemoteHttpClientTransport createIfPossible(Environment environment, SslContextFactory sslContextFactory, + Collection
dockerEngineAuthenticationHeaders) { String host = environment.get(DOCKER_HOST); if (host == null || isLocalFileReference(host)) { return null; } - return create(environment, sslContextFactory, HttpHost.create(host)); + return create(environment, sslContextFactory, HttpHost.create(host), dockerEngineAuthenticationHeaders); } private static boolean isLocalFileReference(String host) { @@ -75,12 +89,15 @@ final class RemoteHttpClientTransport extends HttpClientTransport { } private static RemoteHttpClientTransport create(Environment environment, SslContextFactory sslContextFactory, - HttpHost tcpHost) { + HttpHost tcpHost, Collection
dockerEngineAuthenticationHeaders) { HttpClientBuilder builder = HttpClients.custom(); boolean secure = isSecure(environment); if (secure) { builder.setSSLSocketFactory(getSecureConnectionSocketFactory(environment, sslContextFactory)); } + if (!CollectionUtils.isEmpty(dockerEngineAuthenticationHeaders)) { + builder.setDefaultHeaders(dockerEngineAuthenticationHeaders); + } String scheme = secure ? "https" : "http"; HttpHost httpHost = new HttpHost(tcpHost.getHostName(), tcpHost.getPort(), scheme); return new RemoteHttpClientTransport(builder.build(), httpHost); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderTests.java index dd9669f0ee..740cf75b41 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderTests.java @@ -30,6 +30,7 @@ import org.springframework.boot.buildpack.platform.docker.DockerApi.ContainerApi import org.springframework.boot.buildpack.platform.docker.DockerApi.ImageApi; import org.springframework.boot.buildpack.platform.docker.DockerApi.VolumeApi; import org.springframework.boot.buildpack.platform.docker.TotalProgressPullListener; +import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration; import org.springframework.boot.buildpack.platform.docker.transport.DockerEngineException; import org.springframework.boot.buildpack.platform.docker.type.ContainerReference; import org.springframework.boot.buildpack.platform.docker.type.ContainerStatus; @@ -60,7 +61,14 @@ class BuilderTests { @Test void createWhenLogIsNullThrowsException() { - assertThatIllegalArgumentException().isThrownBy(() -> new Builder(null)).withMessage("Log must not be null"); + assertThatIllegalArgumentException().isThrownBy(() -> new Builder((BuildLog) null)) + .withMessage("Log must not be null"); + } + + @Test + void createWithDockerConfiguration() { + Builder builder = new Builder(BuildLog.toSystemOut(), new DockerConfiguration()); + assertThat(builder).isNotNull(); } @Test diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java index 66a3bd09f2..b953349b53 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java @@ -20,7 +20,9 @@ import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; +import java.util.Collection; +import org.apache.http.Header; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -34,6 +36,8 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.boot.buildpack.platform.docker.DockerApi.ContainerApi; import org.springframework.boot.buildpack.platform.docker.DockerApi.ImageApi; import org.springframework.boot.buildpack.platform.docker.DockerApi.VolumeApi; +import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration; +import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryConfiguration; import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport; import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport.Response; import org.springframework.boot.buildpack.platform.docker.type.ContainerConfig; @@ -48,6 +52,7 @@ import org.springframework.boot.buildpack.platform.io.Content; import org.springframework.boot.buildpack.platform.io.IOConsumer; import org.springframework.boot.buildpack.platform.io.Owner; import org.springframework.boot.buildpack.platform.io.TarArchive; +import org.springframework.util.Base64Utils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -113,6 +118,46 @@ class DockerApiTests { }; } + @Test + void createDockerApi() { + DockerApi api = new DockerApi(); + assertThat(api).isNotNull(); + } + + @Test + void createDockerApiWithDockerConfiguration() { + DockerApi api = new DockerApi(new DockerConfiguration()); + assertThat(api).isNotNull(); + } + + @Test + void createWhenDockerConfigurationIsNullThrowsException() { + assertThatIllegalArgumentException().isThrownBy(() -> new DockerApi((DockerConfiguration) null)) + .withMessage("Docker configuration must not be null"); + } + + @Test + void createDockerEngineAuthenticationHeaders() { + DockerRegistryConfiguration dockerRegistryConfiguration = new DockerRegistryConfiguration(); + dockerRegistryConfiguration.setUsername("username"); + dockerRegistryConfiguration.setPassword("password"); + dockerRegistryConfiguration.setEmail("mock@spring.com"); + dockerRegistryConfiguration.setUrl("http://mock.docker.registry"); + DockerConfiguration dockerConfiguration = new DockerConfiguration(); + dockerConfiguration.setDockerRegistryConfiguration(dockerRegistryConfiguration); + Collection
dockerEngineAuthenticationHeaders = DockerApi + .createDockerEngineAuthenticationHeaders(dockerConfiguration); + assertThat(dockerEngineAuthenticationHeaders.size() == 1).isTrue(); + Header header = dockerEngineAuthenticationHeaders.iterator().next(); + assertThat(header.getName()).isEqualTo("X-Registry-Auth"); + assertThat(header.getValue()).isEqualTo( + "ewogICJ1c2VybmFtZSIgOiAidXNlcm5hbWUiLAogICJwYXNzd29yZCIgOiAicGFzc3dvcmQiLAogICJlbWFpbCIgOiAibW9ja0BzcHJpbmcuY29tIiwKICAic2VydmVyYWRkcmVzcyIgOiAiaHR0cDovL21vY2suZG9ja2VyLnJlZ2lzdHJ5Igp9"); + assertThat(new String(Base64Utils.decodeFromString(header.getValue()))) + .isEqualTo("{\n" + " \"username\" : \"username\",\n" + " \"password\" : \"password\",\n" + + " \"email\" : \"mock@spring.com\",\n" + + " \"serveraddress\" : \"http://mock.docker.registry\"\n" + "}"); + } + @Nested class ImageDockerApiTests { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfigurationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfigurationTests.java new file mode 100644 index 0000000000..592a7f4af9 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfigurationTests.java @@ -0,0 +1,35 @@ +/* + * 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.springframework.boot.buildpack.platform.docker.configuration; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link DockerConfiguration}. + * + * @author Wei Jiang + */ +public class DockerConfigurationTests { + + @Test + void createDockerConfiguration() { + assertThat(new DockerConfiguration()).isNotNull(); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryConfigurationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryConfigurationTests.java new file mode 100644 index 0000000000..0d1aa79b28 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryConfigurationTests.java @@ -0,0 +1,79 @@ +/* + * 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.springframework.boot.buildpack.platform.docker.configuration; + +import org.junit.jupiter.api.Test; + +import org.springframework.util.Base64Utils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link DockerRegistryConfiguration}. + * + * @author Wei Jiang + */ +public class DockerRegistryConfigurationTests { + + @Test + void createDockerRegistryAuthTokenWithToken() { + DockerRegistryConfiguration dockerRegistryConfiguration = new DockerRegistryConfiguration(); + dockerRegistryConfiguration.setToken("mockToken"); + assertThat(dockerRegistryConfiguration.createDockerRegistryAuthToken()).isEqualTo("mockToken"); + } + + @Test + void createDockerRegistryAuthTokenWithoutToken() { + DockerRegistryConfiguration dockerRegistryConfiguration = new DockerRegistryConfiguration(); + dockerRegistryConfiguration.setUsername("username"); + dockerRegistryConfiguration.setPassword("password"); + dockerRegistryConfiguration.setEmail("mock@spring.com"); + dockerRegistryConfiguration.setUrl("http://mock.docker.registry"); + String token = dockerRegistryConfiguration.createDockerRegistryAuthToken(); + assertThat(token).isEqualTo( + "ewogICJ1c2VybmFtZSIgOiAidXNlcm5hbWUiLAogICJwYXNzd29yZCIgOiAicGFzc3dvcmQiLAogICJlbWFpbCIgOiAibW9ja0BzcHJpbmcuY29tIiwKICAic2VydmVyYWRkcmVzcyIgOiAiaHR0cDovL21vY2suZG9ja2VyLnJlZ2lzdHJ5Igp9"); + assertThat(new String(Base64Utils.decodeFromString(token))).isEqualTo("{\n" + " \"username\" : \"username\",\n" + + " \"password\" : \"password\",\n" + " \"email\" : \"mock@spring.com\",\n" + + " \"serveraddress\" : \"http://mock.docker.registry\"\n" + "}"); + } + + @Test + void createDockerRegistryAuthTokenWithUsernameAndPassword() { + DockerRegistryConfiguration dockerRegistryConfiguration = new DockerRegistryConfiguration(); + dockerRegistryConfiguration.setUsername("username"); + dockerRegistryConfiguration.setPassword("password"); + String token = dockerRegistryConfiguration.createDockerRegistryAuthToken(); + assertThat(dockerRegistryConfiguration.getEmail()).isNull(); + assertThat(dockerRegistryConfiguration.getUrl()).isNull(); + assertThat(token).isEqualTo( + "ewogICJ1c2VybmFtZSIgOiAidXNlcm5hbWUiLAogICJwYXNzd29yZCIgOiAicGFzc3dvcmQiLAogICJlbWFpbCIgOiBudWxsLAogICJzZXJ2ZXJhZGRyZXNzIiA6IG51bGwKfQ=="); + assertThat(new String(Base64Utils.decodeFromString(token))).isEqualTo("{\n" + " \"username\" : \"username\",\n" + + " \"password\" : \"password\",\n" + " \"email\" : null,\n" + " \"serveraddress\" : null\n" + "}"); + } + + @Test + void createDockerRegistryAuthTokenWithTokenAndUsername() { + DockerRegistryConfiguration dockerRegistryConfiguration = new DockerRegistryConfiguration(); + dockerRegistryConfiguration.setToken("mockToken"); + dockerRegistryConfiguration.setUsername("username"); + dockerRegistryConfiguration.setPassword("password"); + dockerRegistryConfiguration.setEmail("mock@spring.com"); + dockerRegistryConfiguration.setUrl("http://mock.docker.registry"); + assertThat(dockerRegistryConfiguration.createDockerRegistryAuthToken()).isEqualTo("mockToken"); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransportTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransportTests.java index 38a65a819c..3c4a8bbcc2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransportTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransportTests.java @@ -19,9 +19,13 @@ package org.springframework.boot.buildpack.platform.docker.transport; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Map; +import org.apache.http.Header; +import org.apache.http.message.BasicHeader; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -65,4 +69,12 @@ class HttpTransportTests { assertThat(transport).isInstanceOf(LocalHttpClientTransport.class); } + @Test + void createWithDockerEngineAuthenticationHeaders() { + Collection
dockerEngineAuthenticationHeaders = Arrays.asList(new BasicHeader("X-Registry-Auth", + "eyJ1c2VybmFtZSI6ICJ1c2VybmFtZSIsInBhc3N3b3JkIjogInBhc3N3b3JkIiwiZW1haWwiOiAibW9ja0BzcHJpbmcuY29tIiwic2VydmVyYWRkcmVzcyI6ICJodHRwOi8vbW9jay5kb2NrZXIucmVnaXN0cnkifQ==")); + HttpTransport transport = HttpTransport.create((name) -> null, dockerEngineAuthenticationHeaders); + assertThat(transport).isInstanceOf(LocalHttpClientTransport.class); + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransportTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransportTests.java index 784fa717c3..86c636bfec 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransportTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransportTests.java @@ -19,13 +19,17 @@ package org.springframework.boot.buildpack.platform.docker.transport; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; import java.util.function.Consumer; import javax.net.ssl.SSLContext; +import org.apache.http.Header; import org.apache.http.HttpHost; +import org.apache.http.message.BasicHeader; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -68,6 +72,16 @@ class RemoteHttpClientTransportTests { assertThat(transport).isNotNull(); } + @Test + void createWithDockerEngineAuthenticationHeaders() { + Collection
dockerEngineAuthenticationHeaders = Arrays.asList(new BasicHeader("X-Registry-Auth", + "eyJ1c2VybmFtZSI6ICJ1c2VybmFtZSIsInBhc3N3b3JkIjogInBhc3N3b3JkIiwiZW1haWwiOiAibW9ja0BzcHJpbmcuY29tIiwic2VydmVyYWRkcmVzcyI6ICJodHRwOi8vbW9jay5kb2NrZXIucmVnaXN0cnkifQ==")); + this.environment.put("DOCKER_HOST", "tcp://192.168.1.2:2376"); + RemoteHttpClientTransport transport = RemoteHttpClientTransport.createIfPossible(this.environment::get, + dockerEngineAuthenticationHeaders); + assertThat(transport).isNotNull(); + } + @Test void createIfPossibleWhenTlsVerifyWithMissingCertPathThrowsException() { this.environment.put("DOCKER_HOST", "tcp://192.168.1.2:2376"); 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 dfdc211f2d..a1aa9aa108 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 @@ -35,6 +35,7 @@ import org.springframework.boot.buildpack.platform.build.BuildRequest; import org.springframework.boot.buildpack.platform.build.Builder; import org.springframework.boot.buildpack.platform.build.Creator; import org.springframework.boot.buildpack.platform.build.PullPolicy; +import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration; import org.springframework.boot.buildpack.platform.docker.transport.DockerEngineException; import org.springframework.boot.buildpack.platform.docker.type.ImageName; import org.springframework.boot.buildpack.platform.docker.type.ImageReference; @@ -72,6 +73,8 @@ public class BootBuildImage extends DefaultTask { private PullPolicy pullPolicy; + private Docker docker; + public BootBuildImage() { this.jar = getProject().getObjects().fileProperty(); this.targetJavaVersion = getProject().getObjects().property(JavaVersion.class); @@ -246,9 +249,31 @@ public class BootBuildImage extends DefaultTask { this.pullPolicy = pullPolicy; } + /** + * Returns the Docker configuration with the builder will be used. + * @return docker configuration. + */ + @Input + @Optional + public Docker getDocker() { + return this.docker; + } + + /** + * Sets the Docker configuration with the builder will be used. + * @param docker docker configuration. + */ + @Option(option = "docker", description = "The Docker configuration to use") + public void setDocker(Docker docker) { + this.docker = docker; + } + @TaskAction void buildImage() throws DockerEngineException, IOException { - Builder builder = new Builder(); + DockerConfiguration dockerConfiguration = (this.docker != null) ? this.docker.getDockerConfiguration() + : new DockerConfiguration(); + + Builder builder = new Builder(dockerConfiguration); BuildRequest request = createRequest(); builder.build(request); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/Docker.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/Docker.java new file mode 100644 index 0000000000..188775c9eb --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/Docker.java @@ -0,0 +1,53 @@ +/* + * 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.springframework.boot.gradle.tasks.bundling; + +import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration; +import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryConfiguration; + +/** + * Docker configuration options. + * + * @author Wei Jiang + * @since 2.4.0 + */ +public class Docker { + + /** + * The docker registry configuration. + */ + private DockerRegistry registry; + + public DockerRegistry getRegistry() { + return this.registry; + } + + public void setRegistry(DockerRegistry registry) { + this.registry = registry; + } + + public DockerConfiguration getDockerConfiguration() { + DockerRegistryConfiguration dockerRegistryConfiguration = null; + + if (this.registry != null) { + dockerRegistryConfiguration = this.registry.getDockerRegistryConfiguration(); + } + + return new DockerConfiguration(dockerRegistryConfiguration); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/DockerRegistry.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/DockerRegistry.java new file mode 100644 index 0000000000..0a320ec7bd --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/DockerRegistry.java @@ -0,0 +1,98 @@ +/* + * 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.springframework.boot.gradle.tasks.bundling; + +import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryConfiguration; + +/** + * Docker registry configuration options. + * + * @author Wei Jiang + * @since 2.4.0 + */ +public class DockerRegistry { + + /** + * Docker registry server address. + */ + private String url; + + /** + * Docker registry authentication username. + */ + private String username; + + /** + * Docker registry authentication password. + */ + private String password; + + /** + * Docker registry authentication email. + */ + private String email; + + /** + * Docker registry authentication identity token. + */ + private String token; + + public String getUrl() { + return this.url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getEmail() { + return this.email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getToken() { + return this.token; + } + + public void setToken(String token) { + this.token = token; + } + + public DockerRegistryConfiguration getDockerRegistryConfiguration() { + return new DockerRegistryConfiguration(this.url, this.username, this.password, this.email, this.token); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/DockerRegistryTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/DockerRegistryTests.java new file mode 100644 index 0000000000..bc86e24cba --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/DockerRegistryTests.java @@ -0,0 +1,47 @@ +/* + * 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.springframework.boot.gradle.tasks.bundling; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryConfiguration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link DockerRegistry}. + * + * @author Wei Jiang + */ +public class DockerRegistryTests { + + @Test + void getDockerRegistryConfiguration() { + DockerRegistry dockerRegistry = new DockerRegistry(); + dockerRegistry.setUsername("username"); + dockerRegistry.setPassword("password"); + dockerRegistry.setEmail("mock@spring.com"); + dockerRegistry.setUrl("http://mock.docker.registry"); + DockerRegistryConfiguration dockerRegistryConfiguration = dockerRegistry.getDockerRegistryConfiguration(); + assertThat(dockerRegistryConfiguration).isNotNull(); + assertThat(dockerRegistryConfiguration.getUsername()).isEqualTo(dockerRegistry.getUsername()); + assertThat(dockerRegistryConfiguration.getPassword()).isEqualTo(dockerRegistry.getPassword()); + assertThat(dockerRegistryConfiguration.getEmail()).isEqualTo(dockerRegistry.getEmail()); + assertThat(dockerRegistryConfiguration.getUrl()).isEqualTo(dockerRegistry.getUrl()); + } + +} 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 4451199d6b..52e0dfafb7 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 @@ -44,6 +44,7 @@ import org.springframework.boot.buildpack.platform.build.Builder; import org.springframework.boot.buildpack.platform.build.Creator; import org.springframework.boot.buildpack.platform.build.PullPolicy; import org.springframework.boot.buildpack.platform.docker.TotalProgressEvent; +import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration; import org.springframework.boot.buildpack.platform.io.Owner; import org.springframework.boot.buildpack.platform.io.TarArchive; import org.springframework.boot.loader.tools.EntryWriter; @@ -135,6 +136,13 @@ public class BuildImageMojo extends AbstractPackagerMojo { @Parameter(property = "spring-boot.build-image.pullPolicy", readonly = true) PullPolicy pullPolicy; + /** + * Docker configuration options. + * @since 2.4.0 + */ + @Parameter + private Docker docker; + @Override public void execute() throws MojoExecutionException { if (this.project.getPackaging().equals("pom")) { @@ -151,7 +159,9 @@ public class BuildImageMojo extends AbstractPackagerMojo { private void buildImage() throws MojoExecutionException { Libraries libraries = getLibraries(Collections.emptySet()); try { - Builder builder = new Builder(new MojoBuildLog(this::getLog)); + DockerConfiguration dockerConfiguration = (this.docker != null) ? this.docker.getDockerConfiguration() + : new DockerConfiguration(); + Builder builder = new Builder(new MojoBuildLog(this::getLog), dockerConfiguration); BuildRequest request = getBuildRequest(libraries); builder.build(request); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Docker.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Docker.java new file mode 100644 index 0000000000..14e43af95a --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Docker.java @@ -0,0 +1,53 @@ +/* + * 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.springframework.boot.maven; + +import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration; +import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryConfiguration; + +/** + * Docker configuration options. + * + * @author Wei Jiang + * @since 2.4.0 + */ +public class Docker { + + /** + * The docker registry configuration. + */ + private DockerRegistry registry; + + public DockerRegistry getRegistry() { + return this.registry; + } + + public void setRegistry(DockerRegistry registry) { + this.registry = registry; + } + + public DockerConfiguration getDockerConfiguration() { + DockerRegistryConfiguration dockerRegistryConfiguration = null; + + if (this.registry != null) { + dockerRegistryConfiguration = this.registry.getDockerRegistryConfiguration(); + } + + return new DockerConfiguration(dockerRegistryConfiguration); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/DockerRegistry.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/DockerRegistry.java new file mode 100644 index 0000000000..8020eb261e --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/DockerRegistry.java @@ -0,0 +1,98 @@ +/* + * 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.springframework.boot.maven; + +import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryConfiguration; + +/** + * Docker registry configuration options. + * + * @author Wei Jiang + * @since 2.4.0 + */ +public class DockerRegistry { + + /** + * Docker registry server address. + */ + private String url; + + /** + * Docker registry authentication username. + */ + private String username; + + /** + * Docker registry authentication password. + */ + private String password; + + /** + * Docker registry authentication email. + */ + private String email; + + /** + * Docker registry authentication identity token. + */ + private String token; + + public String getUrl() { + return this.url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getEmail() { + return this.email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getToken() { + return this.token; + } + + public void setToken(String token) { + this.token = token; + } + + public DockerRegistryConfiguration getDockerRegistryConfiguration() { + return new DockerRegistryConfiguration(this.url, this.username, this.password, this.email, this.token); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DockerRegistryTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DockerRegistryTests.java new file mode 100644 index 0000000000..2fcba6fbd9 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DockerRegistryTests.java @@ -0,0 +1,47 @@ +/* + * 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.springframework.boot.maven; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryConfiguration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link DockerRegistry}. + * + * @author Wei Jiang + */ +public class DockerRegistryTests { + + @Test + void getDockerRegistryConfiguration() { + DockerRegistry dockerRegistry = new DockerRegistry(); + dockerRegistry.setUsername("username"); + dockerRegistry.setPassword("password"); + dockerRegistry.setEmail("mock@spring.com"); + dockerRegistry.setUrl("http://mock.docker.registry"); + DockerRegistryConfiguration dockerRegistryConfiguration = dockerRegistry.getDockerRegistryConfiguration(); + assertThat(dockerRegistryConfiguration).isNotNull(); + assertThat(dockerRegistryConfiguration.getUsername()).isEqualTo(dockerRegistry.getUsername()); + assertThat(dockerRegistryConfiguration.getPassword()).isEqualTo(dockerRegistry.getPassword()); + assertThat(dockerRegistryConfiguration.getEmail()).isEqualTo(dockerRegistry.getEmail()); + assertThat(dockerRegistryConfiguration.getUrl()).isEqualTo(dockerRegistry.getUrl()); + } + +}