Add fallback for pull by tag
Akihiro Suda authored on 2020/12/05 10:49:24... | ... |
@@ -112,6 +112,23 @@ func TranslatePullError(err error, ref reference.Named) error { |
112 | 112 |
return errdefs.Unknown(err) |
113 | 113 |
} |
114 | 114 |
|
115 |
+func isNotFound(err error) bool { |
|
116 |
+ switch v := err.(type) { |
|
117 |
+ case errcode.Errors: |
|
118 |
+ for _, e := range v { |
|
119 |
+ if isNotFound(e) { |
|
120 |
+ return true |
|
121 |
+ } |
|
122 |
+ } |
|
123 |
+ case errcode.Error: |
|
124 |
+ switch v.Code { |
|
125 |
+ case errcode.ErrorCodeDenied, v2.ErrorCodeManifestUnknown, v2.ErrorCodeNameUnknown: |
|
126 |
+ return true |
|
127 |
+ } |
|
128 |
+ } |
|
129 |
+ return false |
|
130 |
+} |
|
131 |
+ |
|
115 | 132 |
// continueOnError returns true if we should fallback to the next endpoint |
116 | 133 |
// as a result of this error. |
117 | 134 |
func continueOnError(err error, mirrorEndpoint bool) bool { |
... | ... |
@@ -343,16 +343,19 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named, platform |
343 | 343 |
dgst digest.Digest |
344 | 344 |
mt string |
345 | 345 |
size int64 |
346 |
+ tagged reference.NamedTagged |
|
347 |
+ isTagged bool |
|
346 | 348 |
) |
347 | 349 |
if digested, isDigested := ref.(reference.Canonical); isDigested { |
348 | 350 |
dgst = digested.Digest() |
349 | 351 |
tagOrDigest = digested.String() |
350 |
- } else if tagged, isTagged := ref.(reference.NamedTagged); isTagged { |
|
352 |
+ } else if tagged, isTagged = ref.(reference.NamedTagged); isTagged { |
|
351 | 353 |
tagService := p.repo.Tags(ctx) |
352 | 354 |
desc, err := tagService.Get(ctx, tagged.Tag()) |
353 | 355 |
if err != nil { |
354 | 356 |
return false, allowV1Fallback(err) |
355 | 357 |
} |
358 |
+ |
|
356 | 359 |
dgst = desc.Digest |
357 | 360 |
tagOrDigest = tagged.Tag() |
358 | 361 |
mt = desc.MediaType |
... | ... |
@@ -367,13 +370,40 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named, platform |
367 | 367 |
"remote": ref, |
368 | 368 |
})) |
369 | 369 |
|
370 |
- manifest, err := p.manifestStore.Get(ctx, specs.Descriptor{ |
|
370 |
+ desc := specs.Descriptor{ |
|
371 | 371 |
MediaType: mt, |
372 | 372 |
Digest: dgst, |
373 | 373 |
Size: size, |
374 |
- }) |
|
374 |
+ } |
|
375 |
+ manifest, err := p.manifestStore.Get(ctx, desc) |
|
375 | 376 |
if err != nil { |
376 |
- return false, err |
|
377 |
+ if isTagged && isNotFound(errors.Cause(err)) { |
|
378 |
+ logrus.WithField("ref", ref).WithError(err).Debug("Falling back to pull manifest by tag") |
|
379 |
+ |
|
380 |
+ msg := `%s Failed to pull manifest by the resolved digest. This registry does not |
|
381 |
+ appear to conform to the distribution registry specification; falling back to |
|
382 |
+ pull by tag. This fallback is DEPRECATED, and will be removed in a future |
|
383 |
+ release. Please contact admins of %s. %s |
|
384 |
+` |
|
385 |
+ |
|
386 |
+ warnEmoji := "\U000026A0\U0000FE0F" |
|
387 |
+ progress.Messagef(p.config.ProgressOutput, "WARNING", msg, warnEmoji, p.endpoint.URL, warnEmoji) |
|
388 |
+ |
|
389 |
+ // Fetch by tag worked, but fetch by digest didn't. |
|
390 |
+ // This is a broken registry implementation. |
|
391 |
+ // We'll fallback to the old behavior and get the manifest by tag. |
|
392 |
+ var ms distribution.ManifestService |
|
393 |
+ ms, err = p.repo.Manifests(ctx) |
|
394 |
+ if err != nil { |
|
395 |
+ return false, err |
|
396 |
+ } |
|
397 |
+ |
|
398 |
+ manifest, err = ms.Get(ctx, "", distribution.WithTag(tagged.Tag())) |
|
399 |
+ err = errors.Wrap(err, "error after falling back to get manifest by tag") |
|
400 |
+ } |
|
401 |
+ if err != nil { |
|
402 |
+ return false, err |
|
403 |
+ } |
|
377 | 404 |
} |
378 | 405 |
|
379 | 406 |
if manifest == nil { |
... | ... |
@@ -818,11 +848,12 @@ func (p *v2Puller) pullManifestList(ctx context.Context, ref reference.Named, mf |
818 | 818 |
return "", "", err |
819 | 819 |
} |
820 | 820 |
|
821 |
- manifest, err := p.manifestStore.Get(ctx, specs.Descriptor{ |
|
821 |
+ desc := specs.Descriptor{ |
|
822 | 822 |
Digest: match.Digest, |
823 | 823 |
Size: match.Size, |
824 | 824 |
MediaType: match.MediaType, |
825 |
- }) |
|
825 |
+ } |
|
826 |
+ manifest, err := p.manifestStore.Get(ctx, desc) |
|
826 | 827 |
if err != nil { |
827 | 828 |
return "", "", err |
828 | 829 |
} |