github.com/rawahars/moby@v24.0.4+incompatible/distribution/errors.go (about) 1 package distribution // import "github.com/docker/docker/distribution" 2 3 import ( 4 "fmt" 5 "net/url" 6 "strings" 7 "syscall" 8 9 "github.com/docker/distribution" 10 "github.com/docker/distribution/reference" 11 "github.com/docker/distribution/registry/api/errcode" 12 v2 "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/docker/docker/errdefs" 17 "github.com/pkg/errors" 18 "github.com/sirupsen/logrus" 19 ) 20 21 // fallbackError wraps an error that can possibly allow fallback to a different 22 // endpoint. 23 type fallbackError struct { 24 // err is the error being wrapped. 25 err error 26 // transportOK is set to true if we managed to speak HTTP with the 27 // registry. This confirms that we're using appropriate TLS settings 28 // (or lack of TLS). 29 transportOK bool 30 } 31 32 // Error renders the FallbackError as a string. 33 func (f fallbackError) Error() string { 34 return f.Cause().Error() 35 } 36 37 func (f fallbackError) Cause() error { 38 return f.err 39 } 40 41 type notFoundError struct { 42 cause errcode.Error 43 ref reference.Named 44 } 45 46 func (e notFoundError) Error() string { 47 switch e.cause.Code { 48 case errcode.ErrorCodeDenied: 49 // ErrorCodeDenied is used when access to the repository was denied 50 return errors.Wrapf(e.cause, "pull access denied for %s, repository does not exist or may require 'docker login'", reference.FamiliarName(e.ref)).Error() 51 case v2.ErrorCodeManifestUnknown: 52 return errors.Wrapf(e.cause, "manifest for %s not found", reference.FamiliarString(e.ref)).Error() 53 case v2.ErrorCodeNameUnknown: 54 return errors.Wrapf(e.cause, "repository %s not found", reference.FamiliarName(e.ref)).Error() 55 } 56 // Shouldn't get here, but this is better than returning an empty string 57 return e.cause.Message 58 } 59 60 func (e notFoundError) NotFound() {} 61 62 func (e notFoundError) Cause() error { 63 return e.cause 64 } 65 66 // unsupportedMediaTypeError is an error issued when attempted 67 // to pull unsupported content. 68 type unsupportedMediaTypeError struct { 69 MediaType string 70 } 71 72 func (e unsupportedMediaTypeError) InvalidParameter() {} 73 74 // Error returns the error string for unsupportedMediaTypeError. 75 func (e unsupportedMediaTypeError) Error() string { 76 return "unsupported media type " + e.MediaType 77 } 78 79 // translatePullError is used to convert an error from a registry pull 80 // operation to an error representing the entire pull operation. Any error 81 // information which is not used by the returned error gets output to 82 // log at info level. 83 func translatePullError(err error, ref reference.Named) error { 84 switch v := err.(type) { 85 case errcode.Errors: 86 if len(v) != 0 { 87 for _, extra := range v[1:] { 88 logrus.WithError(extra).Infof("Ignoring extra error returned from registry") 89 } 90 return translatePullError(v[0], ref) 91 } 92 case errcode.Error: 93 switch v.Code { 94 case errcode.ErrorCodeDenied, v2.ErrorCodeManifestUnknown, v2.ErrorCodeNameUnknown: 95 return notFoundError{v, ref} 96 } 97 case xfer.DoNotRetry: 98 return translatePullError(v.Err, ref) 99 } 100 101 return errdefs.Unknown(err) 102 } 103 104 func isNotFound(err error) bool { 105 switch v := err.(type) { 106 case errcode.Errors: 107 for _, e := range v { 108 if isNotFound(e) { 109 return true 110 } 111 } 112 case errcode.Error: 113 switch v.Code { 114 case errcode.ErrorCodeDenied, v2.ErrorCodeManifestUnknown, v2.ErrorCodeNameUnknown: 115 return true 116 } 117 } 118 return false 119 } 120 121 // continueOnError returns true if we should fallback to the next endpoint 122 // as a result of this error. 123 func continueOnError(err error, mirrorEndpoint bool) bool { 124 switch v := err.(type) { 125 case errcode.Errors: 126 if len(v) == 0 { 127 return true 128 } 129 return continueOnError(v[0], mirrorEndpoint) 130 case errcode.Error: 131 return mirrorEndpoint 132 case *client.UnexpectedHTTPResponseError: 133 return true 134 case imageConfigPullError: 135 // imageConfigPullError only happens with v2 images, v1 fallback is 136 // unnecessary. 137 // Failures from a mirror endpoint should result in fallback to the 138 // canonical repo. 139 return mirrorEndpoint 140 case unsupportedMediaTypeError: 141 return false 142 case error: 143 return !strings.Contains(err.Error(), strings.ToLower(syscall.ESRCH.Error())) 144 } 145 // let's be nice and fallback if the error is a completely 146 // unexpected one. 147 // If new errors have to be handled in some way, please 148 // add them to the switch above. 149 return true 150 } 151 152 // retryOnError wraps the error in xfer.DoNotRetry if we should not retry the 153 // operation after this error. 154 func retryOnError(err error) error { 155 switch v := err.(type) { 156 case errcode.Errors: 157 if len(v) != 0 { 158 return retryOnError(v[0]) 159 } 160 case errcode.Error: 161 switch v.Code { 162 case errcode.ErrorCodeUnauthorized, errcode.ErrorCodeUnsupported, errcode.ErrorCodeDenied, errcode.ErrorCodeTooManyRequests, v2.ErrorCodeNameUnknown: 163 return xfer.DoNotRetry{Err: err} 164 } 165 case *url.Error: 166 switch v.Err { 167 case auth.ErrNoBasicAuthCredentials, auth.ErrNoToken: 168 return xfer.DoNotRetry{Err: v.Err} 169 } 170 return retryOnError(v.Err) 171 case *client.UnexpectedHTTPResponseError, unsupportedMediaTypeError: 172 return xfer.DoNotRetry{Err: err} 173 case error: 174 if err == distribution.ErrBlobUnknown { 175 return xfer.DoNotRetry{Err: err} 176 } 177 if strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error())) { 178 return xfer.DoNotRetry{Err: err} 179 } 180 } 181 // let's be nice and fallback if the error is a completely 182 // unexpected one. 183 // If new errors have to be handled in some way, please 184 // add them to the switch above. 185 return err 186 } 187 188 type invalidManifestClassError struct { 189 mediaType string 190 class string 191 } 192 193 func (e invalidManifestClassError) Error() string { 194 return fmt.Sprintf("Encountered remote %q(%s) when fetching", e.mediaType, e.class) 195 } 196 197 func (e invalidManifestClassError) InvalidParameter() {} 198 199 type invalidManifestFormatError struct{} 200 201 func (invalidManifestFormatError) Error() string { 202 return "unsupported manifest format" 203 } 204 205 func (invalidManifestFormatError) InvalidParameter() {} 206 207 type reservedNameError string 208 209 func (e reservedNameError) Error() string { 210 return "'" + string(e) + "' is a reserved name" 211 } 212 213 func (e reservedNameError) Forbidden() {}