Skip to content

Commit e39998f

Browse files
committed
images/push: Accept platform parameter
Signed-off-by: Paweł Gronowski <[email protected]>
1 parent 17eb715 commit e39998f

7 files changed

Lines changed: 42 additions & 12 deletions

File tree

api/server/router/image/backend.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ type importExportBackend interface {
3838

3939
type registryBackend interface {
4040
PullImage(ctx context.Context, image, tag string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
41-
PushImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
41+
PushImage(ctx context.Context, ref reference.Named, platform *specs.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
4242
}
4343

4444
type Searcher interface {

api/server/router/image/image_routes.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,18 @@ func (ir *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter
172172
ref = r
173173
}
174174

175-
if err := ir.backend.PushImage(ctx, ref, metaHeaders, authConfig, output); err != nil {
175+
var optPlatform *specs.Platform
176+
if versions.GreaterThanOrEqualTo(httputils.VersionFromContext(ctx), "1.43") {
177+
if p := r.Form.Get("platform"); p != "" {
178+
platform, err := platforms.Parse(p)
179+
if err != nil {
180+
return errdefs.InvalidParameter(errors.Wrap(err, "invalid platform"))
181+
}
182+
optPlatform = &platform
183+
}
184+
}
185+
186+
if err := ir.backend.PushImage(ctx, ref, optPlatform, metaHeaders, authConfig, output); err != nil {
176187
if !output.Flushed() {
177188
return err
178189
}

api/swagger.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8490,6 +8490,19 @@ paths:
84908490
in: "query"
84918491
description: "The tag to associate with the image on the registry."
84928492
type: "string"
8493+
- name: "platform"
8494+
in: "query"
8495+
description: |
8496+
Platform in the format `os[/arch[/variant]]` used to select
8497+
a platform-specific manifest if the image is an index/manifest list.
8498+
8499+
If the option is not set, then no specific manifest is select and the
8500+
whole image index is pushed.
8501+
8502+
When specified, the daemon checks if the image has any manifest that
8503+
matches the requested platform and pushes it instead of the whole index.
8504+
If there's no matching manifest it returns a `404` status.
8505+
type: "string"
84938506
- name: "X-Registry-Auth"
84948507
in: "header"
84958508
description: |

client/image_push.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/docker/distribution/reference"
1010
"github.com/docker/docker/api/types"
1111
"github.com/docker/docker/api/types/registry"
12+
"github.com/docker/docker/api/types/versions"
1213
"github.com/docker/docker/errdefs"
1314
)
1415

@@ -34,6 +35,9 @@ func (cli *Client) ImagePush(ctx context.Context, image string, options types.Im
3435
query.Set("tag", tagged.Tag())
3536
}
3637
}
38+
if options.Platform != "" && versions.GreaterThanOrEqualTo(cli.version, "1.43") {
39+
query.Set("platform", options.Platform)
40+
}
3741

3842
resp, err := cli.tryImagePush(ctx, name, query, options.RegistryAuth)
3943
if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {

daemon/containerd/image_push.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,13 @@ import (
2323
"golang.org/x/sync/semaphore"
2424
)
2525

26-
func (i *ImageService) PushImage(ctx context.Context, targetRef reference.Named, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error {
27-
// TODO: Expose in API
28-
var platform *ocispec.Platform
29-
return i.pushImage(ctx, targetRef, platform, metaHeaders, authConfig, outStream)
30-
}
31-
3226
// PushImage initiates a push operation of the image pointed to by targetRef.
3327
//
3428
// If image points to an index/manifest list and platform is specified, then only
3529
// a matching platform manifest is pushed.
3630
// Otherwise index is pushed as is, which will probably fail if you don't have all
3731
// content referenced by the index. Cross-repo mounts will be attempted for non-existing blobs.
38-
func (i *ImageService) pushImage(ctx context.Context, targetRef reference.Named, optPlatform *ocispec.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error {
32+
func (i *ImageService) PushImage(ctx context.Context, targetRef reference.Named, optPlatform *ocispec.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error {
3933
if _, ok := targetRef.(reference.Tagged); !ok {
4034
return errdefs.NotImplemented(errors.New("push all tags is not implemented"))
4135
}
@@ -150,7 +144,8 @@ func (i *ImageService) pushImage(ctx context.Context, targetRef reference.Named,
150144
"Note: You're trying to push a manifest list/index which "+
151145
"references multiple platform specific manifests, but not all of them are available locally "+
152146
"or available to the remote repository.\n"+
153-
"Make sure you have all the referenced content and try again.",
147+
"Make sure you have all the referenced content and try again."+
148+
"Alternatively you can push a single platform specific manifest by specifying the platform.\n",
154149
err))
155150
}
156151
}

daemon/image_service.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type ImageService interface {
2626
// Images
2727

2828
PullImage(ctx context.Context, name, tag string, platform *v1.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
29-
PushImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
29+
PushImage(ctx context.Context, ref reference.Named, platform *v1.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
3030
CreateImage(config []byte, parent string) (builder.Image, error)
3131
ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error)
3232
ExportImage(ctx context.Context, names []string, outStream io.Writer) error

daemon/images/image_push.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,18 @@ import (
1010
"github.com/docker/docker/api/types/registry"
1111
"github.com/docker/docker/distribution"
1212
progressutils "github.com/docker/docker/distribution/utils"
13+
"github.com/docker/docker/errdefs"
1314
"github.com/docker/docker/pkg/progress"
15+
v1 "github.com/opencontainers/image-spec/specs-go/v1"
16+
"github.com/pkg/errors"
1417
)
1518

1619
// PushImage initiates a push operation on the repository named localName.
17-
func (i *ImageService) PushImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error {
20+
func (i *ImageService) PushImage(ctx context.Context, ref reference.Named, platform *v1.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error {
21+
if platform != nil {
22+
return errdefs.NotImplemented(errors.Errorf("pushing a specific platform is not implemented"))
23+
}
24+
1825
start := time.Now()
1926
// Include a buffer so that slow client connections don't affect
2027
// transfer performance.

0 commit comments

Comments
 (0)