Browse Source

client: add member update

Xiang Li 10 years ago
parent
commit
6e3769d39e
2 changed files with 76 additions and 4 deletions
  1. 48 3
      client/members.go
  2. 28 1
      client/members_test.go

+ 48 - 3
client/members.go

@@ -67,11 +67,11 @@ func (c *memberCollection) UnmarshalJSON(data []byte) error {
 	return nil
 }
 
-type memberCreateRequest struct {
+type memberCreateOrUpdateRequest struct {
 	PeerURLs types.URLs
 }
 
-func (m *memberCreateRequest) MarshalJSON() ([]byte, error) {
+func (m *memberCreateOrUpdateRequest) MarshalJSON() ([]byte, error) {
 	s := struct {
 		PeerURLs []string `json:"peerURLs"`
 	}{
@@ -102,6 +102,9 @@ type MembersAPI interface {
 
 	// Remove demotes an existing Member out of the cluster.
 	Remove(ctx context.Context, mID string) error
+
+	// Update instructs etcd to update an existing Member in the cluster.
+	Update(ctx context.Context, mID string, peerURLs []string) error
 }
 
 type httpMembersAPI struct {
@@ -159,6 +162,33 @@ func (m *httpMembersAPI) Add(ctx context.Context, peerURL string) (*Member, erro
 	return &memb, nil
 }
 
+func (m *httpMembersAPI) Update(ctx context.Context, memberID string, peerURLs []string) error {
+	urls, err := types.NewURLs(peerURLs)
+	if err != nil {
+		return err
+	}
+
+	req := &membersAPIActionUpdate{peerURLs: urls, memberID: memberID}
+	resp, body, err := m.client.Do(ctx, req)
+	if err != nil {
+		return err
+	}
+
+	if err := assertStatusCode(resp.StatusCode, http.StatusNoContent, http.StatusNotFound, http.StatusConflict); err != nil {
+		return err
+	}
+
+	if resp.StatusCode != http.StatusNoContent {
+		var merr membersError
+		if err := json.Unmarshal(body, &merr); err != nil {
+			return err
+		}
+		return merr
+	}
+
+	return nil
+}
+
 func (m *httpMembersAPI) Remove(ctx context.Context, memberID string) error {
 	req := &membersAPIActionRemove{memberID: memberID}
 	resp, _, err := m.client.Do(ctx, req)
@@ -194,13 +224,28 @@ type membersAPIActionAdd struct {
 
 func (a *membersAPIActionAdd) HTTPRequest(ep url.URL) *http.Request {
 	u := v2MembersURL(ep)
-	m := memberCreateRequest{PeerURLs: a.peerURLs}
+	m := memberCreateOrUpdateRequest{PeerURLs: a.peerURLs}
 	b, _ := json.Marshal(&m)
 	req, _ := http.NewRequest("POST", u.String(), bytes.NewReader(b))
 	req.Header.Set("Content-Type", "application/json")
 	return req
 }
 
+type membersAPIActionUpdate struct {
+	memberID string
+	peerURLs types.URLs
+}
+
+func (a *membersAPIActionUpdate) HTTPRequest(ep url.URL) *http.Request {
+	u := v2MembersURL(ep)
+	m := memberCreateOrUpdateRequest{PeerURLs: a.peerURLs}
+	u.Path = path.Join(u.Path, a.memberID)
+	b, _ := json.Marshal(&m)
+	req, _ := http.NewRequest("PUT", u.String(), bytes.NewReader(b))
+	req.Header.Set("Content-Type", "application/json")
+	return req
+}
+
 func assertStatusCode(got int, want ...int) (err error) {
 	for _, w := range want {
 		if w == got {

+ 28 - 1
client/members_test.go

@@ -70,6 +70,33 @@ func TestMembersAPIActionAdd(t *testing.T) {
 	}
 }
 
+func TestMembersAPIActionUpdate(t *testing.T) {
+	ep := url.URL{Scheme: "http", Host: "example.com"}
+	act := &membersAPIActionUpdate{
+		memberID: "0xabcd",
+		peerURLs: types.URLs([]url.URL{
+			url.URL{Scheme: "https", Host: "127.0.0.1:8081"},
+			url.URL{Scheme: "http", Host: "127.0.0.1:8080"},
+		}),
+	}
+
+	wantURL := &url.URL{
+		Scheme: "http",
+		Host:   "example.com",
+		Path:   "/v2/members/0xabcd",
+	}
+	wantHeader := http.Header{
+		"Content-Type": []string{"application/json"},
+	}
+	wantBody := []byte(`{"peerURLs":["https://127.0.0.1:8081","http://127.0.0.1:8080"]}`)
+
+	got := *act.HTTPRequest(ep)
+	err := assertRequest(got, "PUT", wantURL, wantHeader, wantBody)
+	if err != nil {
+		t.Error(err.Error())
+	}
+}
+
 func TestMembersAPIActionRemove(t *testing.T) {
 	ep := url.URL{Scheme: "http", Host: "example.com"}
 	act := &membersAPIActionRemove{memberID: "XXX"}
@@ -260,7 +287,7 @@ func TestMemberCollectionUnmarshal(t *testing.T) {
 }
 
 func TestMemberCreateRequestMarshal(t *testing.T) {
-	req := memberCreateRequest{
+	req := memberCreateOrUpdateRequest{
 		PeerURLs: types.URLs([]url.URL{
 			url.URL{Scheme: "http", Host: "127.0.0.1:8081"},
 			url.URL{Scheme: "https", Host: "127.0.0.1:8080"},