From 07d2ad30e5f7126800b750d9a4cec412da877507 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 4 Jan 2024 13:41:35 +0100 Subject: [PATCH] daemon/cluster: Cluster.imageWithDigestString: include mirrors to resolve digest If the daemon is configured to use a mirror for the default (Docker Hub) registry, the endpoint did not fall back to querying the upstream if the mirror did not contain the given reference. For pull-through registry-mirrors, this was not a problem, as in that case the registry would forward the request, but for other mirrors, no fallback would happen. This was inconsistent with how "pulling" images handled this situation; when pulling images, both the mirror and upstream would be tried. This patch brings the daemon-side lookup of image-manifests on-par with the client-side lookup (the GET /distribution endpoint) as used in API 1.30 and higher. Signed-off-by: Sebastiaan van Stijn --- daemon/cluster/executor/backend.go | 1 - daemon/cluster/services.go | 27 +++++++++++++++++++++------ daemon/daemon.go | 10 ---------- distribution/repository.go | 16 ---------------- 4 files changed, 21 insertions(+), 33 deletions(-) diff --git a/daemon/cluster/executor/backend.go b/daemon/cluster/executor/backend.go index 60267953c3..638d05e8d4 100644 --- a/daemon/cluster/executor/backend.go +++ b/daemon/cluster/executor/backend.go @@ -77,7 +77,6 @@ type VolumeBackend interface { // ImageBackend is used by an executor to perform image operations type ImageBackend interface { PullImage(ctx context.Context, ref reference.Named, platform *ocispec.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error - GetRepository(context.Context, reference.Named, *registry.AuthConfig) (distribution.Repository, error) GetRepositories(context.Context, reference.Named, *registry.AuthConfig) ([]distribution.Repository, error) GetImage(ctx context.Context, refOrID string, options opts.GetImageOpts) (*image.Image, error) } diff --git a/daemon/cluster/services.go b/daemon/cluster/services.go index b267df52a0..a0e30bad0a 100644 --- a/daemon/cluster/services.go +++ b/daemon/cluster/services.go @@ -25,6 +25,7 @@ import ( runconfigopts "github.com/docker/docker/runconfig/opts" gogotypes "github.com/gogo/protobuf/types" swarmapi "github.com/moby/swarmkit/v2/api" + "github.com/opencontainers/go-digest" "github.com/pkg/errors" "google.golang.org/grpc" ) @@ -635,16 +636,30 @@ func (c *Cluster) imageWithDigestString(ctx context.Context, image string, authC return "", errors.Errorf("image reference not tagged: %s", image) } - repo, err := c.config.ImageBackend.GetRepository(ctx, taggedRef, authConfig) - if err != nil { - return "", err - } - dscrptr, err := repo.Tags(ctx).Get(ctx, taggedRef.Tag()) + // Fetch the image manifest's digest; if a mirror is configured, try the + // mirror first, but continue with upstream on failure. + repos, err := c.config.ImageBackend.GetRepositories(ctx, taggedRef, authConfig) if err != nil { return "", err } - namedDigestedRef, err := reference.WithDigest(taggedRef, dscrptr.Digest) + var ( + imgDigest digest.Digest + lastErr error + ) + for _, repo := range repos { + dscrptr, err := repo.Tags(ctx).Get(ctx, taggedRef.Tag()) + if err != nil { + lastErr = err + continue + } + imgDigest = dscrptr.Digest + } + if lastErr != nil { + return "", lastErr + } + + namedDigestedRef, err := reference.WithDigest(taggedRef, imgDigest) if err != nil { return "", err } diff --git a/daemon/daemon.go b/daemon/daemon.go index 73f7d0db67..9393dd1bbd 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -1586,16 +1586,6 @@ type imageBackend struct { registryService *registry.Service } -// GetRepository returns a repository from the registry. -func (i *imageBackend) GetRepository(ctx context.Context, ref reference.Named, authConfig *registrytypes.AuthConfig) (dist.Repository, error) { - return distribution.GetRepository(ctx, ref, &distribution.ImagePullConfig{ - Config: distribution.Config{ - AuthConfig: authConfig, - RegistryService: i.registryService, - }, - }) -} - // GetRepositories returns a list of repositories configured for the given // reference. Multiple repositories can be returned if the reference is for // the default (Docker Hub) registry and a mirror is configured, but it omits diff --git a/distribution/repository.go b/distribution/repository.go index c5229f7c8d..ac383ed0ca 100644 --- a/distribution/repository.go +++ b/distribution/repository.go @@ -9,15 +9,6 @@ import ( "github.com/docker/docker/errdefs" ) -// GetRepository returns a repository from the registry. -func GetRepository(ctx context.Context, ref reference.Named, config *ImagePullConfig) (repository distribution.Repository, lastError error) { - repos, err := getRepositories(ctx, ref, config, true) - if len(repos) == 0 { - return nil, err - } - return repos[0], nil -} - // GetRepositories returns a list of repositories configured for the given // reference. Multiple repositories can be returned if the reference is for // the default (Docker Hub) registry and a mirror is configured, but it omits @@ -26,10 +17,6 @@ func GetRepository(ctx context.Context, ref reference.Named, config *ImagePullCo // It returns an error if it was unable to reach any of the registries for // the given reference, or if the provided reference is invalid. func GetRepositories(ctx context.Context, ref reference.Named, config *ImagePullConfig) ([]distribution.Repository, error) { - return getRepositories(ctx, ref, config, false) -} - -func getRepositories(ctx context.Context, ref reference.Named, config *ImagePullConfig, firstOnly bool) ([]distribution.Repository, error) { repoInfo, err := config.RegistryService.ResolveRepository(ref) if err != nil { return nil, errdefs.InvalidParameter(err) @@ -56,9 +43,6 @@ func getRepositories(ctx context.Context, ref reference.Named, config *ImagePull continue } repositories = append(repositories, repo) - if firstOnly { - return repositories, nil - } } if len(repositories) == 0 { return nil, lastError