From b0bb4ba7f2ab00594f64e34c2be9bd07de1dc722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= Date: Tue, 6 Aug 2024 14:48:39 +0200 Subject: [PATCH] image/load: Add `--platform` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paweł Gronowski Signed-off-by: Sebastiaan van Stijn --- cli/command/image/load.go | 23 ++++++++--- cli/command/image/load_test.go | 18 +++++++++ .../load-command-success.with platform.golden | 1 + docs/reference/commandline/image_load.md | 38 +++++++++++++++++-- docs/reference/commandline/load.md | 9 +++-- 5 files changed, 76 insertions(+), 13 deletions(-) create mode 100644 cli/command/image/testdata/load-command-success.with platform.golden diff --git a/cli/command/image/load.go b/cli/command/image/load.go index 190e9302a3..0bd09c67ee 100644 --- a/cli/command/image/load.go +++ b/cli/command/image/load.go @@ -4,6 +4,7 @@ import ( "context" "io" + "github.com/containerd/platforms" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/completion" @@ -15,8 +16,9 @@ import ( ) type loadOptions struct { - input string - quiet bool + input string + quiet bool + platform string } // NewLoadCommand creates a new `docker load` command @@ -40,7 +42,10 @@ func NewLoadCommand(dockerCli command.Cli) *cobra.Command { flags.StringVarP(&opts.input, "input", "i", "", "Read from tar archive file, instead of STDIN") flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress the load output") + flags.StringVar(&opts.platform, "platform", "", `Load only the given platform variant. Formatted as "os[/arch[/variant]]" (e.g., "linux/amd64")`) + _ = flags.SetAnnotation("platform", "version", []string{"1.48"}) + _ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms) return cmd } @@ -63,12 +68,20 @@ func runLoad(ctx context.Context, dockerCli command.Cli, opts loadOptions) error return errors.Errorf("requested load from stdin, but stdin is empty") } - var loadOpts image.LoadOptions + var options image.LoadOptions if opts.quiet || !dockerCli.Out().IsTerminal() { - loadOpts.Quiet = true + options.Quiet = true } - response, err := dockerCli.Client().ImageLoad(ctx, input, loadOpts) + if opts.platform != "" { + p, err := platforms.Parse(opts.platform) + if err != nil { + return errors.Wrap(err, "invalid platform") + } + options.Platform = &p + } + + response, err := dockerCli.Client().ImageLoad(ctx, input, options) if err != nil { return err } diff --git a/cli/command/image/load_test.go b/cli/command/image/load_test.go index 30edd87789..5b0e4532e8 100644 --- a/cli/command/image/load_test.go +++ b/cli/command/image/load_test.go @@ -8,8 +8,10 @@ import ( "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types/image" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" "gotest.tools/v3/golden" ) @@ -40,6 +42,14 @@ func TestNewLoadCommandErrors(t *testing.T) { return image.LoadResponse{}, errors.Errorf("something went wrong") }, }, + { + name: "invalid platform", + args: []string{"--platform", ""}, + expectedError: `invalid platform`, + imageLoadFunc: func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error) { + return image.LoadResponse{}, nil + }, + }, } for _, tc := range testCases { tc := tc @@ -96,6 +106,14 @@ func TestNewLoadCommandSuccess(t *testing.T) { return image.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil }, }, + { + name: "with platform", + args: []string{"--platform", "linux/amd64"}, + imageLoadFunc: func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error) { + assert.Check(t, is.DeepEqual(ocispec.Platform{OS: "linux", Architecture: "amd64"}, *options.Platform)) + return image.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil + }, + }, } for _, tc := range testCases { tc := tc diff --git a/cli/command/image/testdata/load-command-success.with platform.golden b/cli/command/image/testdata/load-command-success.with platform.golden new file mode 100644 index 0000000000..51da4200ab --- /dev/null +++ b/cli/command/image/testdata/load-command-success.with platform.golden @@ -0,0 +1 @@ +Success \ No newline at end of file diff --git a/docs/reference/commandline/image_load.md b/docs/reference/commandline/image_load.md index 8b675a3bb1..bd104ed352 100644 --- a/docs/reference/commandline/image_load.md +++ b/docs/reference/commandline/image_load.md @@ -9,10 +9,11 @@ Load an image from a tar archive or STDIN ### Options -| Name | Type | Default | Description | -|:------------------------------------|:---------|:--------|:---------------------------------------------| -| [`-i`](#input), [`--input`](#input) | `string` | | Read from tar archive file, instead of STDIN | -| `-q`, `--quiet` | `bool` | | Suppress the load output | +| Name | Type | Default | Description | +|:------------------------------------|:---------|:--------|:-----------------------------------------------------------------------------------------------| +| [`-i`](#input), [`--input`](#input) | `string` | | Read from tar archive file, instead of STDIN | +| [`--platform`](#platform) | `string` | | Load only the given platform variant. Formatted as `os[/arch[/variant]]` (e.g., `linux/amd64`) | +| `-q`, `--quiet` | `bool` | | Suppress the load output | @@ -58,3 +59,32 @@ fedora 20 58394af37342 7 weeks ago fedora heisenbug 58394af37342 7 weeks ago 385.5 MB fedora latest 58394af37342 7 weeks ago 385.5 MB ``` + + +### Load a specific platform (--platform) + +The `--platform` option allows you to specify which platform variant of the +image to load. By default, `docker load` loads all platform variants that +are present in the archive. Use the `--platform` option to specify which +platform variant of the image to load. An error is produced if the given +platform is not present in the archive. + +The platform option takes the `os[/arch[/variant]]` format; for example, +`linux/amd64` or `linux/arm64/v8`. Architecture and variant are optional, +and default to the daemon's native architecture if omitted. + +The following example loads the `linux/amd64` variant of an `alpine` image +from an archive that contains multiple platform variants. + +```console +$ docker image load -i image.tar --platform=linux/amd64 +Loaded image: alpine:latest +``` + +The following example attempts to load a `linux/ppc64le` image from an +archive, but the given platform is not present in the archive; + +```console +$ docker image load -i image.tar --platform=linux/ppc64le +requested platform (linux/ppc64le) not found: image might be filtered out +``` diff --git a/docs/reference/commandline/load.md b/docs/reference/commandline/load.md index c961f06020..41251b1b13 100644 --- a/docs/reference/commandline/load.md +++ b/docs/reference/commandline/load.md @@ -9,10 +9,11 @@ Load an image from a tar archive or STDIN ### Options -| Name | Type | Default | Description | -|:----------------|:---------|:--------|:---------------------------------------------| -| `-i`, `--input` | `string` | | Read from tar archive file, instead of STDIN | -| `-q`, `--quiet` | `bool` | | Suppress the load output | +| Name | Type | Default | Description | +|:----------------|:---------|:--------|:-----------------------------------------------------------------------------------------------| +| `-i`, `--input` | `string` | | Read from tar archive file, instead of STDIN | +| `--platform` | `string` | | Load only the given platform variant. Formatted as `os[/arch[/variant]]` (e.g., `linux/amd64`) | +| `-q`, `--quiet` | `bool` | | Suppress the load output |