From 2b76200f702b838c4a21f51ccd64df945ca1095f Mon Sep 17 00:00:00 2001 From: Jingyi Hu Date: Tue, 14 May 2019 16:56:44 -0700 Subject: [PATCH] *: add MemberAddAsLearner to clientv3 Cluster API Made changes to Clientv3 Cluster API: - Added MemberAddAsLearner. - Reverted changes to MemberAdd - removed input parameter isLearner. --- clientv3/cluster.go | 17 ++++++++++++++--- clientv3/example_cluster_test.go | 23 ++++++++++++++++++++++- clientv3/integration/cluster_test.go | 11 +++++------ clientv3/snapshot/member_test.go | 2 +- etcdctl/ctlv3/command/member_command.go | 11 ++++++++++- etcdserver/api/v2v3/server.go | 3 ++- proxy/grpcproxy/cluster.go | 18 +++++++++++++++++- 7 files changed, 71 insertions(+), 14 deletions(-) diff --git a/clientv3/cluster.go b/clientv3/cluster.go index 8a407f562..43ceb79c3 100644 --- a/clientv3/cluster.go +++ b/clientv3/cluster.go @@ -16,11 +16,11 @@ package clientv3 import ( "context" + "errors" pb "go.etcd.io/etcd/v3/etcdserver/etcdserverpb" "go.etcd.io/etcd/v3/pkg/types" - "errors" "google.golang.org/grpc" ) @@ -38,7 +38,10 @@ type Cluster interface { MemberList(ctx context.Context) (*MemberListResponse, error) // MemberAdd adds a new member into the cluster. - MemberAdd(ctx context.Context, peerAddrs []string, isLearner bool) (*MemberAddResponse, error) + MemberAdd(ctx context.Context, peerAddrs []string) (*MemberAddResponse, error) + + // MemberAddAsLearner adds a new learner member into the cluster. + MemberAddAsLearner(ctx context.Context, peerAddrs []string) (*MemberAddResponse, error) // MemberRemove removes an existing member from the cluster. MemberRemove(ctx context.Context, id uint64) (*MemberRemoveResponse, error) @@ -71,7 +74,15 @@ func NewClusterFromClusterClient(remote pb.ClusterClient, c *Client) Cluster { return api } -func (c *cluster) MemberAdd(ctx context.Context, peerAddrs []string, isLearner bool) (*MemberAddResponse, error) { +func (c *cluster) MemberAdd(ctx context.Context, peerAddrs []string) (*MemberAddResponse, error) { + return c.memberAdd(ctx, peerAddrs, false) +} + +func (c *cluster) MemberAddAsLearner(ctx context.Context, peerAddrs []string) (*MemberAddResponse, error) { + return c.memberAdd(ctx, peerAddrs, true) +} + +func (c *cluster) memberAdd(ctx context.Context, peerAddrs []string, isLearner bool) (*MemberAddResponse, error) { // fail-fast before panic in rafthttp if _, err := types.NewURLs(peerAddrs); err != nil { return nil, err diff --git a/clientv3/example_cluster_test.go b/clientv3/example_cluster_test.go index 398fd3829..bb1807823 100644 --- a/clientv3/example_cluster_test.go +++ b/clientv3/example_cluster_test.go @@ -51,7 +51,7 @@ func ExampleCluster_memberAdd() { defer cli.Close() peerURLs := endpoints[2:] - mresp, err := cli.MemberAdd(context.Background(), peerURLs, false) + mresp, err := cli.MemberAdd(context.Background(), peerURLs) if err != nil { log.Fatal(err) } @@ -59,6 +59,27 @@ func ExampleCluster_memberAdd() { // added member.PeerURLs: [http://localhost:32380] } +func ExampleCluster_memberAddAsLearner() { + cli, err := clientv3.New(clientv3.Config{ + Endpoints: endpoints[:2], + DialTimeout: dialTimeout, + }) + if err != nil { + log.Fatal(err) + } + defer cli.Close() + + peerURLs := endpoints[2:] + mresp, err := cli.MemberAddAsLearner(context.Background(), peerURLs) + if err != nil { + log.Fatal(err) + } + fmt.Println("added member.PeerURLs:", mresp.Member.PeerURLs) + fmt.Println("added member.IsLearner:", mresp.Member.IsLearner) + // added member.PeerURLs: [http://localhost:32380] + // added member.IsLearner: true +} + func ExampleCluster_memberRemove() { cli, err := clientv3.New(clientv3.Config{ Endpoints: endpoints[1:], diff --git a/clientv3/integration/cluster_test.go b/clientv3/integration/cluster_test.go index 280e98124..fbc35e51f 100644 --- a/clientv3/integration/cluster_test.go +++ b/clientv3/integration/cluster_test.go @@ -53,7 +53,7 @@ func TestMemberAdd(t *testing.T) { capi := clus.RandClient() urls := []string{"http://127.0.0.1:1234"} - resp, err := capi.MemberAdd(context.Background(), urls, false) + resp, err := capi.MemberAdd(context.Background(), urls) if err != nil { t.Fatalf("failed to add member %v", err) } @@ -175,7 +175,7 @@ func TestMemberAddUpdateWrongURLs(t *testing.T) { {"localhost:1234"}, } for i := range tt { - _, err := capi.MemberAdd(context.Background(), tt[i], false) + _, err := capi.MemberAdd(context.Background(), tt[i]) if err == nil { t.Errorf("#%d: MemberAdd err = nil, but error", i) } @@ -195,14 +195,13 @@ func TestMemberAddForLearner(t *testing.T) { capi := clus.RandClient() urls := []string{"http://127.0.0.1:1234"} - isLearner := true - resp, err := capi.MemberAdd(context.Background(), urls, isLearner) + resp, err := capi.MemberAddAsLearner(context.Background(), urls) if err != nil { t.Fatalf("failed to add member %v", err) } - if resp.Member.IsLearner != isLearner { - t.Errorf("Added a member with IsLearner = %v, got %v", isLearner, resp.Member.IsLearner) + if !resp.Member.IsLearner { + t.Errorf("Added a member as learner, got resp.Member.IsLearner = %v", resp.Member.IsLearner) } numOfLearners, err := getNumberOfLearners(clus) diff --git a/clientv3/snapshot/member_test.go b/clientv3/snapshot/member_test.go index d9c0eb7e4..1260eccda 100644 --- a/clientv3/snapshot/member_test.go +++ b/clientv3/snapshot/member_test.go @@ -55,7 +55,7 @@ func TestSnapshotV3RestoreMultiMemberAdd(t *testing.T) { urls := newEmbedURLs(2) newCURLs, newPURLs := urls[:1], urls[1:] - if _, err = cli.MemberAdd(context.Background(), []string{newPURLs[0].String()}, false); err != nil { + if _, err = cli.MemberAdd(context.Background(), []string{newPURLs[0].String()}); err != nil { t.Fatal(err) } diff --git a/etcdctl/ctlv3/command/member_command.go b/etcdctl/ctlv3/command/member_command.go index 3aefe9da9..5c4ca2a72 100644 --- a/etcdctl/ctlv3/command/member_command.go +++ b/etcdctl/ctlv3/command/member_command.go @@ -21,6 +21,7 @@ import ( "strings" "github.com/spf13/cobra" + "go.etcd.io/etcd/v3/clientv3" ) var ( @@ -122,7 +123,15 @@ func memberAddCommandFunc(cmd *cobra.Command, args []string) { urls := strings.Split(memberPeerURLs, ",") ctx, cancel := commandCtx(cmd) cli := mustClientFromCmd(cmd) - resp, err := cli.MemberAdd(ctx, urls, isLearner) + var ( + resp *clientv3.MemberAddResponse + err error + ) + if isLearner { + resp, err = cli.MemberAddAsLearner(ctx, urls) + } else { + resp, err = cli.MemberAdd(ctx, urls) + } cancel() if err != nil { ExitWithError(ExitError, err) diff --git a/etcdserver/api/v2v3/server.go b/etcdserver/api/v2v3/server.go index cc817ccd5..fa9d66d75 100644 --- a/etcdserver/api/v2v3/server.go +++ b/etcdserver/api/v2v3/server.go @@ -63,7 +63,8 @@ func (s *v2v3Server) Leader() types.ID { } func (s *v2v3Server) AddMember(ctx context.Context, memb membership.Member) ([]*membership.Member, error) { - resp, err := s.c.MemberAdd(ctx, memb.PeerURLs, memb.IsLearner) + // adding member as learner is not supported by V2 Server. + resp, err := s.c.MemberAdd(ctx, memb.PeerURLs) if err != nil { return nil, err } diff --git a/proxy/grpcproxy/cluster.go b/proxy/grpcproxy/cluster.go index 6e69d2337..61b5daa46 100644 --- a/proxy/grpcproxy/cluster.go +++ b/proxy/grpcproxy/cluster.go @@ -109,7 +109,23 @@ func (cp *clusterProxy) monitor(wa gnaming.Watcher) { } func (cp *clusterProxy) MemberAdd(ctx context.Context, r *pb.MemberAddRequest) (*pb.MemberAddResponse, error) { - mresp, err := cp.clus.MemberAdd(ctx, r.PeerURLs, r.IsLearner) + if r.IsLearner { + return cp.memberAddAsLearner(ctx, r.PeerURLs) + } + return cp.memberAdd(ctx, r.PeerURLs) +} + +func (cp *clusterProxy) memberAdd(ctx context.Context, peerURLs []string) (*pb.MemberAddResponse, error) { + mresp, err := cp.clus.MemberAdd(ctx, peerURLs) + if err != nil { + return nil, err + } + resp := (pb.MemberAddResponse)(*mresp) + return &resp, err +} + +func (cp *clusterProxy) memberAddAsLearner(ctx context.Context, peerURLs []string) (*pb.MemberAddResponse, error) { + mresp, err := cp.clus.MemberAddAsLearner(ctx, peerURLs) if err != nil { return nil, err }