github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/distribution/errors.go (about) 1 package distribution 2 3 import ( 4 "net/url" 5 "strings" 6 "syscall" 7 8 "github.com/Sirupsen/logrus" 9 "github.com/docker/distribution" 10 "github.com/docker/distribution/registry/api/errcode" 11 "github.com/docker/distribution/registry/api/v2" 12 "github.com/docker/distribution/registry/client" 13 "github.com/docker/distribution/registry/client/auth" 14 "github.com/docker/docker/distribution/xfer" 15 "github.com/docker/docker/reference" 16 "github.com/pkg/errors" 17 ) 18 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 } 22 23 func (e ErrNoSupport) Error() string { 24 if e.Err == nil { 25 return "not supported" 26 } 27 return e.Err.Error() 28 } 29 30 // fallbackError wraps an error that can possibly allow fallback to a different 31 // endpoint. 32 type fallbackError struct { 33 // err is the error being wrapped. 34 err error 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 37 // protocol. 38 confirmedV2 bool 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 41 // (or lack of TLS). 42 transportOK bool 43 } 44 45 // Error renders the FallbackError as a string. 46 func (f fallbackError) Error() string { 47 return f.Cause().Error() 48 } 49 50 func (f fallbackError) Cause() error { 51 return f.err 52 } 53 54 // shouldV2Fallback returns true if this error is a reason to fall back to v1. 55 func shouldV2Fallback(err errcode.Error) bool { 56 switch err.Code { 57 case errcode.ErrorCodeUnauthorized, v2.ErrorCodeManifestUnknown, v2.ErrorCodeNameUnknown: 58 return true 59 } 60 return false 61 } 62 63 func translatePullError(err error, ref reference.Named) error { 64 switch v := err.(type) { 65 case errcode.Errors: 66 if len(v) != 0 { 67 for _, extra := range v[1:] { 68 logrus.Infof("Ignoring extra error returned from registry: %v", extra) 69 } 70 return translatePullError(v[0], ref) 71 } 72 case errcode.Error: 73 var newErr error 74 switch v.Code { 75 case errcode.ErrorCodeDenied: 76 // ErrorCodeDenied is used when access to the repository was denied 77 newErr = errors.Errorf("repository %s not found: does not exist or no read access", ref.Name()) 78 case v2.ErrorCodeManifestUnknown: 79 newErr = errors.Errorf("manifest for %s not found", ref.String()) 80 case v2.ErrorCodeNameUnknown: 81 newErr = errors.Errorf("repository %s not found", ref.Name()) 82 } 83 if newErr != nil { 84 logrus.Infof("Translating %q to %q", err, newErr) 85 return newErr 86 } 87 case xfer.DoNotRetry: 88 return translatePullError(v.Err, ref) 89 } 90 91 return err 92 } 93 94 // continueOnError returns true if we should fallback to the next endpoint 95 // as a result of this error. 96 func continueOnError(err error) bool { 97 switch v := err.(type) { 98 case errcode.Errors: 99 if len(v) == 0 { 100 return true 101 } 102 return continueOnError(v[0]) 103 case ErrNoSupport: 104 return continueOnError(v.Err) 105 case errcode.Error: 106 return shouldV2Fallback(v) 107 case *client.UnexpectedHTTPResponseError: 108 return true 109 case ImageConfigPullError: 110 return false 111 case error: 112 return !strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error())) 113 } 114 // let's be nice and fallback if the error is a completely 115 // unexpected one. 116 // If new errors have to be handled in some way, please 117 // add them to the switch above. 118 return true 119 } 120 121 // retryOnError wraps the error in xfer.DoNotRetry if we should not retry the 122 // operation after this error. 123 func retryOnError(err error) error { 124 switch v := err.(type) { 125 case errcode.Errors: 126 if len(v) != 0 { 127 return retryOnError(v[0]) 128 } 129 case errcode.Error: 130 switch v.Code { 131 case errcode.ErrorCodeUnauthorized, errcode.ErrorCodeUnsupported, errcode.ErrorCodeDenied, errcode.ErrorCodeTooManyRequests, v2.ErrorCodeNameUnknown: 132 return xfer.DoNotRetry{Err: err} 133 } 134 case *url.Error: 135 switch v.Err { 136 case auth.ErrNoBasicAuthCredentials, auth.ErrNoToken: 137 return xfer.DoNotRetry{Err: v.Err} 138 } 139 return retryOnError(v.Err) 140 case *client.UnexpectedHTTPResponseError: 141 return xfer.DoNotRetry{Err: err} 142 case error: 143 if err == distribution.ErrBlobUnknown { 144 return xfer.DoNotRetry{Err: err} 145 } 146 if strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error())) { 147 return xfer.DoNotRetry{Err: err} 148 } 149 } 150 // let's be nice and fallback if the error is a completely 151 // unexpected one. 152 // If new errors have to be handled in some way, please 153 // add them to the switch above. 154 return err 155 }