Merge pull request #2827 from xiang90/cluster_v

etcdhttp: version endpoint also returns cluster version.
release-2.1
Xiang Li 2015-05-13 15:54:54 -07:00
commit 132b12f8db
6 changed files with 39 additions and 20 deletions

View File

@ -53,6 +53,8 @@ type Cluster interface {
// IsIDRemoved checks whether the given ID has been removed from this
// cluster at some point in the past
IsIDRemoved(id types.ID) bool
// ClusterVersion is the cluster-wide minimum major.minor version.
Version() *semver.Version
}
// Cluster is a list of Members that belong to the same raft cluster

View File

@ -92,7 +92,7 @@ func NewClientHandler(server *etcdserver.EtcdServer) http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", http.NotFound)
mux.Handle(healthPath, healthHandler(server))
mux.HandleFunc(versionPath, serveVersion)
mux.HandleFunc(versionPath, versionHandler(server.Cluster(), serveVersion))
mux.Handle(keysPrefix, kh)
mux.Handle(keysPrefix+"/", kh)
mux.HandleFunc(statsPrefix+"/store", sh.serveStore)
@ -357,11 +357,31 @@ func healthHandler(server *etcdserver.EtcdServer) http.HandlerFunc {
}
}
func serveVersion(w http.ResponseWriter, r *http.Request) {
func versionHandler(c etcdserver.Cluster, fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
v := c.Version()
if v != nil {
fn(w, r, v.String())
} else {
fn(w, r, "not_decided")
}
}
}
func serveVersion(w http.ResponseWriter, r *http.Request, clusterV string) {
if !allowMethod(w, r.Method, "GET") {
return
}
w.Write(version.MarshalJSON())
vs := version.Versions{
Server: version.Version,
Cluster: clusterV,
}
b, err := json.Marshal(&vs)
if err != nil {
log.Panicf("version: cannot marshal versions to json (%v)", err)
}
w.Write(b)
}
// parseKeyRequest converts a received http.Request on keysPrefix to

View File

@ -1326,11 +1326,18 @@ func TestServeVersion(t *testing.T) {
t.Fatalf("error creating request: %v", err)
}
rw := httptest.NewRecorder()
serveVersion(rw, req)
serveVersion(rw, req, "2.1.0")
if rw.Code != http.StatusOK {
t.Errorf("code=%d, want %d", rw.Code, http.StatusOK)
}
w := version.MarshalJSON()
vs := version.Versions{
Server: version.Version,
Cluster: "2.1.0",
}
w, err := json.Marshal(&vs)
if err != nil {
t.Fatal(err)
}
if g := rw.Body.String(); g != string(w) {
t.Fatalf("body = %q, want %q", g, string(w))
}
@ -1345,7 +1352,7 @@ func TestServeVersionFails(t *testing.T) {
t.Fatalf("error creating request: %v", err)
}
rw := httptest.NewRecorder()
serveVersion(rw, req)
serveVersion(rw, req, "2.1.0")
if rw.Code != http.StatusMethodNotAllowed {
t.Errorf("method %s: code=%d, want %d", m, rw.Code, http.StatusMethodNotAllowed)
}

View File

@ -48,6 +48,7 @@ func (c *fakeCluster) Members() []*etcdserver.Member {
}
func (c *fakeCluster) Member(id types.ID) *etcdserver.Member { return c.members[uint64(id)] }
func (c *fakeCluster) IsIDRemoved(id types.ID) bool { return false }
func (c *fakeCluster) Version() *semver.Version { return nil }
// errServer implements the etcd.Server interface for testing.
// It returns the given error from any Do/Process/AddMember/RemoveMember calls.

View File

@ -38,7 +38,7 @@ func NewPeerHandler(cluster etcdserver.Cluster, raftHandler http.Handler) http.H
mux.Handle(rafthttp.RaftPrefix, raftHandler)
mux.Handle(rafthttp.RaftPrefix+"/", raftHandler)
mux.Handle(peerMembersPrefix, mh)
mux.HandleFunc(versionPath, serveVersion)
mux.HandleFunc(versionPath, versionHandler(cluster, serveVersion))
return mux
}

View File

@ -15,8 +15,6 @@
package version
import (
"encoding/json"
"log"
"os"
"path"
@ -45,20 +43,11 @@ const (
)
type Versions struct {
Server string `json:"etcdserver"`
// TODO: etcdcluster version
Server string `json:"etcdserver"`
Cluster string `json:"etcdcluster"`
// TODO: raft state machine version
}
// MarshalJSON returns the JSON encoding of Versions struct.
func MarshalJSON() []byte {
b, err := json.Marshal(Versions{Server: Version})
if err != nil {
log.Panicf("version: cannot marshal versions to json (%v)", err)
}
return b
}
func DetectDataDir(dirpath string) (DataDirVersion, error) {
names, err := fileutil.ReadDir(dirpath)
if err != nil {