update StatusDetails to handle Groups

This commit is contained in:
deads2k
2015-12-10 13:32:29 -05:00
parent 5c4479f542
commit 9fda7f1812
75 changed files with 303 additions and 238 deletions

View File

@@ -93,30 +93,32 @@ func FromObject(obj runtime.Object) error {
}
// 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 {
func NewNotFound(qualifiedResource unversioned.GroupResource, name string) error {
return &StatusError{unversioned.Status{
Status: unversioned.StatusFailure,
Code: http.StatusNotFound,
Reason: unversioned.StatusReasonNotFound,
Details: &unversioned.StatusDetails{
Kind: kind,
Name: name,
Group: qualifiedResource.Group,
Kind: qualifiedResource.Resource,
Name: name,
},
Message: fmt.Sprintf("%s %q not found", kind, name),
Message: fmt.Sprintf("%s %q not found", qualifiedResource.String(), name),
}}
}
// NewAlreadyExists returns an error indicating the item requested exists by that identifier.
func NewAlreadyExists(kind, name string) error {
func NewAlreadyExists(qualifiedResource unversioned.GroupResource, name string) error {
return &StatusError{unversioned.Status{
Status: unversioned.StatusFailure,
Code: http.StatusConflict,
Reason: unversioned.StatusReasonAlreadyExists,
Details: &unversioned.StatusDetails{
Kind: kind,
Name: name,
Group: qualifiedResource.Group,
Kind: qualifiedResource.Resource,
Name: name,
},
Message: fmt.Sprintf("%s %q already exists", kind, name),
Message: fmt.Sprintf("%s %q already exists", qualifiedResource.String(), name),
}}
}
@@ -136,30 +138,32 @@ func NewUnauthorized(reason string) error {
}
// NewForbidden returns an error indicating the requested action was forbidden
func NewForbidden(kind, name string, err error) error {
func NewForbidden(qualifiedResource unversioned.GroupResource, name string, err error) error {
return &StatusError{unversioned.Status{
Status: unversioned.StatusFailure,
Code: http.StatusForbidden,
Reason: unversioned.StatusReasonForbidden,
Details: &unversioned.StatusDetails{
Kind: kind,
Name: name,
Group: qualifiedResource.Group,
Kind: qualifiedResource.Resource,
Name: name,
},
Message: fmt.Sprintf("%s %q is forbidden: %v", kind, name, err),
Message: fmt.Sprintf("%s %q is forbidden: %v", qualifiedResource.String(), name, err),
}}
}
// NewConflict returns an error indicating the item can't be updated as provided.
func NewConflict(kind, name string, err error) error {
func NewConflict(qualifiedResource unversioned.GroupResource, name string, err error) error {
return &StatusError{unversioned.Status{
Status: unversioned.StatusFailure,
Code: http.StatusConflict,
Reason: unversioned.StatusReasonConflict,
Details: &unversioned.StatusDetails{
Kind: kind,
Name: name,
Group: qualifiedResource.Group,
Kind: qualifiedResource.Resource,
Name: name,
},
Message: fmt.Sprintf("%s %q cannot be updated: %v", kind, name, err),
Message: fmt.Sprintf("%s %q cannot be updated: %v", qualifiedResource.String(), name, err),
}}
}
@@ -174,7 +178,7 @@ func NewGone(message string) error {
}
// NewInvalid returns an error indicating the item is invalid and cannot be processed.
func NewInvalid(kind, name string, errs field.ErrorList) error {
func NewInvalid(qualifiedKind unversioned.GroupKind, name string, errs field.ErrorList) error {
causes := make([]unversioned.StatusCause, 0, len(errs))
for i := range errs {
err := errs[i]
@@ -189,11 +193,12 @@ func NewInvalid(kind, name string, errs field.ErrorList) error {
Code: StatusUnprocessableEntity, // RFC 4918: StatusUnprocessableEntity
Reason: unversioned.StatusReasonInvalid,
Details: &unversioned.StatusDetails{
Kind: kind,
Group: qualifiedKind.Group,
Kind: qualifiedKind.Kind,
Name: name,
Causes: causes,
},
Message: fmt.Sprintf("%s %q is invalid: %v", kind, name, errs.ToAggregate()),
Message: fmt.Sprintf("%s %q is invalid: %v", qualifiedKind.String(), name, errs.ToAggregate()),
}}
}
@@ -218,34 +223,42 @@ func NewServiceUnavailable(reason string) error {
}
// NewMethodNotSupported returns an error indicating the requested action is not supported on this kind.
func NewMethodNotSupported(kind, action string) error {
func NewMethodNotSupported(qualifiedResource unversioned.GroupResource, action string) error {
return &StatusError{unversioned.Status{
Status: unversioned.StatusFailure,
Code: http.StatusMethodNotAllowed,
Reason: unversioned.StatusReasonMethodNotAllowed,
Details: &unversioned.StatusDetails{
Kind: kind,
Group: qualifiedResource.Group,
Kind: qualifiedResource.Resource,
},
Message: fmt.Sprintf("%s is not supported on resources of kind %q", action, kind),
Message: fmt.Sprintf("%s is not supported on resources of kind %q", action, qualifiedResource.String()),
}}
}
// 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, retryAfterSeconds int) error {
func NewServerTimeout(qualifiedResource unversioned.GroupResource, operation string, retryAfterSeconds int) error {
return &StatusError{unversioned.Status{
Status: unversioned.StatusFailure,
Code: http.StatusInternalServerError,
Reason: unversioned.StatusReasonServerTimeout,
Details: &unversioned.StatusDetails{
Kind: kind,
Group: qualifiedResource.Group,
Kind: qualifiedResource.Resource,
Name: operation,
RetryAfterSeconds: int32(retryAfterSeconds),
},
Message: fmt.Sprintf("The %s operation against %s could not be completed at this time, please try again.", operation, kind),
Message: fmt.Sprintf("The %s operation against %s could not be completed at this time, please try again.", operation, qualifiedResource.String()),
}}
}
// NewServerTimeoutForKind should not exist. Server timeouts happen when accessing resources, the Kind is just what we
// happened to be looking at when the request failed. This delegates to keep code sane, but we should work towards removing this.
func NewServerTimeoutForKind(qualifiedKind unversioned.GroupKind, operation string, retryAfterSeconds int) error {
return NewServerTimeout(unversioned.GroupResource{Group: qualifiedKind.Group, Resource: qualifiedKind.Kind}, operation, retryAfterSeconds)
}
// NewInternalError returns an error indicating the item is invalid and cannot be processed.
func NewInternalError(err error) error {
return &StatusError{unversioned.Status{
@@ -274,7 +287,7 @@ 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, isUnexpectedResponse bool) error {
func NewGenericServerResponse(code int, verb string, qualifiedResource unversioned.GroupResource, name, serverMessage string, retryAfterSeconds int, isUnexpectedResponse bool) error {
reason := unversioned.StatusReasonUnknown
message := fmt.Sprintf("the server responded with the status code %d but did not return more information", code)
switch code {
@@ -316,10 +329,10 @@ func NewGenericServerResponse(code int, verb, kind, name, serverMessage string,
}
}
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)
case !qualifiedResource.IsEmpty() && len(name) > 0:
message = fmt.Sprintf("%s (%s %s %s)", message, strings.ToLower(verb), qualifiedResource.String(), name)
case !qualifiedResource.IsEmpty():
message = fmt.Sprintf("%s (%s %s)", message, strings.ToLower(verb), qualifiedResource.String())
}
var causes []unversioned.StatusCause
if isUnexpectedResponse {
@@ -337,8 +350,9 @@ func NewGenericServerResponse(code int, verb, kind, name, serverMessage string,
Code: int32(code),
Reason: reason,
Details: &unversioned.StatusDetails{
Kind: kind,
Name: name,
Group: qualifiedResource.Group,
Kind: qualifiedResource.Resource,
Name: name,
Causes: causes,
RetryAfterSeconds: int32(retryAfterSeconds),

View File

@@ -22,13 +22,14 @@ import (
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/validation/field"
)
func TestErrorNew(t *testing.T) {
err := NewAlreadyExists("test", "1")
err := NewAlreadyExists(api.Resource("tests"), "1")
if !IsAlreadyExists(err) {
t.Errorf("expected to be %s", unversioned.StatusReasonAlreadyExists)
}
@@ -54,34 +55,34 @@ func TestErrorNew(t *testing.T) {
t.Errorf("expected to not be %s", unversioned.StatusReasonMethodNotAllowed)
}
if !IsConflict(NewConflict("test", "2", errors.New("message"))) {
if !IsConflict(NewConflict(api.Resource("tests"), "2", errors.New("message"))) {
t.Errorf("expected to be conflict")
}
if !IsNotFound(NewNotFound("test", "3")) {
if !IsNotFound(NewNotFound(api.Resource("tests"), "3")) {
t.Errorf("expected to be %s", unversioned.StatusReasonNotFound)
}
if !IsInvalid(NewInvalid("test", "2", nil)) {
if !IsInvalid(NewInvalid(api.Kind("Test"), "2", nil)) {
t.Errorf("expected to be %s", unversioned.StatusReasonInvalid)
}
if !IsBadRequest(NewBadRequest("reason")) {
t.Errorf("expected to be %s", unversioned.StatusReasonBadRequest)
}
if !IsForbidden(NewForbidden("test", "2", errors.New("reason"))) {
if !IsForbidden(NewForbidden(api.Resource("tests"), "2", errors.New("reason"))) {
t.Errorf("expected to be %s", unversioned.StatusReasonForbidden)
}
if !IsUnauthorized(NewUnauthorized("reason")) {
t.Errorf("expected to be %s", unversioned.StatusReasonUnauthorized)
}
if !IsServerTimeout(NewServerTimeout("test", "reason", 0)) {
if !IsServerTimeout(NewServerTimeout(api.Resource("tests"), "reason", 0)) {
t.Errorf("expected to be %s", unversioned.StatusReasonServerTimeout)
}
if time, ok := SuggestsClientDelay(NewServerTimeout("test", "doing something", 10)); time != 10 || !ok {
if time, ok := SuggestsClientDelay(NewServerTimeout(api.Resource("tests"), "doing something", 10)); time != 10 || !ok {
t.Errorf("expected to be %s", unversioned.StatusReasonServerTimeout)
}
if time, ok := SuggestsClientDelay(NewTimeoutError("test reason", 10)); time != 10 || !ok {
t.Errorf("expected to be %s", unversioned.StatusReasonTimeout)
}
if !IsMethodNotSupported(NewMethodNotSupported("foo", "delete")) {
if !IsMethodNotSupported(NewMethodNotSupported(api.Resource("foos"), "delete")) {
t.Errorf("expected to be %s", unversioned.StatusReasonMethodNotAllowed)
}
}
@@ -94,7 +95,7 @@ func TestNewInvalid(t *testing.T) {
{
field.Duplicate(field.NewPath("field[0].name"), "bar"),
&unversioned.StatusDetails{
Kind: "kind",
Kind: "Kind",
Name: "name",
Causes: []unversioned.StatusCause{{
Type: unversioned.CauseTypeFieldValueDuplicate,
@@ -105,7 +106,7 @@ func TestNewInvalid(t *testing.T) {
{
field.Invalid(field.NewPath("field[0].name"), "bar", "detail"),
&unversioned.StatusDetails{
Kind: "kind",
Kind: "Kind",
Name: "name",
Causes: []unversioned.StatusCause{{
Type: unversioned.CauseTypeFieldValueInvalid,
@@ -116,7 +117,7 @@ func TestNewInvalid(t *testing.T) {
{
field.NotFound(field.NewPath("field[0].name"), "bar"),
&unversioned.StatusDetails{
Kind: "kind",
Kind: "Kind",
Name: "name",
Causes: []unversioned.StatusCause{{
Type: unversioned.CauseTypeFieldValueNotFound,
@@ -127,7 +128,7 @@ func TestNewInvalid(t *testing.T) {
{
field.NotSupported(field.NewPath("field[0].name"), "bar", nil),
&unversioned.StatusDetails{
Kind: "kind",
Kind: "Kind",
Name: "name",
Causes: []unversioned.StatusCause{{
Type: unversioned.CauseTypeFieldValueNotSupported,
@@ -138,7 +139,7 @@ func TestNewInvalid(t *testing.T) {
{
field.Required(field.NewPath("field[0].name")),
&unversioned.StatusDetails{
Kind: "kind",
Kind: "Kind",
Name: "name",
Causes: []unversioned.StatusCause{{
Type: unversioned.CauseTypeFieldValueRequired,
@@ -150,7 +151,7 @@ func TestNewInvalid(t *testing.T) {
for i, testCase := range testCases {
vErr, expected := testCase.Err, testCase.Details
expected.Causes[0].Message = vErr.ErrorBody()
err := NewInvalid("kind", "name", field.ErrorList{vErr})
err := NewInvalid(api.Kind("Kind"), "name", field.ErrorList{vErr})
status := err.(*StatusError).ErrStatus
if status.Code != 422 || status.Reason != unversioned.StatusReasonInvalid {
t.Errorf("%d: unexpected status: %#v", i, status)

View File

@@ -18,17 +18,18 @@ package etcd
import (
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/storage"
)
// InterpretListError converts a generic error on a retrieval
// operation into the appropriate API error.
func InterpretListError(err error, kind string) error {
func InterpretListError(err error, qualifiedResource unversioned.GroupResource) error {
switch {
case storage.IsNotFound(err):
return errors.NewNotFound(kind, "")
return errors.NewNotFound(qualifiedResource, "")
case storage.IsUnreachable(err):
return errors.NewServerTimeout(kind, "list", 2) // TODO: make configurable or handled at a higher level
return errors.NewServerTimeout(qualifiedResource, "list", 2) // TODO: make configurable or handled at a higher level
default:
return err
}
@@ -36,12 +37,12 @@ func InterpretListError(err error, kind string) error {
// InterpretGetError converts a generic error on a retrieval
// operation into the appropriate API error.
func InterpretGetError(err error, kind, name string) error {
func InterpretGetError(err error, qualifiedResource unversioned.GroupResource, name string) error {
switch {
case storage.IsNotFound(err):
return errors.NewNotFound(kind, name)
return errors.NewNotFound(qualifiedResource, name)
case storage.IsUnreachable(err):
return errors.NewServerTimeout(kind, "get", 2) // TODO: make configurable or handled at a higher level
return errors.NewServerTimeout(qualifiedResource, "get", 2) // TODO: make configurable or handled at a higher level
default:
return err
}
@@ -49,12 +50,12 @@ func InterpretGetError(err error, kind, name string) error {
// InterpretCreateError converts a generic error on a create
// operation into the appropriate API error.
func InterpretCreateError(err error, kind, name string) error {
func InterpretCreateError(err error, qualifiedResource unversioned.GroupResource, name string) error {
switch {
case storage.IsNodeExist(err):
return errors.NewAlreadyExists(kind, name)
return errors.NewAlreadyExists(qualifiedResource, name)
case storage.IsUnreachable(err):
return errors.NewServerTimeout(kind, "create", 2) // TODO: make configurable or handled at a higher level
return errors.NewServerTimeout(qualifiedResource, "create", 2) // TODO: make configurable or handled at a higher level
default:
return err
}
@@ -62,12 +63,12 @@ func InterpretCreateError(err error, kind, name string) error {
// InterpretUpdateError converts a generic error on a update
// operation into the appropriate API error.
func InterpretUpdateError(err error, kind, name string) error {
func InterpretUpdateError(err error, qualifiedResource unversioned.GroupResource, name string) error {
switch {
case storage.IsTestFailed(err), storage.IsNodeExist(err):
return errors.NewConflict(kind, name, err)
return errors.NewConflict(qualifiedResource, name, err)
case storage.IsUnreachable(err):
return errors.NewServerTimeout(kind, "update", 2) // TODO: make configurable or handled at a higher level
return errors.NewServerTimeout(qualifiedResource, "update", 2) // TODO: make configurable or handled at a higher level
default:
return err
}
@@ -75,12 +76,12 @@ func InterpretUpdateError(err error, kind, name string) error {
// InterpretDeleteError converts a generic error on a delete
// operation into the appropriate API error.
func InterpretDeleteError(err error, kind, name string) error {
func InterpretDeleteError(err error, qualifiedResource unversioned.GroupResource, name string) error {
switch {
case storage.IsNotFound(err):
return errors.NewNotFound(kind, name)
return errors.NewNotFound(qualifiedResource, name)
case storage.IsUnreachable(err):
return errors.NewServerTimeout(kind, "delete", 2) // TODO: make configurable or handled at a higher level
return errors.NewServerTimeout(qualifiedResource, "delete", 2) // TODO: make configurable or handled at a higher level
default:
return err
}