blob: 281ddc7a0dbd25e7d17ab0b09e98bab67d78b24d [file] [log] [blame]
khenaidoo59ce9dd2019-11-11 13:05:32 -05001// Copyright 2016 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package v3rpc
16
17import (
18 "context"
19 "strings"
20
21 "go.etcd.io/etcd/auth"
22 "go.etcd.io/etcd/etcdserver"
23 "go.etcd.io/etcd/etcdserver/api/membership"
24 "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes"
25 pb "go.etcd.io/etcd/etcdserver/etcdserverpb"
26 "go.etcd.io/etcd/lease"
27 "go.etcd.io/etcd/mvcc"
28
29 "google.golang.org/grpc/codes"
30 "google.golang.org/grpc/status"
31)
32
33var toGRPCErrorMap = map[error]error{
34 membership.ErrIDRemoved: rpctypes.ErrGRPCMemberNotFound,
35 membership.ErrIDNotFound: rpctypes.ErrGRPCMemberNotFound,
36 membership.ErrIDExists: rpctypes.ErrGRPCMemberExist,
37 membership.ErrPeerURLexists: rpctypes.ErrGRPCPeerURLExist,
38 membership.ErrMemberNotLearner: rpctypes.ErrGRPCMemberNotLearner,
39 membership.ErrTooManyLearners: rpctypes.ErrGRPCTooManyLearners,
40 etcdserver.ErrNotEnoughStartedMembers: rpctypes.ErrMemberNotEnoughStarted,
41 etcdserver.ErrLearnerNotReady: rpctypes.ErrGRPCLearnerNotReady,
42
43 mvcc.ErrCompacted: rpctypes.ErrGRPCCompacted,
44 mvcc.ErrFutureRev: rpctypes.ErrGRPCFutureRev,
45 etcdserver.ErrRequestTooLarge: rpctypes.ErrGRPCRequestTooLarge,
46 etcdserver.ErrNoSpace: rpctypes.ErrGRPCNoSpace,
47 etcdserver.ErrTooManyRequests: rpctypes.ErrTooManyRequests,
48
49 etcdserver.ErrNoLeader: rpctypes.ErrGRPCNoLeader,
50 etcdserver.ErrNotLeader: rpctypes.ErrGRPCNotLeader,
51 etcdserver.ErrLeaderChanged: rpctypes.ErrGRPCLeaderChanged,
52 etcdserver.ErrStopped: rpctypes.ErrGRPCStopped,
53 etcdserver.ErrTimeout: rpctypes.ErrGRPCTimeout,
54 etcdserver.ErrTimeoutDueToLeaderFail: rpctypes.ErrGRPCTimeoutDueToLeaderFail,
55 etcdserver.ErrTimeoutDueToConnectionLost: rpctypes.ErrGRPCTimeoutDueToConnectionLost,
56 etcdserver.ErrUnhealthy: rpctypes.ErrGRPCUnhealthy,
57 etcdserver.ErrKeyNotFound: rpctypes.ErrGRPCKeyNotFound,
58 etcdserver.ErrCorrupt: rpctypes.ErrGRPCCorrupt,
59 etcdserver.ErrBadLeaderTransferee: rpctypes.ErrGRPCBadLeaderTransferee,
60
61 lease.ErrLeaseNotFound: rpctypes.ErrGRPCLeaseNotFound,
62 lease.ErrLeaseExists: rpctypes.ErrGRPCLeaseExist,
63 lease.ErrLeaseTTLTooLarge: rpctypes.ErrGRPCLeaseTTLTooLarge,
64
65 auth.ErrRootUserNotExist: rpctypes.ErrGRPCRootUserNotExist,
66 auth.ErrRootRoleNotExist: rpctypes.ErrGRPCRootRoleNotExist,
67 auth.ErrUserAlreadyExist: rpctypes.ErrGRPCUserAlreadyExist,
68 auth.ErrUserEmpty: rpctypes.ErrGRPCUserEmpty,
69 auth.ErrUserNotFound: rpctypes.ErrGRPCUserNotFound,
70 auth.ErrRoleAlreadyExist: rpctypes.ErrGRPCRoleAlreadyExist,
71 auth.ErrRoleNotFound: rpctypes.ErrGRPCRoleNotFound,
72 auth.ErrRoleEmpty: rpctypes.ErrGRPCRoleEmpty,
73 auth.ErrAuthFailed: rpctypes.ErrGRPCAuthFailed,
74 auth.ErrPermissionDenied: rpctypes.ErrGRPCPermissionDenied,
75 auth.ErrRoleNotGranted: rpctypes.ErrGRPCRoleNotGranted,
76 auth.ErrPermissionNotGranted: rpctypes.ErrGRPCPermissionNotGranted,
77 auth.ErrAuthNotEnabled: rpctypes.ErrGRPCAuthNotEnabled,
78 auth.ErrInvalidAuthToken: rpctypes.ErrGRPCInvalidAuthToken,
79 auth.ErrInvalidAuthMgmt: rpctypes.ErrGRPCInvalidAuthMgmt,
80}
81
82func togRPCError(err error) error {
83 // let gRPC server convert to codes.Canceled, codes.DeadlineExceeded
84 if err == context.Canceled || err == context.DeadlineExceeded {
85 return err
86 }
87 grpcErr, ok := toGRPCErrorMap[err]
88 if !ok {
89 return status.Error(codes.Unknown, err.Error())
90 }
91 return grpcErr
92}
93
94func isClientCtxErr(ctxErr error, err error) bool {
95 if ctxErr != nil {
96 return true
97 }
98
99 ev, ok := status.FromError(err)
100 if !ok {
101 return false
102 }
103
104 switch ev.Code() {
105 case codes.Canceled, codes.DeadlineExceeded:
106 // client-side context cancel or deadline exceeded
107 // "rpc error: code = Canceled desc = context canceled"
108 // "rpc error: code = DeadlineExceeded desc = context deadline exceeded"
109 return true
110 case codes.Unavailable:
111 msg := ev.Message()
112 // client-side context cancel or deadline exceeded with TLS ("http2.errClientDisconnected")
113 // "rpc error: code = Unavailable desc = client disconnected"
114 if msg == "client disconnected" {
115 return true
116 }
117 // "grpc/transport.ClientTransport.CloseStream" on canceled streams
118 // "rpc error: code = Unavailable desc = stream error: stream ID 21; CANCEL")
119 if strings.HasPrefix(msg, "stream error: ") && strings.HasSuffix(msg, "; CANCEL") {
120 return true
121 }
122 }
123 return false
124}
125
126// in v3.4, learner is allowed to serve serializable read and endpoint status
127func isRPCSupportedForLearner(req interface{}) bool {
128 switch r := req.(type) {
129 case *pb.StatusRequest:
130 return true
131 case *pb.RangeRequest:
132 return r.Serializable
133 default:
134 return false
135 }
136}