Add a new generic error that can indicate a server response was underspecified

Allows clients to distinguish between a server that returns us an error we
recognize, and errors that are generic HTTP (due to an intervening proxy)
This commit is contained in:
Clayton Coleman 2015-04-01 23:18:26 -04:00
parent 412a836bf7
commit 1233843a1d
2 changed files with 71 additions and 0 deletions

View File

@ -19,6 +19,7 @@ package errors
import (
"fmt"
"net/http"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
@ -239,6 +240,72 @@ func NewTimeoutError(message string, retryAfterSeconds int) error {
}}
}
// NewGenericServerResponse returns a new error for server responses that are not in a recognizable form.
func NewGenericServerResponse(code int, verb, kind, name, serverMessage string, retryAfterSeconds int) error {
reason := api.StatusReasonUnknown
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" {
reason = api.StatusReasonAlreadyExists
} else {
reason = api.StatusReasonConflict
}
message = "the server reported a conflict"
case http.StatusNotFound:
reason = api.StatusReasonNotFound
message = "the server could not find the requested resource"
case http.StatusBadRequest:
reason = api.StatusReasonBadRequest
message = "the server rejected our request for an unknown reason"
case http.StatusUnauthorized:
reason = api.StatusReasonUnauthorized
message = "the server has asked for the client to provide credentials"
case http.StatusForbidden:
reason = api.StatusReasonForbidden
message = "the server does not allow access to the requested resource"
case StatusUnprocessableEntity:
reason = api.StatusReasonInvalid
message = "the server rejected our request due to an error in our request"
case StatusServerTimeout:
reason = api.StatusReasonServerTimeout
message = "the server cannot complete the requested operation at this time, try again later"
case StatusTooManyRequests:
reason = api.StatusReasonTimeout
message = "the server has received too many requests and has asked us to try again later"
default:
if code >= 500 {
reason = api.StatusReasonInternalError
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)
}
return &StatusError{api.Status{
Status: api.StatusFailure,
Code: code,
Reason: reason,
Details: &api.StatusDetails{
Kind: kind,
ID: name,
Causes: []api.StatusCause{
{
Type: api.CauseTypeUnexpectedServerResponse,
Message: serverMessage,
},
},
RetryAfterSeconds: retryAfterSeconds,
},
Message: message,
}}
}
// IsNotFound returns true if the specified error was created by NewNotFoundErr.
func IsNotFound(err error) bool {
return reasonForError(err) == api.StatusReasonNotFound

View File

@ -1431,6 +1431,10 @@ const (
// CauseTypeFieldValueNotSupported is used to report valid (as per formatting rules)
// values that can not be handled (e.g. an enumerated string).
CauseTypeFieldValueNotSupported CauseType = "FieldValueNotSupported"
// CauseTypeUnexpectedServerResponse is used to report when the server responded to the client
// without the expected return type. The presence of this cause indicates the error may be
// due to an intervening proxy or the server software malfunctioning.
CauseTypeUnexpectedServerResponse CauseType = "UnexpectedServerResponse"
)
// ObjectReference contains enough information to let you inspect or modify the referred object.