From 8d6bb4a4716b70412dfb87f2f2a7f00c283ee0ac Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Thu, 23 Oct 2014 08:41:59 -0700 Subject: [PATCH] etcdserver: support GET on admin endpoint --- etcdserver/etcdhttp/http.go | 31 ++++++++++++++- etcdserver/etcdhttp/http_test.go | 65 ++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/etcdserver/etcdhttp/http.go b/etcdserver/etcdhttp/http.go index c63e5b550..67fb416e0 100644 --- a/etcdserver/etcdhttp/http.go +++ b/etcdserver/etcdhttp/http.go @@ -149,13 +149,42 @@ func (h serverHandler) serveMachines(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 } ctx, cancel := context.WithTimeout(context.Background(), defaultServerTimeout) defer cancel() 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": ctype := r.Header.Get("Content-Type") if ctype != "application/json" { diff --git a/etcdserver/etcdhttp/http_test.go b/etcdserver/etcdhttp/http_test.go index 339e928a8..00c7f3a83 100644 --- a/etcdserver/etcdhttp/http_test.go +++ b/etcdserver/etcdhttp/http_test.go @@ -1485,6 +1485,16 @@ func TestServeAdminMembersFail(t *testing.T) { 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 { h := &serverHandler{ @@ -1527,6 +1537,61 @@ func (s *serverRecorder) RemoveMember(_ context.Context, id uint64) error { 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) { u := mustNewURL(t, adminMembersPrefix) raftAttr := etcdserver.RaftAttributes{PeerURLs: []string{"http://127.0.0.1:1"}}