github.com/reds/docker@v1.11.2-rc1/distribution/errors.go (about) 1 package distribution 2 3 import ( 4 "net/url" 5 "strings" 6 "syscall" 7 8 "github.com/docker/distribution/registry/api/errcode" 9 "github.com/docker/distribution/registry/api/v2" 10 "github.com/docker/distribution/registry/client" 11 "github.com/docker/distribution/registry/client/auth" 12 "github.com/docker/docker/distribution/xfer" 13 ) 14 15 // ErrNoSupport is an error type used for errors indicating that an operation 16 // is not supported. It encapsulates a more specific error. 17 type ErrNoSupport struct{ Err error } 18 19 func (e ErrNoSupport) Error() string { 20 if e.Err == nil { 21 return "not supported" 22 } 23 return e.Err.Error() 24 } 25 26 // fallbackError wraps an error that can possibly allow fallback to a different 27 // endpoint. 28 type fallbackError struct { 29 // err is the error being wrapped. 30 err error 31 // confirmedV2 is set to true if it was confirmed that the registry 32 // supports the v2 protocol. This is used to limit fallbacks to the v1 33 // protocol. 34 confirmedV2 bool 35 // transportOK is set to true if we managed to speak HTTP with the 36 // registry. This confirms that we're using appropriate TLS settings 37 // (or lack of TLS). 38 transportOK bool 39 } 40 41 // Error renders the FallbackError as a string. 42 func (f fallbackError) Error() string { 43 return f.err.Error() 44 } 45 46 // shouldV2Fallback returns true if this error is a reason to fall back to v1. 47 func shouldV2Fallback(err errcode.Error) bool { 48 switch err.Code { 49 case errcode.ErrorCodeUnauthorized, v2.ErrorCodeManifestUnknown, v2.ErrorCodeNameUnknown: 50 return true 51 } 52 return false 53 } 54 55 // continueOnError returns true if we should fallback to the next endpoint 56 // as a result of this error. 57 func continueOnError(err error) bool { 58 switch v := err.(type) { 59 case errcode.Errors: 60 if len(v) == 0 { 61 return true 62 } 63 return continueOnError(v[0]) 64 case ErrNoSupport: 65 return continueOnError(v.Err) 66 case errcode.Error: 67 return shouldV2Fallback(v) 68 case *client.UnexpectedHTTPResponseError: 69 return true 70 case ImageConfigPullError: 71 return false 72 case error: 73 return !strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error())) 74 } 75 // let's be nice and fallback if the error is a completely 76 // unexpected one. 77 // If new errors have to be handled in some way, please 78 // add them to the switch above. 79 return true 80 } 81 82 // retryOnError wraps the error in xfer.DoNotRetry if we should not retry the 83 // operation after this error. 84 func retryOnError(err error) error { 85 switch v := err.(type) { 86 case errcode.Errors: 87 if len(v) != 0 { 88 return retryOnError(v[0]) 89 } 90 case errcode.Error: 91 switch v.Code { 92 case errcode.ErrorCodeUnauthorized, errcode.ErrorCodeUnsupported, errcode.ErrorCodeDenied: 93 return xfer.DoNotRetry{Err: err} 94 } 95 case *url.Error: 96 switch v.Err { 97 case auth.ErrNoBasicAuthCredentials, auth.ErrNoToken: 98 return xfer.DoNotRetry{Err: v.Err} 99 } 100 return retryOnError(v.Err) 101 case *client.UnexpectedHTTPResponseError: 102 return xfer.DoNotRetry{Err: err} 103 case error: 104 if strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error())) { 105 return xfer.DoNotRetry{Err: err} 106 } 107 } 108 // let's be nice and fallback if the error is a completely 109 // unexpected one. 110 // If new errors have to be handled in some way, please 111 // add them to the switch above. 112 return err 113 }