From 232fb980a7768180e6b0c200b99c996de90998bb Mon Sep 17 00:00:00 2001 From: Chris Ayoub Date: Sat, 9 Apr 2022 21:25:42 -0400 Subject: [PATCH] clientv3: filter learners members during autosync This change is to ensure that all members returned during the client's AutoSync are started and are not learners, which are not valid etcd members to make requests to. --- client/v3/client.go | 4 +++- client/v3/client_test.go | 49 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/client/v3/client.go b/client/v3/client.go index ba08cf5bbdf..2990379ab9f 100644 --- a/client/v3/client.go +++ b/client/v3/client.go @@ -185,7 +185,9 @@ func (c *Client) Sync(ctx context.Context) error { } var eps []string for _, m := range mresp.Members { - eps = append(eps, m.ClientURLs...) + if len(m.Name) != 0 && !m.IsLearner { + eps = append(eps, m.ClientURLs...) + } } c.SetEndpoints(eps...) return nil diff --git a/client/v3/client_test.go b/client/v3/client_test.go index 0804f05c5c4..8e2c03e280b 100644 --- a/client/v3/client_test.go +++ b/client/v3/client_test.go @@ -17,13 +17,14 @@ package clientv3 import ( "context" "fmt" - "go.uber.org/zap" "net" "testing" "time" + "go.etcd.io/etcd/api/v3/etcdserverpb" "go.etcd.io/etcd/api/v3/v3rpc/rpctypes" "go.etcd.io/etcd/client/pkg/v3/testutil" + "go.uber.org/zap" "go.uber.org/zap/zaptest" "google.golang.org/grpc" @@ -198,3 +199,49 @@ func TestZapWithLogger(t *testing.T) { t.Errorf("WithZapLogger should modify *zap.Logger") } } + +func TestSyncFiltersMembers(t *testing.T) { + c, _ := NewClient(t, Config{Endpoints: []string{"http://254.0.0.1:12345"}}) + defer c.Close() + c.Cluster = &mockCluster{ + []*etcdserverpb.Member{ + {ID: 0, Name: "", ClientURLs: []string{"http://254.0.0.1:12345"}, IsLearner: false}, + {ID: 1, Name: "isStarted", ClientURLs: []string{"http://254.0.0.2:12345"}, IsLearner: true}, + {ID: 2, Name: "isStartedAndNotLearner", ClientURLs: []string{"http://254.0.0.3:12345"}, IsLearner: false}, + }, + } + c.Sync(context.Background()) + + endpoints := c.Endpoints() + if len(endpoints) != 1 || endpoints[0] != "http://254.0.0.3:12345" { + t.Error("Client.Sync uses learner and/or non-started member client URLs") + } +} + +type mockCluster struct { + members []*etcdserverpb.Member +} + +func (mc *mockCluster) MemberList(ctx context.Context) (*MemberListResponse, error) { + return &MemberListResponse{Members: mc.members}, nil +} + +func (mc *mockCluster) MemberAdd(ctx context.Context, peerAddrs []string) (*MemberAddResponse, error) { + return nil, nil +} + +func (mc *mockCluster) MemberAddAsLearner(ctx context.Context, peerAddrs []string) (*MemberAddResponse, error) { + return nil, nil +} + +func (mc *mockCluster) MemberRemove(ctx context.Context, id uint64) (*MemberRemoveResponse, error) { + return nil, nil +} + +func (mc *mockCluster) MemberUpdate(ctx context.Context, id uint64, peerAddrs []string) (*MemberUpdateResponse, error) { + return nil, nil +} + +func (mc *mockCluster) MemberPromote(ctx context.Context, id uint64) (*MemberPromoteResponse, error) { + return nil, nil +}