github.com/DaoCloud/dao@v0.0.0-20161212064103-c3dbfd13ee36/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.Cause().Error() 44 } 45 46 func (f fallbackError) Cause() error { 47 return f.err 48 } 49 50 // shouldV2Fallback returns true if this error is a reason to fall back to v1. 51 func shouldV2Fallback(err errcode.Error) bool { 52 switch err.Code { 53 case errcode.ErrorCodeUnauthorized, v2.ErrorCodeManifestUnknown, v2.ErrorCodeNameUnknown: 54 return true 55 } 56 return false 57 } 58 59 // continueOnError returns true if we should fallback to the next endpoint 60 // as a result of this error. 61 func continueOnError(err error) bool { 62 switch v := err.(type) { 63 case errcode.Errors: 64 if len(v) == 0 { 65 return true 66 } 67 return continueOnError(v[0]) 68 case ErrNoSupport: 69 return continueOnError(v.Err) 70 case errcode.Error: 71 return shouldV2Fallback(v) 72 case *client.UnexpectedHTTPResponseError: 73 return true 74 case ImageConfigPullError: 75 return false 76 case error: 77 return !strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error())) 78 } 79 // let's be nice and fallback if the error is a completely 80 // unexpected one. 81 // If new errors have to be handled in some way, please 82 // add them to the switch above. 83 return true 84 } 85 86 // retryOnError wraps the error in xfer.DoNotRetry if we should not retry the 87 // operation after this error. 88 func retryOnError(err error) error { 89 switch v := err.(type) { 90 case errcode.Errors: 91 if len(v) != 0 { 92 return retryOnError(v[0]) 93 } 94 case errcode.Error: 95 switch v.Code { 96 case errcode.ErrorCodeUnauthorized, errcode.ErrorCodeUnsupported, errcode.ErrorCodeDenied, errcode.ErrorCodeTooManyRequests, v2.ErrorCodeNameUnknown: 97 return xfer.DoNotRetry{Err: err} 98 } 99 case *url.Error: 100 switch v.Err { 101 case auth.ErrNoBasicAuthCredentials, auth.ErrNoToken: 102 return xfer.DoNotRetry{Err: v.Err} 103 } 104 return retryOnError(v.Err) 105 case *client.UnexpectedHTTPResponseError: 106 return xfer.DoNotRetry{Err: err} 107 case error: 108 if strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error())) { 109 return xfer.DoNotRetry{Err: err} 110 } 111 } 112 // let's be nice and fallback if the error is a completely 113 // unexpected one. 114 // If new errors have to be handled in some way, please 115 // add them to the switch above. 116 return err 117 }