Browse Source

*: add MemberAddAsLearner to clientv3 Cluster API

Made changes to Clientv3 Cluster API:

- Added MemberAddAsLearner.
- Reverted changes to MemberAdd - removed input parameter isLearner.
Jingyi Hu 6 years ago
parent
commit
2b76200f70

+ 14 - 3
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

+ 22 - 1
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:],

+ 5 - 6
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)

+ 1 - 1
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)
 	}
 

+ 10 - 1
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)

+ 2 - 1
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
 	}

+ 17 - 1
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
 	}