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:
Brian Grant
2015-03-27 14:17:11 -07:00
12 changed files with 294 additions and 50 deletions

View File

@@ -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:

View File

@@ -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)
}

View File

@@ -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.

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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