diff --git a/cli/command/container/client_test.go b/cli/command/container/client_test.go index b883ad1db1..67ae04904f 100644 --- a/cli/command/container/client_test.go +++ b/cli/command/container/client_test.go @@ -8,6 +8,7 @@ import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" + specs "github.com/opencontainers/image-spec/specs-go/v1" ) type fakeClient struct { @@ -18,6 +19,7 @@ type fakeClient struct { createContainerFunc func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, + platform *specs.Platform, containerName string) (container.ContainerCreateCreatedBody, error) containerStartFunc func(container string, options types.ContainerStartOptions) error imageCreateFunc func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) @@ -69,10 +71,11 @@ func (f *fakeClient) ContainerCreate( config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, + platform *specs.Platform, containerName string, ) (container.ContainerCreateCreatedBody, error) { if f.createContainerFunc != nil { - return f.createContainerFunc(config, hostConfig, networkingConfig, containerName) + return f.createContainerFunc(config, hostConfig, networkingConfig, platform, containerName) } return container.ContainerCreateCreatedBody{}, nil } diff --git a/cli/command/container/create.go b/cli/command/container/create.go index 0141775b5a..743878be18 100644 --- a/cli/command/container/create.go +++ b/cli/command/container/create.go @@ -7,6 +7,7 @@ import ( "os" "regexp" + "github.com/containerd/containerd/platforms" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/image" @@ -14,9 +15,11 @@ import ( "github.com/docker/distribution/reference" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/versions" apiclient "github.com/docker/docker/client" "github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/registry" + specs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -233,13 +236,26 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig return nil } + var platform *specs.Platform + // Engine API version 1.41 first introduced the option to specify platform on + // create. It will produce an error if you try to set a platform on older API + // versions, so check the API version here to maintain backwards + // compatibility for CLI users. + if opts.platform != "" && versions.GreaterThanOrEqualTo(dockerCli.Client().ClientVersion(), "1.41") { + p, err := platforms.Parse(opts.platform) + if err != nil { + return nil, errors.Wrap(err, "error parsing specified platform") + } + platform = &p + } + if opts.pull == PullImageAlways { if err := pullAndTagImage(); err != nil { return nil, err } } - response, err := dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, opts.name) + response, err := dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, platform, opts.name) if err != nil { // Pull image if it does not exist locally and we have the PullImageMissing option. Default behavior. if apiclient.IsErrNotFound(err) && namedRef != nil && opts.pull == PullImageMissing { @@ -250,7 +266,7 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig } var retryErr error - response, retryErr = dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, opts.name) + response, retryErr = dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, platform, opts.name) if retryErr != nil { return nil, retryErr } diff --git a/cli/command/container/create_test.go b/cli/command/container/create_test.go index 4e0bfa07ca..15a9c41749 100644 --- a/cli/command/container/create_test.go +++ b/cli/command/container/create_test.go @@ -18,6 +18,7 @@ import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" "github.com/google/go-cmp/cmp" + specs "github.com/opencontainers/image-spec/specs-go/v1" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" "gotest.tools/v3/fs" @@ -116,6 +117,7 @@ func TestCreateContainerImagePullPolicy(t *testing.T) { config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, + platform *specs.Platform, containerName string, ) (container.ContainerCreateCreatedBody, error) { defer func() { c.ResponseCounter++ }() @@ -184,6 +186,7 @@ func TestNewCreateCommandWithContentTrustErrors(t *testing.T) { createContainerFunc: func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, + platform *specs.Platform, containerName string, ) (container.ContainerCreateCreatedBody, error) { return container.ContainerCreateCreatedBody{}, fmt.Errorf("shouldn't try to pull image") @@ -244,6 +247,7 @@ func TestNewCreateCommandWithWarnings(t *testing.T) { createContainerFunc: func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, + platform *specs.Platform, containerName string, ) (container.ContainerCreateCreatedBody, error) { return container.ContainerCreateCreatedBody{}, nil @@ -280,6 +284,7 @@ func TestCreateContainerWithProxyConfig(t *testing.T) { createContainerFunc: func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, + platform *specs.Platform, containerName string, ) (container.ContainerCreateCreatedBody, error) { sort.Strings(config.Env) diff --git a/cli/command/container/run_test.go b/cli/command/container/run_test.go index 8c5f3c3d85..5821d66e66 100644 --- a/cli/command/container/run_test.go +++ b/cli/command/container/run_test.go @@ -9,13 +9,14 @@ import ( "github.com/docker/cli/internal/test/notary" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" + specs "github.com/opencontainers/image-spec/specs-go/v1" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) func TestRunLabel(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ - createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ string) (container.ContainerCreateCreatedBody, error) { + createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ *specs.Platform, _ string) (container.ContainerCreateCreatedBody, error) { return container.ContainerCreateCreatedBody{ ID: "id", }, nil @@ -58,6 +59,7 @@ func TestRunCommandWithContentTrustErrors(t *testing.T) { createContainerFunc: func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, + platform *specs.Platform, containerName string, ) (container.ContainerCreateCreatedBody, error) { return container.ContainerCreateCreatedBody{}, fmt.Errorf("shouldn't try to pull image")