2014-09-03 21:16:00 +00:00
|
|
|
/*
|
2015-05-01 16:19:44 +00:00
|
|
|
Copyright 2014 The Kubernetes Authors All rights reserved.
|
2014-09-03 21:16:00 +00:00
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package errors
|
|
|
|
|
|
|
|
import (
|
2015-04-02 03:20:09 +00:00
|
|
|
"encoding/json"
|
2014-09-03 21:16:00 +00:00
|
|
|
"fmt"
|
|
|
|
"net/http"
|
2015-04-02 03:18:26 +00:00
|
|
|
"strings"
|
2014-09-03 21:16:00 +00:00
|
|
|
|
2015-09-09 21:59:11 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/runtime"
|
2015-10-14 05:18:37 +00:00
|
|
|
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/util/fielderrors"
|
2014-09-03 21:16:00 +00:00
|
|
|
)
|
|
|
|
|
2015-01-24 01:17:11 +00:00
|
|
|
// HTTP Status codes not in the golang http package.
|
|
|
|
const (
|
|
|
|
StatusUnprocessableEntity = 422
|
|
|
|
StatusTooManyRequests = 429
|
2015-02-09 14:47:13 +00:00
|
|
|
// HTTP recommendations are for servers to define 5xx error codes
|
2015-02-12 17:24:34 +00:00
|
|
|
// for scenarios not covered by behavior. In this case, ServerTimeout
|
2015-08-08 21:29:57 +00:00
|
|
|
// is an indication that a transient server error has occurred and the
|
2015-02-09 14:47:13 +00:00
|
|
|
// client *should* retry, with an optional Retry-After header to specify
|
|
|
|
// the back off window.
|
2015-02-12 17:24:34 +00:00
|
|
|
StatusServerTimeout = 504
|
2015-01-24 01:17:11 +00:00
|
|
|
)
|
|
|
|
|
2014-11-21 00:01:42 +00:00
|
|
|
// StatusError is an error intended for consumption by a REST API server; it can also be
|
|
|
|
// reconstructed by clients from a REST response. Public to allow easy type switches.
|
|
|
|
type StatusError struct {
|
2015-09-09 21:59:11 +00:00
|
|
|
ErrStatus unversioned.Status
|
2014-09-03 21:16:00 +00:00
|
|
|
}
|
|
|
|
|
2014-11-20 22:24:10 +00:00
|
|
|
var _ error = &StatusError{}
|
2014-11-20 22:11:23 +00:00
|
|
|
|
2014-09-03 21:16:00 +00:00
|
|
|
// Error implements the Error interface.
|
2014-11-21 00:01:42 +00:00
|
|
|
func (e *StatusError) Error() string {
|
|
|
|
return e.ErrStatus.Message
|
2014-09-03 21:16:00 +00:00
|
|
|
}
|
|
|
|
|
2014-11-21 00:01:42 +00:00
|
|
|
// Status allows access to e's status without having to know the detailed workings
|
|
|
|
// of StatusError. Used by pkg/apiserver.
|
2015-09-09 21:59:11 +00:00
|
|
|
func (e *StatusError) Status() unversioned.Status {
|
2014-11-21 00:01:42 +00:00
|
|
|
return e.ErrStatus
|
2014-09-03 21:16:00 +00:00
|
|
|
}
|
|
|
|
|
2015-04-02 03:20:09 +00:00
|
|
|
// DebugError reports extended info about the error to debug output.
|
|
|
|
func (e *StatusError) DebugError() (string, []interface{}) {
|
|
|
|
if out, err := json.MarshalIndent(e.ErrStatus, "", " "); err == nil {
|
|
|
|
return "server response object: %s", []interface{}{string(out)}
|
|
|
|
}
|
|
|
|
return "server response object: %#v", []interface{}{e.ErrStatus}
|
|
|
|
}
|
|
|
|
|
2014-11-21 00:01:42 +00:00
|
|
|
// UnexpectedObjectError can be returned by FromObject if it's passed a non-status object.
|
|
|
|
type UnexpectedObjectError struct {
|
|
|
|
Object runtime.Object
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error returns an error message describing 'u'.
|
|
|
|
func (u *UnexpectedObjectError) Error() string {
|
|
|
|
return fmt.Sprintf("unexpected object: %v", u.Object)
|
|
|
|
}
|
|
|
|
|
2015-09-09 21:59:11 +00:00
|
|
|
// FromObject generates an StatusError from an unversioned.Status, if that is the type of obj; otherwise,
|
2014-11-21 00:01:42 +00:00
|
|
|
// returns an UnexpecteObjectError.
|
2014-09-23 00:37:12 +00:00
|
|
|
func FromObject(obj runtime.Object) error {
|
|
|
|
switch t := obj.(type) {
|
2015-09-09 21:59:11 +00:00
|
|
|
case *unversioned.Status:
|
2014-11-21 00:01:42 +00:00
|
|
|
return &StatusError{*t}
|
2014-09-23 00:37:12 +00:00
|
|
|
}
|
2014-11-21 00:01:42 +00:00
|
|
|
return &UnexpectedObjectError{obj}
|
2014-09-23 00:37:12 +00:00
|
|
|
}
|
|
|
|
|
2014-09-03 21:16:00 +00:00
|
|
|
// NewNotFound returns a new error which indicates that the resource of the kind and the name was not found.
|
|
|
|
func NewNotFound(kind, name string) error {
|
2015-09-09 21:59:11 +00:00
|
|
|
return &StatusError{unversioned.Status{
|
|
|
|
Status: unversioned.StatusFailure,
|
2014-09-03 21:16:00 +00:00
|
|
|
Code: http.StatusNotFound,
|
2015-09-09 21:59:11 +00:00
|
|
|
Reason: unversioned.StatusReasonNotFound,
|
|
|
|
Details: &unversioned.StatusDetails{
|
2014-09-03 21:16:00 +00:00
|
|
|
Kind: kind,
|
2015-06-05 13:45:59 +00:00
|
|
|
Name: name,
|
2014-09-03 21:16:00 +00:00
|
|
|
},
|
|
|
|
Message: fmt.Sprintf("%s %q not found", kind, name),
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewAlreadyExists returns an error indicating the item requested exists by that identifier.
|
|
|
|
func NewAlreadyExists(kind, name string) error {
|
2015-09-09 21:59:11 +00:00
|
|
|
return &StatusError{unversioned.Status{
|
|
|
|
Status: unversioned.StatusFailure,
|
2014-09-03 21:16:00 +00:00
|
|
|
Code: http.StatusConflict,
|
2015-09-09 21:59:11 +00:00
|
|
|
Reason: unversioned.StatusReasonAlreadyExists,
|
|
|
|
Details: &unversioned.StatusDetails{
|
2014-09-03 21:16:00 +00:00
|
|
|
Kind: kind,
|
2015-06-05 13:45:59 +00:00
|
|
|
Name: name,
|
2014-09-03 21:16:00 +00:00
|
|
|
},
|
|
|
|
Message: fmt.Sprintf("%s %q already exists", kind, name),
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2015-03-24 02:56:22 +00:00
|
|
|
// 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"
|
|
|
|
}
|
2015-09-09 21:59:11 +00:00
|
|
|
return &StatusError{unversioned.Status{
|
|
|
|
Status: unversioned.StatusFailure,
|
2015-03-24 02:56:22 +00:00
|
|
|
Code: http.StatusUnauthorized,
|
2015-09-09 21:59:11 +00:00
|
|
|
Reason: unversioned.StatusReasonUnauthorized,
|
2015-03-24 02:56:22 +00:00
|
|
|
Message: message,
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2015-01-07 19:33:21 +00:00
|
|
|
// NewForbidden returns an error indicating the requested action was forbidden
|
|
|
|
func NewForbidden(kind, name string, err error) error {
|
2015-09-09 21:59:11 +00:00
|
|
|
return &StatusError{unversioned.Status{
|
|
|
|
Status: unversioned.StatusFailure,
|
2015-01-07 19:33:21 +00:00
|
|
|
Code: http.StatusForbidden,
|
2015-09-09 21:59:11 +00:00
|
|
|
Reason: unversioned.StatusReasonForbidden,
|
|
|
|
Details: &unversioned.StatusDetails{
|
2015-01-07 19:33:21 +00:00
|
|
|
Kind: kind,
|
2015-06-05 13:45:59 +00:00
|
|
|
Name: name,
|
2015-01-07 19:33:21 +00:00
|
|
|
},
|
2015-01-15 16:22:15 +00:00
|
|
|
Message: fmt.Sprintf("%s %q is forbidden: %v", kind, name, err),
|
2015-01-07 19:33:21 +00:00
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2014-09-03 21:16:00 +00:00
|
|
|
// NewConflict returns an error indicating the item can't be updated as provided.
|
|
|
|
func NewConflict(kind, name string, err error) error {
|
2015-09-09 21:59:11 +00:00
|
|
|
return &StatusError{unversioned.Status{
|
|
|
|
Status: unversioned.StatusFailure,
|
2014-09-03 21:16:00 +00:00
|
|
|
Code: http.StatusConflict,
|
2015-09-09 21:59:11 +00:00
|
|
|
Reason: unversioned.StatusReasonConflict,
|
|
|
|
Details: &unversioned.StatusDetails{
|
2014-09-03 21:16:00 +00:00
|
|
|
Kind: kind,
|
2015-06-05 13:45:59 +00:00
|
|
|
Name: name,
|
2014-09-03 21:16:00 +00:00
|
|
|
},
|
2014-11-20 10:00:36 +00:00
|
|
|
Message: fmt.Sprintf("%s %q cannot be updated: %v", kind, name, err),
|
2014-09-03 21:16:00 +00:00
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewInvalid returns an error indicating the item is invalid and cannot be processed.
|
2015-03-22 21:40:47 +00:00
|
|
|
func NewInvalid(kind, name string, errs fielderrors.ValidationErrorList) error {
|
2015-09-09 21:59:11 +00:00
|
|
|
causes := make([]unversioned.StatusCause, 0, len(errs))
|
2014-09-03 21:16:00 +00:00
|
|
|
for i := range errs {
|
2015-03-22 21:40:47 +00:00
|
|
|
if err, ok := errs[i].(*fielderrors.ValidationError); ok {
|
2015-09-09 21:59:11 +00:00
|
|
|
causes = append(causes, unversioned.StatusCause{
|
|
|
|
Type: unversioned.CauseType(err.Type),
|
2015-06-30 06:59:33 +00:00
|
|
|
Message: err.ErrorBody(),
|
2014-09-03 21:16:00 +00:00
|
|
|
Field: err.Field,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2015-09-09 21:59:11 +00:00
|
|
|
return &StatusError{unversioned.Status{
|
|
|
|
Status: unversioned.StatusFailure,
|
2015-01-24 01:17:11 +00:00
|
|
|
Code: StatusUnprocessableEntity, // RFC 4918: StatusUnprocessableEntity
|
2015-09-09 21:59:11 +00:00
|
|
|
Reason: unversioned.StatusReasonInvalid,
|
|
|
|
Details: &unversioned.StatusDetails{
|
2014-09-03 21:16:00 +00:00
|
|
|
Kind: kind,
|
2015-06-05 13:45:59 +00:00
|
|
|
Name: name,
|
2014-09-03 21:16:00 +00:00
|
|
|
Causes: causes,
|
|
|
|
},
|
2015-10-14 05:18:37 +00:00
|
|
|
Message: fmt.Sprintf("%s %q is invalid: %v", kind, name, utilerrors.NewAggregate(errs)),
|
2014-09-03 21:16:00 +00:00
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2014-11-02 20:30:25 +00:00
|
|
|
// NewBadRequest creates an error that indicates that the request is invalid and can not be processed.
|
|
|
|
func NewBadRequest(reason string) error {
|
2015-09-09 21:59:11 +00:00
|
|
|
return &StatusError{unversioned.Status{
|
|
|
|
Status: unversioned.StatusFailure,
|
2015-01-25 17:24:04 +00:00
|
|
|
Code: http.StatusBadRequest,
|
2015-09-09 21:59:11 +00:00
|
|
|
Reason: unversioned.StatusReasonBadRequest,
|
2015-01-25 17:24:04 +00:00
|
|
|
Message: reason,
|
2014-11-20 22:11:23 +00:00
|
|
|
}}
|
2014-11-02 20:30:25 +00:00
|
|
|
}
|
|
|
|
|
2015-07-10 20:25:43 +00:00
|
|
|
// NewServiceUnavailable creates an error that indicates that the requested service is unavailable.
|
|
|
|
func NewServiceUnavailable(reason string) error {
|
2015-09-09 21:59:11 +00:00
|
|
|
return &StatusError{unversioned.Status{
|
|
|
|
Status: unversioned.StatusFailure,
|
2015-07-10 20:25:43 +00:00
|
|
|
Code: http.StatusServiceUnavailable,
|
2015-09-09 21:59:11 +00:00
|
|
|
Reason: unversioned.StatusReasonServiceUnavailable,
|
2015-07-10 20:25:43 +00:00
|
|
|
Message: reason,
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2015-01-12 05:12:49 +00:00
|
|
|
// NewMethodNotSupported returns an error indicating the requested action is not supported on this kind.
|
|
|
|
func NewMethodNotSupported(kind, action string) error {
|
2015-09-09 21:59:11 +00:00
|
|
|
return &StatusError{unversioned.Status{
|
|
|
|
Status: unversioned.StatusFailure,
|
2015-01-12 05:12:49 +00:00
|
|
|
Code: http.StatusMethodNotAllowed,
|
2015-09-09 21:59:11 +00:00
|
|
|
Reason: unversioned.StatusReasonMethodNotAllowed,
|
|
|
|
Details: &unversioned.StatusDetails{
|
2015-01-12 05:12:49 +00:00
|
|
|
Kind: kind,
|
|
|
|
},
|
|
|
|
Message: fmt.Sprintf("%s is not supported on resources of kind %q", action, kind),
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2015-02-12 17:24:34 +00:00
|
|
|
// NewServerTimeout returns an error indicating the requested action could not be completed due to a
|
2015-01-29 04:11:29 +00:00
|
|
|
// transient error, and the client should try again.
|
2015-03-26 21:24:17 +00:00
|
|
|
func NewServerTimeout(kind, operation string, retryAfterSeconds int) error {
|
2015-09-09 21:59:11 +00:00
|
|
|
return &StatusError{unversioned.Status{
|
|
|
|
Status: unversioned.StatusFailure,
|
2015-01-29 04:11:29 +00:00
|
|
|
Code: http.StatusInternalServerError,
|
2015-09-09 21:59:11 +00:00
|
|
|
Reason: unversioned.StatusReasonServerTimeout,
|
|
|
|
Details: &unversioned.StatusDetails{
|
2015-03-26 21:24:17 +00:00
|
|
|
Kind: kind,
|
2015-06-05 13:45:59 +00:00
|
|
|
Name: operation,
|
2015-03-26 21:24:17 +00:00
|
|
|
RetryAfterSeconds: retryAfterSeconds,
|
2015-01-29 04:11:29 +00:00
|
|
|
},
|
|
|
|
Message: fmt.Sprintf("The %s operation against %s could not be completed at this time, please try again.", operation, kind),
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2014-10-31 06:03:52 +00:00
|
|
|
// NewInternalError returns an error indicating the item is invalid and cannot be processed.
|
|
|
|
func NewInternalError(err error) error {
|
2015-09-09 21:59:11 +00:00
|
|
|
return &StatusError{unversioned.Status{
|
|
|
|
Status: unversioned.StatusFailure,
|
2014-11-11 07:11:45 +00:00
|
|
|
Code: http.StatusInternalServerError,
|
2015-09-09 21:59:11 +00:00
|
|
|
Reason: unversioned.StatusReasonInternalError,
|
|
|
|
Details: &unversioned.StatusDetails{
|
|
|
|
Causes: []unversioned.StatusCause{{Message: err.Error()}},
|
2014-10-31 06:03:52 +00:00
|
|
|
},
|
|
|
|
Message: fmt.Sprintf("Internal error occurred: %v", err),
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2015-02-09 14:47:13 +00:00
|
|
|
// NewTimeoutError returns an error indicating that a timeout occurred before the request
|
|
|
|
// could be completed. Clients may retry, but the operation may still complete.
|
2015-03-26 21:24:17 +00:00
|
|
|
func NewTimeoutError(message string, retryAfterSeconds int) error {
|
2015-09-09 21:59:11 +00:00
|
|
|
return &StatusError{unversioned.Status{
|
|
|
|
Status: unversioned.StatusFailure,
|
2015-02-12 17:24:34 +00:00
|
|
|
Code: StatusServerTimeout,
|
2015-09-09 21:59:11 +00:00
|
|
|
Reason: unversioned.StatusReasonTimeout,
|
2015-02-09 14:47:13 +00:00
|
|
|
Message: fmt.Sprintf("Timeout: %s", message),
|
2015-09-09 21:59:11 +00:00
|
|
|
Details: &unversioned.StatusDetails{
|
2015-03-26 21:24:17 +00:00
|
|
|
RetryAfterSeconds: retryAfterSeconds,
|
2015-03-24 02:56:22 +00:00
|
|
|
},
|
2015-02-09 14:47:13 +00:00
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2015-04-02 03:18:26 +00:00
|
|
|
// NewGenericServerResponse returns a new error for server responses that are not in a recognizable form.
|
2015-04-15 23:33:35 +00:00
|
|
|
func NewGenericServerResponse(code int, verb, kind, name, serverMessage string, retryAfterSeconds int, isUnexpectedResponse bool) error {
|
2015-09-09 21:59:11 +00:00
|
|
|
reason := unversioned.StatusReasonUnknown
|
2015-04-02 03:18:26 +00:00
|
|
|
message := fmt.Sprintf("the server responded with the status code %d but did not return more information", code)
|
|
|
|
switch code {
|
|
|
|
case http.StatusConflict:
|
|
|
|
if verb == "POST" {
|
2015-09-09 21:59:11 +00:00
|
|
|
reason = unversioned.StatusReasonAlreadyExists
|
2015-04-02 03:18:26 +00:00
|
|
|
} else {
|
2015-09-09 21:59:11 +00:00
|
|
|
reason = unversioned.StatusReasonConflict
|
2015-04-02 03:18:26 +00:00
|
|
|
}
|
|
|
|
message = "the server reported a conflict"
|
|
|
|
case http.StatusNotFound:
|
2015-09-09 21:59:11 +00:00
|
|
|
reason = unversioned.StatusReasonNotFound
|
2015-04-02 03:18:26 +00:00
|
|
|
message = "the server could not find the requested resource"
|
|
|
|
case http.StatusBadRequest:
|
2015-09-09 21:59:11 +00:00
|
|
|
reason = unversioned.StatusReasonBadRequest
|
2015-04-02 03:18:26 +00:00
|
|
|
message = "the server rejected our request for an unknown reason"
|
|
|
|
case http.StatusUnauthorized:
|
2015-09-09 21:59:11 +00:00
|
|
|
reason = unversioned.StatusReasonUnauthorized
|
2015-04-02 03:18:26 +00:00
|
|
|
message = "the server has asked for the client to provide credentials"
|
|
|
|
case http.StatusForbidden:
|
2015-09-09 21:59:11 +00:00
|
|
|
reason = unversioned.StatusReasonForbidden
|
2015-04-02 03:18:26 +00:00
|
|
|
message = "the server does not allow access to the requested resource"
|
2015-04-15 15:26:56 +00:00
|
|
|
case http.StatusMethodNotAllowed:
|
2015-09-09 21:59:11 +00:00
|
|
|
reason = unversioned.StatusReasonMethodNotAllowed
|
2015-04-15 15:26:56 +00:00
|
|
|
message = "the server does not allow this method on the requested resource"
|
2015-04-02 03:18:26 +00:00
|
|
|
case StatusUnprocessableEntity:
|
2015-09-09 21:59:11 +00:00
|
|
|
reason = unversioned.StatusReasonInvalid
|
2015-04-02 03:18:26 +00:00
|
|
|
message = "the server rejected our request due to an error in our request"
|
|
|
|
case StatusServerTimeout:
|
2015-09-09 21:59:11 +00:00
|
|
|
reason = unversioned.StatusReasonServerTimeout
|
2015-04-02 03:18:26 +00:00
|
|
|
message = "the server cannot complete the requested operation at this time, try again later"
|
|
|
|
case StatusTooManyRequests:
|
2015-09-09 21:59:11 +00:00
|
|
|
reason = unversioned.StatusReasonTimeout
|
2015-04-02 03:18:26 +00:00
|
|
|
message = "the server has received too many requests and has asked us to try again later"
|
|
|
|
default:
|
|
|
|
if code >= 500 {
|
2015-09-09 21:59:11 +00:00
|
|
|
reason = unversioned.StatusReasonInternalError
|
2015-04-02 03:18:26 +00:00
|
|
|
message = "an error on the server has prevented the request from succeeding"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch {
|
|
|
|
case len(kind) > 0 && len(name) > 0:
|
|
|
|
message = fmt.Sprintf("%s (%s %s %s)", message, strings.ToLower(verb), kind, name)
|
|
|
|
case len(kind) > 0:
|
|
|
|
message = fmt.Sprintf("%s (%s %s)", message, strings.ToLower(verb), kind)
|
|
|
|
}
|
2015-09-09 21:59:11 +00:00
|
|
|
var causes []unversioned.StatusCause
|
2015-04-15 23:33:35 +00:00
|
|
|
if isUnexpectedResponse {
|
2015-09-09 21:59:11 +00:00
|
|
|
causes = []unversioned.StatusCause{
|
2015-04-15 23:33:35 +00:00
|
|
|
{
|
2015-09-09 21:59:11 +00:00
|
|
|
Type: unversioned.CauseTypeUnexpectedServerResponse,
|
2015-04-15 23:33:35 +00:00
|
|
|
Message: serverMessage,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
causes = nil
|
|
|
|
}
|
2015-09-09 21:59:11 +00:00
|
|
|
return &StatusError{unversioned.Status{
|
|
|
|
Status: unversioned.StatusFailure,
|
2015-04-02 03:18:26 +00:00
|
|
|
Code: code,
|
|
|
|
Reason: reason,
|
2015-09-09 21:59:11 +00:00
|
|
|
Details: &unversioned.StatusDetails{
|
2015-04-02 03:18:26 +00:00
|
|
|
Kind: kind,
|
2015-06-05 13:45:59 +00:00
|
|
|
Name: name,
|
2015-04-02 03:18:26 +00:00
|
|
|
|
2015-04-15 23:33:35 +00:00
|
|
|
Causes: causes,
|
2015-04-02 03:18:26 +00:00
|
|
|
RetryAfterSeconds: retryAfterSeconds,
|
|
|
|
},
|
|
|
|
Message: message,
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2015-06-25 12:13:16 +00:00
|
|
|
// IsNotFound returns true if the specified error was created by NewNotFound.
|
2014-09-03 21:16:00 +00:00
|
|
|
func IsNotFound(err error) bool {
|
2015-09-09 21:59:11 +00:00
|
|
|
return reasonForError(err) == unversioned.StatusReasonNotFound
|
2014-09-03 21:16:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// IsAlreadyExists determines if the err is an error which indicates that a specified resource already exists.
|
|
|
|
func IsAlreadyExists(err error) bool {
|
2015-09-09 21:59:11 +00:00
|
|
|
return reasonForError(err) == unversioned.StatusReasonAlreadyExists
|
2014-09-03 21:16:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// IsConflict determines if the err is an error which indicates the provided update conflicts.
|
|
|
|
func IsConflict(err error) bool {
|
2015-09-09 21:59:11 +00:00
|
|
|
return reasonForError(err) == unversioned.StatusReasonConflict
|
2014-09-03 21:16:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// IsInvalid determines if the err is an error which indicates the provided resource is not valid.
|
|
|
|
func IsInvalid(err error) bool {
|
2015-09-09 21:59:11 +00:00
|
|
|
return reasonForError(err) == unversioned.StatusReasonInvalid
|
2014-09-03 21:16:00 +00:00
|
|
|
}
|
|
|
|
|
2015-01-12 05:12:49 +00:00
|
|
|
// IsMethodNotSupported determines if the err is an error which indicates the provided action could not
|
|
|
|
// be performed because it is not supported by the server.
|
|
|
|
func IsMethodNotSupported(err error) bool {
|
2015-09-09 21:59:11 +00:00
|
|
|
return reasonForError(err) == unversioned.StatusReasonMethodNotAllowed
|
2015-01-12 05:12:49 +00:00
|
|
|
}
|
|
|
|
|
2014-11-02 20:30:25 +00:00
|
|
|
// IsBadRequest determines if err is an error which indicates that the request is invalid.
|
|
|
|
func IsBadRequest(err error) bool {
|
2015-09-09 21:59:11 +00:00
|
|
|
return reasonForError(err) == unversioned.StatusReasonBadRequest
|
2014-11-02 20:30:25 +00:00
|
|
|
}
|
|
|
|
|
2015-03-24 02:56:22 +00:00
|
|
|
// 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 {
|
2015-09-09 21:59:11 +00:00
|
|
|
return reasonForError(err) == unversioned.StatusReasonUnauthorized
|
2015-03-24 02:56:22 +00:00
|
|
|
}
|
|
|
|
|
2015-01-29 04:11:29 +00:00
|
|
|
// 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 {
|
2015-09-09 21:59:11 +00:00
|
|
|
return reasonForError(err) == unversioned.StatusReasonForbidden
|
2015-01-29 04:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-02-12 17:24:34 +00:00
|
|
|
// IsServerTimeout determines if err is an error which indicates that the request needs to be retried
|
2015-01-29 04:11:29 +00:00
|
|
|
// by the client.
|
2015-02-12 17:24:34 +00:00
|
|
|
func IsServerTimeout(err error) bool {
|
2015-09-09 21:59:11 +00:00
|
|
|
return reasonForError(err) == unversioned.StatusReasonServerTimeout
|
2015-01-29 04:11:29 +00:00
|
|
|
}
|
|
|
|
|
2015-04-02 03:20:09 +00:00
|
|
|
// IsUnexpectedServerError returns true if the server response was not in the expected API format,
|
|
|
|
// and may be the result of another HTTP actor.
|
|
|
|
func IsUnexpectedServerError(err error) bool {
|
|
|
|
switch t := err.(type) {
|
|
|
|
case *StatusError:
|
|
|
|
if d := t.Status().Details; d != nil {
|
|
|
|
for _, cause := range d.Causes {
|
2015-09-09 21:59:11 +00:00
|
|
|
if cause.Type == unversioned.CauseTypeUnexpectedServerResponse {
|
2015-04-02 03:20:09 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
2015-03-04 00:24:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// IsUnexpectedObjectError determines if err is due to an unexpected object from the master.
|
|
|
|
func IsUnexpectedObjectError(err error) bool {
|
|
|
|
_, ok := err.(*UnexpectedObjectError)
|
2015-04-02 03:20:09 +00:00
|
|
|
return err != nil && ok
|
2015-03-04 00:24:29 +00:00
|
|
|
}
|
|
|
|
|
2015-03-24 02:56:22 +00:00
|
|
|
// 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 {
|
2015-09-09 21:59:11 +00:00
|
|
|
case unversioned.StatusReasonServerTimeout, unversioned.StatusReasonTimeout:
|
2015-03-26 21:24:17 +00:00
|
|
|
return t.Status().Details.RetryAfterSeconds, true
|
2015-03-24 02:56:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0, false
|
|
|
|
}
|
|
|
|
|
2015-09-09 21:59:11 +00:00
|
|
|
func reasonForError(err error) unversioned.StatusReason {
|
2014-09-03 21:16:00 +00:00
|
|
|
switch t := err.(type) {
|
2014-11-21 00:01:42 +00:00
|
|
|
case *StatusError:
|
|
|
|
return t.ErrStatus.Reason
|
2014-09-03 21:16:00 +00:00
|
|
|
}
|
2015-09-09 21:59:11 +00:00
|
|
|
return unversioned.StatusReasonUnknown
|
2014-09-03 21:16:00 +00:00
|
|
|
}
|