8 "github.com/Sirupsen/logrus"
9 "github.com/docker/distribution"
10 "github.com/docker/distribution/reference"
11 "github.com/docker/distribution/registry/api/errcode"
12 "github.com/docker/distribution/registry/api/v2"
13 "github.com/docker/distribution/registry/client"
14 "github.com/docker/distribution/registry/client/auth"
15 "github.com/docker/docker/distribution/xfer"
16 "github.com/pkg/errors"
19 // ErrNoSupport is an error type used for errors indicating that an operation
20 // is not supported. It encapsulates a more specific error.
21 type ErrNoSupport struct{ Err error }
23 func (e ErrNoSupport) Error() string {
25 return "not supported"
30 // fallbackError wraps an error that can possibly allow fallback to a different
32 type fallbackError struct {
33 // err is the error being wrapped.
35 // confirmedV2 is set to true if it was confirmed that the registry
36 // supports the v2 protocol. This is used to limit fallbacks to the v1
39 // transportOK is set to true if we managed to speak HTTP with the
40 // registry. This confirms that we're using appropriate TLS settings
45 // Error renders the FallbackError as a string.
46 func (f fallbackError) Error() string {
47 return f.Cause().Error()
50 func (f fallbackError) Cause() error {
54 // shouldV2Fallback returns true if this error is a reason to fall back to v1.
55 func shouldV2Fallback(err errcode.Error) bool {
57 case errcode.ErrorCodeUnauthorized, v2.ErrorCodeManifestUnknown, v2.ErrorCodeNameUnknown:
63 // TranslatePullError is used to convert an error from a registry pull
64 // operation to an error representing the entire pull operation. Any error
65 // information which is not used by the returned error gets output to
67 func TranslatePullError(err error, ref reference.Named) error {
68 switch v := err.(type) {
71 for _, extra := range v[1:] {
72 logrus.Infof("Ignoring extra error returned from registry: %v", extra)
74 return TranslatePullError(v[0], ref)
79 case errcode.ErrorCodeDenied:
80 // ErrorCodeDenied is used when access to the repository was denied
81 newErr = errors.Errorf("pull access denied for %s, repository does not exist or may require 'docker login'", reference.FamiliarName(ref))
82 case v2.ErrorCodeManifestUnknown:
83 newErr = errors.Errorf("manifest for %s not found", reference.FamiliarString(ref))
84 case v2.ErrorCodeNameUnknown:
85 newErr = errors.Errorf("repository %s not found", reference.FamiliarName(ref))
88 logrus.Infof("Translating %q to %q", err, newErr)
92 return TranslatePullError(v.Err, ref)
98 // continueOnError returns true if we should fallback to the next endpoint
99 // as a result of this error.
100 func continueOnError(err error) bool {
101 switch v := err.(type) {
106 return continueOnError(v[0])
108 return continueOnError(v.Err)
110 return shouldV2Fallback(v)
111 case *client.UnexpectedHTTPResponseError:
113 case ImageConfigPullError:
116 return !strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error()))
118 // let's be nice and fallback if the error is a completely
120 // If new errors have to be handled in some way, please
121 // add them to the switch above.
125 // retryOnError wraps the error in xfer.DoNotRetry if we should not retry the
126 // operation after this error.
127 func retryOnError(err error) error {
128 switch v := err.(type) {
131 return retryOnError(v[0])
135 case errcode.ErrorCodeUnauthorized, errcode.ErrorCodeUnsupported, errcode.ErrorCodeDenied, errcode.ErrorCodeTooManyRequests, v2.ErrorCodeNameUnknown:
136 return xfer.DoNotRetry{Err: err}
140 case auth.ErrNoBasicAuthCredentials, auth.ErrNoToken:
141 return xfer.DoNotRetry{Err: v.Err}
143 return retryOnError(v.Err)
144 case *client.UnexpectedHTTPResponseError:
145 return xfer.DoNotRetry{Err: err}
147 if err == distribution.ErrBlobUnknown {
148 return xfer.DoNotRetry{Err: err}
150 if strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error())) {
151 return xfer.DoNotRetry{Err: err}
154 // let's be nice and fallback if the error is a completely
156 // If new errors have to be handled in some way, please
157 // add them to the switch above.