Merge pull request #1158 from smarterclayton/separate_errors

Errors should be part of api/errors, not apiserver
This commit is contained in:
Daniel Smith 2014-09-03 15:46:29 -07:00
commit 51a86f839c
20 changed files with 620 additions and 555 deletions

View File

@ -18,138 +18,117 @@ package errors
import ( import (
"fmt" "fmt"
"strings" "net/http"
"github.com/golang/glog" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
) )
// ValidationErrorType is a machine readable value providing more detail about why // statusError is an error intended for consumption by a REST API server.
// a field is invalid. These values are expected to match 1-1 with type statusError struct {
// CauseType in api/types.go. status api.Status
type ValidationErrorType string
const (
// ValidationErrorTypeNotFound is used to report failure to find a requested value
// (e.g. looking up an ID).
ValidationErrorTypeNotFound ValidationErrorType = "fieldValueNotFound"
// ValidationErrorTypeRequired is used to report required values that are not
// provided (e.g. empty strings, null values, or empty arrays).
ValidationErrorTypeRequired ValidationErrorType = "fieldValueRequired"
// ValidationErrorTypeDuplicate is used to report collisions of values that must be
// unique (e.g. unique IDs).
ValidationErrorTypeDuplicate ValidationErrorType = "fieldValueDuplicate"
// ValidationErrorTypeInvalid is used to report malformed values (e.g. failed regex
// match).
ValidationErrorTypeInvalid ValidationErrorType = "fieldValueInvalid"
// ValidationErrorTypeNotSupported is used to report valid (as per formatting rules)
// values that can not be handled (e.g. an enumerated string).
ValidationErrorTypeNotSupported ValidationErrorType = "fieldValueNotSupported"
)
func ValueOf(t ValidationErrorType) string {
switch t {
case ValidationErrorTypeNotFound:
return "not found"
case ValidationErrorTypeRequired:
return "required value"
case ValidationErrorTypeDuplicate:
return "duplicate value"
case ValidationErrorTypeInvalid:
return "invalid value"
case ValidationErrorTypeNotSupported:
return "unsupported value"
default:
glog.Errorf("unrecognized validation type: %#v", t)
return ""
}
} }
// ValidationError is an implementation of the 'error' interface, which represents an error of validation. // Error implements the Error interface.
type ValidationError struct { func (e *statusError) Error() string {
Type ValidationErrorType return e.status.Message
Field string
BadValue interface{}
} }
func (v ValidationError) Error() string { // Status converts this error into an api.Status object.
return fmt.Sprintf("%s: %v '%v'", v.Field, ValueOf(v.Type), v.BadValue) func (e *statusError) Status() api.Status {
return e.status
} }
// NewInvalid returns a ValidationError indicating "value required" // NewNotFound returns a new error which indicates that the resource of the kind and the name was not found.
func NewRequired(field string, value interface{}) ValidationError { func NewNotFound(kind, name string) error {
return ValidationError{ValidationErrorTypeRequired, field, value} return &statusError{api.Status{
Status: api.StatusFailure,
Code: http.StatusNotFound,
Reason: api.StatusReasonNotFound,
Details: &api.StatusDetails{
Kind: kind,
ID: name,
},
Message: fmt.Sprintf("%s %q not found", kind, name),
}}
} }
// NewInvalid returns a ValidationError indicating "invalid value" // NewAlreadyExists returns an error indicating the item requested exists by that identifier.
func NewInvalid(field string, value interface{}) ValidationError { func NewAlreadyExists(kind, name string) error {
return ValidationError{ValidationErrorTypeInvalid, field, value} return &statusError{api.Status{
Status: api.StatusFailure,
Code: http.StatusConflict,
Reason: api.StatusReasonAlreadyExists,
Details: &api.StatusDetails{
Kind: kind,
ID: name,
},
Message: fmt.Sprintf("%s %q already exists", kind, name),
}}
} }
// NewNotSupported returns a ValidationError indicating "unsupported value" // NewConflict returns an error indicating the item can't be updated as provided.
func NewNotSupported(field string, value interface{}) ValidationError { func NewConflict(kind, name string, err error) error {
return ValidationError{ValidationErrorTypeNotSupported, field, value} return &statusError{api.Status{
Status: api.StatusFailure,
Code: http.StatusConflict,
Reason: api.StatusReasonConflict,
Details: &api.StatusDetails{
Kind: kind,
ID: name,
},
Message: fmt.Sprintf("%s %q cannot be updated: %s", kind, name, err),
}}
} }
// NewDuplicate returns a ValidationError indicating "duplicate value" // NewInvalid returns an error indicating the item is invalid and cannot be processed.
func NewDuplicate(field string, value interface{}) ValidationError { func NewInvalid(kind, name string, errs ErrorList) error {
return ValidationError{ValidationErrorTypeDuplicate, field, value} causes := make([]api.StatusCause, 0, len(errs))
} for i := range errs {
if err, ok := errs[i].(ValidationError); ok {
// NewNotFound returns a ValidationError indicating "value not found" causes = append(causes, api.StatusCause{
func NewNotFound(field string, value interface{}) ValidationError { Type: api.CauseType(err.Type),
return ValidationError{ValidationErrorTypeNotFound, field, value} Message: err.Error(),
} Field: err.Field,
})
// ErrorList is a collection of errors. This does not implement the error
// interface to avoid confusion where an empty ErrorList would still be an
// error (non-nil). To produce a single error instance from an ErrorList, use
// the ToError() method, which will return nil for an empty ErrorList.
type ErrorList []error
// This helper implements the error interface for ErrorList, but prevents
// accidental conversion of ErrorList to error.
type errorListInternal ErrorList
// Error is part of the error interface.
func (list errorListInternal) Error() string {
if len(list) == 0 {
return ""
}
sl := make([]string, len(list))
for i := range list {
sl[i] = list[i].Error()
}
return strings.Join(sl, "; ")
}
// ToError converts an ErrorList into a "normal" error, or nil if the list is empty.
func (list ErrorList) ToError() error {
if len(list) == 0 {
return nil
}
return errorListInternal(list)
}
// Prefix adds a prefix to the Field of every ValidationError in the list. Returns
// the list for convenience.
func (list ErrorList) Prefix(prefix string) ErrorList {
for i := range list {
if err, ok := list[i].(ValidationError); ok {
if strings.HasPrefix(err.Field, "[") {
err.Field = prefix + err.Field
} else if len(err.Field) != 0 {
err.Field = prefix + "." + err.Field
} else {
err.Field = prefix
}
list[i] = err
} }
} }
return list return &statusError{api.Status{
Status: api.StatusFailure,
Code: 422, // RFC 4918
Reason: api.StatusReasonInvalid,
Details: &api.StatusDetails{
Kind: kind,
ID: name,
Causes: causes,
},
Message: fmt.Sprintf("%s %q is invalid: %s", kind, name, errs.ToError()),
}}
} }
// PrefixIndex adds an index to the Field of every ValidationError in the list. Returns // IsNotFound returns true if the specified error was created by NewNotFoundErr.
// the list for convenience. func IsNotFound(err error) bool {
func (list ErrorList) PrefixIndex(index int) ErrorList { return reasonForError(err) == api.StatusReasonNotFound
return list.Prefix(fmt.Sprintf("[%d]", index)) }
// IsAlreadyExists determines if the err is an error which indicates that a specified resource already exists.
func IsAlreadyExists(err error) bool {
return reasonForError(err) == api.StatusReasonAlreadyExists
}
// IsConflict determines if the err is an error which indicates the provided update conflicts.
func IsConflict(err error) bool {
return reasonForError(err) == api.StatusReasonConflict
}
// IsInvalid determines if the err is an error which indicates the provided resource is not valid.
func IsInvalid(err error) bool {
return reasonForError(err) == api.StatusReasonInvalid
}
func reasonForError(err error) api.StatusReason {
switch t := err.(type) {
case *statusError:
return t.status.Reason
}
return api.StatusReasonUnknown
} }

View File

@ -17,147 +17,117 @@ limitations under the License.
package errors package errors
import ( import (
"errors"
"fmt" "fmt"
"strings" "reflect"
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
) )
func TestMakeFuncs(t *testing.T) { func TestErrorNew(t *testing.T) {
err := NewAlreadyExists("test", "1")
if !IsAlreadyExists(err) {
t.Errorf("expected to be already_exists")
}
if IsConflict(err) {
t.Errorf("expected to not be confict")
}
if IsNotFound(err) {
t.Errorf(fmt.Sprintf("expected to not be %s", api.StatusReasonNotFound))
}
if IsInvalid(err) {
t.Errorf("expected to not be invalid")
}
if !IsConflict(NewConflict("test", "2", errors.New("message"))) {
t.Errorf("expected to be conflict")
}
if !IsNotFound(NewNotFound("test", "3")) {
t.Errorf("expected to be not found")
}
if !IsInvalid(NewInvalid("test", "2", nil)) {
t.Errorf("expected to be invalid")
}
}
func TestNewInvalid(t *testing.T) {
testCases := []struct { testCases := []struct {
fn func() ValidationError Err ValidationError
expected ValidationErrorType Details *api.StatusDetails
}{ }{
{ {
func() ValidationError { return NewInvalid("f", "v") }, NewFieldDuplicate("field[0].name", "bar"),
ValidationErrorTypeInvalid, &api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueDuplicate,
Field: "field[0].name",
}},
},
}, },
{ {
func() ValidationError { return NewNotSupported("f", "v") }, NewFieldInvalid("field[0].name", "bar"),
ValidationErrorTypeNotSupported, &api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueInvalid,
Field: "field[0].name",
}},
},
}, },
{ {
func() ValidationError { return NewDuplicate("f", "v") }, NewFieldNotFound("field[0].name", "bar"),
ValidationErrorTypeDuplicate, &api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueNotFound,
Field: "field[0].name",
}},
},
}, },
{ {
func() ValidationError { return NewNotFound("f", "v") }, NewFieldNotSupported("field[0].name", "bar"),
ValidationErrorTypeNotFound, &api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueNotSupported,
Field: "field[0].name",
}},
},
}, },
{ {
func() ValidationError { return NewRequired("f", "v") }, NewFieldRequired("field[0].name", "bar"),
ValidationErrorTypeRequired, &api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueRequired,
Field: "field[0].name",
}},
},
}, },
} }
for i, testCase := range testCases {
for _, testCase := range testCases { vErr, expected := testCase.Err, testCase.Details
err := testCase.fn() expected.Causes[0].Message = vErr.Error()
if err.Type != testCase.expected { err := NewInvalid("kind", "name", ErrorList{vErr})
t.Errorf("expected Type %q, got %q", testCase.expected, err.Type) status := err.(*statusError).Status()
if status.Code != 422 || status.Reason != api.StatusReasonInvalid {
t.Errorf("%d: unexpected status: %#v", i, status)
}
if !reflect.DeepEqual(expected, status.Details) {
t.Errorf("%d: expected %#v, got %#v", expected, status.Details)
} }
} }
} }
func TestValidationError(t *testing.T) { func Test_reasonForError(t *testing.T) {
s := NewInvalid("foo", "bar").Error() if e, a := api.StatusReasonUnknown, reasonForError(nil); e != a {
if !strings.Contains(s, "foo") || !strings.Contains(s, "bar") || !strings.Contains(s, ValueOf(ValidationErrorTypeInvalid)) { t.Errorf("unexpected reason type: %#v", a)
t.Errorf("error message did not contain expected values, got %s", s)
}
}
func TestErrorList(t *testing.T) {
errList := ErrorList{}
if a := errList.ToError(); a != nil {
t.Errorf("unexpected non-nil error for empty list: %v", a)
}
if a := errorListInternal(errList).Error(); a != "" {
t.Errorf("expected empty string, got %v", a)
}
errList = append(errList, NewInvalid("field", "value"))
// The fact that this compiles is the test.
}
func TestErrorListToError(t *testing.T) {
errList := ErrorList{}
err := errList.ToError()
if err != nil {
t.Errorf("expected nil, got %v", err)
}
testCases := []struct {
errs ErrorList
expected string
}{
{ErrorList{fmt.Errorf("abc")}, "abc"},
{ErrorList{fmt.Errorf("abc"), fmt.Errorf("123")}, "abc; 123"},
}
for _, testCase := range testCases {
err := testCase.errs.ToError()
if err == nil {
t.Errorf("expected an error, got nil: ErrorList=%v", testCase)
continue
}
if err.Error() != testCase.expected {
t.Errorf("expected %q, got %q", testCase.expected, err.Error())
}
}
}
func TestErrListPrefix(t *testing.T) {
testCases := []struct {
Err ValidationError
Expected string
}{
{
NewNotFound("[0].bar", "value"),
"foo[0].bar",
},
{
NewInvalid("field", "value"),
"foo.field",
},
{
NewDuplicate("", "value"),
"foo",
},
}
for _, testCase := range testCases {
errList := ErrorList{testCase.Err}
prefix := errList.Prefix("foo")
if prefix == nil || len(prefix) != len(errList) {
t.Errorf("Prefix should return self")
}
if e, a := testCase.Expected, errList[0].(ValidationError).Field; e != a {
t.Errorf("expected %s, got %s", e, a)
}
}
}
func TestErrListPrefixIndex(t *testing.T) {
testCases := []struct {
Err ValidationError
Expected string
}{
{
NewNotFound("[0].bar", "value"),
"[1][0].bar",
},
{
NewInvalid("field", "value"),
"[1].field",
},
{
NewDuplicate("", "value"),
"[1]",
},
}
for _, testCase := range testCases {
errList := ErrorList{testCase.Err}
prefix := errList.PrefixIndex(1)
if prefix == nil || len(prefix) != len(errList) {
t.Errorf("PrefixIndex should return self")
}
if e, a := testCase.Expected, errList[0].(ValidationError).Field; e != a {
t.Errorf("expected %s, got %s", e, a)
}
} }
} }

View File

@ -0,0 +1,155 @@
/*
Copyright 2014 Google Inc. All rights reserved.
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 (
"fmt"
"strings"
"github.com/golang/glog"
)
// ValidationErrorType is a machine readable value providing more detail about why
// a field is invalid. These values are expected to match 1-1 with
// CauseType in api/types.go.
type ValidationErrorType string
const (
// ValidationErrorTypeNotFound is used to report failure to find a requested value
// (e.g. looking up an ID).
ValidationErrorTypeNotFound ValidationErrorType = "fieldValueNotFound"
// ValidationErrorTypeRequired is used to report required values that are not
// provided (e.g. empty strings, null values, or empty arrays).
ValidationErrorTypeRequired ValidationErrorType = "fieldValueRequired"
// ValidationErrorTypeDuplicate is used to report collisions of values that must be
// unique (e.g. unique IDs).
ValidationErrorTypeDuplicate ValidationErrorType = "fieldValueDuplicate"
// ValidationErrorTypeInvalid is used to report malformed values (e.g. failed regex
// match).
ValidationErrorTypeInvalid ValidationErrorType = "fieldValueInvalid"
// ValidationErrorTypeNotSupported is used to report valid (as per formatting rules)
// values that can not be handled (e.g. an enumerated string).
ValidationErrorTypeNotSupported ValidationErrorType = "fieldValueNotSupported"
)
func ValueOf(t ValidationErrorType) string {
switch t {
case ValidationErrorTypeNotFound:
return "not found"
case ValidationErrorTypeRequired:
return "required value"
case ValidationErrorTypeDuplicate:
return "duplicate value"
case ValidationErrorTypeInvalid:
return "invalid value"
case ValidationErrorTypeNotSupported:
return "unsupported value"
default:
glog.Errorf("unrecognized validation type: %#v", t)
return ""
}
}
// ValidationError is an implementation of the 'error' interface, which represents an error of validation.
type ValidationError struct {
Type ValidationErrorType
Field string
BadValue interface{}
}
func (v ValidationError) Error() string {
return fmt.Sprintf("%s: %v '%v'", v.Field, ValueOf(v.Type), v.BadValue)
}
// NewFieldRequired returns a ValidationError indicating "value required"
func NewFieldRequired(field string, value interface{}) ValidationError {
return ValidationError{ValidationErrorTypeRequired, field, value}
}
// NewFieldInvalid returns a ValidationError indicating "invalid value"
func NewFieldInvalid(field string, value interface{}) ValidationError {
return ValidationError{ValidationErrorTypeInvalid, field, value}
}
// NewFieldNotSupported returns a ValidationError indicating "unsupported value"
func NewFieldNotSupported(field string, value interface{}) ValidationError {
return ValidationError{ValidationErrorTypeNotSupported, field, value}
}
// NewFieldDuplicate returns a ValidationError indicating "duplicate value"
func NewFieldDuplicate(field string, value interface{}) ValidationError {
return ValidationError{ValidationErrorTypeDuplicate, field, value}
}
// NewFieldNotFound returns a ValidationError indicating "value not found"
func NewFieldNotFound(field string, value interface{}) ValidationError {
return ValidationError{ValidationErrorTypeNotFound, field, value}
}
// ErrorList is a collection of errors. This does not implement the error
// interface to avoid confusion where an empty ErrorList would still be an
// error (non-nil). To produce a single error instance from an ErrorList, use
// the ToError() method, which will return nil for an empty ErrorList.
type ErrorList []error
// This helper implements the error interface for ErrorList, but prevents
// accidental conversion of ErrorList to error.
type errorListInternal ErrorList
// Error is part of the error interface.
func (list errorListInternal) Error() string {
if len(list) == 0 {
return ""
}
sl := make([]string, len(list))
for i := range list {
sl[i] = list[i].Error()
}
return strings.Join(sl, "; ")
}
// ToError converts an ErrorList into a "normal" error, or nil if the list is empty.
func (list ErrorList) ToError() error {
if len(list) == 0 {
return nil
}
return errorListInternal(list)
}
// Prefix adds a prefix to the Field of every ValidationError in the list. Returns
// the list for convenience.
func (list ErrorList) Prefix(prefix string) ErrorList {
for i := range list {
if err, ok := list[i].(ValidationError); ok {
if strings.HasPrefix(err.Field, "[") {
err.Field = prefix + err.Field
} else if len(err.Field) != 0 {
err.Field = prefix + "." + err.Field
} else {
err.Field = prefix
}
list[i] = err
}
}
return list
}
// PrefixIndex adds an index to the Field of every ValidationError in the list. Returns
// the list for convenience.
func (list ErrorList) PrefixIndex(index int) ErrorList {
return list.Prefix(fmt.Sprintf("[%d]", index))
}

View File

@ -0,0 +1,163 @@
/*
Copyright 2014 Google Inc. All rights reserved.
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 (
"fmt"
"strings"
"testing"
)
func TestMakeFuncs(t *testing.T) {
testCases := []struct {
fn func() ValidationError
expected ValidationErrorType
}{
{
func() ValidationError { return NewFieldInvalid("f", "v") },
ValidationErrorTypeInvalid,
},
{
func() ValidationError { return NewFieldNotSupported("f", "v") },
ValidationErrorTypeNotSupported,
},
{
func() ValidationError { return NewFieldDuplicate("f", "v") },
ValidationErrorTypeDuplicate,
},
{
func() ValidationError { return NewFieldNotFound("f", "v") },
ValidationErrorTypeNotFound,
},
{
func() ValidationError { return NewFieldRequired("f", "v") },
ValidationErrorTypeRequired,
},
}
for _, testCase := range testCases {
err := testCase.fn()
if err.Type != testCase.expected {
t.Errorf("expected Type %q, got %q", testCase.expected, err.Type)
}
}
}
func TestValidationError(t *testing.T) {
s := NewFieldInvalid("foo", "bar").Error()
if !strings.Contains(s, "foo") || !strings.Contains(s, "bar") || !strings.Contains(s, ValueOf(ValidationErrorTypeInvalid)) {
t.Errorf("error message did not contain expected values, got %s", s)
}
}
func TestErrorList(t *testing.T) {
errList := ErrorList{}
if a := errList.ToError(); a != nil {
t.Errorf("unexpected non-nil error for empty list: %v", a)
}
if a := errorListInternal(errList).Error(); a != "" {
t.Errorf("expected empty string, got %v", a)
}
errList = append(errList, NewFieldInvalid("field", "value"))
// The fact that this compiles is the test.
}
func TestErrorListToError(t *testing.T) {
errList := ErrorList{}
err := errList.ToError()
if err != nil {
t.Errorf("expected nil, got %v", err)
}
testCases := []struct {
errs ErrorList
expected string
}{
{ErrorList{fmt.Errorf("abc")}, "abc"},
{ErrorList{fmt.Errorf("abc"), fmt.Errorf("123")}, "abc; 123"},
}
for _, testCase := range testCases {
err := testCase.errs.ToError()
if err == nil {
t.Errorf("expected an error, got nil: ErrorList=%v", testCase)
continue
}
if err.Error() != testCase.expected {
t.Errorf("expected %q, got %q", testCase.expected, err.Error())
}
}
}
func TestErrListPrefix(t *testing.T) {
testCases := []struct {
Err ValidationError
Expected string
}{
{
NewFieldNotFound("[0].bar", "value"),
"foo[0].bar",
},
{
NewFieldInvalid("field", "value"),
"foo.field",
},
{
NewFieldDuplicate("", "value"),
"foo",
},
}
for _, testCase := range testCases {
errList := ErrorList{testCase.Err}
prefix := errList.Prefix("foo")
if prefix == nil || len(prefix) != len(errList) {
t.Errorf("Prefix should return self")
}
if e, a := testCase.Expected, errList[0].(ValidationError).Field; e != a {
t.Errorf("expected %s, got %s", e, a)
}
}
}
func TestErrListPrefixIndex(t *testing.T) {
testCases := []struct {
Err ValidationError
Expected string
}{
{
NewFieldNotFound("[0].bar", "value"),
"[1][0].bar",
},
{
NewFieldInvalid("field", "value"),
"[1].field",
},
{
NewFieldDuplicate("", "value"),
"[1]",
},
}
for _, testCase := range testCases {
errList := ErrorList{testCase.Err}
prefix := errList.PrefixIndex(1)
if prefix == nil || len(prefix) != len(errList) {
t.Errorf("PrefixIndex should return self")
}
if e, a := testCase.Expected, errList[0].(ValidationError).Field; e != a {
t.Errorf("expected %s, got %s", e, a)
}
}
}

View File

@ -37,11 +37,11 @@ func validateVolumes(volumes []api.Volume) (util.StringSet, errs.ErrorList) {
el = validateSource(vol.Source).Prefix("source") el = validateSource(vol.Source).Prefix("source")
} }
if len(vol.Name) == 0 { if len(vol.Name) == 0 {
el = append(el, errs.NewRequired("name", vol.Name)) el = append(el, errs.NewFieldRequired("name", vol.Name))
} else if !util.IsDNSLabel(vol.Name) { } else if !util.IsDNSLabel(vol.Name) {
el = append(el, errs.NewInvalid("name", vol.Name)) el = append(el, errs.NewFieldInvalid("name", vol.Name))
} else if allNames.Has(vol.Name) { } else if allNames.Has(vol.Name) {
el = append(el, errs.NewDuplicate("name", vol.Name)) el = append(el, errs.NewFieldDuplicate("name", vol.Name))
} }
if len(el) == 0 { if len(el) == 0 {
allNames.Insert(vol.Name) allNames.Insert(vol.Name)
@ -64,7 +64,7 @@ func validateSource(source *api.VolumeSource) errs.ErrorList {
//EmptyDirs have nothing to validate //EmptyDirs have nothing to validate
} }
if numVolumes != 1 { if numVolumes != 1 {
allErrs = append(allErrs, errs.NewInvalid("", source)) allErrs = append(allErrs, errs.NewFieldInvalid("", source))
} }
return allErrs return allErrs
} }
@ -88,25 +88,25 @@ func validatePorts(ports []api.Port) errs.ErrorList {
port := &ports[i] // so we can set default values port := &ports[i] // so we can set default values
if len(port.Name) > 0 { if len(port.Name) > 0 {
if len(port.Name) > 63 || !util.IsDNSLabel(port.Name) { if len(port.Name) > 63 || !util.IsDNSLabel(port.Name) {
pErrs = append(pErrs, errs.NewInvalid("name", port.Name)) pErrs = append(pErrs, errs.NewFieldInvalid("name", port.Name))
} else if allNames.Has(port.Name) { } else if allNames.Has(port.Name) {
pErrs = append(pErrs, errs.NewDuplicate("name", port.Name)) pErrs = append(pErrs, errs.NewFieldDuplicate("name", port.Name))
} else { } else {
allNames.Insert(port.Name) allNames.Insert(port.Name)
} }
} }
if port.ContainerPort == 0 { if port.ContainerPort == 0 {
pErrs = append(pErrs, errs.NewRequired("containerPort", port.ContainerPort)) pErrs = append(pErrs, errs.NewFieldRequired("containerPort", port.ContainerPort))
} else if !util.IsValidPortNum(port.ContainerPort) { } else if !util.IsValidPortNum(port.ContainerPort) {
pErrs = append(pErrs, errs.NewInvalid("containerPort", port.ContainerPort)) pErrs = append(pErrs, errs.NewFieldInvalid("containerPort", port.ContainerPort))
} }
if port.HostPort != 0 && !util.IsValidPortNum(port.HostPort) { if port.HostPort != 0 && !util.IsValidPortNum(port.HostPort) {
pErrs = append(pErrs, errs.NewInvalid("hostPort", port.HostPort)) pErrs = append(pErrs, errs.NewFieldInvalid("hostPort", port.HostPort))
} }
if len(port.Protocol) == 0 { if len(port.Protocol) == 0 {
port.Protocol = "TCP" port.Protocol = "TCP"
} else if !supportedPortProtocols.Has(strings.ToUpper(port.Protocol)) { } else if !supportedPortProtocols.Has(strings.ToUpper(port.Protocol)) {
pErrs = append(pErrs, errs.NewNotSupported("protocol", port.Protocol)) pErrs = append(pErrs, errs.NewFieldNotSupported("protocol", port.Protocol))
} }
allErrs = append(allErrs, pErrs.PrefixIndex(i)...) allErrs = append(allErrs, pErrs.PrefixIndex(i)...)
} }
@ -120,10 +120,10 @@ func validateEnv(vars []api.EnvVar) errs.ErrorList {
vErrs := errs.ErrorList{} vErrs := errs.ErrorList{}
ev := &vars[i] // so we can set default values ev := &vars[i] // so we can set default values
if len(ev.Name) == 0 { if len(ev.Name) == 0 {
vErrs = append(vErrs, errs.NewRequired("name", ev.Name)) vErrs = append(vErrs, errs.NewFieldRequired("name", ev.Name))
} }
if !util.IsCIdentifier(ev.Name) { if !util.IsCIdentifier(ev.Name) {
vErrs = append(vErrs, errs.NewInvalid("name", ev.Name)) vErrs = append(vErrs, errs.NewFieldInvalid("name", ev.Name))
} }
allErrs = append(allErrs, vErrs.PrefixIndex(i)...) allErrs = append(allErrs, vErrs.PrefixIndex(i)...)
} }
@ -137,12 +137,12 @@ func validateVolumeMounts(mounts []api.VolumeMount, volumes util.StringSet) errs
mErrs := errs.ErrorList{} mErrs := errs.ErrorList{}
mnt := &mounts[i] // so we can set default values mnt := &mounts[i] // so we can set default values
if len(mnt.Name) == 0 { if len(mnt.Name) == 0 {
mErrs = append(mErrs, errs.NewRequired("name", mnt.Name)) mErrs = append(mErrs, errs.NewFieldRequired("name", mnt.Name))
} else if !volumes.Has(mnt.Name) { } else if !volumes.Has(mnt.Name) {
mErrs = append(mErrs, errs.NewNotFound("name", mnt.Name)) mErrs = append(mErrs, errs.NewNotFound("name", mnt.Name))
} }
if len(mnt.MountPath) == 0 { if len(mnt.MountPath) == 0 {
mErrs = append(mErrs, errs.NewRequired("mountPath", mnt.MountPath)) mErrs = append(mErrs, errs.NewFieldRequired("mountPath", mnt.MountPath))
} }
allErrs = append(allErrs, mErrs.PrefixIndex(i)...) allErrs = append(allErrs, mErrs.PrefixIndex(i)...)
} }
@ -163,7 +163,7 @@ func AccumulateUniquePorts(containers []api.Container, accumulator map[int]bool,
continue continue
} }
if accumulator[port] { if accumulator[port] {
cErrs = append(cErrs, errs.NewDuplicate("Port", port)) cErrs = append(cErrs, errs.NewFieldDuplicate("Port", port))
} else { } else {
accumulator[port] = true accumulator[port] = true
} }
@ -188,16 +188,16 @@ func validateContainers(containers []api.Container, volumes util.StringSet) errs
cErrs := errs.ErrorList{} cErrs := errs.ErrorList{}
ctr := &containers[i] // so we can set default values ctr := &containers[i] // so we can set default values
if len(ctr.Name) == 0 { if len(ctr.Name) == 0 {
cErrs = append(cErrs, errs.NewRequired("name", ctr.Name)) cErrs = append(cErrs, errs.NewFieldRequired("name", ctr.Name))
} else if !util.IsDNSLabel(ctr.Name) { } else if !util.IsDNSLabel(ctr.Name) {
cErrs = append(cErrs, errs.NewInvalid("name", ctr.Name)) cErrs = append(cErrs, errs.NewFieldInvalid("name", ctr.Name))
} else if allNames.Has(ctr.Name) { } else if allNames.Has(ctr.Name) {
cErrs = append(cErrs, errs.NewDuplicate("name", ctr.Name)) cErrs = append(cErrs, errs.NewFieldDuplicate("name", ctr.Name))
} else { } else {
allNames.Insert(ctr.Name) allNames.Insert(ctr.Name)
} }
if len(ctr.Image) == 0 { if len(ctr.Image) == 0 {
cErrs = append(cErrs, errs.NewRequired("image", ctr.Image)) cErrs = append(cErrs, errs.NewFieldRequired("image", ctr.Image))
} }
cErrs = append(cErrs, validatePorts(ctr.Ports).Prefix("ports")...) cErrs = append(cErrs, validatePorts(ctr.Ports).Prefix("ports")...)
cErrs = append(cErrs, validateEnv(ctr.Env).Prefix("env")...) cErrs = append(cErrs, validateEnv(ctr.Env).Prefix("env")...)
@ -224,9 +224,9 @@ func ValidateManifest(manifest *api.ContainerManifest) errs.ErrorList {
allErrs := errs.ErrorList{} allErrs := errs.ErrorList{}
if len(manifest.Version) == 0 { if len(manifest.Version) == 0 {
allErrs = append(allErrs, errs.NewRequired("version", manifest.Version)) allErrs = append(allErrs, errs.NewFieldRequired("version", manifest.Version))
} else if !supportedManifestVersions.Has(strings.ToLower(manifest.Version)) { } else if !supportedManifestVersions.Has(strings.ToLower(manifest.Version)) {
allErrs = append(allErrs, errs.NewNotSupported("version", manifest.Version)) allErrs = append(allErrs, errs.NewFieldNotSupported("version", manifest.Version))
} }
allVolumes, errs := validateVolumes(manifest.Volumes) allVolumes, errs := validateVolumes(manifest.Volumes)
allErrs = append(allErrs, errs.Prefix("volumes")...) allErrs = append(allErrs, errs.Prefix("volumes")...)
@ -241,7 +241,7 @@ func ValidatePodState(podState *api.PodState) errs.ErrorList {
} else if podState.RestartPolicy.Type != api.RestartAlways && } else if podState.RestartPolicy.Type != api.RestartAlways &&
podState.RestartPolicy.Type != api.RestartOnFailure && podState.RestartPolicy.Type != api.RestartOnFailure &&
podState.RestartPolicy.Type != api.RestartNever { podState.RestartPolicy.Type != api.RestartNever {
allErrs = append(allErrs, errs.NewNotSupported("restartPolicy.type", podState.RestartPolicy.Type)) allErrs = append(allErrs, errs.NewFieldNotSupported("restartPolicy.type", podState.RestartPolicy.Type))
} }
return allErrs return allErrs
@ -251,7 +251,7 @@ func ValidatePodState(podState *api.PodState) errs.ErrorList {
func ValidatePod(pod *api.Pod) errs.ErrorList { func ValidatePod(pod *api.Pod) errs.ErrorList {
allErrs := errs.ErrorList{} allErrs := errs.ErrorList{}
if len(pod.ID) == 0 { if len(pod.ID) == 0 {
allErrs = append(allErrs, errs.NewRequired("id", pod.ID)) allErrs = append(allErrs, errs.NewFieldRequired("id", pod.ID))
} }
allErrs = append(allErrs, ValidatePodState(&pod.DesiredState).Prefix("desiredState")...) allErrs = append(allErrs, ValidatePodState(&pod.DesiredState).Prefix("desiredState")...)
return allErrs return allErrs
@ -261,15 +261,15 @@ func ValidatePod(pod *api.Pod) errs.ErrorList {
func ValidateService(service *api.Service) errs.ErrorList { func ValidateService(service *api.Service) errs.ErrorList {
allErrs := errs.ErrorList{} allErrs := errs.ErrorList{}
if len(service.ID) == 0 { if len(service.ID) == 0 {
allErrs = append(allErrs, errs.NewRequired("id", service.ID)) allErrs = append(allErrs, errs.NewFieldRequired("id", service.ID))
} else if !util.IsDNS952Label(service.ID) { } else if !util.IsDNS952Label(service.ID) {
allErrs = append(allErrs, errs.NewInvalid("id", service.ID)) allErrs = append(allErrs, errs.NewFieldInvalid("id", service.ID))
} }
if !util.IsValidPortNum(service.Port) { if !util.IsValidPortNum(service.Port) {
allErrs = append(allErrs, errs.NewInvalid("Service.Port", service.Port)) allErrs = append(allErrs, errs.NewFieldInvalid("Service.Port", service.Port))
} }
if labels.Set(service.Selector).AsSelector().Empty() { if labels.Set(service.Selector).AsSelector().Empty() {
allErrs = append(allErrs, errs.NewRequired("selector", service.Selector)) allErrs = append(allErrs, errs.NewFieldRequired("selector", service.Selector))
} }
return allErrs return allErrs
} }
@ -278,18 +278,18 @@ func ValidateService(service *api.Service) errs.ErrorList {
func ValidateReplicationController(controller *api.ReplicationController) errs.ErrorList { func ValidateReplicationController(controller *api.ReplicationController) errs.ErrorList {
allErrs := errs.ErrorList{} allErrs := errs.ErrorList{}
if len(controller.ID) == 0 { if len(controller.ID) == 0 {
allErrs = append(allErrs, errs.NewRequired("id", controller.ID)) allErrs = append(allErrs, errs.NewFieldRequired("id", controller.ID))
} }
if labels.Set(controller.DesiredState.ReplicaSelector).AsSelector().Empty() { if labels.Set(controller.DesiredState.ReplicaSelector).AsSelector().Empty() {
allErrs = append(allErrs, errs.NewRequired("desiredState.replicaSelector", controller.DesiredState.ReplicaSelector)) allErrs = append(allErrs, errs.NewFieldRequired("desiredState.replicaSelector", controller.DesiredState.ReplicaSelector))
} }
selector := labels.Set(controller.DesiredState.ReplicaSelector).AsSelector() selector := labels.Set(controller.DesiredState.ReplicaSelector).AsSelector()
labels := labels.Set(controller.DesiredState.PodTemplate.Labels) labels := labels.Set(controller.DesiredState.PodTemplate.Labels)
if !selector.Matches(labels) { if !selector.Matches(labels) {
allErrs = append(allErrs, errs.NewInvalid("desiredState.podTemplate.labels", controller.DesiredState.PodTemplate)) allErrs = append(allErrs, errs.NewFieldInvalid("desiredState.podTemplate.labels", controller.DesiredState.PodTemplate))
} }
if controller.DesiredState.Replicas < 0 { if controller.DesiredState.Replicas < 0 {
allErrs = append(allErrs, errs.NewInvalid("desiredState.replicas", controller.DesiredState.Replicas)) allErrs = append(allErrs, errs.NewFieldInvalid("desiredState.replicas", controller.DesiredState.Replicas))
} }
allErrs = append(allErrs, ValidateManifest(&controller.DesiredState.PodTemplate.DesiredState.Manifest).Prefix("desiredState.podTemplate.desiredState.manifest")...) allErrs = append(allErrs, ValidateManifest(&controller.DesiredState.PodTemplate.DesiredState.Manifest).Prefix("desiredState.podTemplate.desiredState.manifest")...)
return allErrs return allErrs

View File

@ -31,6 +31,7 @@ import (
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
apierrs "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/version" "github.com/GoogleCloudPlatform/kubernetes/pkg/version"
@ -331,7 +332,7 @@ func TestGet(t *testing.T) {
func TestGetMissing(t *testing.T) { func TestGetMissing(t *testing.T) {
storage := map[string]RESTStorage{} storage := map[string]RESTStorage{}
simpleStorage := SimpleRESTStorage{ simpleStorage := SimpleRESTStorage{
errors: map[string]error{"get": NewNotFoundErr("simple", "id")}, errors: map[string]error{"get": apierrs.NewNotFound("simple", "id")},
} }
storage["simple"] = &simpleStorage storage["simple"] = &simpleStorage
handler := Handle(storage, codec, "/prefix/version") handler := Handle(storage, codec, "/prefix/version")
@ -371,7 +372,7 @@ func TestDeleteMissing(t *testing.T) {
storage := map[string]RESTStorage{} storage := map[string]RESTStorage{}
ID := "id" ID := "id"
simpleStorage := SimpleRESTStorage{ simpleStorage := SimpleRESTStorage{
errors: map[string]error{"delete": NewNotFoundErr("simple", ID)}, errors: map[string]error{"delete": apierrs.NewNotFound("simple", ID)},
} }
storage["simple"] = &simpleStorage storage["simple"] = &simpleStorage
handler := Handle(storage, codec, "/prefix/version") handler := Handle(storage, codec, "/prefix/version")
@ -421,7 +422,7 @@ func TestUpdateMissing(t *testing.T) {
storage := map[string]RESTStorage{} storage := map[string]RESTStorage{}
ID := "id" ID := "id"
simpleStorage := SimpleRESTStorage{ simpleStorage := SimpleRESTStorage{
errors: map[string]error{"update": NewNotFoundErr("simple", ID)}, errors: map[string]error{"update": apierrs.NewNotFound("simple", ID)},
} }
storage["simple"] = &simpleStorage storage["simple"] = &simpleStorage
handler := Handle(storage, codec, "/prefix/version") handler := Handle(storage, codec, "/prefix/version")
@ -490,7 +491,7 @@ func TestCreateNotFound(t *testing.T) {
"simple": &SimpleRESTStorage{ "simple": &SimpleRESTStorage{
// storage.Create can fail with not found error in theory. // storage.Create can fail with not found error in theory.
// See https://github.com/GoogleCloudPlatform/kubernetes/pull/486#discussion_r15037092. // See https://github.com/GoogleCloudPlatform/kubernetes/pull/486#discussion_r15037092.
errors: map[string]error{"create": NewNotFoundErr("simple", "id")}, errors: map[string]error{"create": apierrs.NewNotFound("simple", "id")},
}, },
}, codec, "/prefix/version") }, codec, "/prefix/version")
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
@ -597,41 +598,10 @@ func expectApiStatus(t *testing.T, method, url string, data []byte, code int) *a
return &status return &status
} }
func TestErrorsToAPIStatus(t *testing.T) {
cases := map[error]api.Status{
NewAlreadyExistsErr("foo", "bar"): {
Status: api.StatusFailure,
Code: http.StatusConflict,
Reason: "already_exists",
Message: "foo \"bar\" already exists",
Details: &api.StatusDetails{
Kind: "foo",
ID: "bar",
},
},
NewConflictErr("foo", "bar", errors.New("failure")): {
Status: api.StatusFailure,
Code: http.StatusConflict,
Reason: "conflict",
Message: "foo \"bar\" cannot be updated: failure",
Details: &api.StatusDetails{
Kind: "foo",
ID: "bar",
},
},
}
for k, v := range cases {
actual := errToAPIStatus(k)
if !reflect.DeepEqual(actual, &v) {
t.Errorf("Expected %#v, Got %#v", v, actual)
}
}
}
func TestAsyncDelayReturnsError(t *testing.T) { func TestAsyncDelayReturnsError(t *testing.T) {
storage := SimpleRESTStorage{ storage := SimpleRESTStorage{
injectedFunction: func(obj interface{}) (interface{}, error) { injectedFunction: func(obj interface{}) (interface{}, error) {
return nil, NewAlreadyExistsErr("foo", "bar") return nil, apierrs.NewAlreadyExists("foo", "bar")
}, },
} }
handler := Handle(map[string]RESTStorage{"foo": &storage}, codec, "/prefix/version") handler := Handle(map[string]RESTStorage{"foo": &storage}, codec, "/prefix/version")
@ -649,7 +619,7 @@ func TestAsyncCreateError(t *testing.T) {
storage := SimpleRESTStorage{ storage := SimpleRESTStorage{
injectedFunction: func(obj interface{}) (interface{}, error) { injectedFunction: func(obj interface{}) (interface{}, error) {
<-ch <-ch
return nil, NewAlreadyExistsErr("foo", "bar") return nil, apierrs.NewAlreadyExists("foo", "bar")
}, },
} }
handler := Handle(map[string]RESTStorage{"foo": &storage}, codec, "/prefix/version") handler := Handle(map[string]RESTStorage{"foo": &storage}, codec, "/prefix/version")
@ -673,7 +643,7 @@ func TestAsyncCreateError(t *testing.T) {
time.Sleep(time.Millisecond) time.Sleep(time.Millisecond)
finalStatus := expectApiStatus(t, "GET", fmt.Sprintf("%s/prefix/version/operations/%s?after=1", server.URL, status.Details.ID), []byte{}, http.StatusOK) finalStatus := expectApiStatus(t, "GET", fmt.Sprintf("%s/prefix/version/operations/%s?after=1", server.URL, status.Details.ID), []byte{}, http.StatusOK)
expectedErr := NewAlreadyExistsErr("foo", "bar") expectedErr := apierrs.NewAlreadyExists("foo", "bar")
expectedStatus := &api.Status{ expectedStatus := &api.Status{
Status: api.StatusFailure, Status: api.StatusFailure,
Code: http.StatusConflict, Code: http.StatusConflict,

View File

@ -21,120 +21,19 @@ import (
"net/http" "net/http"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools" "github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
) )
// apiServerError is an error intended for consumption by a REST API server. // statusError is an object that can be converted into an api.Status
type apiServerError struct { type statusError interface {
api.Status Status() api.Status
}
// Error implements the Error interface.
func (e *apiServerError) Error() string {
return e.Status.Message
}
// NewNotFoundErr returns a new error which indicates that the resource of the kind and the name was not found.
func NewNotFoundErr(kind, name string) error {
return &apiServerError{api.Status{
Status: api.StatusFailure,
Code: http.StatusNotFound,
Reason: api.StatusReasonNotFound,
Details: &api.StatusDetails{
Kind: kind,
ID: name,
},
Message: fmt.Sprintf("%s %q not found", kind, name),
}}
}
// NewAlreadyExistsErr returns an error indicating the item requested exists by that identifier.
func NewAlreadyExistsErr(kind, name string) error {
return &apiServerError{api.Status{
Status: api.StatusFailure,
Code: http.StatusConflict,
Reason: api.StatusReasonAlreadyExists,
Details: &api.StatusDetails{
Kind: kind,
ID: name,
},
Message: fmt.Sprintf("%s %q already exists", kind, name),
}}
}
// NewConflictErr returns an error indicating the item can't be updated as provided.
func NewConflictErr(kind, name string, err error) error {
return &apiServerError{api.Status{
Status: api.StatusFailure,
Code: http.StatusConflict,
Reason: api.StatusReasonConflict,
Details: &api.StatusDetails{
Kind: kind,
ID: name,
},
Message: fmt.Sprintf("%s %q cannot be updated: %s", kind, name, err),
}}
}
// NewInvalidErr returns an error indicating the item is invalid and cannot be processed.
func NewInvalidErr(kind, name string, errs errors.ErrorList) error {
causes := make([]api.StatusCause, 0, len(errs))
for i := range errs {
if err, ok := errs[i].(errors.ValidationError); ok {
causes = append(causes, api.StatusCause{
Type: api.CauseType(err.Type),
Message: err.Error(),
Field: err.Field,
})
}
}
return &apiServerError{api.Status{
Status: api.StatusFailure,
Code: 422, // RFC 4918
Reason: api.StatusReasonInvalid,
Details: &api.StatusDetails{
Kind: kind,
ID: name,
Causes: causes,
},
Message: fmt.Sprintf("%s %q is invalid: %s", kind, name, errs.ToError()),
}}
}
// IsNotFound returns true if the specified error was created by NewNotFoundErr.
func IsNotFound(err error) bool {
return reasonForError(err) == api.StatusReasonNotFound
}
// IsAlreadyExists determines if the err is an error which indicates that a specified resource already exists.
func IsAlreadyExists(err error) bool {
return reasonForError(err) == api.StatusReasonAlreadyExists
}
// IsConflict determines if the err is an error which indicates the provided update conflicts.
func IsConflict(err error) bool {
return reasonForError(err) == api.StatusReasonConflict
}
// IsInvalid determines if the err is an error which indicates the provided resource is not valid.
func IsInvalid(err error) bool {
return reasonForError(err) == api.StatusReasonInvalid
}
func reasonForError(err error) api.StatusReason {
switch t := err.(type) {
case *apiServerError:
return t.Status.Reason
}
return api.StatusReasonUnknown
} }
// errToAPIStatus converts an error to an api.Status object. // errToAPIStatus converts an error to an api.Status object.
func errToAPIStatus(err error) *api.Status { func errToAPIStatus(err error) *api.Status {
switch t := err.(type) { switch t := err.(type) {
case *apiServerError: case statusError:
status := t.Status status := t.Status()
status.Status = api.StatusFailure status.Status = api.StatusFailure
//TODO: check for invalid responses //TODO: check for invalid responses
return &status return &status

View File

@ -17,126 +17,50 @@ limitations under the License.
package apiserver package apiserver
import ( import (
"errors" stderrs "errors"
"fmt" "net/http"
"reflect" "reflect"
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
apierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
) )
func TestErrorNew(t *testing.T) {
err := NewAlreadyExistsErr("test", "1")
if !IsAlreadyExists(err) {
t.Errorf("expected to be already_exists")
}
if IsConflict(err) {
t.Errorf("expected to not be confict")
}
if IsNotFound(err) {
t.Errorf(fmt.Sprintf("expected to not be %s", api.StatusReasonNotFound))
}
if IsInvalid(err) {
t.Errorf("expected to not be invalid")
}
if !IsConflict(NewConflictErr("test", "2", errors.New("message"))) {
t.Errorf("expected to be conflict")
}
if !IsNotFound(NewNotFoundErr("test", "3")) {
t.Errorf("expected to be not found")
}
if !IsInvalid(NewInvalidErr("test", "2", nil)) {
t.Errorf("expected to be invalid")
}
}
func TestNewInvalidErr(t *testing.T) {
testCases := []struct {
Err apierrors.ValidationError
Details *api.StatusDetails
}{
{
apierrors.NewDuplicate("field[0].name", "bar"),
&api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueDuplicate,
Field: "field[0].name",
}},
},
},
{
apierrors.NewInvalid("field[0].name", "bar"),
&api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueInvalid,
Field: "field[0].name",
}},
},
},
{
apierrors.NewNotFound("field[0].name", "bar"),
&api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueNotFound,
Field: "field[0].name",
}},
},
},
{
apierrors.NewNotSupported("field[0].name", "bar"),
&api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueNotSupported,
Field: "field[0].name",
}},
},
},
{
apierrors.NewRequired("field[0].name", "bar"),
&api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueRequired,
Field: "field[0].name",
}},
},
},
}
for i := range testCases {
vErr, expected := testCases[i].Err, testCases[i].Details
expected.Causes[0].Message = vErr.Error()
err := NewInvalidErr("kind", "name", apierrors.ErrorList{vErr})
status := errToAPIStatus(err)
if status.Code != 422 || status.Reason != api.StatusReasonInvalid {
t.Errorf("unexpected status: %#v", status)
}
if !reflect.DeepEqual(expected, status.Details) {
t.Errorf("expected %#v, got %#v", expected, status.Details)
}
}
}
func Test_errToAPIStatus(t *testing.T) { func Test_errToAPIStatus(t *testing.T) {
err := &apiServerError{} err := errors.NewNotFound("foo", "bar")
status := errToAPIStatus(err) status := errToAPIStatus(err)
if status.Reason != api.StatusReasonUnknown || status.Status != api.StatusFailure { if status.Reason != api.StatusReasonNotFound || status.Status != api.StatusFailure {
t.Errorf("unexpected status object: %#v", status) t.Errorf("unexpected status object: %#v", status)
} }
} }
func Test_reasonForError(t *testing.T) { func TestErrorsToAPIStatus(t *testing.T) {
if e, a := api.StatusReasonUnknown, reasonForError(nil); e != a { cases := map[error]api.Status{
t.Errorf("unexpected reason type: %#v", a) errors.NewAlreadyExists("foo", "bar"): {
Status: api.StatusFailure,
Code: http.StatusConflict,
Reason: "already_exists",
Message: "foo \"bar\" already exists",
Details: &api.StatusDetails{
Kind: "foo",
ID: "bar",
},
},
errors.NewConflict("foo", "bar", stderrs.New("failure")): {
Status: api.StatusFailure,
Code: http.StatusConflict,
Reason: "conflict",
Message: "foo \"bar\" cannot be updated: failure",
Details: &api.StatusDetails{
Kind: "foo",
ID: "bar",
},
},
}
for k, v := range cases {
actual := errToAPIStatus(k)
if !reflect.DeepEqual(actual, &v) {
t.Errorf("%s: Expected %#v, Got %#v", k, v, actual)
}
} }
} }

View File

@ -251,7 +251,7 @@ func filterInvalidPods(pods []kubelet.Pod, source string) (filtered []*kubelet.P
for i := range pods { for i := range pods {
var errors []error var errors []error
if names.Has(pods[i].Name) { if names.Has(pods[i].Name) {
errors = append(errors, apierrs.NewDuplicate("Pod.Name", pods[i].Name)) errors = append(errors, apierrs.NewFieldDuplicate("name", pods[i].Name))
} else { } else {
names.Insert(pods[i].Name) names.Insert(pods[i].Name)
} }

View File

@ -24,7 +24,7 @@ import (
func ValidatePod(pod *Pod) (errors []error) { func ValidatePod(pod *Pod) (errors []error) {
if !util.IsDNSSubdomain(pod.Name) { if !util.IsDNSSubdomain(pod.Name) {
errors = append(errors, apierrs.NewInvalid("Pod.Name", pod.Name)) errors = append(errors, apierrs.NewFieldInvalid("name", pod.Name))
} }
if errs := validation.ValidateManifest(&pod.Manifest); len(errs) != 0 { if errs := validation.ValidateManifest(&pod.Manifest); len(errs) != 0 {
errors = append(errors, errs...) errors = append(errors, errs...)

View File

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
) )
@ -40,17 +41,17 @@ func NewBindingStorage(bindingRegistry Registry) *BindingStorage {
// List returns an error because bindings are write-only objects. // List returns an error because bindings are write-only objects.
func (*BindingStorage) List(selector labels.Selector) (interface{}, error) { func (*BindingStorage) List(selector labels.Selector) (interface{}, error) {
return nil, apiserver.NewNotFoundErr("binding", "list") return nil, errors.NewNotFound("binding", "list")
} }
// Get returns an error because bindings are write-only objects. // Get returns an error because bindings are write-only objects.
func (*BindingStorage) Get(id string) (interface{}, error) { func (*BindingStorage) Get(id string) (interface{}, error) {
return nil, apiserver.NewNotFoundErr("binding", id) return nil, errors.NewNotFound("binding", id)
} }
// Delete returns an error because bindings are write-only objects. // Delete returns an error because bindings are write-only objects.
func (*BindingStorage) Delete(id string) (<-chan interface{}, error) { func (*BindingStorage) Delete(id string) (<-chan interface{}, error) {
return nil, apiserver.NewNotFoundErr("binding", id) return nil, errors.NewNotFound("binding", id)
} }
// New returns a new binding object fit for having data unmarshalled into it. // New returns a new binding object fit for having data unmarshalled into it.

View File

@ -21,6 +21,7 @@ import (
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
@ -61,7 +62,7 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
// Pod Manifest ID should be assigned by the pod API // Pod Manifest ID should be assigned by the pod API
controller.DesiredState.PodTemplate.DesiredState.Manifest.ID = "" controller.DesiredState.PodTemplate.DesiredState.Manifest.ID = ""
if errs := validation.ValidateReplicationController(controller); len(errs) > 0 { if errs := validation.ValidateReplicationController(controller); len(errs) > 0 {
return nil, apiserver.NewInvalidErr("replicationController", controller.ID, errs) return nil, errors.NewInvalid("replicationController", controller.ID, errs)
} }
controller.CreationTimestamp = util.Now() controller.CreationTimestamp = util.Now()
@ -120,7 +121,7 @@ func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
return nil, fmt.Errorf("not a replication controller: %#v", obj) return nil, fmt.Errorf("not a replication controller: %#v", obj)
} }
if errs := validation.ValidateReplicationController(controller); len(errs) > 0 { if errs := validation.ValidateReplicationController(controller); len(errs) > 0 {
return nil, apiserver.NewInvalidErr("replicationController", controller.ID, errs) return nil, errors.NewInvalid("replicationController", controller.ID, errs)
} }
return apiserver.MakeAsync(func() (interface{}, error) { return apiserver.MakeAsync(func() (interface{}, error) {
err := rs.registry.UpdateController(*controller) err := rs.registry.UpdateController(*controller)

View File

@ -25,7 +25,7 @@ import (
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
@ -280,7 +280,7 @@ func TestControllerStorageValidatesCreate(t *testing.T) {
if c != nil { if c != nil {
t.Errorf("Expected nil channel") t.Errorf("Expected nil channel")
} }
if !apiserver.IsInvalid(err) { if !errors.IsInvalid(err) {
t.Errorf("Expected to get an invalid resource error, got %v", err) t.Errorf("Expected to get an invalid resource error, got %v", err)
} }
} }
@ -310,7 +310,7 @@ func TestControllerStorageValidatesUpdate(t *testing.T) {
if c != nil { if c != nil {
t.Errorf("Expected nil channel") t.Errorf("Expected nil channel")
} }
if !apiserver.IsInvalid(err) { if !errors.IsInvalid(err) {
t.Errorf("Expected to get an invalid resource error, got %v", err) t.Errorf("Expected to get an invalid resource error, got %v", err)
} }
} }

View File

@ -21,7 +21,7 @@ import (
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
) )
@ -45,13 +45,13 @@ func TestGetEndpoints(t *testing.T) {
func TestGetEndpointsMissingService(t *testing.T) { func TestGetEndpointsMissingService(t *testing.T) {
registry := &registrytest.ServiceRegistry{ registry := &registrytest.ServiceRegistry{
Err: apiserver.NewNotFoundErr("service", "foo"), Err: errors.NewNotFound("service", "foo"),
} }
storage := NewStorage(registry) storage := NewStorage(registry)
// returns service not found // returns service not found
_, err := storage.Get("foo") _, err := storage.Get("foo")
if !apiserver.IsNotFound(err) || !reflect.DeepEqual(err, apiserver.NewNotFoundErr("service", "foo")) { if !errors.IsNotFound(err) || !reflect.DeepEqual(err, errors.NewNotFound("service", "foo")) {
t.Errorf("expected NotFound error, got %#v", err) t.Errorf("expected NotFound error, got %#v", err)
} }

View File

@ -20,7 +20,7 @@ import (
"fmt" "fmt"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/constraint" "github.com/GoogleCloudPlatform/kubernetes/pkg/constraint"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
@ -184,7 +184,7 @@ func (r *Registry) DeletePod(podID string) error {
podKey := makePodKey(podID) podKey := makePodKey(podID)
err := r.ExtractObj(podKey, &pod, false) err := r.ExtractObj(podKey, &pod, false)
if tools.IsEtcdNotFound(err) { if tools.IsEtcdNotFound(err) {
return apiserver.NewNotFoundErr("pod", podID) return errors.NewNotFound("pod", podID)
} }
if err != nil { if err != nil {
return err return err
@ -193,7 +193,7 @@ func (r *Registry) DeletePod(podID string) error {
// machine and attempt to put it somewhere. // machine and attempt to put it somewhere.
err = r.Delete(podKey, true) err = r.Delete(podKey, true)
if tools.IsEtcdNotFound(err) { if tools.IsEtcdNotFound(err) {
return apiserver.NewNotFoundErr("pod", podID) return errors.NewNotFound("pod", podID)
} }
if err != nil { if err != nil {
return err return err
@ -249,7 +249,7 @@ func (r *Registry) GetController(controllerID string) (*api.ReplicationControlle
key := makeControllerKey(controllerID) key := makeControllerKey(controllerID)
err := r.ExtractObj(key, &controller, false) err := r.ExtractObj(key, &controller, false)
if tools.IsEtcdNotFound(err) { if tools.IsEtcdNotFound(err) {
return nil, apiserver.NewNotFoundErr("replicationController", controllerID) return nil, errors.NewNotFound("replicationController", controllerID)
} }
if err != nil { if err != nil {
return nil, err return nil, err
@ -261,7 +261,7 @@ func (r *Registry) GetController(controllerID string) (*api.ReplicationControlle
func (r *Registry) CreateController(controller api.ReplicationController) error { func (r *Registry) CreateController(controller api.ReplicationController) error {
err := r.CreateObj(makeControllerKey(controller.ID), controller) err := r.CreateObj(makeControllerKey(controller.ID), controller)
if tools.IsEtcdNodeExist(err) { if tools.IsEtcdNodeExist(err) {
return apiserver.NewAlreadyExistsErr("replicationController", controller.ID) return errors.NewAlreadyExists("replicationController", controller.ID)
} }
return err return err
} }
@ -276,7 +276,7 @@ func (r *Registry) DeleteController(controllerID string) error {
key := makeControllerKey(controllerID) key := makeControllerKey(controllerID)
err := r.Delete(key, false) err := r.Delete(key, false)
if tools.IsEtcdNotFound(err) { if tools.IsEtcdNotFound(err) {
return apiserver.NewNotFoundErr("replicationController", controllerID) return errors.NewNotFound("replicationController", controllerID)
} }
return err return err
} }
@ -296,7 +296,7 @@ func (r *Registry) ListServices() (*api.ServiceList, error) {
func (r *Registry) CreateService(svc api.Service) error { func (r *Registry) CreateService(svc api.Service) error {
err := r.CreateObj(makeServiceKey(svc.ID), svc) err := r.CreateObj(makeServiceKey(svc.ID), svc)
if tools.IsEtcdNodeExist(err) { if tools.IsEtcdNodeExist(err) {
return apiserver.NewAlreadyExistsErr("service", svc.ID) return errors.NewAlreadyExists("service", svc.ID)
} }
return err return err
} }
@ -307,7 +307,7 @@ func (r *Registry) GetService(name string) (*api.Service, error) {
var svc api.Service var svc api.Service
err := r.ExtractObj(key, &svc, false) err := r.ExtractObj(key, &svc, false)
if tools.IsEtcdNotFound(err) { if tools.IsEtcdNotFound(err) {
return nil, apiserver.NewNotFoundErr("service", name) return nil, errors.NewNotFound("service", name)
} }
if err != nil { if err != nil {
return nil, err return nil, err
@ -321,7 +321,7 @@ func (r *Registry) GetEndpoints(name string) (*api.Endpoints, error) {
var endpoints api.Endpoints var endpoints api.Endpoints
err := r.ExtractObj(key, &endpoints, false) err := r.ExtractObj(key, &endpoints, false)
if tools.IsEtcdNotFound(err) { if tools.IsEtcdNotFound(err) {
return nil, apiserver.NewNotFoundErr("endpoints", name) return nil, errors.NewNotFound("endpoints", name)
} }
if err != nil { if err != nil {
return nil, err return nil, err
@ -338,7 +338,7 @@ func (r *Registry) DeleteService(name string) error {
key := makeServiceKey(name) key := makeServiceKey(name)
err := r.Delete(key, true) err := r.Delete(key, true)
if tools.IsEtcdNotFound(err) { if tools.IsEtcdNotFound(err) {
return apiserver.NewNotFoundErr("service", name) return errors.NewNotFound("service", name)
} }
if err != nil { if err != nil {
return err return err

View File

@ -21,8 +21,8 @@ import (
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" _ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
@ -627,7 +627,7 @@ func TestEtcdCreateControllerAlreadyExisting(t *testing.T) {
ID: "foo", ID: "foo",
}, },
}) })
if !apiserver.IsAlreadyExists(err) { if !errors.IsAlreadyExists(err) {
t.Errorf("expected already exists err, got %#v", err) t.Errorf("expected already exists err, got %#v", err)
} }
} }
@ -716,7 +716,7 @@ func TestEtcdCreateServiceAlreadyExisting(t *testing.T) {
err := registry.CreateService(api.Service{ err := registry.CreateService(api.Service{
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
}) })
if !apiserver.IsAlreadyExists(err) { if !errors.IsAlreadyExists(err) {
t.Errorf("expected already exists err, got %#v", err) t.Errorf("expected already exists err, got %#v", err)
} }
} }

View File

@ -23,6 +23,7 @@ import (
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
@ -70,7 +71,7 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
} }
pod.DesiredState.Manifest.ID = pod.ID pod.DesiredState.Manifest.ID = pod.ID
if errs := validation.ValidatePod(pod); len(errs) > 0 { if errs := validation.ValidatePod(pod); len(errs) > 0 {
return nil, apiserver.NewInvalidErr("pod", pod.ID, errs) return nil, errors.NewInvalid("pod", pod.ID, errs)
} }
pod.CreationTimestamp = util.Now() pod.CreationTimestamp = util.Now()
@ -137,7 +138,7 @@ func (rs RegistryStorage) New() interface{} {
func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) { func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
pod := obj.(*api.Pod) pod := obj.(*api.Pod)
if errs := validation.ValidatePod(pod); len(errs) > 0 { if errs := validation.ValidatePod(pod); len(errs) > 0 {
return nil, apiserver.NewInvalidErr("pod", pod.ID, errs) return nil, errors.NewInvalid("pod", pod.ID, errs)
} }
return apiserver.MakeAsync(func() (interface{}, error) { return apiserver.MakeAsync(func() (interface{}, error) {
if err := rs.registry.UpdatePod(*pod); err != nil { if err := rs.registry.UpdatePod(*pod); err != nil {

View File

@ -23,7 +23,7 @@ import (
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/fake" "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/fake"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest" "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
@ -337,7 +337,7 @@ func TestPodStorageValidatesCreate(t *testing.T) {
if c != nil { if c != nil {
t.Errorf("Expected nil channel") t.Errorf("Expected nil channel")
} }
if !apiserver.IsInvalid(err) { if !errors.IsInvalid(err) {
t.Errorf("Expected to get an invalid resource error, got %v", err) t.Errorf("Expected to get an invalid resource error, got %v", err)
} }
} }
@ -353,7 +353,7 @@ func TestPodStorageValidatesUpdate(t *testing.T) {
if c != nil { if c != nil {
t.Errorf("Expected nil channel") t.Errorf("Expected nil channel")
} }
if !apiserver.IsInvalid(err) { if !errors.IsInvalid(err) {
t.Errorf("Expected to get an invalid resource error, got %v", err) t.Errorf("Expected to get an invalid resource error, got %v", err)
} }
} }

View File

@ -23,6 +23,7 @@ import (
"strings" "strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider" "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
@ -51,7 +52,7 @@ func NewRegistryStorage(registry Registry, cloud cloudprovider.Interface, machin
func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) { func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
srv := obj.(*api.Service) srv := obj.(*api.Service)
if errs := validation.ValidateService(srv); len(errs) > 0 { if errs := validation.ValidateService(srv); len(errs) > 0 {
return nil, apiserver.NewInvalidErr("service", srv.ID, errs) return nil, errors.NewInvalid("service", srv.ID, errs)
} }
srv.CreationTimestamp = util.Now() srv.CreationTimestamp = util.Now()
@ -157,7 +158,7 @@ func GetServiceEnvironmentVariables(registry Registry, machine string) ([]api.En
func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) { func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
srv := obj.(*api.Service) srv := obj.(*api.Service)
if errs := validation.ValidateService(srv); len(errs) > 0 { if errs := validation.ValidateService(srv); len(errs) > 0 {
return nil, apiserver.NewInvalidErr("service", srv.ID, errs) return nil, errors.NewInvalid("service", srv.ID, errs)
} }
return apiserver.MakeAsync(func() (interface{}, error) { return apiserver.MakeAsync(func() (interface{}, error) {
// TODO: check to see if external load balancer status changed // TODO: check to see if external load balancer status changed

View File

@ -21,6 +21,7 @@ import (
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
cloud "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/fake" cloud "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/fake"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
@ -79,7 +80,7 @@ func TestServiceStorageValidatesCreate(t *testing.T) {
if c != nil { if c != nil {
t.Errorf("Expected nil channel") t.Errorf("Expected nil channel")
} }
if !apiserver.IsInvalid(err) { if !errors.IsInvalid(err) {
t.Errorf("Expected to get an invalid resource error, got %v", err) t.Errorf("Expected to get an invalid resource error, got %v", err)
} }
@ -140,7 +141,7 @@ func TestServiceStorageValidatesUpdate(t *testing.T) {
if c != nil { if c != nil {
t.Errorf("Expected nil channel") t.Errorf("Expected nil channel")
} }
if !apiserver.IsInvalid(err) { if !errors.IsInvalid(err) {
t.Errorf("Expected to get an invalid resource error, got %v", err) t.Errorf("Expected to get an invalid resource error, got %v", err)
} }
} }