Browse Source

Merge pull request #41749 from cpuguy83/fallback_manifest_store

Add fallback for pull by tag
Akihiro Suda 4 years ago
parent
commit
9f72510b69
2 changed files with 54 additions and 6 deletions
  1. 17 0
      distribution/errors.go
  2. 37 6
      distribution/pull_v2.go

+ 17 - 0
distribution/errors.go

@@ -112,6 +112,23 @@ func TranslatePullError(err error, ref reference.Named) error {
 	return errdefs.Unknown(err)
 }
 
+func isNotFound(err error) bool {
+	switch v := err.(type) {
+	case errcode.Errors:
+		for _, e := range v {
+			if isNotFound(e) {
+				return true
+			}
+		}
+	case errcode.Error:
+		switch v.Code {
+		case errcode.ErrorCodeDenied, v2.ErrorCodeManifestUnknown, v2.ErrorCodeNameUnknown:
+			return true
+		}
+	}
+	return false
+}
+
 // continueOnError returns true if we should fallback to the next endpoint
 // as a result of this error.
 func continueOnError(err error, mirrorEndpoint bool) bool {

+ 37 - 6
distribution/pull_v2.go

@@ -343,16 +343,19 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named, platform
 		dgst        digest.Digest
 		mt          string
 		size        int64
+		tagged      reference.NamedTagged
+		isTagged    bool
 	)
 	if digested, isDigested := ref.(reference.Canonical); isDigested {
 		dgst = digested.Digest()
 		tagOrDigest = digested.String()
-	} else if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
+	} else if tagged, isTagged = ref.(reference.NamedTagged); isTagged {
 		tagService := p.repo.Tags(ctx)
 		desc, err := tagService.Get(ctx, tagged.Tag())
 		if err != nil {
 			return false, allowV1Fallback(err)
 		}
+
 		dgst = desc.Digest
 		tagOrDigest = tagged.Tag()
 		mt = desc.MediaType
@@ -367,13 +370,40 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named, platform
 			"remote": ref,
 		}))
 
-	manifest, err := p.manifestStore.Get(ctx, specs.Descriptor{
+	desc := specs.Descriptor{
 		MediaType: mt,
 		Digest:    dgst,
 		Size:      size,
-	})
+	}
+	manifest, err := p.manifestStore.Get(ctx, desc)
 	if err != nil {
-		return false, err
+		if isTagged && isNotFound(errors.Cause(err)) {
+			logrus.WithField("ref", ref).WithError(err).Debug("Falling back to pull manifest by tag")
+
+			msg := `%s Failed to pull manifest by the resolved digest. This registry does not
+	appear to conform to the distribution registry specification; falling back to
+	pull by tag.  This fallback is DEPRECATED, and will be removed in a future
+	release.  Please contact admins of %s. %s
+`
+
+			warnEmoji := "\U000026A0\U0000FE0F"
+			progress.Messagef(p.config.ProgressOutput, "WARNING", msg, warnEmoji, p.endpoint.URL, warnEmoji)
+
+			// Fetch by tag worked, but fetch by digest didn't.
+			// This is a broken registry implementation.
+			// We'll fallback to the old behavior and get the manifest by tag.
+			var ms distribution.ManifestService
+			ms, err = p.repo.Manifests(ctx)
+			if err != nil {
+				return false, err
+			}
+
+			manifest, err = ms.Get(ctx, "", distribution.WithTag(tagged.Tag()))
+			err = errors.Wrap(err, "error after falling back to get manifest by tag")
+		}
+		if err != nil {
+			return false, err
+		}
 	}
 
 	if manifest == nil {
@@ -818,11 +848,12 @@ func (p *v2Puller) pullManifestList(ctx context.Context, ref reference.Named, mf
 		return "", "", err
 	}
 
-	manifest, err := p.manifestStore.Get(ctx, specs.Descriptor{
+	desc := specs.Descriptor{
 		Digest:    match.Digest,
 		Size:      match.Size,
 		MediaType: match.MediaType,
-	})
+	}
+	manifest, err := p.manifestStore.Get(ctx, desc)
 	if err != nil {
 		return "", "", err
 	}