diff --git a/etcdserver/api/v3rpc/rpctypes/error.go b/etcdserver/api/v3rpc/rpctypes/error.go index 0de407732..5b0d5630c 100644 --- a/etcdserver/api/v3rpc/rpctypes/error.go +++ b/etcdserver/api/v3rpc/rpctypes/error.go @@ -20,62 +20,104 @@ import ( ) var ( - ErrEmptyKey = grpc.Errorf(codes.InvalidArgument, "etcdserver: key is not provided") - ErrTooManyOps = grpc.Errorf(codes.InvalidArgument, "etcdserver: too many operations in txn request") - ErrDuplicateKey = grpc.Errorf(codes.InvalidArgument, "etcdserver: duplicate key given in txn request") - ErrCompacted = grpc.Errorf(codes.OutOfRange, "etcdserver: mvcc: required revision has been compacted") - ErrFutureRev = grpc.Errorf(codes.OutOfRange, "etcdserver: mvcc: required revision is a future revision") - ErrNoSpace = grpc.Errorf(codes.ResourceExhausted, "etcdserver: mvcc: database space exceeded") + // server-side error + ErrGRPCEmptyKey = grpc.Errorf(codes.InvalidArgument, "etcdserver: key is not provided") + ErrGRPCTooManyOps = grpc.Errorf(codes.InvalidArgument, "etcdserver: too many operations in txn request") + ErrGRPCDuplicateKey = grpc.Errorf(codes.InvalidArgument, "etcdserver: duplicate key given in txn request") + ErrGRPCCompacted = grpc.Errorf(codes.OutOfRange, "etcdserver: mvcc: required revision has been compacted") + ErrGRPCFutureRev = grpc.Errorf(codes.OutOfRange, "etcdserver: mvcc: required revision is a future revision") + ErrGRPCNoSpace = grpc.Errorf(codes.ResourceExhausted, "etcdserver: mvcc: database space exceeded") - ErrLeaseNotFound = grpc.Errorf(codes.NotFound, "etcdserver: requested lease not found") - ErrLeaseExist = grpc.Errorf(codes.FailedPrecondition, "etcdserver: lease already exists") + ErrGRPCLeaseNotFound = grpc.Errorf(codes.NotFound, "etcdserver: requested lease not found") + ErrGRPCLeaseExist = grpc.Errorf(codes.FailedPrecondition, "etcdserver: lease already exists") - ErrMemberExist = grpc.Errorf(codes.FailedPrecondition, "etcdserver: member ID already exist") - ErrPeerURLExist = grpc.Errorf(codes.FailedPrecondition, "etcdserver: Peer URLs already exists") - ErrMemberBadURLs = grpc.Errorf(codes.InvalidArgument, "etcdserver: given member URLs are invalid") - ErrMemberNotFound = grpc.Errorf(codes.NotFound, "etcdserver: member not found") + ErrGRPCMemberExist = grpc.Errorf(codes.FailedPrecondition, "etcdserver: member ID already exist") + ErrGRPCPeerURLExist = grpc.Errorf(codes.FailedPrecondition, "etcdserver: Peer URLs already exists") + ErrGRPCMemberBadURLs = grpc.Errorf(codes.InvalidArgument, "etcdserver: given member URLs are invalid") + ErrGRPCMemberNotFound = grpc.Errorf(codes.NotFound, "etcdserver: member not found") - ErrRequestTooLarge = grpc.Errorf(codes.InvalidArgument, "etcdserver: request is too large") + ErrGRPCRequestTooLarge = grpc.Errorf(codes.InvalidArgument, "etcdserver: request is too large") - ErrUserAlreadyExist = grpc.Errorf(codes.FailedPrecondition, "etcdserver: user name already exists") - ErrUserNotFound = grpc.Errorf(codes.FailedPrecondition, "etcdserver: user name not found") - ErrRoleAlreadyExist = grpc.Errorf(codes.FailedPrecondition, "etcdserver: role name already exists") - ErrRoleNotFound = grpc.Errorf(codes.FailedPrecondition, "etcdserver: role name not found") - ErrAuthFailed = grpc.Errorf(codes.InvalidArgument, "etcdserver: authentication failed, invalid user ID or password") + ErrGRPCUserAlreadyExist = grpc.Errorf(codes.FailedPrecondition, "etcdserver: user name already exists") + ErrGRPCUserNotFound = grpc.Errorf(codes.FailedPrecondition, "etcdserver: user name not found") + ErrGRPCRoleAlreadyExist = grpc.Errorf(codes.FailedPrecondition, "etcdserver: role name already exists") + ErrGRPCRoleNotFound = grpc.Errorf(codes.FailedPrecondition, "etcdserver: role name not found") + ErrGRPCAuthFailed = grpc.Errorf(codes.InvalidArgument, "etcdserver: authentication failed, invalid user ID or password") errStringToError = map[string]error{ - grpc.ErrorDesc(ErrEmptyKey): ErrEmptyKey, - grpc.ErrorDesc(ErrTooManyOps): ErrTooManyOps, - grpc.ErrorDesc(ErrDuplicateKey): ErrDuplicateKey, - grpc.ErrorDesc(ErrCompacted): ErrCompacted, - grpc.ErrorDesc(ErrFutureRev): ErrFutureRev, - grpc.ErrorDesc(ErrNoSpace): ErrNoSpace, + grpc.ErrorDesc(ErrGRPCEmptyKey): ErrGRPCEmptyKey, + grpc.ErrorDesc(ErrGRPCTooManyOps): ErrGRPCTooManyOps, + grpc.ErrorDesc(ErrGRPCDuplicateKey): ErrGRPCDuplicateKey, + grpc.ErrorDesc(ErrGRPCCompacted): ErrGRPCCompacted, + grpc.ErrorDesc(ErrGRPCFutureRev): ErrGRPCFutureRev, + grpc.ErrorDesc(ErrGRPCNoSpace): ErrGRPCNoSpace, - grpc.ErrorDesc(ErrLeaseNotFound): ErrLeaseNotFound, - grpc.ErrorDesc(ErrLeaseExist): ErrLeaseExist, + grpc.ErrorDesc(ErrGRPCLeaseNotFound): ErrGRPCLeaseNotFound, + grpc.ErrorDesc(ErrGRPCLeaseExist): ErrGRPCLeaseExist, - grpc.ErrorDesc(ErrMemberExist): ErrMemberExist, - grpc.ErrorDesc(ErrPeerURLExist): ErrPeerURLExist, - grpc.ErrorDesc(ErrMemberBadURLs): ErrMemberBadURLs, - grpc.ErrorDesc(ErrMemberNotFound): ErrMemberNotFound, + grpc.ErrorDesc(ErrGRPCMemberExist): ErrGRPCMemberExist, + grpc.ErrorDesc(ErrGRPCPeerURLExist): ErrGRPCPeerURLExist, + grpc.ErrorDesc(ErrGRPCMemberBadURLs): ErrGRPCMemberBadURLs, + grpc.ErrorDesc(ErrGRPCMemberNotFound): ErrGRPCMemberNotFound, - grpc.ErrorDesc(ErrRequestTooLarge): ErrRequestTooLarge, + grpc.ErrorDesc(ErrGRPCRequestTooLarge): ErrGRPCRequestTooLarge, - grpc.ErrorDesc(ErrUserAlreadyExist): ErrUserAlreadyExist, - grpc.ErrorDesc(ErrUserNotFound): ErrUserNotFound, - grpc.ErrorDesc(ErrRoleAlreadyExist): ErrRoleAlreadyExist, - grpc.ErrorDesc(ErrRoleNotFound): ErrRoleNotFound, - grpc.ErrorDesc(ErrAuthFailed): ErrAuthFailed, + grpc.ErrorDesc(ErrGRPCUserAlreadyExist): ErrGRPCUserAlreadyExist, + grpc.ErrorDesc(ErrGRPCUserNotFound): ErrGRPCUserNotFound, + grpc.ErrorDesc(ErrGRPCRoleAlreadyExist): ErrGRPCRoleAlreadyExist, + grpc.ErrorDesc(ErrGRPCRoleNotFound): ErrGRPCRoleNotFound, + grpc.ErrorDesc(ErrGRPCAuthFailed): ErrGRPCAuthFailed, } + + // client-side error + ErrEmptyKey = Error(ErrGRPCEmptyKey) + ErrTooManyOps = Error(ErrGRPCTooManyOps) + ErrDuplicateKey = Error(ErrGRPCDuplicateKey) + ErrCompacted = Error(ErrGRPCCompacted) + ErrFutureRev = Error(ErrGRPCFutureRev) + ErrNoSpace = Error(ErrGRPCNoSpace) + + ErrLeaseNotFound = Error(ErrGRPCLeaseNotFound) + ErrLeaseExist = Error(ErrGRPCLeaseExist) + + ErrMemberExist = Error(ErrGRPCMemberExist) + ErrPeerURLExist = Error(ErrGRPCPeerURLExist) + ErrMemberBadURLs = Error(ErrGRPCMemberBadURLs) + ErrMemberNotFound = Error(ErrGRPCMemberNotFound) + + ErrRequestTooLarge = Error(ErrGRPCRequestTooLarge) + + ErrUserAlreadyExist = Error(ErrGRPCUserAlreadyExist) + ErrUserNotFound = Error(ErrGRPCUserNotFound) + ErrRoleAlreadyExist = Error(ErrGRPCRoleAlreadyExist) + ErrRoleNotFound = Error(ErrGRPCRoleNotFound) + ErrAuthFailed = Error(ErrGRPCAuthFailed) ) +// EtcdError defines gRPC server errors. +// (https://github.com/grpc/grpc-go/blob/master/rpc_util.go#L319-L323) +type EtcdError struct { + code codes.Code + desc string +} + +// Code returns grpc/codes.Code. +// TODO: define clientv3/codes.Code. +func (e EtcdError) Code() codes.Code { + return e.code +} + +func (e EtcdError) Error() string { + return e.desc +} + func Error(err error) error { if err == nil { return nil } - v, ok := errStringToError[err.Error()] - if !ok { + verr, ok := errStringToError[grpc.ErrorDesc(err)] + if !ok { // not gRPC error return err } - return v + return EtcdError{code: grpc.Code(verr), desc: grpc.ErrorDesc(verr)} } diff --git a/etcdserver/api/v3rpc/rpctypes/error_test.go b/etcdserver/api/v3rpc/rpctypes/error_test.go new file mode 100644 index 000000000..991670f33 --- /dev/null +++ b/etcdserver/api/v3rpc/rpctypes/error_test.go @@ -0,0 +1,42 @@ +// Copyright 2016 CoreOS, Inc. +// +// 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 rpctypes + +import ( + "testing" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" +) + +func TestConvert(t *testing.T) { + e1 := grpc.Errorf(codes.InvalidArgument, "etcdserver: key is not provided") + e2 := ErrGRPCEmptyKey + e3 := ErrEmptyKey + + if e1 != e2 { + t.Fatalf("expected 'true', got %T != %T", e1, e2) + } + if grpc.Code(e1) != e3.(EtcdError).Code() { + t.Fatalf("expected them to be equal, got %v / %v", grpc.Code(e1), e3.(EtcdError).Code()) + } + + if e1 == e3 { + t.Fatalf("expected 'false', got %T == %T", e1, e3) + } + if grpc.Code(e2) != e3.(EtcdError).Code() { + t.Fatalf("expected them to be equal, got %v / %v", grpc.Code(e2), e3.(EtcdError).Code()) + } +}