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 <github@gone.nl>
This commit is contained in:
parent
9cebefa717
commit
07d2ad30e5
4 changed files with 21 additions and 33 deletions
|
@ -77,7 +77,6 @@ type VolumeBackend interface {
|
||||||
// ImageBackend is used by an executor to perform image operations
|
// ImageBackend is used by an executor to perform image operations
|
||||||
type ImageBackend interface {
|
type ImageBackend interface {
|
||||||
PullImage(ctx context.Context, ref reference.Named, platform *ocispec.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
|
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)
|
GetRepositories(context.Context, reference.Named, *registry.AuthConfig) ([]distribution.Repository, error)
|
||||||
GetImage(ctx context.Context, refOrID string, options opts.GetImageOpts) (*image.Image, error)
|
GetImage(ctx context.Context, refOrID string, options opts.GetImageOpts) (*image.Image, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
runconfigopts "github.com/docker/docker/runconfig/opts"
|
runconfigopts "github.com/docker/docker/runconfig/opts"
|
||||||
gogotypes "github.com/gogo/protobuf/types"
|
gogotypes "github.com/gogo/protobuf/types"
|
||||||
swarmapi "github.com/moby/swarmkit/v2/api"
|
swarmapi "github.com/moby/swarmkit/v2/api"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"google.golang.org/grpc"
|
"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)
|
return "", errors.Errorf("image reference not tagged: %s", image)
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := c.config.ImageBackend.GetRepository(ctx, taggedRef, authConfig)
|
// Fetch the image manifest's digest; if a mirror is configured, try the
|
||||||
if err != nil {
|
// mirror first, but continue with upstream on failure.
|
||||||
return "", err
|
repos, err := c.config.ImageBackend.GetRepositories(ctx, taggedRef, authConfig)
|
||||||
}
|
|
||||||
dscrptr, err := repo.Tags(ctx).Get(ctx, taggedRef.Tag())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
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 {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1586,16 +1586,6 @@ type imageBackend struct {
|
||||||
registryService *registry.Service
|
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
|
// GetRepositories returns a list of repositories configured for the given
|
||||||
// reference. Multiple repositories can be returned if the reference is for
|
// reference. Multiple repositories can be returned if the reference is for
|
||||||
// the default (Docker Hub) registry and a mirror is configured, but it omits
|
// the default (Docker Hub) registry and a mirror is configured, but it omits
|
||||||
|
|
|
@ -9,15 +9,6 @@ import (
|
||||||
"github.com/docker/docker/errdefs"
|
"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
|
// GetRepositories returns a list of repositories configured for the given
|
||||||
// reference. Multiple repositories can be returned if the reference is for
|
// reference. Multiple repositories can be returned if the reference is for
|
||||||
// the default (Docker Hub) registry and a mirror is configured, but it omits
|
// 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
|
// 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.
|
// the given reference, or if the provided reference is invalid.
|
||||||
func GetRepositories(ctx context.Context, ref reference.Named, config *ImagePullConfig) ([]distribution.Repository, error) {
|
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)
|
repoInfo, err := config.RegistryService.ResolveRepository(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errdefs.InvalidParameter(err)
|
return nil, errdefs.InvalidParameter(err)
|
||||||
|
@ -56,9 +43,6 @@ func getRepositories(ctx context.Context, ref reference.Named, config *ImagePull
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
repositories = append(repositories, repo)
|
repositories = append(repositories, repo)
|
||||||
if firstOnly {
|
|
||||||
return repositories, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if len(repositories) == 0 {
|
if len(repositories) == 0 {
|
||||||
return nil, lastError
|
return nil, lastError
|
||||||
|
|
Loading…
Reference in a new issue