Skip to content

Commit ccd9d63

Browse files
committed
Set platform on container create API.
Previously we only set the platform when performing a pull, which is only initiated if pull always is set, or if the image reference does not exist in the daemon. The daemon now supports specifying which platform you wanted on container create so it can validate the image reference is the platform you thought you were getting. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
1 parent 8c986d3 commit ccd9d63

4 files changed

Lines changed: 30 additions & 4 deletions

File tree

cli/command/container/client_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/docker/docker/api/types/container"
99
"github.com/docker/docker/api/types/network"
1010
"github.com/docker/docker/client"
11+
specs "github.com/opencontainers/image-spec/specs-go/v1"
1112
)
1213

1314
type fakeClient struct {
@@ -18,6 +19,7 @@ type fakeClient struct {
1819
createContainerFunc func(config *container.Config,
1920
hostConfig *container.HostConfig,
2021
networkingConfig *network.NetworkingConfig,
22+
platform *specs.Platform,
2123
containerName string) (container.ContainerCreateCreatedBody, error)
2224
containerStartFunc func(container string, options types.ContainerStartOptions) error
2325
imageCreateFunc func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error)
@@ -69,10 +71,11 @@ func (f *fakeClient) ContainerCreate(
6971
config *container.Config,
7072
hostConfig *container.HostConfig,
7173
networkingConfig *network.NetworkingConfig,
74+
platform *specs.Platform,
7275
containerName string,
7376
) (container.ContainerCreateCreatedBody, error) {
7477
if f.createContainerFunc != nil {
75-
return f.createContainerFunc(config, hostConfig, networkingConfig, containerName)
78+
return f.createContainerFunc(config, hostConfig, networkingConfig, platform, containerName)
7679
}
7780
return container.ContainerCreateCreatedBody{}, nil
7881
}

cli/command/container/create.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@ import (
77
"os"
88
"regexp"
99

10+
"github.com/containerd/containerd/platforms"
1011
"github.com/docker/cli/cli"
1112
"github.com/docker/cli/cli/command"
1213
"github.com/docker/cli/cli/command/image"
1314
"github.com/docker/cli/opts"
1415
"github.com/docker/distribution/reference"
1516
"github.com/docker/docker/api/types"
1617
"github.com/docker/docker/api/types/container"
18+
"github.com/docker/docker/api/types/versions"
1719
apiclient "github.com/docker/docker/client"
1820
"github.com/docker/docker/pkg/jsonmessage"
1921
"github.com/docker/docker/registry"
22+
specs "github.com/opencontainers/image-spec/specs-go/v1"
2023
"github.com/pkg/errors"
2124
"github.com/spf13/cobra"
2225
"github.com/spf13/pflag"
@@ -233,13 +236,26 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig
233236
return nil
234237
}
235238

239+
var platform *specs.Platform
240+
// Engine API version 1.41 first introduced the option to specify platform on
241+
// create. It will produce an error if you try to set a platform on older API
242+
// versions, so check the API version here to maintain backwards
243+
// compatibility for CLI users.
244+
if opts.platform != "" && versions.GreaterThanOrEqualTo(dockerCli.Client().ClientVersion(), "1.41") {
245+
p, err := platforms.Parse(opts.platform)
246+
if err != nil {
247+
return nil, errors.Wrap(err, "error parsing specified platform")
248+
}
249+
platform = &p
250+
}
251+
236252
if opts.pull == PullImageAlways {
237253
if err := pullAndTagImage(); err != nil {
238254
return nil, err
239255
}
240256
}
241257

242-
response, err := dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, opts.name)
258+
response, err := dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, platform, opts.name)
243259
if err != nil {
244260
// Pull image if it does not exist locally and we have the PullImageMissing option. Default behavior.
245261
if apiclient.IsErrNotFound(err) && namedRef != nil && opts.pull == PullImageMissing {
@@ -250,7 +266,7 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig
250266
}
251267

252268
var retryErr error
253-
response, retryErr = dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, opts.name)
269+
response, retryErr = dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, platform, opts.name)
254270
if retryErr != nil {
255271
return nil, retryErr
256272
}

cli/command/container/create_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/docker/docker/api/types/container"
1919
"github.com/docker/docker/api/types/network"
2020
"github.com/google/go-cmp/cmp"
21+
specs "github.com/opencontainers/image-spec/specs-go/v1"
2122
"gotest.tools/v3/assert"
2223
is "gotest.tools/v3/assert/cmp"
2324
"gotest.tools/v3/fs"
@@ -116,6 +117,7 @@ func TestCreateContainerImagePullPolicy(t *testing.T) {
116117
config *container.Config,
117118
hostConfig *container.HostConfig,
118119
networkingConfig *network.NetworkingConfig,
120+
platform *specs.Platform,
119121
containerName string,
120122
) (container.ContainerCreateCreatedBody, error) {
121123
defer func() { c.ResponseCounter++ }()
@@ -184,6 +186,7 @@ func TestNewCreateCommandWithContentTrustErrors(t *testing.T) {
184186
createContainerFunc: func(config *container.Config,
185187
hostConfig *container.HostConfig,
186188
networkingConfig *network.NetworkingConfig,
189+
platform *specs.Platform,
187190
containerName string,
188191
) (container.ContainerCreateCreatedBody, error) {
189192
return container.ContainerCreateCreatedBody{}, fmt.Errorf("shouldn't try to pull image")
@@ -244,6 +247,7 @@ func TestNewCreateCommandWithWarnings(t *testing.T) {
244247
createContainerFunc: func(config *container.Config,
245248
hostConfig *container.HostConfig,
246249
networkingConfig *network.NetworkingConfig,
250+
platform *specs.Platform,
247251
containerName string,
248252
) (container.ContainerCreateCreatedBody, error) {
249253
return container.ContainerCreateCreatedBody{}, nil
@@ -280,6 +284,7 @@ func TestCreateContainerWithProxyConfig(t *testing.T) {
280284
createContainerFunc: func(config *container.Config,
281285
hostConfig *container.HostConfig,
282286
networkingConfig *network.NetworkingConfig,
287+
platform *specs.Platform,
283288
containerName string,
284289
) (container.ContainerCreateCreatedBody, error) {
285290
sort.Strings(config.Env)

cli/command/container/run_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ import (
99
"github.com/docker/cli/internal/test/notary"
1010
"github.com/docker/docker/api/types/container"
1111
"github.com/docker/docker/api/types/network"
12+
specs "github.com/opencontainers/image-spec/specs-go/v1"
1213
"gotest.tools/v3/assert"
1314
is "gotest.tools/v3/assert/cmp"
1415
)
1516

1617
func TestRunLabel(t *testing.T) {
1718
cli := test.NewFakeCli(&fakeClient{
18-
createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ string) (container.ContainerCreateCreatedBody, error) {
19+
createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ *specs.Platform, _ string) (container.ContainerCreateCreatedBody, error) {
1920
return container.ContainerCreateCreatedBody{
2021
ID: "id",
2122
}, nil
@@ -58,6 +59,7 @@ func TestRunCommandWithContentTrustErrors(t *testing.T) {
5859
createContainerFunc: func(config *container.Config,
5960
hostConfig *container.HostConfig,
6061
networkingConfig *network.NetworkingConfig,
62+
platform *specs.Platform,
6163
containerName string,
6264
) (container.ContainerCreateCreatedBody, error) {
6365
return container.ContainerCreateCreatedBody{}, fmt.Errorf("shouldn't try to pull image")

0 commit comments

Comments
 (0)