Browse code

Merge pull request #41749 from cpuguy83/fallback_manifest_store

Add fallback for pull by tag

Akihiro Suda authored on 2020/12/05 10:49:24
Showing 2 changed files
... ...
@@ -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
 	}