Skip to content

Commit

Permalink
Fail on bootBuildImage with launch script
Browse files Browse the repository at this point in the history
This commit adds a check to the support code for the Gradle plugin
bootBuildImage task to ensure that the jar file that will be passed
to a builder is readable and has a valid directory. This prevents a
situation where the jar file cannot be read because it is prepended
with a launch script, and the builder does not receive any files to
process.

Notes have also been added to the Gradle plugin documentation to warn
against using a bootJar launchScript configuration and bootBuildImage
together, as well as caveats about launchScript that match the Maven
plugin documentation.

Fixes gh-22223
  • Loading branch information
scottfrederick committed Jul 15, 2020
1 parent 259ea65 commit 2102822
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 2 deletions.
Expand Up @@ -235,7 +235,6 @@ public boolean isVerboseLogging() {
* @return a new build request instance
*/
public static BuildRequest forJarFile(File jarFile) {
assertJarFile(jarFile);
return forJarFile(ImageReference.forJarFile(jarFile).inTaggedForm(), jarFile);
}

Expand Down
Expand Up @@ -35,6 +35,7 @@
* Adapter class to convert a ZIP file to a {@link TarArchive}.
*
* @author Phillip Webb
* @author Scott Frederick
* @since 2.3.0
*/
public class ZipFileTarArchive implements TarArchive {
Expand All @@ -54,6 +55,7 @@ public class ZipFileTarArchive implements TarArchive {
public ZipFileTarArchive(File zip, Owner owner) {
Assert.notNull(zip, "Zip must not be null");
Assert.notNull(owner, "Owner must not be null");
assertArchiveHasEntries(zip);
this.zip = zip;
this.owner = owner;
}
Expand All @@ -72,6 +74,16 @@ public void writeTo(OutputStream outputStream) throws IOException {
tar.finish();
}

private void assertArchiveHasEntries(File jarFile) {
try (ZipFile zipFile = new ZipFile(jarFile)) {
Assert.state(zipFile.getEntries().hasMoreElements(), "File '" + jarFile.toString()
+ "' is not compatible with buildpacks; ensure jar file is valid and launch script is not enabled");
}
catch (IOException ex) {
throw new IllegalStateException("File is not readable", ex);
}
}

private void copy(ZipArchiveEntry zipEntry, InputStream zip, TarArchiveOutputStream tar) throws IOException {
TarArchiveEntry tarEntry = convert(zipEntry);
tar.putArchiveEntry(tarEntry);
Expand Down
Expand Up @@ -4,7 +4,8 @@ The plugin can create an https://github.com/opencontainers/image-spec[OCI image]
Images can be built using the `bootBuildImage` task.
The task is automatically created when the `java` plugin is applied and is an instance of {boot-build-image-javadoc}[`BootBuildImage`].


NOTE: The `bootBuildImage` task can not be used with a <<packaging-executable-configuring-launch-script, fully executable Spring Boot archive>> that includes a launch script.
Disable launch script configuration in the `bootJar` task when building a jar file that is intended to be used with `bootBuildImage`.

[[build-image-docker-daemon]]
=== Docker Daemon
Expand Down
Expand Up @@ -201,6 +201,10 @@ Spring Boot provides support for fully executable archives.
An archive is made fully executable by prepending a shell script that knows how to launch the application.
On Unix-like platforms, this launch script allows the archive to be run directly like any other executable or to be installed as a service.

NOTE: Currently, some tools do not accept this format so you may not always be able to use this technique.
For example, `jar -xf` may silently fail to extract a jar or war that has been made fully-executable.
It is recommended that you only enable this option if you intend to execute it directly, rather than running it with `java -jar`, deploying it to a servlet container, or including it in an OCI image.

To use this feature, the inclusion of the launch script must be enabled:

[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
Expand Down
Expand Up @@ -126,6 +126,15 @@ void buildsImageWithCommandLineOptions() throws IOException {
}
}

@TestTemplate
void failsWithLaunchScript() {
writeMainClass();
writeLongNameResource();
BuildResult result = this.gradleBuild.buildAndFail("bootBuildImage");
assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.FAILED);
assertThat(result.getOutput()).contains("not compatible with buildpacks");
}

@TestTemplate
void failsWithBuilderError() {
writeMainClass();
Expand Down
@@ -0,0 +1,11 @@
plugins {
id 'java'
id 'org.springframework.boot' version '{version}'
}

sourceCompatibility = '1.8'
targetCompatibility = '1.8'

bootJar {
launchScript()
}

0 comments on commit 2102822

Please sign in to comment.