etcdserver: support GET on admin endpoint

This commit is contained in:
Xiang Li 2014-10-23 08:41:59 -07:00
parent 051ad7585f
commit 8d6bb4a471
2 changed files with 95 additions and 1 deletions

View File

@ -149,13 +149,42 @@ func (h serverHandler) serveMachines(w http.ResponseWriter, r *http.Request) {
} }
func (h serverHandler) serveAdminMembers(w http.ResponseWriter, r *http.Request) { func (h serverHandler) serveAdminMembers(w http.ResponseWriter, r *http.Request) {
if !allowMethod(w, r.Method, "POST", "DELETE") { if !allowMethod(w, r.Method, "GET", "POST", "DELETE") {
return return
} }
ctx, cancel := context.WithTimeout(context.Background(), defaultServerTimeout) ctx, cancel := context.WithTimeout(context.Background(), defaultServerTimeout)
defer cancel() defer cancel()
switch r.Method { switch r.Method {
case "GET":
idStr := strings.TrimPrefix(r.URL.Path, adminMembersPrefix)
if idStr == "" {
msmap := h.clusterStore.Get().Members()
ms := make([]*etcdserver.Member, 0, len(msmap))
for _, m := range msmap {
ms = append(ms, m)
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(ms); err != nil {
log.Printf("etcdhttp: %v", err)
}
return
}
id, err := strconv.ParseUint(idStr, 16, 64)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
m := h.clusterStore.Get().FindID(id)
if m == nil {
http.Error(w, "member not found", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(m); err != nil {
log.Printf("etcdhttp: %v", err)
}
return
case "POST": case "POST":
ctype := r.Header.Get("Content-Type") ctype := r.Header.Get("Content-Type")
if ctype != "application/json" { if ctype != "application/json" {

View File

@ -1485,6 +1485,16 @@ func TestServeAdminMembersFail(t *testing.T) {
http.StatusInternalServerError, http.StatusInternalServerError,
}, },
{
// etcdserver.GetMember bad id
&http.Request{
URL: mustNewURL(t, path.Join(adminMembersPrefix, "badid")),
Method: "GET",
},
&errServer{},
http.StatusBadRequest,
},
} }
for i, tt := range tests { for i, tt := range tests {
h := &serverHandler{ h := &serverHandler{
@ -1527,6 +1537,61 @@ func (s *serverRecorder) RemoveMember(_ context.Context, id uint64) error {
return nil return nil
} }
func TestServeAdminMembersGet(t *testing.T) {
cluster := &fakeCluster{
members: []etcdserver.Member{
{ID: 1, Attributes: etcdserver.Attributes{ClientURLs: []string{"http://localhost:8080"}}},
{ID: 2, Attributes: etcdserver.Attributes{ClientURLs: []string{"http://localhost:8081"}}},
},
}
h := &serverHandler{
server: &serverRecorder{},
clock: clockwork.NewFakeClock(),
clusterStore: cluster,
}
msb, err := json.Marshal(cluster.members)
if err != nil {
t.Fatal(err)
}
wms := string(msb) + "\n"
mb, err := json.Marshal(cluster.members[0])
if err != nil {
t.Fatal(err)
}
wm := string(mb) + "\n"
tests := []struct {
path string
wcode int
wct string
wbody string
}{
{adminMembersPrefix, http.StatusOK, "application/json", wms},
{path.Join(adminMembersPrefix, "1"), http.StatusOK, "application/json", wm},
{path.Join(adminMembersPrefix, "100"), http.StatusNotFound, "text/plain; charset=utf-8", "member not found\n"},
}
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)
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)
}
}
}
func TestServeAdminMembersPut(t *testing.T) { func TestServeAdminMembersPut(t *testing.T) {
u := mustNewURL(t, adminMembersPrefix) u := mustNewURL(t, adminMembersPrefix)
raftAttr := etcdserver.RaftAttributes{PeerURLs: []string{"http://127.0.0.1:1"}} raftAttr := etcdserver.RaftAttributes{PeerURLs: []string{"http://127.0.0.1:1"}}