Skip to content

Commit dd49de0

Browse files
committed
Relocate DockerConfiguration and refactor buildpack platform code
Relate `DockerConfiguration` from `...platform.docker` to `...platform.build` since it contains build specific concepts. This commit also refactors a few other areas of the code to make it easier to support credential helpers in the future. Closes gh-45283
1 parent 0351e33 commit dd49de0

File tree

20 files changed

+593
-393
lines changed

20 files changed

+593
-393
lines changed

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Builder.java

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
import org.springframework.boot.buildpack.platform.docker.TotalProgressPullListener;
2727
import org.springframework.boot.buildpack.platform.docker.TotalProgressPushListener;
2828
import org.springframework.boot.buildpack.platform.docker.UpdateListener;
29-
import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration;
29+
import org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;
30+
import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryAuthentication;
3031
import org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost;
3132
import org.springframework.boot.buildpack.platform.docker.transport.DockerEngineException;
3233
import org.springframework.boot.buildpack.platform.docker.type.Binding;
@@ -54,7 +55,7 @@ public class Builder {
5455

5556
private final DockerApi docker;
5657

57-
private final DockerConfiguration dockerConfiguration;
58+
private final BuilderDockerConfiguration dockerConfiguration;
5859

5960
/**
6061
* Create a new builder instance.
@@ -67,8 +68,22 @@ public Builder() {
6768
* Create a new builder instance.
6869
* @param dockerConfiguration the docker configuration
6970
* @since 2.4.0
71+
* @deprecated since 3.5.0 for removal in 4.0.0 in favor of
72+
* {@link #Builder(BuilderDockerConfiguration)}
7073
*/
71-
public Builder(DockerConfiguration dockerConfiguration) {
74+
@Deprecated(since = "3.5.0", forRemoval = true)
75+
@SuppressWarnings("removal")
76+
public Builder(
77+
org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration dockerConfiguration) {
78+
this(BuildLog.toSystemOut(), dockerConfiguration);
79+
}
80+
81+
/**
82+
* Create a new builder instance.
83+
* @param dockerConfiguration the docker configuration
84+
* @since 3.5.0
85+
*/
86+
public Builder(BuilderDockerConfiguration dockerConfiguration) {
7287
this(BuildLog.toSystemOut(), dockerConfiguration);
7388
}
7489

@@ -85,17 +100,45 @@ public Builder(BuildLog log) {
85100
* @param log a logger used to record output
86101
* @param dockerConfiguration the docker configuration
87102
* @since 2.4.0
103+
* @deprecated since 3.5.0 for removal in 4.0.0 in favor of
104+
* {@link #Builder(BuildLog, BuilderDockerConfiguration)}
88105
*/
89-
public Builder(BuildLog log, DockerConfiguration dockerConfiguration) {
90-
this(log, new DockerApi((dockerConfiguration != null) ? dockerConfiguration.getHost() : null,
106+
@Deprecated(since = "3.5.0", forRemoval = true)
107+
@SuppressWarnings("removal")
108+
public Builder(BuildLog log,
109+
org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration dockerConfiguration) {
110+
this(log, adaptDeprecatedConfiguration(dockerConfiguration));
111+
}
112+
113+
@SuppressWarnings("removal")
114+
private static BuilderDockerConfiguration adaptDeprecatedConfiguration(
115+
org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration configuration) {
116+
if (configuration == null) {
117+
return null;
118+
}
119+
DockerConnectionConfiguration connection = org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration.DockerHostConfiguration
120+
.asConnectionConfiguration(configuration.getHost());
121+
return new BuilderDockerConfiguration(connection, configuration.isBindHostToBuilder(),
122+
configuration.getBuilderRegistryAuthentication(), configuration.getPublishRegistryAuthentication());
123+
}
124+
125+
/**
126+
* Create a new builder instance.
127+
* @param log a logger used to record output
128+
* @param dockerConfiguration the docker configuration
129+
* @since 3.5.0
130+
*/
131+
public Builder(BuildLog log, BuilderDockerConfiguration dockerConfiguration) {
132+
this(log, new DockerApi((dockerConfiguration != null) ? dockerConfiguration.connection() : null,
91133
BuildLogAdapter.get(log)), dockerConfiguration);
92134
}
93135

94-
Builder(BuildLog log, DockerApi docker, DockerConfiguration dockerConfiguration) {
136+
Builder(BuildLog log, DockerApi docker, BuilderDockerConfiguration dockerConfiguration) {
95137
Assert.notNull(log, "'log' must not be null");
96138
this.log = log;
97139
this.docker = docker;
98-
this.dockerConfiguration = dockerConfiguration;
140+
this.dockerConfiguration = (dockerConfiguration != null) ? dockerConfiguration
141+
: new BuilderDockerConfiguration();
99142
}
100143

101144
public void build(BuildRequest request) throws DockerEngineException, IOException {
@@ -104,8 +147,8 @@ public void build(BuildRequest request) throws DockerEngineException, IOExceptio
104147
validateBindings(request.getBindings());
105148
String domain = request.getBuilder().getDomain();
106149
PullPolicy pullPolicy = request.getPullPolicy();
107-
ImageFetcher imageFetcher = new ImageFetcher(domain, getBuilderAuthHeader(), pullPolicy,
108-
request.getImagePlatform());
150+
ImageFetcher imageFetcher = new ImageFetcher(domain, this.dockerConfiguration.builderRegistryAuthentication(),
151+
pullPolicy, request.getImagePlatform());
109152
Image builderImage = imageFetcher.fetchImage(ImageType.BUILDER, request.getBuilder());
110153
BuilderMetadata builderMetadata = BuilderMetadata.fromImage(builderImage);
111154
request = withRunImageIfNeeded(request, builderMetadata);
@@ -182,8 +225,8 @@ private void executeLifecycle(EphemeralBuilder builder, Lifecycle lifecycle) thr
182225
}
183226

184227
private ResolvedDockerHost getDockerHost() {
185-
boolean bindHostToBuilder = this.dockerConfiguration != null && this.dockerConfiguration.isBindHostToBuilder();
186-
return (bindHostToBuilder) ? ResolvedDockerHost.from(this.dockerConfiguration.getHost()) : null;
228+
boolean bindToBuilder = this.dockerConfiguration.bindHostToBuilder();
229+
return (bindToBuilder) ? ResolvedDockerHost.from(this.dockerConfiguration.connection()) : null;
187230
}
188231

189232
private void tagImage(ImageReference sourceReference, List<ImageReference> tags) throws IOException {
@@ -203,18 +246,13 @@ private void pushImages(ImageReference name, List<ImageReference> tags) throws I
203246
private void pushImage(ImageReference reference) throws IOException {
204247
Consumer<TotalProgressEvent> progressConsumer = this.log.pushingImage(reference);
205248
TotalProgressPushListener listener = new TotalProgressPushListener(progressConsumer);
206-
this.docker.image().push(reference, listener, getPublishAuthHeader());
249+
String authHeader = authHeader(this.dockerConfiguration.publishRegistryAuthentication());
250+
this.docker.image().push(reference, listener, authHeader);
207251
this.log.pushedImage(reference);
208252
}
209253

210-
private String getBuilderAuthHeader() {
211-
return (this.dockerConfiguration != null && this.dockerConfiguration.getBuilderRegistryAuthentication() != null)
212-
? this.dockerConfiguration.getBuilderRegistryAuthentication().getAuthHeader() : null;
213-
}
214-
215-
private String getPublishAuthHeader() {
216-
return (this.dockerConfiguration != null && this.dockerConfiguration.getPublishRegistryAuthentication() != null)
217-
? this.dockerConfiguration.getPublishRegistryAuthentication().getAuthHeader() : null;
254+
private static String authHeader(DockerRegistryAuthentication authentication) {
255+
return (authentication != null) ? authentication.getAuthHeader() : null;
218256
}
219257

220258
/**
@@ -224,23 +262,25 @@ private class ImageFetcher {
224262

225263
private final String domain;
226264

227-
private final String authHeader;
265+
private final DockerRegistryAuthentication registryAuthentication;
228266

229267
private final PullPolicy pullPolicy;
230268

231269
private ImagePlatform defaultPlatform;
232270

233-
ImageFetcher(String domain, String authHeader, PullPolicy pullPolicy, ImagePlatform platform) {
271+
ImageFetcher(String domain, DockerRegistryAuthentication registryAuthentication, PullPolicy pullPolicy,
272+
ImagePlatform platform) {
234273
this.domain = domain;
235-
this.authHeader = authHeader;
274+
this.registryAuthentication = registryAuthentication;
236275
this.pullPolicy = pullPolicy;
237276
this.defaultPlatform = platform;
238277
}
239278

240279
Image fetchImage(ImageType type, ImageReference reference) throws IOException {
241280
Assert.notNull(type, "'type' must not be null");
242281
Assert.notNull(reference, "'reference' must not be null");
243-
Assert.state(this.authHeader == null || reference.getDomain().equals(this.domain),
282+
String authHeader = authHeader(this.registryAuthentication);
283+
Assert.state(authHeader == null || reference.getDomain().equals(this.domain),
244284
() -> String.format("%s '%s' must be pulled from the '%s' authenticated registry",
245285
StringUtils.capitalize(type.getDescription()), reference, this.domain));
246286
if (this.pullPolicy == PullPolicy.ALWAYS) {
@@ -260,7 +300,8 @@ Image fetchImage(ImageType type, ImageReference reference) throws IOException {
260300
private Image pullImage(ImageReference reference, ImageType imageType) throws IOException {
261301
TotalProgressPullListener listener = new TotalProgressPullListener(
262302
Builder.this.log.pullingImage(reference, this.defaultPlatform, imageType));
263-
Image image = Builder.this.docker.image().pull(reference, this.defaultPlatform, listener, this.authHeader);
303+
String authHeader = authHeader(this.registryAuthentication);
304+
Image image = Builder.this.docker.image().pull(reference, this.defaultPlatform, listener, authHeader);
264305
Builder.this.log.pulledImage(image, imageType);
265306
if (this.defaultPlatform == null) {
266307
this.defaultPlatform = ImagePlatform.from(image);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.buildpack.platform.build;
18+
19+
import org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;
20+
import org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryAuthentication;
21+
22+
/**
23+
* {@link Builder} configuration options for Docker.
24+
*
25+
* @param connection the Docker host configuration
26+
* @param bindHostToBuilder if the host resolved from the connection should be bound to
27+
* the builder
28+
* @param builderRegistryAuthentication the builder {@link DockerRegistryAuthentication}
29+
* @param publishRegistryAuthentication the publish {@link DockerRegistryAuthentication}
30+
* @author Phillip Webb
31+
* @author Wei Jiang
32+
* @author Scott Frederick
33+
* @since 3.5.0
34+
*/
35+
public record BuilderDockerConfiguration(DockerConnectionConfiguration connection, boolean bindHostToBuilder,
36+
DockerRegistryAuthentication builderRegistryAuthentication,
37+
DockerRegistryAuthentication publishRegistryAuthentication) {
38+
39+
public BuilderDockerConfiguration() {
40+
this(null, false, null, null);
41+
}
42+
43+
public BuilderDockerConfiguration withContext(String context) {
44+
return withConnection(new DockerConnectionConfiguration.Context(context));
45+
}
46+
47+
public BuilderDockerConfiguration withHost(String address, boolean secure, String certificatePath) {
48+
return withConnection(new DockerConnectionConfiguration.Host(address, secure, certificatePath));
49+
}
50+
51+
private BuilderDockerConfiguration withConnection(DockerConnectionConfiguration hostConfiguration) {
52+
return new BuilderDockerConfiguration(hostConfiguration, this.bindHostToBuilder,
53+
this.builderRegistryAuthentication, this.publishRegistryAuthentication);
54+
}
55+
56+
public BuilderDockerConfiguration withBindHostToBuilder(boolean bindHostToBuilder) {
57+
return new BuilderDockerConfiguration(this.connection, bindHostToBuilder, this.builderRegistryAuthentication,
58+
this.publishRegistryAuthentication);
59+
}
60+
61+
public BuilderDockerConfiguration withBuilderRegistryAuthentication(
62+
DockerRegistryAuthentication builderRegistryAuthentication) {
63+
return new BuilderDockerConfiguration(this.connection, this.bindHostToBuilder, builderRegistryAuthentication,
64+
this.publishRegistryAuthentication);
65+
66+
}
67+
68+
public BuilderDockerConfiguration withPublishRegistryAuthentication(
69+
DockerRegistryAuthentication publishRegistryAuthentication) {
70+
return new BuilderDockerConfiguration(this.connection, this.bindHostToBuilder,
71+
this.builderRegistryAuthentication, publishRegistryAuthentication);
72+
}
73+
74+
}

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import org.apache.hc.core5.http.Header;
2929
import org.apache.hc.core5.net.URIBuilder;
3030

31-
import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration.DockerHostConfiguration;
31+
import org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;
3232
import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport;
3333
import org.springframework.boot.buildpack.platform.docker.transport.HttpTransport.Response;
3434
import org.springframework.boot.buildpack.platform.docker.type.ApiVersion;
@@ -87,26 +87,32 @@ public class DockerApi {
8787
* Create a new {@link DockerApi} instance.
8888
*/
8989
public DockerApi() {
90-
this(null);
90+
this(HttpTransport.create((DockerConnectionConfiguration) null), DockerLog.toSystemOut());
9191
}
9292

9393
/**
9494
* Create a new {@link DockerApi} instance.
9595
* @param dockerHost the Docker daemon host information
9696
* @since 2.4.0
97+
* @deprecated since 3.5.0 for removal in 4.0.0 in favor of
98+
* {@link #DockerApi(DockerConnectionConfiguration, DockerLog)}
9799
*/
98-
public DockerApi(DockerHostConfiguration dockerHost) {
99-
this(dockerHost, DockerLog.toSystemOut());
100+
@Deprecated(since = "3.5.0", forRemoval = true)
101+
@SuppressWarnings("removal")
102+
public DockerApi(
103+
org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration.DockerHostConfiguration dockerHost) {
104+
this(org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration.DockerHostConfiguration
105+
.asConnectionConfiguration(dockerHost), DockerLog.toSystemOut());
100106
}
101107

102108
/**
103109
* Create a new {@link DockerApi} instance.
104-
* @param dockerHost the Docker daemon host information
110+
* @param connectionConfiguration the connection configuration to use
105111
* @param log a logger used to record output
106112
* @since 3.5.0
107113
*/
108-
public DockerApi(DockerHostConfiguration dockerHost, DockerLog log) {
109-
this(HttpTransport.create(dockerHost), log);
114+
public DockerApi(DockerConnectionConfiguration connectionConfiguration, DockerLog log) {
115+
this(HttpTransport.create(connectionConfiguration), log);
110116
}
111117

112118
/**

spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfiguration.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,19 @@
1717
package org.springframework.boot.buildpack.platform.docker.configuration;
1818

1919
import org.springframework.util.Assert;
20+
import org.springframework.util.StringUtils;
2021

2122
/**
2223
* Docker configuration options.
2324
*
2425
* @author Wei Jiang
2526
* @author Scott Frederick
2627
* @since 2.4.0
28+
* @deprecated since 3.5.0 for removal in 4.0.0 in favor of
29+
* {@link org.springframework.boot.buildpack.platform.build.BuilderDockerConfiguration}.
2730
*/
31+
@Deprecated(since = "3.5.0", forRemoval = true)
32+
@SuppressWarnings("removal")
2833
public final class DockerConfiguration {
2934

3035
private final DockerHostConfiguration host;
@@ -113,6 +118,13 @@ public DockerConfiguration withEmptyPublishRegistryAuthentication() {
113118
new DockerRegistryUserAuthentication("", "", "", ""), this.bindHostToBuilder);
114119
}
115120

121+
/**
122+
* Docker host configuration.
123+
*
124+
* @deprecated since 3.5.0 for removal in 4.0.0 in favor of
125+
* {@link DockerHostConfiguration}
126+
*/
127+
@Deprecated(since = "3.5.0", forRemoval = true)
116128
public static class DockerHostConfiguration {
117129

118130
private final String address;
@@ -158,6 +170,24 @@ static DockerHostConfiguration forContext(String context) {
158170
return new DockerHostConfiguration(null, context, false, null);
159171
}
160172

173+
/**
174+
* Adapts a {@link DockerHostConfiguration} to a
175+
* {@link DockerConnectionConfiguration}.
176+
* @param configuration the configuration to adapt
177+
* @return the adapted configuration
178+
* @since 3.5.0
179+
*/
180+
public static DockerConnectionConfiguration asConnectionConfiguration(DockerHostConfiguration configuration) {
181+
if (configuration != null && StringUtils.hasLength(configuration.context)) {
182+
return new DockerConnectionConfiguration.Context(configuration.context);
183+
}
184+
if (configuration != null && StringUtils.hasLength(configuration.address)) {
185+
return new DockerConnectionConfiguration.Host(configuration.address, configuration.secure,
186+
configuration.certificatePath);
187+
}
188+
return null;
189+
}
190+
161191
}
162192

163193
}

0 commit comments

Comments
 (0)