From 1233843a1d0995eaa2c9ef97e55f8d56bc3e666d Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Wed, 1 Apr 2015 23:18:26 -0400 Subject: [PATCH] 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) --- pkg/api/errors/errors.go | 67 ++++++++++++++++++++++++++++++++++++++++ pkg/api/types.go | 4 +++ 2 files changed, 71 insertions(+) diff --git a/pkg/api/errors/errors.go b/pkg/api/errors/errors.go index 5ebabfc33a9..94177d649ee 100644 --- a/pkg/api/errors/errors.go +++ b/pkg/api/errors/errors.go @@ -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 diff --git a/pkg/api/types.go b/pkg/api/types.go index 95aa9274cf1..eed4d82b2df 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -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.