mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-07 04:03:20 +00:00
Merge pull request #5831 from smarterclayton/add_more_errors
Add more specific error handling and handle generic errors more effectively
This commit is contained in:
@@ -105,6 +105,21 @@ func NewAlreadyExists(kind, name string) error {
|
||||
}}
|
||||
}
|
||||
|
||||
// NewUnauthorized returns an error indicating the client is not authorized to perform the requested
|
||||
// action.
|
||||
func NewUnauthorized(reason string) error {
|
||||
message := reason
|
||||
if len(message) == 0 {
|
||||
message = "not authorized"
|
||||
}
|
||||
return &StatusError{api.Status{
|
||||
Status: api.StatusFailure,
|
||||
Code: http.StatusUnauthorized,
|
||||
Reason: api.StatusReasonUnauthorized,
|
||||
Message: message,
|
||||
}}
|
||||
}
|
||||
|
||||
// NewForbidden returns an error indicating the requested action was forbidden
|
||||
func NewForbidden(kind, name string, err error) error {
|
||||
return &StatusError{api.Status{
|
||||
@@ -183,14 +198,15 @@ func NewMethodNotSupported(kind, action string) error {
|
||||
|
||||
// NewServerTimeout returns an error indicating the requested action could not be completed due to a
|
||||
// transient error, and the client should try again.
|
||||
func NewServerTimeout(kind, operation string) error {
|
||||
func NewServerTimeout(kind, operation string, retryAfterSeconds int) error {
|
||||
return &StatusError{api.Status{
|
||||
Status: api.StatusFailure,
|
||||
Code: http.StatusInternalServerError,
|
||||
Reason: api.StatusReasonServerTimeout,
|
||||
Details: &api.StatusDetails{
|
||||
Kind: kind,
|
||||
ID: operation,
|
||||
Kind: kind,
|
||||
ID: operation,
|
||||
RetryAfterSeconds: retryAfterSeconds,
|
||||
},
|
||||
Message: fmt.Sprintf("The %s operation against %s could not be completed at this time, please try again.", operation, kind),
|
||||
}}
|
||||
@@ -211,12 +227,15 @@ func NewInternalError(err error) error {
|
||||
|
||||
// NewTimeoutError returns an error indicating that a timeout occurred before the request
|
||||
// could be completed. Clients may retry, but the operation may still complete.
|
||||
func NewTimeoutError(message string) error {
|
||||
func NewTimeoutError(message string, retryAfterSeconds int) error {
|
||||
return &StatusError{api.Status{
|
||||
Status: api.StatusFailure,
|
||||
Code: StatusServerTimeout,
|
||||
Reason: api.StatusReasonTimeout,
|
||||
Message: fmt.Sprintf("Timeout: %s", message),
|
||||
Details: &api.StatusDetails{
|
||||
RetryAfterSeconds: retryAfterSeconds,
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -251,6 +270,12 @@ func IsBadRequest(err error) bool {
|
||||
return reasonForError(err) == api.StatusReasonBadRequest
|
||||
}
|
||||
|
||||
// IsUnauthorized determines if err is an error which indicates that the request is unauthorized and
|
||||
// requires authentication by the user.
|
||||
func IsUnauthorized(err error) bool {
|
||||
return reasonForError(err) == api.StatusReasonUnauthorized
|
||||
}
|
||||
|
||||
// IsForbidden determines if err is an error which indicates that the request is forbidden and cannot
|
||||
// be completed as requested.
|
||||
func IsForbidden(err error) bool {
|
||||
@@ -275,6 +300,21 @@ func IsUnexpectedObjectError(err error) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// SuggestsClientDelay returns true if this error suggests a client delay as well as the
|
||||
// suggested seconds to wait, or false if the error does not imply a wait.
|
||||
func SuggestsClientDelay(err error) (int, bool) {
|
||||
switch t := err.(type) {
|
||||
case *StatusError:
|
||||
if t.Status().Details != nil {
|
||||
switch t.Status().Reason {
|
||||
case api.StatusReasonServerTimeout, api.StatusReasonTimeout:
|
||||
return t.Status().Details.RetryAfterSeconds, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func reasonForError(err error) api.StatusReason {
|
||||
switch t := err.(type) {
|
||||
case *StatusError:
|
||||
|
@@ -69,9 +69,18 @@ func TestErrorNew(t *testing.T) {
|
||||
if !IsForbidden(NewForbidden("test", "2", errors.New("reason"))) {
|
||||
t.Errorf("expected to be %s", api.StatusReasonForbidden)
|
||||
}
|
||||
if !IsServerTimeout(NewServerTimeout("test", "reason")) {
|
||||
if !IsUnauthorized(NewUnauthorized("reason")) {
|
||||
t.Errorf("expected to be %s", api.StatusReasonUnauthorized)
|
||||
}
|
||||
if !IsServerTimeout(NewServerTimeout("test", "reason", 0)) {
|
||||
t.Errorf("expected to be %s", api.StatusReasonServerTimeout)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewServerTimeout("test", "doing something", 10)); time != 10 || !ok {
|
||||
t.Errorf("expected to be %s", api.StatusReasonServerTimeout)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewTimeoutError("test reason", 10)); time != 10 || !ok {
|
||||
t.Errorf("expected to be %s", api.StatusReasonTimeout)
|
||||
}
|
||||
if !IsMethodNotSupported(NewMethodNotSupported("foo", "delete")) {
|
||||
t.Errorf("expected to be %s", api.StatusReasonMethodNotAllowed)
|
||||
}
|
||||
|
@@ -85,7 +85,7 @@ func CheckGeneratedNameError(strategy RESTCreateStrategy, err error, obj runtime
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.NewServerTimeout(kind, "POST")
|
||||
return errors.NewServerTimeout(kind, "POST", 0)
|
||||
}
|
||||
|
||||
// objectMetaAndKind retrieves kind and ObjectMeta from a runtime object, or returns an error.
|
||||
|
@@ -1243,6 +1243,8 @@ type StatusDetails struct {
|
||||
// The Causes array includes more details associated with the StatusReason
|
||||
// failure. Not all StatusReasons may provide detailed causes.
|
||||
Causes []StatusCause `json:"causes,omitempty"`
|
||||
// If specified, the time in seconds before the operation should be retried.
|
||||
RetryAfterSeconds int `json:"retryAfterSeconds,omitempty"`
|
||||
}
|
||||
|
||||
// Values of Status.Status
|
||||
@@ -1263,6 +1265,13 @@ const (
|
||||
// Status code 500.
|
||||
StatusReasonUnknown StatusReason = ""
|
||||
|
||||
// StatusReasonUnauthorized means the server can be reached and understood the request, but requires
|
||||
// the user to present appropriate authorization credentials (identified by the WWW-Authenticate header)
|
||||
// in order for the action to be completed. If the user has specified credentials on the request, the
|
||||
// server considers them insufficient.
|
||||
// Status code 401
|
||||
StatusReasonUnauthorized StatusReason = "Unauthorized"
|
||||
|
||||
// StatusReasonForbidden means the server can be reached and understood the request, but refuses
|
||||
// to take any further action. It is the result of the server being configured to deny access for some reason
|
||||
// to the requested resource by the client.
|
||||
@@ -1319,12 +1328,17 @@ const (
|
||||
// Details (optional):
|
||||
// "kind" string - the kind attribute of the resource being acted on.
|
||||
// "id" string - the operation that is being attempted.
|
||||
// "retryAfterSeconds" int - the number of seconds before the operation should be retried
|
||||
// Status code 500
|
||||
StatusReasonServerTimeout StatusReason = "ServerTimeout"
|
||||
|
||||
// StatusReasonTimeout means that the request could not be completed within the given time.
|
||||
// Clients can get this response only when they specified a timeout param in the request.
|
||||
// The request might succeed with an increased value of timeout param.
|
||||
// Clients can get this response only when they specified a timeout param in the request,
|
||||
// or if the server cannot complete the operation within a reasonable amount of time.
|
||||
// The request might succeed with an increased value of timeout param. The client *should*
|
||||
// wait at least the number of seconds specified by the retryAfterSeconds field.
|
||||
// Details (optional):
|
||||
// "retryAfterSeconds" int - the number of seconds before the operation should be retried
|
||||
// Status code 504
|
||||
StatusReasonTimeout StatusReason = "Timeout"
|
||||
|
||||
|
@@ -1073,6 +1073,8 @@ type StatusDetails struct {
|
||||
// The Causes array includes more details associated with the StatusReason
|
||||
// failure. Not all StatusReasons may provide detailed causes.
|
||||
Causes []StatusCause `json:"causes,omitempty" description:"the Causes array includes more details associated with the StatusReason failure; not all StatusReasons may provide detailed causes"`
|
||||
// If specified, the time in seconds before the operation should be retried.
|
||||
RetryAfterSeconds int `json:"retryAfterSeconds,omitempty" description:"the number of seconds before the client should attempt to retry this operation"`
|
||||
}
|
||||
|
||||
// Values of Status.Status
|
||||
|
@@ -1087,6 +1087,8 @@ type StatusDetails struct {
|
||||
// The Causes array includes more details associated with the StatusReason
|
||||
// failure. Not all StatusReasons may provide detailed causes.
|
||||
Causes []StatusCause `json:"causes,omitempty" description:"the Causes array includes more details associated with the StatusReason failure; not all StatusReasons may provide detailed causes"`
|
||||
// If specified, the time in seconds before the operation should be retried.
|
||||
RetryAfterSeconds int `json:"retryAfterSeconds,omitempty" description:"the number of seconds before the client should attempt to retry this operation"`
|
||||
}
|
||||
|
||||
// Values of Status.Status
|
||||
|
@@ -1229,6 +1229,8 @@ type StatusDetails struct {
|
||||
// The Causes array includes more details associated with the StatusReason
|
||||
// failure. Not all StatusReasons may provide detailed causes.
|
||||
Causes []StatusCause `json:"causes,omitempty" description:"the Causes array includes more details associated with the StatusReason failure; not all StatusReasons may provide detailed causes"`
|
||||
// If specified, the time in seconds before the operation should be retried.
|
||||
RetryAfterSeconds int `json:"retryAfterSeconds,omitempty" description:"the number of seconds before the client should attempt to retry this operation"`
|
||||
}
|
||||
|
||||
// Values of Status.Status
|
||||
|
Reference in New Issue
Block a user