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 (
"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
// 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 ""
}
// statusError is an error intended for consumption by a REST API server.
type statusError struct {
status api.Status
}
// ValidationError is an implementation of the 'error' interface, which represents an error of validation.
type ValidationError struct {
Type ValidationErrorType
Field string
BadValue interface{}
// Error implements the Error interface.
func (e *statusError) Error() string {
return e.status.Message
}
func (v ValidationError) Error() string {
return fmt.Sprintf("%s: %v '%v'", v.Field, ValueOf(v.Type), v.BadValue)
// Status converts this error into an api.Status object.
func (e *statusError) Status() api.Status {
return e.status
}
// NewInvalid returns a ValidationError indicating "value required"
func NewRequired(field string, value interface{}) ValidationError {
return ValidationError{ValidationErrorTypeRequired, field, value}
// 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 {
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"
func NewInvalid(field string, value interface{}) ValidationError {
return ValidationError{ValidationErrorTypeInvalid, field, value}
// NewAlreadyExists returns an error indicating the item requested exists by that identifier.
func NewAlreadyExists(kind, name string) error {
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"
func NewNotSupported(field string, value interface{}) ValidationError {
return ValidationError{ValidationErrorTypeNotSupported, field, value}
// NewConflict returns an error indicating the item can't be updated as provided.
func NewConflict(kind, name string, err error) error {
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"
func NewDuplicate(field string, value interface{}) ValidationError {
return ValidationError{ValidationErrorTypeDuplicate, field, value}
}
// NewNotFound returns a ValidationError indicating "value not found"
func NewNotFound(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
// NewInvalid returns an error indicating the item is invalid and cannot be processed.
func NewInvalid(kind, name string, errs ErrorList) error {
causes := make([]api.StatusCause, 0, len(errs))
for i := range errs {
if err, ok := errs[i].(ValidationError); ok {
causes = append(causes, api.StatusCause{
Type: api.CauseType(err.Type),
Message: err.Error(),
Field: err.Field,
})
}
}
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
// the list for convenience.
func (list ErrorList) PrefixIndex(index int) ErrorList {
return list.Prefix(fmt.Sprintf("[%d]", index))
// 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 *statusError:
return t.status.Reason
}
return api.StatusReasonUnknown
}

View File

@ -17,147 +17,117 @@ limitations under the License.
package errors
import (
"errors"
"fmt"
"strings"
"reflect"
"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 {
fn func() ValidationError
expected ValidationErrorType
Err ValidationError
Details *api.StatusDetails
}{
{
func() ValidationError { return NewInvalid("f", "v") },
ValidationErrorTypeInvalid,
NewFieldDuplicate("field[0].name", "bar"),
&api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueDuplicate,
Field: "field[0].name",
}},
},
},
{
func() ValidationError { return NewNotSupported("f", "v") },
ValidationErrorTypeNotSupported,
NewFieldInvalid("field[0].name", "bar"),
&api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueInvalid,
Field: "field[0].name",
}},
},
},
{
func() ValidationError { return NewDuplicate("f", "v") },
ValidationErrorTypeDuplicate,
NewFieldNotFound("field[0].name", "bar"),
&api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueNotFound,
Field: "field[0].name",
}},
},
},
{
func() ValidationError { return NewNotFound("f", "v") },
ValidationErrorTypeNotFound,
NewFieldNotSupported("field[0].name", "bar"),
&api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueNotSupported,
Field: "field[0].name",
}},
},
},
{
func() ValidationError { return NewRequired("f", "v") },
ValidationErrorTypeRequired,
NewFieldRequired("field[0].name", "bar"),
&api.StatusDetails{
Kind: "kind",
ID: "name",
Causes: []api.StatusCause{{
Type: api.CauseTypeFieldValueRequired,
Field: "field[0].name",
}},
},
},
}
for _, testCase := range testCases {
err := testCase.fn()
if err.Type != testCase.expected {
t.Errorf("expected Type %q, got %q", testCase.expected, err.Type)
for i, testCase := range testCases {
vErr, expected := testCase.Err, testCase.Details
expected.Causes[0].Message = vErr.Error()
err := NewInvalid("kind", "name", ErrorList{vErr})
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) {
s := NewInvalid("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, 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)
}
func Test_reasonForError(t *testing.T) {
if e, a := api.StatusReasonUnknown, reasonForError(nil); e != a {
t.Errorf("unexpected reason type: %#v", 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")
}
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) {
el = append(el, errs.NewInvalid("name", vol.Name))
el = append(el, errs.NewFieldInvalid("name", 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 {
allNames.Insert(vol.Name)
@ -64,7 +64,7 @@ func validateSource(source *api.VolumeSource) errs.ErrorList {
//EmptyDirs have nothing to validate
}
if numVolumes != 1 {
allErrs = append(allErrs, errs.NewInvalid("", source))
allErrs = append(allErrs, errs.NewFieldInvalid("", source))
}
return allErrs
}
@ -88,25 +88,25 @@ func validatePorts(ports []api.Port) errs.ErrorList {
port := &ports[i] // so we can set default values
if len(port.Name) > 0 {
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) {
pErrs = append(pErrs, errs.NewDuplicate("name", port.Name))
pErrs = append(pErrs, errs.NewFieldDuplicate("name", port.Name))
} else {
allNames.Insert(port.Name)
}
}
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) {
pErrs = append(pErrs, errs.NewInvalid("containerPort", port.ContainerPort))
pErrs = append(pErrs, errs.NewFieldInvalid("containerPort", port.ContainerPort))
}
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 {
port.Protocol = "TCP"
} 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)...)
}
@ -120,10 +120,10 @@ func validateEnv(vars []api.EnvVar) errs.ErrorList {
vErrs := errs.ErrorList{}
ev := &vars[i] // so we can set default values
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) {
vErrs = append(vErrs, errs.NewInvalid("name", ev.Name))
vErrs = append(vErrs, errs.NewFieldInvalid("name", ev.Name))
}
allErrs = append(allErrs, vErrs.PrefixIndex(i)...)
}
@ -137,12 +137,12 @@ func validateVolumeMounts(mounts []api.VolumeMount, volumes util.StringSet) errs
mErrs := errs.ErrorList{}
mnt := &mounts[i] // so we can set default values
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) {
mErrs = append(mErrs, errs.NewNotFound("name", mnt.Name))
}
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)...)
}
@ -163,7 +163,7 @@ func AccumulateUniquePorts(containers []api.Container, accumulator map[int]bool,
continue
}
if accumulator[port] {
cErrs = append(cErrs, errs.NewDuplicate("Port", port))
cErrs = append(cErrs, errs.NewFieldDuplicate("Port", port))
} else {
accumulator[port] = true
}
@ -188,16 +188,16 @@ func validateContainers(containers []api.Container, volumes util.StringSet) errs
cErrs := errs.ErrorList{}
ctr := &containers[i] // so we can set default values
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) {
cErrs = append(cErrs, errs.NewInvalid("name", ctr.Name))
cErrs = append(cErrs, errs.NewFieldInvalid("name", 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 {
allNames.Insert(ctr.Name)
}
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, validateEnv(ctr.Env).Prefix("env")...)
@ -224,9 +224,9 @@ func ValidateManifest(manifest *api.ContainerManifest) errs.ErrorList {
allErrs := errs.ErrorList{}
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)) {
allErrs = append(allErrs, errs.NewNotSupported("version", manifest.Version))
allErrs = append(allErrs, errs.NewFieldNotSupported("version", manifest.Version))
}
allVolumes, errs := validateVolumes(manifest.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 &&
podState.RestartPolicy.Type != api.RestartOnFailure &&
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
@ -251,7 +251,7 @@ func ValidatePodState(podState *api.PodState) errs.ErrorList {
func ValidatePod(pod *api.Pod) errs.ErrorList {
allErrs := errs.ErrorList{}
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")...)
return allErrs
@ -261,15 +261,15 @@ func ValidatePod(pod *api.Pod) errs.ErrorList {
func ValidateService(service *api.Service) errs.ErrorList {
allErrs := errs.ErrorList{}
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) {
allErrs = append(allErrs, errs.NewInvalid("id", service.ID))
allErrs = append(allErrs, errs.NewFieldInvalid("id", service.ID))
}
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() {
allErrs = append(allErrs, errs.NewRequired("selector", service.Selector))
allErrs = append(allErrs, errs.NewFieldRequired("selector", service.Selector))
}
return allErrs
}
@ -278,18 +278,18 @@ func ValidateService(service *api.Service) errs.ErrorList {
func ValidateReplicationController(controller *api.ReplicationController) errs.ErrorList {
allErrs := errs.ErrorList{}
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() {
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()
labels := labels.Set(controller.DesiredState.PodTemplate.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 {
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")...)
return allErrs

View File

@ -31,6 +31,7 @@ import (
"time"
"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/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
@ -331,7 +332,7 @@ func TestGet(t *testing.T) {
func TestGetMissing(t *testing.T) {
storage := map[string]RESTStorage{}
simpleStorage := SimpleRESTStorage{
errors: map[string]error{"get": NewNotFoundErr("simple", "id")},
errors: map[string]error{"get": apierrs.NewNotFound("simple", "id")},
}
storage["simple"] = &simpleStorage
handler := Handle(storage, codec, "/prefix/version")
@ -371,7 +372,7 @@ func TestDeleteMissing(t *testing.T) {
storage := map[string]RESTStorage{}
ID := "id"
simpleStorage := SimpleRESTStorage{
errors: map[string]error{"delete": NewNotFoundErr("simple", ID)},
errors: map[string]error{"delete": apierrs.NewNotFound("simple", ID)},
}
storage["simple"] = &simpleStorage
handler := Handle(storage, codec, "/prefix/version")
@ -421,7 +422,7 @@ func TestUpdateMissing(t *testing.T) {
storage := map[string]RESTStorage{}
ID := "id"
simpleStorage := SimpleRESTStorage{
errors: map[string]error{"update": NewNotFoundErr("simple", ID)},
errors: map[string]error{"update": apierrs.NewNotFound("simple", ID)},
}
storage["simple"] = &simpleStorage
handler := Handle(storage, codec, "/prefix/version")
@ -490,7 +491,7 @@ func TestCreateNotFound(t *testing.T) {
"simple": &SimpleRESTStorage{
// storage.Create can fail with not found error in theory.
// 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")
server := httptest.NewServer(handler)
@ -597,41 +598,10 @@ func expectApiStatus(t *testing.T, method, url string, data []byte, code int) *a
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) {
storage := SimpleRESTStorage{
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")
@ -649,7 +619,7 @@ func TestAsyncCreateError(t *testing.T) {
storage := SimpleRESTStorage{
injectedFunction: func(obj interface{}) (interface{}, error) {
<-ch
return nil, NewAlreadyExistsErr("foo", "bar")
return nil, apierrs.NewAlreadyExists("foo", "bar")
},
}
handler := Handle(map[string]RESTStorage{"foo": &storage}, codec, "/prefix/version")
@ -673,7 +643,7 @@ func TestAsyncCreateError(t *testing.T) {
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)
expectedErr := NewAlreadyExistsErr("foo", "bar")
expectedErr := apierrs.NewAlreadyExists("foo", "bar")
expectedStatus := &api.Status{
Status: api.StatusFailure,
Code: http.StatusConflict,

View File

@ -21,120 +21,19 @@ import (
"net/http"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
)
// apiServerError is an error intended for consumption by a REST API server.
type apiServerError struct {
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
// statusError is an object that can be converted into an api.Status
type statusError interface {
Status() api.Status
}
// errToAPIStatus converts an error to an api.Status object.
func errToAPIStatus(err error) *api.Status {
switch t := err.(type) {
case *apiServerError:
status := t.Status
case statusError:
status := t.Status()
status.Status = api.StatusFailure
//TODO: check for invalid responses
return &status

View File

@ -17,126 +17,50 @@ limitations under the License.
package apiserver
import (
"errors"
"fmt"
stderrs "errors"
"net/http"
"reflect"
"testing"
"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) {
err := &apiServerError{}
err := errors.NewNotFound("foo", "bar")
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)
}
}
func Test_reasonForError(t *testing.T) {
if e, a := api.StatusReasonUnknown, reasonForError(nil); e != a {
t.Errorf("unexpected reason type: %#v", a)
func TestErrorsToAPIStatus(t *testing.T) {
cases := map[error]api.Status{
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 {
var errors []error
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 {
names.Insert(pods[i].Name)
}

View File

@ -24,7 +24,7 @@ import (
func ValidatePod(pod *Pod) (errors []error) {
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 {
errors = append(errors, errs...)

View File

@ -20,6 +20,7 @@ import (
"fmt"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"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.
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.
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.
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.

View File

@ -21,6 +21,7 @@ import (
"time"
"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/apiserver"
"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
controller.DesiredState.PodTemplate.DesiredState.Manifest.ID = ""
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()
@ -120,7 +121,7 @@ func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
return nil, fmt.Errorf("not a replication controller: %#v", obj)
}
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) {
err := rs.registry.UpdateController(*controller)

View File

@ -25,7 +25,7 @@ import (
"time"
"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/registry/registrytest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
@ -280,7 +280,7 @@ func TestControllerStorageValidatesCreate(t *testing.T) {
if c != nil {
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)
}
}
@ -310,7 +310,7 @@ func TestControllerStorageValidatesUpdate(t *testing.T) {
if c != nil {
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)
}
}

View File

@ -21,7 +21,7 @@ import (
"testing"
"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/registry/registrytest"
)
@ -45,13 +45,13 @@ func TestGetEndpoints(t *testing.T) {
func TestGetEndpointsMissingService(t *testing.T) {
registry := &registrytest.ServiceRegistry{
Err: apiserver.NewNotFoundErr("service", "foo"),
Err: errors.NewNotFound("service", "foo"),
}
storage := NewStorage(registry)
// returns service not found
_, 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)
}

View File

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

View File

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

View File

@ -23,6 +23,7 @@ import (
"time"
"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/apiserver"
"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
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()
@ -137,7 +138,7 @@ func (rs RegistryStorage) New() interface{} {
func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
pod := obj.(*api.Pod)
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) {
if err := rs.registry.UpdatePod(*pod); err != nil {

View File

@ -23,7 +23,7 @@ import (
"time"
"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/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
@ -337,7 +337,7 @@ func TestPodStorageValidatesCreate(t *testing.T) {
if c != nil {
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)
}
}
@ -353,7 +353,7 @@ func TestPodStorageValidatesUpdate(t *testing.T) {
if c != nil {
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)
}
}

View File

@ -23,6 +23,7 @@ import (
"strings"
"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/apiserver"
"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) {
srv := obj.(*api.Service)
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()
@ -157,7 +158,7 @@ func GetServiceEnvironmentVariables(registry Registry, machine string) ([]api.En
func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) {
srv := obj.(*api.Service)
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) {
// TODO: check to see if external load balancer status changed

View File

@ -21,6 +21,7 @@ import (
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
cloud "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/fake"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
@ -79,7 +80,7 @@ func TestServiceStorageValidatesCreate(t *testing.T) {
if c != nil {
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)
}
@ -140,7 +141,7 @@ func TestServiceStorageValidatesUpdate(t *testing.T) {
if c != nil {
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)
}
}