Forráskód Böngészése

c8d: Better pull progress

- check if we have to download layers and print the approriate message
- show the digest of the pulled manifest(list)
- skip pulling if we already have the right manifest

Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
Djordje Lukic 1 éve
szülő
commit
776c376227

+ 46 - 2
daemon/containerd/image_pull.go

@@ -14,6 +14,7 @@ import (
 	"github.com/docker/docker/api/types/events"
 	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/errdefs"
+	"github.com/docker/docker/pkg/progress"
 	"github.com/docker/docker/pkg/streamformatter"
 	"github.com/opencontainers/go-digest"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -49,9 +50,18 @@ func (i *ImageService) PullImage(ctx context.Context, image, tagOrDigest string,
 	resolver, _ := i.newResolverFromAuthConfig(ctx, authConfig)
 	opts = append(opts, containerd.WithResolver(resolver))
 
+	old, err := i.resolveDescriptor(ctx, ref.String())
+	if err != nil && !errdefs.IsNotFound(err) {
+		return err
+	}
+	p := platforms.Default()
+	if platform != nil {
+		p = platforms.Only(*platform)
+	}
+
 	jobs := newJobs()
 	h := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
-		if desc.MediaType != images.MediaTypeDockerSchema1Manifest {
+		if images.IsLayerType(desc.MediaType) {
 			jobs.Add(desc)
 		}
 		return nil, nil
@@ -59,9 +69,26 @@ func (i *ImageService) PullImage(ctx context.Context, image, tagOrDigest string,
 	opts = append(opts, containerd.WithImageHandler(h))
 
 	out := streamformatter.NewJSONProgressOutput(outStream, false)
-	finishProgress := jobs.showProgress(ctx, out, pullProgress{Store: i.client.ContentStore(), ShowExists: true})
+	pp := pullProgress{store: i.client.ContentStore(), showExists: true}
+	finishProgress := jobs.showProgress(ctx, out, pp)
 	defer finishProgress()
 
+	ah := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+		if images.IsManifestType(desc.MediaType) {
+			available, _, _, missing, err := images.Check(ctx, i.client.ContentStore(), desc, p)
+			if err != nil {
+				return nil, err
+			}
+			// If we already have all the contents pull shouldn't show any layer
+			// download progress, not even a "Already present" message.
+			if available && len(missing) == 0 {
+				pp.hideLayers = true
+			}
+		}
+		return nil, nil
+	})
+	opts = append(opts, containerd.WithImageHandler(ah))
+
 	opts = append(opts, containerd.WithPullUnpack)
 	// TODO(thaJeztah): we may have to pass the snapshotter to use if the pull is part of a "docker run" (container create -> pull image if missing). See https://github.com/moby/moby/issues/45273
 	opts = append(opts, containerd.WithPullSnapshotter(i.snapshotter))
@@ -71,6 +98,8 @@ func (i *ImageService) PullImage(ctx context.Context, image, tagOrDigest string,
 	infoHandler := snapshotters.AppendInfoHandlerWrapper(ref.String())
 	opts = append(opts, containerd.WithImageHandlerWrapper(infoHandler))
 
+	progress.Message(out, tagOrDigest, "Pulling from "+reference.Path(ref))
+
 	img, err := i.client.Pull(ctx, ref.String(), opts...)
 	if err != nil {
 		return err
@@ -81,6 +110,9 @@ func (i *ImageService) PullImage(ctx context.Context, image, tagOrDigest string,
 		"remote": ref.String(),
 	})
 	logger.Info("image pulled")
+	progress.Message(out, "", "Digest: "+img.Target().Digest.String())
+
+	writeStatus(out, reference.FamiliarString(ref), old.Digest != img.Target().Digest)
 
 	// The pull succeeded, so try to remove any dangling image we have for this target
 	err = i.client.ImageService().Delete(context.Background(), danglingImageName(img.Target().Digest))
@@ -94,3 +126,15 @@ func (i *ImageService) PullImage(ctx context.Context, image, tagOrDigest string,
 
 	return nil
 }
+
+// writeStatus writes a status message to out. If newerDownloaded is true, the
+// status message indicates that a newer image was downloaded. Otherwise, it
+// indicates that the image is up to date. requestedTag is the tag the message
+// will refer to.
+func writeStatus(out progress.Output, requestedTag string, newerDownloaded bool) {
+	if newerDownloaded {
+		progress.Message(out, "", "Status: Downloaded newer image for "+requestedTag)
+	} else {
+		progress.Message(out, "", "Status: Image is up to date for "+requestedTag)
+	}
+}

+ 1 - 1
daemon/containerd/image_push.go

@@ -68,7 +68,7 @@ func (i *ImageService) PushImage(ctx context.Context, targetRef reference.Named,
 	jobsQueue := newJobs()
 	finishProgress := jobsQueue.showProgress(ctx, out, combinedProgress([]progressUpdater{
 		&pp,
-		pullProgress{ShowExists: false, Store: store},
+		pullProgress{showExists: false, store: store},
 	}))
 	defer func() {
 		finishProgress()

+ 10 - 5
daemon/containerd/progress.go

@@ -104,12 +104,13 @@ func (j *jobs) Jobs() []ocispec.Descriptor {
 }
 
 type pullProgress struct {
-	Store      content.Store
-	ShowExists bool
+	store      content.Store
+	showExists bool
+	hideLayers bool
 }
 
 func (p pullProgress) UpdateProgress(ctx context.Context, ongoing *jobs, out progress.Output, start time.Time) error {
-	actives, err := p.Store.ListStatuses(ctx, "")
+	actives, err := p.store.ListStatuses(ctx, "")
 	if err != nil {
 		if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
 			return err
@@ -125,6 +126,10 @@ func (p pullProgress) UpdateProgress(ctx context.Context, ongoing *jobs, out pro
 	}
 
 	for _, j := range ongoing.Jobs() {
+		if p.hideLayers {
+			ongoing.Remove(j)
+			continue
+		}
 		key := remotes.MakeRefKey(ctx, j)
 		if info, ok := pulling[key]; ok {
 			out.WriteProgress(progress.Progress{
@@ -136,7 +141,7 @@ func (p pullProgress) UpdateProgress(ctx context.Context, ongoing *jobs, out pro
 			continue
 		}
 
-		info, err := p.Store.Info(ctx, j.Digest)
+		info, err := p.store.Info(ctx, j.Digest)
 		if err != nil {
 			if !cerrdefs.IsNotFound(err) {
 				return err
@@ -149,7 +154,7 @@ func (p pullProgress) UpdateProgress(ctx context.Context, ongoing *jobs, out pro
 				LastUpdate: true,
 			})
 			ongoing.Remove(j)
-		} else if p.ShowExists {
+		} else if p.showExists {
 			out.WriteProgress(progress.Progress{
 				ID:         stringid.TruncateID(j.Digest.Encoded()),
 				Action:     "Already exists",