c8d/push: Support pushing all tags

Implement missing feature that pushes all tags from the provided local
repository.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
Paweł Gronowski 2023-09-14 16:17:56 +02:00
parent 01cc1cc923
commit babf907bfd
No known key found for this signature in database
GPG key ID: B85EFCFE26DEF92A

View file

@ -4,6 +4,8 @@ import (
"context"
"fmt"
"io"
"regexp"
"strconv"
"strings"
"sync"
@ -27,7 +29,8 @@ import (
"golang.org/x/sync/semaphore"
)
// PushImage initiates a push operation of the image pointed to by targetRef.
// PushImage initiates a push operation of the image pointed to by sourceRef.
// If reference is untagged, all tags from the reference repository are pushed.
// Image manifest (or index) is pushed as is, which will probably fail if you
// don't have all content referenced by the index.
// Cross-repo mounts will be attempted for non-existing blobs.
@ -36,13 +39,44 @@ import (
// pointing to the new target repository. This will allow subsequent pushes
// to perform cross-repo mounts of the shared content when pushing to a different
// repository on the same registry.
func (i *ImageService) PushImage(ctx context.Context, targetRef reference.Named, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) (retErr error) {
if _, tagged := targetRef.(reference.Tagged); !tagged {
if _, digested := targetRef.(reference.Digested); !digested {
return errdefs.NotImplemented(errors.New("push all tags is not implemented"))
func (i *ImageService) PushImage(ctx context.Context, sourceRef reference.Named, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) (retErr error) {
out := streamformatter.NewJSONProgressOutput(outStream, false)
if _, tagged := sourceRef.(reference.Tagged); !tagged {
if _, digested := sourceRef.(reference.Digested); !digested {
// Image is not tagged nor digested, that means all tags push was requested.
// Find all images with the same repository.
nameFilter := "^" + regexp.QuoteMeta(sourceRef.Name()) + ":" + reference.TagRegexp.String() + "$"
imgs, err := i.client.ImageService().List(ctx, "name~="+strconv.Quote(nameFilter))
if err != nil {
return err
}
for _, img := range imgs {
named, err := reference.ParseNamed(img.Name)
if err != nil {
// This shouldn't happen, but log a warning just in case.
log.G(ctx).WithFields(log.Fields{
"image": img.Name,
"sourceRef": sourceRef,
}).Warn("refusing to push an invalid tag")
continue
}
if err := i.pushRef(ctx, named, metaHeaders, authConfig, out); err != nil {
return err
}
}
return nil
}
}
return i.pushRef(ctx, sourceRef, metaHeaders, authConfig, out)
}
func (i *ImageService) pushRef(ctx context.Context, targetRef reference.Named, metaHeaders map[string][]string, authConfig *registry.AuthConfig, out progress.Output) (retErr error) {
leasedCtx, release, err := i.client.WithLease(ctx)
if err != nil {
return err
@ -53,8 +87,6 @@ func (i *ImageService) PushImage(ctx context.Context, targetRef reference.Named,
}
}()
out := streamformatter.NewJSONProgressOutput(outStream, false)
img, err := i.client.ImageService().Get(ctx, targetRef.String())
if err != nil {
return errdefs.NotFound(err)