From 9a465b9cf5a34ede13ab8be5b723fe1869f3ce3f Mon Sep 17 00:00:00 2001 From: Jonathan Boulle Date: Fri, 24 Oct 2014 14:22:41 -0700 Subject: [PATCH] etcdhttp: add /version endpoint --- etcdserver/etcdhttp/http.go | 13 +++++++++--- etcdserver/etcdhttp/http_test.go | 36 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/etcdserver/etcdhttp/http.go b/etcdserver/etcdhttp/http.go index ab69dc1c3..1a5f276a3 100644 --- a/etcdserver/etcdhttp/http.go +++ b/etcdserver/etcdhttp/http.go @@ -37,6 +37,7 @@ import ( "github.com/coreos/etcd/pkg/types" "github.com/coreos/etcd/raft/raftpb" "github.com/coreos/etcd/store" + "github.com/coreos/etcd/version" ) const ( @@ -45,6 +46,7 @@ const ( deprecatedMachinesPrefix = "/v2/machines" adminMembersPrefix = "/v2/admin/members/" statsPrefix = "/v2/stats" + versionPrefix = "/version" // prefixes of peer endpoint raftPrefix = "/raft" membersPrefix = "/members" @@ -74,11 +76,9 @@ func NewClientHandler(server *etcdserver.EtcdServer) http.Handler { mux.HandleFunc(statsPrefix+"/store", sh.serveStoreStats) mux.HandleFunc(statsPrefix+"/self", sh.serveSelfStats) mux.HandleFunc(statsPrefix+"/leader", sh.serveLeaderStats) - // TODO: dynamic configuration may make this outdated. take care of it. - // TODO: dynamic configuration may introduce race also. - // TODO: add serveMembers mux.HandleFunc(deprecatedMachinesPrefix, sh.serveMachines) mux.HandleFunc(adminMembersPrefix, sh.serveAdminMembers) + mux.HandleFunc(versionPrefix, sh.serveVersion) mux.HandleFunc("/", http.NotFound) return mux } @@ -249,6 +249,13 @@ func (h serverHandler) serveLeaderStats(w http.ResponseWriter, r *http.Request) w.Write(h.stats.LeaderStats()) } +func (h serverHandler) serveVersion(w http.ResponseWriter, r *http.Request) { + if !allowMethod(w, r.Method, "GET") { + return + } + w.Write([]byte("etcd " + version.Version)) +} + func (h serverHandler) serveRaft(w http.ResponseWriter, r *http.Request) { if !allowMethod(w, r.Method, "POST") { return diff --git a/etcdserver/etcdhttp/http_test.go b/etcdserver/etcdhttp/http_test.go index cbebc12a0..084c8d6c3 100644 --- a/etcdserver/etcdhttp/http_test.go +++ b/etcdserver/etcdhttp/http_test.go @@ -20,6 +20,7 @@ import ( "bytes" "encoding/json" "errors" + "fmt" "io" "io/ioutil" "net/http" @@ -40,6 +41,7 @@ import ( "github.com/coreos/etcd/etcdserver/etcdserverpb" "github.com/coreos/etcd/raft/raftpb" "github.com/coreos/etcd/store" + "github.com/coreos/etcd/version" ) func boolp(b bool) *bool { return &b } @@ -754,6 +756,40 @@ func TestServeStoreStats(t *testing.T) { } +func TestServeVersion(t *testing.T) { + req, err := http.NewRequest("GET", "", nil) + if err != nil { + t.Fatalf("error creating request: %v", err) + } + h := &serverHandler{} + rw := httptest.NewRecorder() + h.serveVersion(rw, req) + if rw.Code != http.StatusOK { + t.Errorf("code=%d, want %d", rw.Code, http.StatusOK) + } + w := fmt.Sprintf("etcd %s", version.Version) + if g := rw.Body.String(); g != w { + t.Fatalf("body = %q, want %q", g, w) + } +} + +func TestServeVersionFails(t *testing.T) { + for _, m := range []string{ + "CONNECT", "TRACE", "PUT", "POST", "HEAD", + } { + req, err := http.NewRequest(m, "", nil) + if err != nil { + t.Fatalf("error creating request: %v", err) + } + h := &serverHandler{} + rw := httptest.NewRecorder() + h.serveVersion(rw, req) + if rw.Code != http.StatusMethodNotAllowed { + t.Errorf("method %s: code=%d, want %d", m, rw.Code, http.StatusMethodNotAllowed) + } + } +} + func TestAllowMethod(t *testing.T) { tests := []struct { m string