Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ public Image fetchImage(ImageReference reference, ImageType imageType) throws IO
@Override
public void exportImageLayers(ImageReference reference, IOBiConsumer<String, TarArchive> exports)
throws IOException {
Builder.this.docker.image().exportLayers(reference, exports);
Builder.this.docker.image().exportLayers(reference, this.imageFetcher.defaultPlatform, exports);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ public class DockerApi {

static final ApiVersion PLATFORM_API_VERSION = ApiVersion.of(1, 41);

static final ApiVersion EXPORT_PLATFORM_API_VERSION = ApiVersion.of(1, 48);

static final ApiVersion INSPECT_PLATFORM_API_VERSION = ApiVersion.of(1, 49);

static final ApiVersion UNKNOWN_API_VERSION = ApiVersion.of(0, 0);

static final String API_VERSION_HEADER_NAME = "API-Version";
Expand Down Expand Up @@ -239,7 +243,17 @@ public Image pull(ImageReference reference, @Nullable ImagePlatform platform,
listener.onUpdate(event);
});
}
return inspect((platform != null) ? PLATFORM_API_VERSION : API_VERSION, reference);
if (platform != null) {
if (getApiVersion().supports(INSPECT_PLATFORM_API_VERSION)) {
return inspect(INSPECT_PLATFORM_API_VERSION, reference, platform);
}
String digest = digestCapture.getDigest();
if (digest != null) {
ImageReference digestRef = reference.withDigest(digest);
return inspect(PLATFORM_API_VERSION, digestRef);
}
}
return inspect(API_VERSION, reference);
}
finally {
listener.onFinish();
Expand Down Expand Up @@ -311,9 +325,28 @@ public void load(ImageArchive archive, UpdateListener<LoadImageUpdateEvent> list
*/
public void exportLayers(ImageReference reference, IOBiConsumer<String, TarArchive> exports)
throws IOException {
exportLayers(reference, null, exports);
}

/**
* Export the layers of an image as {@link TarArchive TarArchives}.
* @param reference the reference to export
* @param platform the platform (os/architecture/variant) of the image to export
* @param exports a consumer to receive the layers (contents can only be accessed
* during the callback)
* @throws IOException on IO error
*/
public void exportLayers(ImageReference reference, @Nullable ImagePlatform platform,
IOBiConsumer<String, TarArchive> exports) throws IOException {
Assert.notNull(reference, "'reference' must not be null");
Assert.notNull(exports, "'exports' must not be null");
URI uri = buildUrl("/images/" + reference + "/get");
if (platform != null) {
if (getApiVersion().supports(EXPORT_PLATFORM_API_VERSION)) {
uri = buildUrl(EXPORT_PLATFORM_API_VERSION, "/images/" + reference + "/get", "platform",
platform.toJson());
}
}
try (Response response = http().get(uri)) {
try (ExportedImageTar exportedImageTar = new ExportedImageTar(reference, response.getContent())) {
exportedImageTar.exportLayers(exports);
Expand Down Expand Up @@ -345,8 +378,15 @@ public Image inspect(ImageReference reference) throws IOException {
}

private Image inspect(ApiVersion apiVersion, ImageReference reference) throws IOException {
return inspect(apiVersion, reference, null);
}

private Image inspect(ApiVersion apiVersion, ImageReference reference, @Nullable ImagePlatform platform)
throws IOException {
Assert.notNull(reference, "'reference' must not be null");
URI imageUri = buildUrl(apiVersion, "/images/" + reference + "/json");
URI imageUri = (platform != null)
? buildUrl(apiVersion, "/images/" + reference + "/json", "platform", platform.toJson())
: buildUrl(apiVersion, "/images/" + reference + "/json");
try (Response response = http().get(imageUri)) {
return Image.of(response.getContent());
}
Expand Down Expand Up @@ -549,6 +589,10 @@ public void onUpdate(ProgressUpdateEvent event) {
}
}

private @Nullable String getDigest() {
return this.digest;
}

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,22 @@ public static ImagePlatform from(Image image) {
return new ImagePlatform(image.getOs(), image.getArchitecture(), image.getVariant());
}

/**
* Return a JSON-encoded representation of this platform for use with Docker Engine
* API 1.48+ endpoints that require the platform parameter in JSON format
* (e.g., image inspect and export operations).
* @return a JSON object in the form {@code {"os":"...","architecture":"...","variant":"..."}}
*/
public String toJson() {
StringBuilder json = new StringBuilder("{");
json.append("\"os\":\"").append(this.os).append("\"");
if (this.architecture != null && !this.architecture.isEmpty()) {
json.append(",\"architecture\":\"").append(this.architecture).append("\"");
}
if (this.variant != null && !this.variant.isEmpty()) {
json.append(",\"variant\":\"").append(this.variant).append("\"");
}
json.append("}");
return json.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ void pullWithPlatformPullsImageAndProducesEvents() throws Exception {
ImagePlatform platform = ImagePlatform.of("linux/arm64/v1");
URI createUri = new URI(PLATFORM_IMAGES_URL
+ "/create?fromImage=gcr.io%2Fpaketo-buildpacks%2Fbuilder%3Abase&platform=linux%2Farm64%2Fv1");
URI imageUri = new URI(PLATFORM_IMAGES_URL + "/gcr.io/paketo-buildpacks/builder:base/json");
URI imageUri = new URI(PLATFORM_IMAGES_URL
+ "/gcr.io/paketo-buildpacks/builder@sha256:4acb6bfd6c4f0cabaf7f3690e444afe51f1c7de54d51da7e63fac709c56f1c30/json");
given(http().head(eq(new URI(PING_URL))))
.willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, "1.41")));
given(http().post(eq(createUri), isNull())).willReturn(responseOf("pull-stream.json"));
Expand Down