mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Merge pull request #51519 from DevJunz
Closes gh-51519 * gh-51519: Polish "Delete layer temp file when layer creation fails" Delete layer temp file when layer creation fails
This commit is contained in:
+31
-15
@@ -49,6 +49,7 @@ import org.springframework.util.StreamUtils;
|
||||
*
|
||||
* @author Scott Frederick
|
||||
* @author Phillip Webb
|
||||
* @author Junhwan Choi
|
||||
*/
|
||||
final class ImageBuildpack implements Buildpack {
|
||||
|
||||
@@ -137,22 +138,17 @@ final class ImageBuildpack implements Buildpack {
|
||||
tarArchive.writeTo(out);
|
||||
}
|
||||
Path layerFile = Files.createTempFile("create-builder-scratch-", null);
|
||||
try (TarArchiveOutputStream out = new TarArchiveOutputStream(Files.newOutputStream(layerFile))) {
|
||||
try (TarArchiveInputStream in = new TarArchiveInputStream(Files.newInputStream(sourceTarFile))) {
|
||||
out.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
|
||||
TarArchiveEntry entry = in.getNextEntry();
|
||||
while (entry != null) {
|
||||
String entryName = entry.getName();
|
||||
Path entryPath = Path.of(entryName);
|
||||
Assert.state(entryPath.toAbsolutePath().equals(entryPath.toAbsolutePath().normalize()),
|
||||
() -> "Malformed zip entry name '%s'".formatted(entryName));
|
||||
out.putArchiveEntry(entry);
|
||||
StreamUtils.copy(in, out);
|
||||
out.closeArchiveEntry();
|
||||
entry = in.getNextEntry();
|
||||
}
|
||||
out.finish();
|
||||
try {
|
||||
writeLayerFile(layerFile, sourceTarFile);
|
||||
}
|
||||
catch (IOException | RuntimeException ex) {
|
||||
try {
|
||||
Files.deleteIfExists(layerFile);
|
||||
}
|
||||
catch (IOException suppressed) {
|
||||
ex.addSuppressed(suppressed);
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
return layerFile;
|
||||
}
|
||||
@@ -161,6 +157,26 @@ final class ImageBuildpack implements Buildpack {
|
||||
}
|
||||
}
|
||||
|
||||
private void writeLayerFile(Path layerFile, Path sourceTarFile) throws IOException {
|
||||
try (TarArchiveOutputStream out = new TarArchiveOutputStream(Files.newOutputStream(layerFile))) {
|
||||
try (TarArchiveInputStream in = new TarArchiveInputStream(Files.newInputStream(sourceTarFile))) {
|
||||
out.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
|
||||
TarArchiveEntry entry = in.getNextEntry();
|
||||
while (entry != null) {
|
||||
String entryName = entry.getName();
|
||||
Path entryPath = Path.of(entryName);
|
||||
Assert.state(entryPath.toAbsolutePath().equals(entryPath.toAbsolutePath().normalize()),
|
||||
() -> "Malformed zip entry name '%s'".formatted(entryName));
|
||||
out.putArchiveEntry(entry);
|
||||
StreamUtils.copy(in, out);
|
||||
out.closeArchiveEntry();
|
||||
entry = in.getNextEntry();
|
||||
}
|
||||
out.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void apply(IOConsumer<Layer> layers) throws IOException {
|
||||
for (Path path : this.layerFiles) {
|
||||
layers.accept(Layer.fromTarArchive((out) -> {
|
||||
|
||||
+20
@@ -61,6 +61,7 @@ import static org.mockito.Mockito.mock;
|
||||
*
|
||||
* @author Scott Frederick
|
||||
* @author Phillip Webb
|
||||
* @author Junhwan Choi
|
||||
*/
|
||||
class ImageBuildpackTests extends AbstractJsonTests {
|
||||
|
||||
@@ -200,6 +201,25 @@ class ImageBuildpackTests extends AbstractJsonTests {
|
||||
.withMessage("Malformed zip entry name '../cnb/'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveWhenLayerCreationFailsDeletesLayerTempFiles() throws Exception {
|
||||
File tempDir = new File(System.getProperty("java.io.tmpdir"));
|
||||
Set<String> tempsBefore = listTempFileNames(tempDir, "create-builder-scratch-");
|
||||
Image image = Image.of(getContent("buildpack-image.json"));
|
||||
ImageReference imageReference = ImageReference.of("example/buildpack1:latest");
|
||||
BuildpackResolverContext resolverContext = mock(BuildpackResolverContext.class);
|
||||
given(resolverContext.getBuildpackLayersMetadata()).willReturn(BuildpackLayersMetadata.fromJson("{}"));
|
||||
given(resolverContext.fetchImage(eq(imageReference), eq(ImageType.BUILDPACK))).willReturn(image);
|
||||
willAnswer((invocation) -> withMockLayers(invocation, "..")).given(resolverContext)
|
||||
.exportImageLayers(eq(imageReference), any());
|
||||
BuildpackReference reference = BuildpackReference.of("example/buildpack1");
|
||||
assertThatIllegalStateException().isThrownBy(() -> ImageBuildpack.resolve(resolverContext, reference))
|
||||
.withMessage("Malformed zip entry name '../cnb/'");
|
||||
Set<String> tempsAfter = new HashSet<>(listTempFileNames(tempDir, "create-builder-scratch-"));
|
||||
tempsAfter.removeAll(tempsBefore);
|
||||
assertThat(tempsAfter).as("layer temp files must be deleted when layer creation fails").isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveDeletesIntermediateSourceTarTempFiles() throws Exception {
|
||||
File tempDir = new File(System.getProperty("java.io.tmpdir"));
|
||||
|
||||
Reference in New Issue
Block a user