Browse Source

rpctypes: define a new error interface

Gyu-Ho Lee 9 years ago
parent
commit
2b361cf06b
2 changed files with 127 additions and 43 deletions
  1. 85 43
      etcdserver/api/v3rpc/rpctypes/error.go
  2. 42 0
      etcdserver/api/v3rpc/rpctypes/error_test.go

+ 85 - 43
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(ErrLeaseNotFound): ErrLeaseNotFound,
-		grpc.ErrorDesc(ErrLeaseExist):    ErrLeaseExist,
-
-		grpc.ErrorDesc(ErrMemberExist):    ErrMemberExist,
-		grpc.ErrorDesc(ErrPeerURLExist):   ErrPeerURLExist,
-		grpc.ErrorDesc(ErrMemberBadURLs):  ErrMemberBadURLs,
-		grpc.ErrorDesc(ErrMemberNotFound): ErrMemberNotFound,
-
-		grpc.ErrorDesc(ErrRequestTooLarge): ErrRequestTooLarge,
-
-		grpc.ErrorDesc(ErrUserAlreadyExist): ErrUserAlreadyExist,
-		grpc.ErrorDesc(ErrUserNotFound):     ErrUserNotFound,
-		grpc.ErrorDesc(ErrRoleAlreadyExist): ErrRoleAlreadyExist,
-		grpc.ErrorDesc(ErrRoleNotFound):     ErrRoleNotFound,
-		grpc.ErrorDesc(ErrAuthFailed):       ErrAuthFailed,
+		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(ErrGRPCLeaseNotFound): ErrGRPCLeaseNotFound,
+		grpc.ErrorDesc(ErrGRPCLeaseExist):    ErrGRPCLeaseExist,
+
+		grpc.ErrorDesc(ErrGRPCMemberExist):    ErrGRPCMemberExist,
+		grpc.ErrorDesc(ErrGRPCPeerURLExist):   ErrGRPCPeerURLExist,
+		grpc.ErrorDesc(ErrGRPCMemberBadURLs):  ErrGRPCMemberBadURLs,
+		grpc.ErrorDesc(ErrGRPCMemberNotFound): ErrGRPCMemberNotFound,
+
+		grpc.ErrorDesc(ErrGRPCRequestTooLarge): ErrGRPCRequestTooLarge,
+
+		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)}
 }

+ 42 - 0
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())
+	}
+}