Commit 1c72ba68 authored by k8s-merge-robot's avatar k8s-merge-robot Committed by GitHub

Merge pull request #29520 from hongchaodeng/serr

Automatic merge from submit-queue storage error: precondition failure should return invalid object error In introducing the preconditions by @caesarxuchao , if check preconditions failed, it returns resource version conflict error. This is the wrong error to return, and instead it should return invalid object error. We need to separate these two types of errors. See the implementation in etcd3 [https://github.com/kubernetes/kubernetes/blob/master/pkg/storage/etcd3/store.go#L467]. Also renaming "ErrCodeResourceVersionConflicts" to "ErrCodeVersionConflicts" for simpler reading.
parents fe66c5c5 60d165a8
...@@ -65,7 +65,7 @@ func InterpretCreateError(err error, qualifiedResource unversioned.GroupResource ...@@ -65,7 +65,7 @@ func InterpretCreateError(err error, qualifiedResource unversioned.GroupResource
// operation into the appropriate API error. // operation into the appropriate API error.
func InterpretUpdateError(err error, qualifiedResource unversioned.GroupResource, name string) error { func InterpretUpdateError(err error, qualifiedResource unversioned.GroupResource, name string) error {
switch { switch {
case storage.IsTestFailed(err), storage.IsNodeExist(err): case storage.IsTestFailed(err), storage.IsNodeExist(err), storage.IsInvalidObj(err):
return errors.NewConflict(qualifiedResource, name, err) return errors.NewConflict(qualifiedResource, name, err)
case storage.IsUnreachable(err): case storage.IsUnreachable(err):
return errors.NewServerTimeout(qualifiedResource, "update", 2) // TODO: make configurable or handled at a higher level return errors.NewServerTimeout(qualifiedResource, "update", 2) // TODO: make configurable or handled at a higher level
...@@ -86,7 +86,7 @@ func InterpretDeleteError(err error, qualifiedResource unversioned.GroupResource ...@@ -86,7 +86,7 @@ func InterpretDeleteError(err error, qualifiedResource unversioned.GroupResource
return errors.NewNotFound(qualifiedResource, name) return errors.NewNotFound(qualifiedResource, name)
case storage.IsUnreachable(err): case storage.IsUnreachable(err):
return errors.NewServerTimeout(qualifiedResource, "delete", 2) // TODO: make configurable or handled at a higher level return errors.NewServerTimeout(qualifiedResource, "delete", 2) // TODO: make configurable or handled at a higher level
case storage.IsTestFailed(err), storage.IsNodeExist(err): case storage.IsTestFailed(err), storage.IsNodeExist(err), storage.IsInvalidObj(err):
return errors.NewConflict(qualifiedResource, name, err) return errors.NewConflict(qualifiedResource, name, err)
case storage.IsInternalError(err): case storage.IsInternalError(err):
return errors.NewInternalError(err) return errors.NewInternalError(err)
......
...@@ -107,7 +107,7 @@ func IsUnreachable(err error) bool { ...@@ -107,7 +107,7 @@ func IsUnreachable(err error) bool {
// IsTestFailed returns true if and only if err is a write conflict. // IsTestFailed returns true if and only if err is a write conflict.
func IsTestFailed(err error) bool { func IsTestFailed(err error) bool {
return isErrCode(err, ErrCodeResourceVersionConflicts, ErrCodeInvalidObj) return isErrCode(err, ErrCodeResourceVersionConflicts)
} }
// IsInvalidUID returns true if and only if err is invalid UID error // IsInvalidUID returns true if and only if err is invalid UID error
...@@ -115,16 +115,12 @@ func IsInvalidObj(err error) bool { ...@@ -115,16 +115,12 @@ func IsInvalidObj(err error) bool {
return isErrCode(err, ErrCodeInvalidObj) return isErrCode(err, ErrCodeInvalidObj)
} }
func isErrCode(err error, codes ...int) bool { func isErrCode(err error, code int) bool {
if err == nil { if err == nil {
return false return false
} }
if e, ok := err.(*StorageError); ok { if e, ok := err.(*StorageError); ok {
for _, code := range codes { return e.Code == code
if e.Code == code {
return true
}
}
} }
return false return false
} }
......
...@@ -150,7 +150,7 @@ func (h *etcdHelper) Create(ctx context.Context, key string, obj, out runtime.Ob ...@@ -150,7 +150,7 @@ func (h *etcdHelper) Create(ctx context.Context, key string, obj, out runtime.Ob
return err return err
} }
func checkPreconditions(preconditions *storage.Preconditions, out runtime.Object) error { func checkPreconditions(key string, preconditions *storage.Preconditions, out runtime.Object) error {
if preconditions == nil { if preconditions == nil {
return nil return nil
} }
...@@ -159,7 +159,8 @@ func checkPreconditions(preconditions *storage.Preconditions, out runtime.Object ...@@ -159,7 +159,8 @@ func checkPreconditions(preconditions *storage.Preconditions, out runtime.Object
return storage.NewInternalErrorf("can't enforce preconditions %v on un-introspectable object %v, got error: %v", *preconditions, out, err) return storage.NewInternalErrorf("can't enforce preconditions %v on un-introspectable object %v, got error: %v", *preconditions, out, err)
} }
if preconditions.UID != nil && *preconditions.UID != objMeta.UID { if preconditions.UID != nil && *preconditions.UID != objMeta.UID {
return etcd.Error{Code: etcd.ErrorCodeTestFailed, Message: fmt.Sprintf("the UID in the precondition (%s) does not match the UID in record (%s). The object might have been deleted and then recreated", *preconditions.UID, objMeta.UID)} errMsg := fmt.Sprintf("Precondition failed: UID in precondition: %v, UID in object meta: %v", preconditions.UID, objMeta.UID)
return storage.NewInvalidObjError(key, errMsg)
} }
return nil return nil
} }
...@@ -195,7 +196,7 @@ func (h *etcdHelper) Delete(ctx context.Context, key string, out runtime.Object, ...@@ -195,7 +196,7 @@ func (h *etcdHelper) Delete(ctx context.Context, key string, out runtime.Object,
if err != nil { if err != nil {
return toStorageErr(err, key, 0) return toStorageErr(err, key, 0)
} }
if err := checkPreconditions(preconditions, obj); err != nil { if err := checkPreconditions(key, preconditions, obj); err != nil {
return toStorageErr(err, key, 0) return toStorageErr(err, key, 0)
} }
index := uint64(0) index := uint64(0)
...@@ -471,7 +472,7 @@ func (h *etcdHelper) GuaranteedUpdate(ctx context.Context, key string, ptrToType ...@@ -471,7 +472,7 @@ func (h *etcdHelper) GuaranteedUpdate(ctx context.Context, key string, ptrToType
if err != nil { if err != nil {
return toStorageErr(err, key, 0) return toStorageErr(err, key, 0)
} }
if err := checkPreconditions(preconditions, obj); err != nil { if err := checkPreconditions(key, preconditions, obj); err != nil {
return toStorageErr(err, key, 0) return toStorageErr(err, key, 0)
} }
meta := storage.ResponseMeta{} meta := storage.ResponseMeta{}
......
...@@ -460,7 +460,7 @@ func TestGuaranteedUpdateUIDMismatch(t *testing.T) { ...@@ -460,7 +460,7 @@ func TestGuaranteedUpdateUIDMismatch(t *testing.T) {
err = helper.GuaranteedUpdate(context.TODO(), "/some/key", podPtr, true, storage.NewUIDPreconditions("B"), storage.SimpleUpdate(func(in runtime.Object) (runtime.Object, error) { err = helper.GuaranteedUpdate(context.TODO(), "/some/key", podPtr, true, storage.NewUIDPreconditions("B"), storage.SimpleUpdate(func(in runtime.Object) (runtime.Object, error) {
return obj, nil return obj, nil
})) }))
if !storage.IsTestFailed(err) { if !storage.IsInvalidObj(err) {
t.Fatalf("Expect a Test Failed (write conflict) error, got: %v", err) t.Fatalf("Expect a Test Failed (write conflict) error, got: %v", err)
} }
} }
...@@ -499,7 +499,7 @@ func TestDeleteUIDMismatch(t *testing.T) { ...@@ -499,7 +499,7 @@ func TestDeleteUIDMismatch(t *testing.T) {
t.Fatalf("Unexpected error %#v", err) t.Fatalf("Unexpected error %#v", err)
} }
err = helper.Delete(context.TODO(), "/some/key", obj, storage.NewUIDPreconditions("B")) err = helper.Delete(context.TODO(), "/some/key", obj, storage.NewUIDPreconditions("B"))
if !storage.IsTestFailed(err) { if !storage.IsInvalidObj(err) {
t.Fatalf("Expect a Test Failed (write conflict) error, got: %v", err) t.Fatalf("Expect a Test Failed (write conflict) error, got: %v", err)
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment