Browse Source

c8d/pull: Handle pull all tags

Use the distribution code to query the remote repository for tags and
pull them sequentially just like the non-c8d pull.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
Paweł Gronowski 1 year ago
parent
commit
d9b5445f39
3 changed files with 45 additions and 8 deletions
  1. 39 4
      daemon/containerd/image_pull.go
  2. 1 1
      daemon/containerd/resolver.go
  3. 5 3
      daemon/containerd/service.go

+ 39 - 4
daemon/containerd/image_pull.go

@@ -2,6 +2,7 @@ package containerd
 
 import (
 	"context"
+	"fmt"
 	"io"
 
 	"github.com/containerd/containerd"
@@ -12,7 +13,7 @@ import (
 	"github.com/containerd/log"
 	"github.com/distribution/reference"
 	"github.com/docker/docker/api/types/events"
-	"github.com/docker/docker/api/types/registry"
+	registrytypes "github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/distribution"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/internal/compatcontext"
@@ -21,8 +22,43 @@ import (
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
-// PullImage initiates a pull operation. ref is the image to pull.
-func (i *ImageService) PullImage(ctx context.Context, ref reference.Named, platform *ocispec.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error {
+// PullImage initiates a pull operation. baseRef is the image to pull.
+// If reference is not tagged, all tags are pulled.
+func (i *ImageService) PullImage(ctx context.Context, baseRef reference.Named, platform *ocispec.Platform, metaHeaders map[string][]string, authConfig *registrytypes.AuthConfig, outStream io.Writer) error {
+	out := streamformatter.NewJSONProgressOutput(outStream, false)
+
+	if tagged, ok := baseRef.(reference.NamedTagged); ok {
+		return i.pullTag(ctx, tagged, platform, metaHeaders, authConfig, out)
+	}
+
+	tags, err := distribution.Tags(ctx, baseRef, &distribution.Config{
+		RegistryService: i.registryService,
+		MetaHeaders:     metaHeaders,
+		AuthConfig:      authConfig,
+	})
+	if err != nil {
+		return err
+	}
+
+	for _, tag := range tags {
+		ref, err := reference.WithTag(baseRef, tag)
+		if err != nil {
+			log.G(ctx).WithFields(log.Fields{
+				"tag":     tag,
+				"baseRef": baseRef,
+			}).Warn("invalid tag, won't pull")
+			continue
+		}
+
+		if err := i.pullTag(ctx, ref, platform, metaHeaders, authConfig, out); err != nil {
+			return fmt.Errorf("error pulling %s: %w", ref, err)
+		}
+	}
+
+	return nil
+}
+
+func (i *ImageService) pullTag(ctx context.Context, ref reference.NamedTagged, platform *ocispec.Platform, metaHeaders map[string][]string, authConfig *registrytypes.AuthConfig, out progress.Output) error {
 	var opts []containerd.RemoteOpt
 	if platform != nil {
 		opts = append(opts, containerd.WithPlatform(platforms.Format(*platform)))
@@ -49,7 +85,6 @@ func (i *ImageService) PullImage(ctx context.Context, ref reference.Named, platf
 	})
 	opts = append(opts, containerd.WithImageHandler(h))
 
-	out := streamformatter.NewJSONProgressOutput(outStream, false)
 	pp := pullProgress{store: i.client.ContentStore(), showExists: true}
 	finishProgress := jobs.showProgress(ctx, out, pp)
 

+ 1 - 1
daemon/containerd/resolver.go

@@ -31,7 +31,7 @@ func (i *ImageService) newResolverFromAuthConfig(ctx context.Context, authConfig
 	}), tracker
 }
 
-func hostsWrapper(hostsFn docker.RegistryHosts, optAuthConfig *registrytypes.AuthConfig, regService RegistryConfigProvider) docker.RegistryHosts {
+func hostsWrapper(hostsFn docker.RegistryHosts, optAuthConfig *registrytypes.AuthConfig, regService registryResolver) docker.RegistryHosts {
 	var authorizer docker.Authorizer
 	if optAuthConfig != nil {
 		authorizer = authorizerFromAuthConfig(*optAuthConfig)

+ 5 - 3
daemon/containerd/service.go

@@ -30,16 +30,18 @@ type ImageService struct {
 	containers      container.Store
 	snapshotter     string
 	registryHosts   docker.RegistryHosts
-	registryService RegistryConfigProvider
+	registryService registryResolver
 	eventsService   *daemonevents.Events
 	pruneRunning    atomic.Bool
 	refCountMounter snapshotter.Mounter
 	idMapping       idtools.IdentityMapping
 }
 
-type RegistryConfigProvider interface {
+type registryResolver interface {
 	IsInsecureRegistry(host string) bool
 	ResolveRepository(name reference.Named) (*registry.RepositoryInfo, error)
+	LookupPullEndpoints(hostname string) ([]registry.APIEndpoint, error)
+	LookupPushEndpoints(hostname string) ([]registry.APIEndpoint, error)
 }
 
 type ImageServiceConfig struct {
@@ -47,7 +49,7 @@ type ImageServiceConfig struct {
 	Containers      container.Store
 	Snapshotter     string
 	RegistryHosts   docker.RegistryHosts
-	Registry        RegistryConfigProvider
+	Registry        registryResolver
 	EventsService   *daemonevents.Events
 	RefCountMounter snapshotter.Mounter
 	IDMapping       idtools.IdentityMapping