Selaa lähdekoodia

distribution: Error when pulling OCI artifacts

Currently an attempt to pull a reference which resolves to an OCI
artifact (Helm chart for example), results in a bit unrelated error
message `invalid rootfs in image configuration`.

This provides a more meaningful error in case a user attempts to
download a media type which isn't image related.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
Paweł Gronowski 2 vuotta sitten
vanhempi
commit
407e3a4552
2 muutettua tiedostoa jossa 39 lisäystä ja 1 poistoa
  1. 16 1
      distribution/errors.go
  2. 23 0
      distribution/pull_v2.go

+ 16 - 1
distribution/errors.go

@@ -63,6 +63,19 @@ func (e notFoundError) Cause() error {
 	return e.cause
 }
 
+// unsupportedMediaTypeError is an error issued when attempted
+// to pull unsupported content.
+type unsupportedMediaTypeError struct {
+	MediaType string
+}
+
+func (e unsupportedMediaTypeError) InvalidParameter() {}
+
+// Error returns the error string for unsupportedMediaTypeError.
+func (e unsupportedMediaTypeError) Error() string {
+	return "unsupported media type " + e.MediaType
+}
+
 // translatePullError is used to convert an error from a registry pull
 // operation to an error representing the entire pull operation. Any error
 // information which is not used by the returned error gets output to
@@ -124,6 +137,8 @@ func continueOnError(err error, mirrorEndpoint bool) bool {
 		// Failures from a mirror endpoint should result in fallback to the
 		// canonical repo.
 		return mirrorEndpoint
+	case unsupportedMediaTypeError:
+		return false
 	case error:
 		return !strings.Contains(err.Error(), strings.ToLower(syscall.ESRCH.Error()))
 	}
@@ -153,7 +168,7 @@ func retryOnError(err error) error {
 			return xfer.DoNotRetry{Err: v.Err}
 		}
 		return retryOnError(v.Err)
-	case *client.UnexpectedHTTPResponseError:
+	case *client.UnexpectedHTTPResponseError, unsupportedMediaTypeError:
 		return xfer.DoNotRetry{Err: err}
 	case error:
 		if err == distribution.ErrBlobUnknown {

+ 23 - 0
distribution/pull_v2.go

@@ -7,6 +7,7 @@ import (
 	"io"
 	"os"
 	"runtime"
+	"strings"
 	"time"
 
 	"github.com/containerd/containerd/log"
@@ -606,6 +607,21 @@ func (p *puller) pullSchema1(ctx context.Context, ref reference.Reference, unver
 	return imageID, manifestDigest, nil
 }
 
+func checkSupportedMediaType(mediaType string) error {
+	supportedMediaTypes := []string{
+		"application/vnd.oci.image.",
+		"application/vnd.docker.",
+	}
+
+	lowerMt := strings.ToLower(mediaType)
+	for _, mt := range supportedMediaTypes {
+		if strings.HasPrefix(lowerMt, mt) {
+			return nil
+		}
+	}
+	return unsupportedMediaTypeError{MediaType: mediaType}
+}
+
 func (p *puller) pullSchema2Layers(ctx context.Context, target distribution.Descriptor, layers []distribution.Descriptor, platform *specs.Platform) (id digest.Digest, err error) {
 	if _, err := p.config.ImageStore.Get(ctx, target.Digest); err == nil {
 		// If the image already exists locally, no need to pull
@@ -613,6 +629,10 @@ func (p *puller) pullSchema2Layers(ctx context.Context, target distribution.Desc
 		return target.Digest, nil
 	}
 
+	if err := checkSupportedMediaType(target.MediaType); err != nil {
+		return "", err
+	}
+
 	var descriptors []xfer.DownloadDescriptor
 
 	// Note that the order of this loop is in the direction of bottom-most
@@ -621,6 +641,9 @@ func (p *puller) pullSchema2Layers(ctx context.Context, target distribution.Desc
 		if err := d.Digest.Validate(); err != nil {
 			return "", errors.Wrapf(err, "could not validate layer digest %q", d.Digest)
 		}
+		if err := checkSupportedMediaType(d.MediaType); err != nil {
+			return "", err
+		}
 		layerDescriptor := &layerDescriptor{
 			digest:          d.Digest,
 			repo:            p.repo,