Browse Source

etcdserver: add member endpoint to peerurl

Xiang Li 11 years ago
parent
commit
02551c277d
2 changed files with 59 additions and 16 deletions
  1. 12 1
      etcdserver/etcdhttp/http.go
  2. 47 15
      etcdserver/etcdhttp/http_test.go

+ 12 - 1
etcdserver/etcdhttp/http.go

@@ -41,11 +41,14 @@ import (
 )
 )
 
 
 const (
 const (
+	// prefixes of client endpoint
 	keysPrefix               = "/v2/keys"
 	keysPrefix               = "/v2/keys"
 	deprecatedMachinesPrefix = "/v2/machines"
 	deprecatedMachinesPrefix = "/v2/machines"
 	adminMembersPrefix       = "/v2/admin/members/"
 	adminMembersPrefix       = "/v2/admin/members/"
-	raftPrefix               = "/raft"
 	statsPrefix              = "/v2/stats"
 	statsPrefix              = "/v2/stats"
+	// prefixes of peer endpoint
+	raftPrefix    = "/raft"
+	membersPrefix = "/members"
 
 
 	// time to wait for response from EtcdServer requests
 	// time to wait for response from EtcdServer requests
 	defaultServerTimeout = 500 * time.Millisecond
 	defaultServerTimeout = 500 * time.Millisecond
@@ -91,6 +94,7 @@ func NewPeerHandler(server *etcdserver.EtcdServer) http.Handler {
 	}
 	}
 	mux := http.NewServeMux()
 	mux := http.NewServeMux()
 	mux.HandleFunc(raftPrefix, sh.serveRaft)
 	mux.HandleFunc(raftPrefix, sh.serveRaft)
+	mux.HandleFunc(membersPrefix, sh.serveMembers)
 	mux.HandleFunc("/", http.NotFound)
 	mux.HandleFunc("/", http.NotFound)
 	return mux
 	return mux
 }
 }
@@ -306,6 +310,13 @@ func (h serverHandler) serveRaft(w http.ResponseWriter, r *http.Request) {
 	w.WriteHeader(http.StatusNoContent)
 	w.WriteHeader(http.StatusNoContent)
 }
 }
 
 
+func (h serverHandler) serveMembers(w http.ResponseWriter, r *http.Request) {
+	if !allowMethod(w, r.Method, "GET") {
+		return
+	}
+	h.serveAdminMembers(w, r)
+}
+
 // parseKeyRequest converts a received http.Request on keysPrefix to
 // parseKeyRequest converts a received http.Request on keysPrefix to
 // a server Request, performing validation of supplied fields as appropriate.
 // a server Request, performing validation of supplied fields as appropriate.
 // If any validation fails, an empty Request and non-nil error is returned.
 // If any validation fails, an empty Request and non-nil error is returned.

+ 47 - 15
etcdserver/etcdhttp/http_test.go

@@ -988,6 +988,34 @@ func TestServeRaft(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func TestServeMembersFails(t *testing.T) {
+	tests := []struct {
+		method string
+		wcode  int
+	}{
+		{
+			"POST",
+			http.StatusMethodNotAllowed,
+		},
+		{
+			"DELETE",
+			http.StatusMethodNotAllowed,
+		},
+		{
+			"BAD",
+			http.StatusMethodNotAllowed,
+		},
+	}
+	for i, tt := range tests {
+		h := &serverHandler{}
+		rw := httptest.NewRecorder()
+		h.serveMembers(rw, &http.Request{Method: tt.method})
+		if rw.Code != tt.wcode {
+			t.Errorf("#%d: code=%d, want %d", i, rw.Code, tt.wcode)
+		}
+	}
+}
+
 // resServer implements the etcd.Server interface for testing.
 // resServer implements the etcd.Server interface for testing.
 // It returns the given responsefrom any Do calls, and nil error
 // It returns the given responsefrom any Do calls, and nil error
 type resServer struct {
 type resServer struct {
@@ -1532,7 +1560,7 @@ func (s *serverRecorder) RemoveMember(_ context.Context, id uint64) error {
 	return nil
 	return nil
 }
 }
 
 
-func TestServeAdminMembersGet(t *testing.T) {
+func TestServeAdminMembersAndMembersGet(t *testing.T) {
 	memb1 := etcdserver.Member{ID: 1, Attributes: etcdserver.Attributes{ClientURLs: []string{"http://localhost:8080"}}}
 	memb1 := etcdserver.Member{ID: 1, Attributes: etcdserver.Attributes{ClientURLs: []string{"http://localhost:8080"}}}
 	memb2 := etcdserver.Member{ID: 2, Attributes: etcdserver.Attributes{ClientURLs: []string{"http://localhost:8081"}}}
 	memb2 := etcdserver.Member{ID: 2, Attributes: etcdserver.Attributes{ClientURLs: []string{"http://localhost:8081"}}}
 	cluster := &fakeCluster{
 	cluster := &fakeCluster{
@@ -1566,22 +1594,26 @@ func TestServeAdminMembersGet(t *testing.T) {
 		{path.Join(adminMembersPrefix, "100"), http.StatusNotFound, "text/plain; charset=utf-8", "member not found\n"},
 		{path.Join(adminMembersPrefix, "100"), http.StatusNotFound, "text/plain; charset=utf-8", "member not found\n"},
 	}
 	}
 
 
+	funcs := []func(w http.ResponseWriter, r *http.Request){h.serveAdminMembers, h.serveMembers}
+
 	for i, tt := range tests {
 	for i, tt := range tests {
-		req, err := http.NewRequest("GET", mustNewURL(t, tt.path).String(), nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-		rw := httptest.NewRecorder()
-		h.serveAdminMembers(rw, req)
+		for j, f := range funcs {
+			req, err := http.NewRequest("GET", mustNewURL(t, tt.path).String(), nil)
+			if err != nil {
+				t.Fatal(err)
+			}
+			rw := httptest.NewRecorder()
+			f(rw, req)
 
 
-		if rw.Code != tt.wcode {
-			t.Errorf("#%d: code=%d, want %d", i, rw.Code, tt.wcode)
-		}
-		if gct := rw.Header().Get("Content-Type"); gct != tt.wct {
-			t.Errorf("#%d: content-type = %s, want %s", i, gct, tt.wct)
-		}
-		if rw.Body.String() != tt.wbody {
-			t.Errorf("#%d: body = %s, want %s", i, rw.Body.String(), tt.wbody)
+			if rw.Code != tt.wcode {
+				t.Errorf("#%d.%d: code=%d, want %d", i, j, rw.Code, tt.wcode)
+			}
+			if gct := rw.Header().Get("Content-Type"); gct != tt.wct {
+				t.Errorf("#%d.%d: content-type = %s, want %s", i, j, gct, tt.wct)
+			}
+			if rw.Body.String() != tt.wbody {
+				t.Errorf("#%d.%d: body = %s, want %s", i, j, rw.Body.String(), tt.wbody)
+			}
 		}
 		}
 	}
 	}
 }
 }