Skip to content

Commit dc36346

Browse files
jeliebigscottfrederick
authored andcommitted
Add option to customize cache volume names when building an image
This commit adds configuration to the Maven and Gradle plugins to allow specifying the names of build and launch cache volumes provided to the CNB builder. See gh-28292
1 parent 9d6a0cf commit dc36346

File tree

8 files changed

+171
-17
lines changed

8 files changed

+171
-17
lines changed

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

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
* @author Andrey Shlykov
3939
* @author Jeroen Meijer
4040
* @author Rafael Ceccone
41+
* @author Julian Liebig
4142
* @since 2.3.0
4243
*/
4344
public class BuildRequest {
@@ -74,6 +75,8 @@ public class BuildRequest {
7475

7576
private final List<ImageReference> tags;
7677

78+
private final Map<String, String> cacheVolumeNames;
79+
7780
BuildRequest(ImageReference name, Function<Owner, TarArchive> applicationContent) {
7881
Assert.notNull(name, "Name must not be null");
7982
Assert.notNull(applicationContent, "ApplicationContent must not be null");
@@ -91,12 +94,13 @@ public class BuildRequest {
9194
this.bindings = Collections.emptyList();
9295
this.network = null;
9396
this.tags = Collections.emptyList();
97+
this.cacheVolumeNames = Collections.emptyMap();
9498
}
9599

96100
BuildRequest(ImageReference name, Function<Owner, TarArchive> applicationContent, ImageReference builder,
97101
ImageReference runImage, Creator creator, Map<String, String> env, boolean cleanCache,
98102
boolean verboseLogging, PullPolicy pullPolicy, boolean publish, List<BuildpackReference> buildpacks,
99-
List<Binding> bindings, String network, List<ImageReference> tags) {
103+
List<Binding> bindings, String network, List<ImageReference> tags, Map<String, String> cacheVolumeNames) {
100104
this.name = name;
101105
this.applicationContent = applicationContent;
102106
this.builder = builder;
@@ -111,6 +115,7 @@ public class BuildRequest {
111115
this.bindings = bindings;
112116
this.network = network;
113117
this.tags = tags;
118+
this.cacheVolumeNames = cacheVolumeNames;
114119
}
115120

116121
/**
@@ -122,7 +127,7 @@ public BuildRequest withBuilder(ImageReference builder) {
122127
Assert.notNull(builder, "Builder must not be null");
123128
return new BuildRequest(this.name, this.applicationContent, builder.inTaggedOrDigestForm(), this.runImage,
124129
this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
125-
this.buildpacks, this.bindings, this.network, this.tags);
130+
this.buildpacks, this.bindings, this.network, this.tags, this.cacheVolumeNames);
126131
}
127132

128133
/**
@@ -133,7 +138,7 @@ public BuildRequest withBuilder(ImageReference builder) {
133138
public BuildRequest withRunImage(ImageReference runImageName) {
134139
return new BuildRequest(this.name, this.applicationContent, this.builder, runImageName.inTaggedOrDigestForm(),
135140
this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
136-
this.buildpacks, this.bindings, this.network, this.tags);
141+
this.buildpacks, this.bindings, this.network, this.tags, this.cacheVolumeNames);
137142
}
138143

139144
/**
@@ -145,7 +150,7 @@ public BuildRequest withCreator(Creator creator) {
145150
Assert.notNull(creator, "Creator must not be null");
146151
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, creator, this.env,
147152
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
148-
this.network, this.tags);
153+
this.network, this.tags, this.cacheVolumeNames);
149154
}
150155

151156
/**
@@ -161,7 +166,7 @@ public BuildRequest withEnv(String name, String value) {
161166
env.put(name, value);
162167
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator,
163168
Collections.unmodifiableMap(env), this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
164-
this.buildpacks, this.bindings, this.network, this.tags);
169+
this.buildpacks, this.bindings, this.network, this.tags, this.cacheVolumeNames);
165170
}
166171

167172
/**
@@ -175,7 +180,7 @@ public BuildRequest withEnv(Map<String, String> env) {
175180
updatedEnv.putAll(env);
176181
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator,
177182
Collections.unmodifiableMap(updatedEnv), this.cleanCache, this.verboseLogging, this.pullPolicy,
178-
this.publish, this.buildpacks, this.bindings, this.network, this.tags);
183+
this.publish, this.buildpacks, this.bindings, this.network, this.tags, this.cacheVolumeNames);
179184
}
180185

181186
/**
@@ -186,7 +191,7 @@ public BuildRequest withEnv(Map<String, String> env) {
186191
public BuildRequest withCleanCache(boolean cleanCache) {
187192
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
188193
cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
189-
this.network, this.tags);
194+
this.network, this.tags, this.cacheVolumeNames);
190195
}
191196

192197
/**
@@ -197,7 +202,7 @@ public BuildRequest withCleanCache(boolean cleanCache) {
197202
public BuildRequest withVerboseLogging(boolean verboseLogging) {
198203
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
199204
this.cleanCache, verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
200-
this.network, this.tags);
205+
this.network, this.tags, this.cacheVolumeNames);
201206
}
202207

203208
/**
@@ -208,7 +213,7 @@ public BuildRequest withVerboseLogging(boolean verboseLogging) {
208213
public BuildRequest withPullPolicy(PullPolicy pullPolicy) {
209214
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
210215
this.cleanCache, this.verboseLogging, pullPolicy, this.publish, this.buildpacks, this.bindings,
211-
this.network, this.tags);
216+
this.network, this.tags, this.cacheVolumeNames);
212217
}
213218

214219
/**
@@ -219,7 +224,7 @@ public BuildRequest withPullPolicy(PullPolicy pullPolicy) {
219224
public BuildRequest withPublish(boolean publish) {
220225
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
221226
this.cleanCache, this.verboseLogging, this.pullPolicy, publish, this.buildpacks, this.bindings,
222-
this.network, this.tags);
227+
this.network, this.tags, this.cacheVolumeNames);
223228
}
224229

225230
/**
@@ -243,7 +248,7 @@ public BuildRequest withBuildpacks(List<BuildpackReference> buildpacks) {
243248
Assert.notNull(buildpacks, "Buildpacks must not be null");
244249
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
245250
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, buildpacks, this.bindings,
246-
this.network, this.tags);
251+
this.network, this.tags, this.cacheVolumeNames);
247252
}
248253

249254
/**
@@ -267,7 +272,7 @@ public BuildRequest withBindings(List<Binding> bindings) {
267272
Assert.notNull(bindings, "Bindings must not be null");
268273
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
269274
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, bindings,
270-
this.network, this.tags);
275+
this.network, this.tags, this.cacheVolumeNames);
271276
}
272277

273278
/**
@@ -279,7 +284,7 @@ public BuildRequest withBindings(List<Binding> bindings) {
279284
public BuildRequest withNetwork(String network) {
280285
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
281286
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
282-
network, this.tags);
287+
network, this.tags, this.cacheVolumeNames);
283288
}
284289

285290
/**
@@ -301,7 +306,39 @@ public BuildRequest withTags(List<ImageReference> tags) {
301306
Assert.notNull(tags, "Tags must not be null");
302307
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
303308
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
304-
this.network, tags);
309+
this.network, tags, this.cacheVolumeNames);
310+
}
311+
312+
/**
313+
* Return a new {@link BuildRequest} with an additional cache volume name.
314+
* @param type the cache volume type
315+
* @param name the cache volume name
316+
* @return an updated build request
317+
*/
318+
public BuildRequest withCacheVolumeName(String type, String name) {
319+
Assert.hasText(type, "Type must not be empty");
320+
Assert.state((type.equals("build") || type.equals("launch")), "Type must be either 'build' or 'launch'");
321+
Assert.hasText(name, "Name must not be empty");
322+
Map<String, String> cacheVolumeNames = new LinkedHashMap<>(this.cacheVolumeNames);
323+
cacheVolumeNames.put(type, name);
324+
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
325+
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
326+
this.network, this.tags, Collections.unmodifiableMap(cacheVolumeNames));
327+
}
328+
329+
/**
330+
* Return a new {@link BuildRequest} with additional cache volume names.
331+
* @param entries the additional cache volume names
332+
* @return an updated build request
333+
*/
334+
public BuildRequest withCacheVolumeNames(Map<String, String> entries) {
335+
Assert.notNull(entries, "Entries must not be null");
336+
Assert.state(!entries.isEmpty(), "Entries must not be empty");
337+
BuildRequest request = null;
338+
for (Map.Entry<String, String> entry : entries.entrySet()) {
339+
request = withCacheVolumeName(entry.getKey(), entry.getValue());
340+
}
341+
return request;
305342
}
306343

307344
/**
@@ -421,6 +458,14 @@ public List<ImageReference> getTags() {
421458
return this.tags;
422459
}
423460

461+
/**
462+
* Return the custom cache volume names that should be used by the lifecycle.
463+
* @return the cache volume names
464+
*/
465+
public Map<String, String> getCacheVolumeNames() {
466+
return this.cacheVolumeNames;
467+
}
468+
424469
/**
425470
* Factory method to create a new {@link BuildRequest} from a JAR file.
426471
* @param jarFile the source jar file

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
* @author Phillip Webb
4040
* @author Scott Frederick
4141
* @author Jeroen Meijer
42+
* @author Julian Liebig
4243
*/
4344
class Lifecycle implements Closeable {
4445

@@ -86,16 +87,19 @@ class Lifecycle implements Closeable {
8687
this.platformVersion = getPlatformVersion(builder.getBuilderMetadata().getLifecycle());
8788
this.layersVolume = createRandomVolumeName("pack-layers-");
8889
this.applicationVolume = createRandomVolumeName("pack-app-");
89-
this.buildCacheVolume = createCacheVolumeName(request, ".build");
90-
this.launchCacheVolume = createCacheVolumeName(request, ".launch");
90+
this.buildCacheVolume = createCacheVolumeName(request, "build");
91+
this.launchCacheVolume = createCacheVolumeName(request, "launch");
9192
}
9293

9394
protected VolumeName createRandomVolumeName(String prefix) {
9495
return VolumeName.random(prefix);
9596
}
9697

9798
private VolumeName createCacheVolumeName(BuildRequest request, String suffix) {
98-
return VolumeName.basedOn(request.getName(), ImageReference::toLegacyString, "pack-cache-", suffix, 6);
99+
if (!request.getCacheVolumeNames().isEmpty() && request.getCacheVolumeNames().containsKey(suffix)) {
100+
return VolumeName.of(request.getCacheVolumeNames().get(suffix));
101+
}
102+
return VolumeName.basedOn(request.getName(), ImageReference::toLegacyString, "pack-cache-", "." + suffix, 6);
99103
}
100104

101105
private ApiVersion getPlatformVersion(BuilderMetadata.Lifecycle lifecycle) {

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging-oci-image.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ The value supplied will be passed unvalidated to Docker when creating the builde
181181
| A list of one or more additional tags to apply to the generated image.
182182
|
183183

184+
| `cacheVolumeNames`
185+
|
186+
| Cache volume names that should be used by the builder instead of generating random names.
187+
|
188+
184189
|===
185190

186191
NOTE: The plugin detects the target Java compatibility of the project using the JavaPlugin's `targetCompatibility` property.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
plugins {
2+
id 'java'
3+
id 'org.springframework.boot' version '{gradle-project-version}'
4+
}
5+
6+
bootJar {
7+
mainClass = 'com.example.ExampleApplication'
8+
}
9+
10+
// tag::cacheVolumeNames[]
11+
bootBuildImage {
12+
cacheVolumeNames = [
13+
"build": "example-build-cachevol",
14+
"launch": "example-launch-cachevol"
15+
]
16+
}
17+
// end::cacheVolumeNames[]
18+
19+
task bootBuildImageCacheVolumeNames {
20+
doFirst {
21+
bootBuildImage.cacheVolumeNames.each { type, name -> println "$type=$name" }
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import org.springframework.boot.gradle.tasks.bundling.BootBuildImage
2+
3+
plugins {
4+
java
5+
id("org.springframework.boot") version "{gradle-project-version}"
6+
}
7+
8+
// tag::cacheVolumeNames[]
9+
tasks.getByName<BootBuildImage>("bootBuildImage") {
10+
cacheVolumeNames = mapOf("build" to "example-build-cachevol",
11+
"launch" to "example-launch-cachevol")
12+
}
13+
// end::cacheVolumeNames[]
14+
15+
tasks.register("bootBuildImageEnvironment") {
16+
doFirst {
17+
for((type, name) in tasks.getByName<BootBuildImage>("bootBuildImage").cacheVolumeNames) {
18+
print(type + "=" + name)
19+
}
20+
}
21+
}

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
* @author Scott Frederick
6161
* @author Rafael Ceccone
6262
* @author Jeroen Meijer
63+
* @author Julian Liebig
6364
* @since 2.3.0
6465
*/
6566
public class BootBuildImage extends DefaultTask {
@@ -98,6 +99,8 @@ public class BootBuildImage extends DefaultTask {
9899

99100
private final ListProperty<String> tags;
100101

102+
private Map<String, String> cacheVolumeNames = new HashMap<>();
103+
101104
private final DockerSpec docker = new DockerSpec();
102105

103106
public BootBuildImage() {
@@ -417,6 +420,41 @@ public void tags(List<String> tags) {
417420
this.tags.addAll(tags);
418421
}
419422

423+
/**
424+
* Returns the cache volume names that will be used when building the image.
425+
* @return the cache volume names
426+
*/
427+
@Input
428+
@Optional
429+
public Map<String, String> getCacheVolumeNames() {
430+
return this.cacheVolumeNames;
431+
}
432+
433+
/**
434+
* Sets the cache volume names that will be used when building the image.
435+
* @param cacheVolumeNames the cache volume names
436+
*/
437+
public void setCacheVolumeNames(Map<String, String> cacheVolumeNames) {
438+
this.cacheVolumeNames = cacheVolumeNames;
439+
}
440+
441+
/**
442+
* Add an entry to cache volume names that will be used when building the image.
443+
* @param type the type of the entry
444+
* @param name the name of the entry
445+
*/
446+
public void cacheVolumeName(String type, String name) {
447+
this.cacheVolumeNames.put(type, name);
448+
}
449+
450+
/**
451+
* Adds entries to cache volume names that will be used when building the image.
452+
* @param entries the entries to add to cache volume names
453+
*/
454+
public void cacheVolumeNames(Map<String, String> entries) {
455+
this.cacheVolumeNames.putAll(entries);
456+
}
457+
420458
/**
421459
* Returns the network the build container will connect to.
422460
* @return the network
@@ -499,6 +537,7 @@ private BuildRequest customize(BuildRequest request) {
499537
request = customizeBuildpacks(request);
500538
request = customizeBindings(request);
501539
request = customizeTags(request);
540+
request = customizeCacheVolumeNames(request);
502541
request = request.withNetwork(this.network);
503542
return request;
504543
}
@@ -576,6 +615,13 @@ private BuildRequest customizeTags(BuildRequest request) {
576615
return request;
577616
}
578617

618+
private BuildRequest customizeCacheVolumeNames(BuildRequest request) {
619+
if (this.cacheVolumeNames != null && !this.cacheVolumeNames.isEmpty()) {
620+
request = request.withCacheVolumeNames(this.cacheVolumeNames);
621+
}
622+
return request;
623+
}
624+
579625
private String translateTargetJavaVersion() {
580626
return this.targetJavaVersion.get().getMajorVersion() + ".*";
581627
}

spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ The value supplied will be passed unvalidated to Docker when creating the builde
187187
| One or more additional tags to apply to the generated image.
188188
|
189189

190+
| `cacheVolumeNames`
191+
| Cache volume names that should be used by the builder instead of generating random names.
192+
|
193+
190194
|===
191195

192196
NOTE: The plugin detects the target Java compatibility of the project using the compiler's plugin configuration or the `maven.compiler.target` property.

0 commit comments

Comments
 (0)