mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
*: implement a retry logic for auth old revision in the client
This commit is contained in:
parent
79bbc8fdb7
commit
dec6f72d68
@ -65,6 +65,7 @@ var (
|
|||||||
ErrGRPCAuthNotEnabled = status.New(codes.FailedPrecondition, "etcdserver: authentication is not enabled").Err()
|
ErrGRPCAuthNotEnabled = status.New(codes.FailedPrecondition, "etcdserver: authentication is not enabled").Err()
|
||||||
ErrGRPCInvalidAuthToken = status.New(codes.Unauthenticated, "etcdserver: invalid auth token").Err()
|
ErrGRPCInvalidAuthToken = status.New(codes.Unauthenticated, "etcdserver: invalid auth token").Err()
|
||||||
ErrGRPCInvalidAuthMgmt = status.New(codes.InvalidArgument, "etcdserver: invalid auth management").Err()
|
ErrGRPCInvalidAuthMgmt = status.New(codes.InvalidArgument, "etcdserver: invalid auth management").Err()
|
||||||
|
ErrGRPCAuthOldRevision = status.New(codes.InvalidArgument, "etcdserver: revision of auth store is old").Err()
|
||||||
|
|
||||||
ErrGRPCNoLeader = status.New(codes.Unavailable, "etcdserver: no leader").Err()
|
ErrGRPCNoLeader = status.New(codes.Unavailable, "etcdserver: no leader").Err()
|
||||||
ErrGRPCNotLeader = status.New(codes.FailedPrecondition, "etcdserver: not leader").Err()
|
ErrGRPCNotLeader = status.New(codes.FailedPrecondition, "etcdserver: not leader").Err()
|
||||||
@ -131,6 +132,7 @@ var (
|
|||||||
ErrorDesc(ErrGRPCAuthNotEnabled): ErrGRPCAuthNotEnabled,
|
ErrorDesc(ErrGRPCAuthNotEnabled): ErrGRPCAuthNotEnabled,
|
||||||
ErrorDesc(ErrGRPCInvalidAuthToken): ErrGRPCInvalidAuthToken,
|
ErrorDesc(ErrGRPCInvalidAuthToken): ErrGRPCInvalidAuthToken,
|
||||||
ErrorDesc(ErrGRPCInvalidAuthMgmt): ErrGRPCInvalidAuthMgmt,
|
ErrorDesc(ErrGRPCInvalidAuthMgmt): ErrGRPCInvalidAuthMgmt,
|
||||||
|
ErrorDesc(ErrGRPCAuthOldRevision): ErrGRPCAuthOldRevision,
|
||||||
|
|
||||||
ErrorDesc(ErrGRPCNoLeader): ErrGRPCNoLeader,
|
ErrorDesc(ErrGRPCNoLeader): ErrGRPCNoLeader,
|
||||||
ErrorDesc(ErrGRPCNotLeader): ErrGRPCNotLeader,
|
ErrorDesc(ErrGRPCNotLeader): ErrGRPCNotLeader,
|
||||||
@ -195,6 +197,7 @@ var (
|
|||||||
ErrPermissionNotGranted = Error(ErrGRPCPermissionNotGranted)
|
ErrPermissionNotGranted = Error(ErrGRPCPermissionNotGranted)
|
||||||
ErrAuthNotEnabled = Error(ErrGRPCAuthNotEnabled)
|
ErrAuthNotEnabled = Error(ErrGRPCAuthNotEnabled)
|
||||||
ErrInvalidAuthToken = Error(ErrGRPCInvalidAuthToken)
|
ErrInvalidAuthToken = Error(ErrGRPCInvalidAuthToken)
|
||||||
|
ErrAuthOldRevision = Error(ErrGRPCAuthOldRevision)
|
||||||
ErrInvalidAuthMgmt = Error(ErrGRPCInvalidAuthMgmt)
|
ErrInvalidAuthMgmt = Error(ErrGRPCInvalidAuthMgmt)
|
||||||
|
|
||||||
ErrNoLeader = Error(ErrGRPCNoLeader)
|
ErrNoLeader = Error(ErrGRPCNoLeader)
|
||||||
|
@ -156,7 +156,9 @@ func (c *Client) shouldRefreshToken(err error, callOpts *options) bool {
|
|||||||
// which is possible when the client token is cleared somehow
|
// which is possible when the client token is cleared somehow
|
||||||
return c.authTokenBundle != nil // equal to c.Username != "" && c.Password != ""
|
return c.authTokenBundle != nil // equal to c.Username != "" && c.Password != ""
|
||||||
}
|
}
|
||||||
return callOpts.retryAuth && rpctypes.Error(err) == rpctypes.ErrInvalidAuthToken
|
|
||||||
|
return callOpts.retryAuth &&
|
||||||
|
(rpctypes.Error(err) == rpctypes.ErrInvalidAuthToken || rpctypes.Error(err) == rpctypes.ErrAuthOldRevision)
|
||||||
}
|
}
|
||||||
|
|
||||||
// type serverStreamingRetryingStream is the implementation of grpc.ClientStream that acts as a
|
// type serverStreamingRetryingStream is the implementation of grpc.ClientStream that acts as a
|
||||||
|
124
client/v3/retry_interceptor_test.go
Normal file
124
client/v3/retry_interceptor_test.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package clientv3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.etcd.io/etcd/api/v3/v3rpc/rpctypes"
|
||||||
|
"go.etcd.io/etcd/client/v3/credentials"
|
||||||
|
grpccredentials "google.golang.org/grpc/credentials"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dummyAuthTokenBundle struct{}
|
||||||
|
|
||||||
|
func (d dummyAuthTokenBundle) TransportCredentials() grpccredentials.TransportCredentials {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dummyAuthTokenBundle) PerRPCCredentials() grpccredentials.PerRPCCredentials {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dummyAuthTokenBundle) NewWithMode(mode string) (grpccredentials.Bundle, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dummyAuthTokenBundle) UpdateAuthToken(token string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClientShouldRefreshToken(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
authTokenBundle credentials.Bundle
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
err error
|
||||||
|
callOpts *options
|
||||||
|
}
|
||||||
|
|
||||||
|
optsWithTrue := &options{
|
||||||
|
retryAuth: true,
|
||||||
|
}
|
||||||
|
optsWithFalse := &options{
|
||||||
|
retryAuth: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "ErrUserEmpty and non nil authTokenBundle",
|
||||||
|
fields: fields{
|
||||||
|
authTokenBundle: &dummyAuthTokenBundle{},
|
||||||
|
},
|
||||||
|
args: args{rpctypes.ErrGRPCUserEmpty, optsWithTrue},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ErrUserEmpty and nil authTokenBundle",
|
||||||
|
fields: fields{
|
||||||
|
authTokenBundle: nil,
|
||||||
|
},
|
||||||
|
args: args{rpctypes.ErrGRPCUserEmpty, optsWithTrue},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ErrGRPCInvalidAuthToken and retryAuth",
|
||||||
|
fields: fields{
|
||||||
|
authTokenBundle: nil,
|
||||||
|
},
|
||||||
|
args: args{rpctypes.ErrGRPCInvalidAuthToken, optsWithTrue},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ErrGRPCInvalidAuthToken and !retryAuth",
|
||||||
|
fields: fields{
|
||||||
|
authTokenBundle: nil,
|
||||||
|
},
|
||||||
|
args: args{rpctypes.ErrGRPCInvalidAuthToken, optsWithFalse},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ErrGRPCAuthOldRevision and retryAuth",
|
||||||
|
fields: fields{
|
||||||
|
authTokenBundle: nil,
|
||||||
|
},
|
||||||
|
args: args{rpctypes.ErrGRPCAuthOldRevision, optsWithTrue},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ErrGRPCAuthOldRevision and !retryAuth",
|
||||||
|
fields: fields{
|
||||||
|
authTokenBundle: nil,
|
||||||
|
},
|
||||||
|
args: args{rpctypes.ErrGRPCAuthOldRevision, optsWithFalse},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Other error and retryAuth",
|
||||||
|
fields: fields{
|
||||||
|
authTokenBundle: nil,
|
||||||
|
},
|
||||||
|
args: args{rpctypes.ErrGRPCAuthFailed, optsWithTrue},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Other error and !retryAuth",
|
||||||
|
fields: fields{
|
||||||
|
authTokenBundle: nil,
|
||||||
|
},
|
||||||
|
args: args{rpctypes.ErrGRPCAuthFailed, optsWithFalse},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
c := &Client{
|
||||||
|
authTokenBundle: tt.fields.authTokenBundle,
|
||||||
|
}
|
||||||
|
if got := c.shouldRefreshToken(tt.args.err, tt.args.callOpts); got != tt.want {
|
||||||
|
t.Errorf("shouldRefreshToken() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -84,6 +84,7 @@ var toGRPCErrorMap = map[error]error{
|
|||||||
auth.ErrAuthNotEnabled: rpctypes.ErrGRPCAuthNotEnabled,
|
auth.ErrAuthNotEnabled: rpctypes.ErrGRPCAuthNotEnabled,
|
||||||
auth.ErrInvalidAuthToken: rpctypes.ErrGRPCInvalidAuthToken,
|
auth.ErrInvalidAuthToken: rpctypes.ErrGRPCInvalidAuthToken,
|
||||||
auth.ErrInvalidAuthMgmt: rpctypes.ErrGRPCInvalidAuthMgmt,
|
auth.ErrInvalidAuthMgmt: rpctypes.ErrGRPCInvalidAuthMgmt,
|
||||||
|
auth.ErrAuthOldRevision: rpctypes.ErrGRPCAuthOldRevision,
|
||||||
|
|
||||||
// In sync with status.FromContextError
|
// In sync with status.FromContextError
|
||||||
context.Canceled: rpctypes.ErrGRPCCanceled,
|
context.Canceled: rpctypes.ErrGRPCCanceled,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user