From 0c1d1b7aeb8612bb5f9a231e7e5448db2307b417 Mon Sep 17 00:00:00 2001 From: Yicheng Qin Date: Mon, 8 Sep 2014 16:34:29 -0700 Subject: [PATCH] etcdhttp: add /v2/machines endpoint --- etcdserver/etcdhttp/http.go | 29 +++++++++++++++++++++++++++-- etcdserver/etcdhttp/http_test.go | 32 ++++++++++++++++++++++++++++++++ main.go | 1 + 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/etcdserver/etcdhttp/http.go b/etcdserver/etcdhttp/http.go index c42bd77bf..c15100310 100644 --- a/etcdserver/etcdhttp/http.go +++ b/etcdserver/etcdhttp/http.go @@ -11,6 +11,7 @@ import ( "log" "net/http" "net/url" + "sort" "strconv" "strings" "time" @@ -27,7 +28,10 @@ import ( "github.com/coreos/etcd/third_party/code.google.com/p/go.net/context" ) -const keysPrefix = "/v2/keys" +const ( + keysPrefix = "/v2/keys" + machinesPrefix = "/v2/machines" +) type Peers map[int64][]string @@ -36,7 +40,12 @@ func (ps Peers) Pick(id int64) string { if len(addrs) == 0 { return "" } - return fmt.Sprintf("http://%s", addrs[rand.Intn(len(addrs))]) + return addScheme(addrs[rand.Intn(len(addrs))]) +} + +// TODO: improve this when implementing TLS +func addScheme(addr string) string { + return fmt.Sprintf("http://%s", addr) } // Set parses command line sets of names to ips formatted like: @@ -138,6 +147,7 @@ func httpPost(url string, data []byte) bool { type Handler struct { Timeout time.Duration Server *etcdserver.Server + Peers Peers } func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -156,6 +166,8 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { h.serveRaft(ctx, w, r) case strings.HasPrefix(r.URL.Path, keysPrefix): h.serveKeys(ctx, w, r) + case strings.HasPrefix(r.URL.Path, machinesPrefix): + h.serveMachines(w, r) default: http.NotFound(w, r) } @@ -188,6 +200,19 @@ func (h Handler) serveKeys(ctx context.Context, w http.ResponseWriter, r *http.R } } +// serveMachines responds address list in the format '0.0.0.0, 1.1.1.1'. +// TODO: rethink the format of machine list because it is not json format. +func (h Handler) serveMachines(w http.ResponseWriter, r *http.Request) { + urls := make([]string, 0) + for _, addrs := range h.Peers { + for _, addr := range addrs { + urls = append(urls, addScheme(addr)) + } + } + sort.Sort(sort.StringSlice(urls)) + w.Write([]byte(strings.Join(urls, ", "))) +} + func (h Handler) serveRaft(ctx context.Context, w http.ResponseWriter, r *http.Request) { b, err := ioutil.ReadAll(r.Body) if err != nil { diff --git a/etcdserver/etcdhttp/http_test.go b/etcdserver/etcdhttp/http_test.go index 61107e0b1..c0b667279 100644 --- a/etcdserver/etcdhttp/http_test.go +++ b/etcdserver/etcdhttp/http_test.go @@ -347,3 +347,35 @@ func TestWaitForEventCancelledContext(t *testing.T) { t.Fatalf("nil err returned with cancelled context!") } } + +func TestV2MachinesEndpoint(t *testing.T) { + h := Handler{Peers: Peers{}} + + s := httptest.NewServer(h) + defer s.Close() + + resp, err := http.Get(s.URL + machinesPrefix) + if err != nil { + t.Fatal(err) + } + + if resp.StatusCode != http.StatusOK { + t.Errorf("StatusCode = %d, expected %d", resp.StatusCode, http.StatusOK) + } +} + +func TestServeMachines(t *testing.T) { + peers := Peers{} + peers.Set("0xBEEF0=localhost:8080&0xBEEF1=localhost:8081&0xBEEF2=localhost:8082") + h := Handler{Peers: peers} + + writer := httptest.NewRecorder() + h.serveMachines(writer, nil) + w := "http://localhost:8080, http://localhost:8081, http://localhost:8082" + if g := writer.Body.String(); g != w { + t.Errorf("data = %s, want %s", g, w) + } + if writer.Code != http.StatusOK { + t.Errorf("header = %d, want %d", writer.Code, http.StatusOK) + } +} diff --git a/main.go b/main.go index 8e3e5694f..93fcdac2a 100644 --- a/main.go +++ b/main.go @@ -70,6 +70,7 @@ func main() { h := &etcdhttp.Handler{ Timeout: *timeout, Server: s, + Peers: peers, } http.Handle("/", h) log.Fatal(http.ListenAndServe(*laddr, nil))