Bläddra i källkod

Merge pull request #1426 from xiangli-cmu/clusterid

etcdhttp: attach clusterID to key and adminMember endpoint
Xiang Li 11 år sedan
förälder
incheckning
9964bfa6b9
2 ändrade filer med 73 tillägg och 19 borttagningar
  1. 13 6
      etcdserver/etcdhttp/client.go
  2. 60 13
      etcdserver/etcdhttp/client_test.go

+ 13 - 6
etcdserver/etcdhttp/client.go

@@ -50,9 +50,10 @@ const (
 // NewClientHandler generates a muxed http.Handler with the given parameters to serve etcd client requests.
 func NewClientHandler(server *etcdserver.EtcdServer) http.Handler {
 	kh := &keysHandler{
-		server:  server,
-		timer:   server,
-		timeout: defaultServerTimeout,
+		server:      server,
+		clusterInfo: server.Cluster,
+		timer:       server,
+		timeout:     defaultServerTimeout,
 	}
 
 	sh := &statsHandler{
@@ -83,15 +84,18 @@ func NewClientHandler(server *etcdserver.EtcdServer) http.Handler {
 }
 
 type keysHandler struct {
-	server  etcdserver.Server
-	timer   etcdserver.RaftTimer
-	timeout time.Duration
+	server      etcdserver.Server
+	clusterInfo etcdserver.ClusterInfo
+	timer       etcdserver.RaftTimer
+	timeout     time.Duration
 }
 
 func (h *keysHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	if !allowMethod(w, r.Method, "GET", "PUT", "POST", "DELETE") {
 		return
 	}
+	cid := strconv.FormatUint(h.clusterInfo.ID(), 16)
+	w.Header().Set("X-Etcd-Cluster-ID", cid)
 
 	ctx, cancel := context.WithTimeout(context.Background(), h.timeout)
 	defer cancel()
@@ -146,6 +150,9 @@ func (h *adminMembersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 	if !allowMethod(w, r.Method, "GET", "POST", "DELETE") {
 		return
 	}
+	cid := strconv.FormatUint(h.clusterInfo.ID(), 16)
+	w.Header().Set("X-Etcd-Cluster-ID", cid)
+
 	ctx, cancel := context.WithTimeout(context.Background(), defaultServerTimeout)
 	defer cancel()
 

+ 60 - 13
etcdserver/etcdhttp/client_test.go

@@ -27,6 +27,7 @@ import (
 	"net/url"
 	"path"
 	"reflect"
+	"strconv"
 	"strings"
 	"testing"
 	"time"
@@ -551,6 +552,7 @@ func TestServeAdminMembers(t *testing.T) {
 	memb1 := etcdserver.Member{ID: 1, Attributes: etcdserver.Attributes{ClientURLs: []string{"http://localhost:8080"}}}
 	memb2 := etcdserver.Member{ID: 2, Attributes: etcdserver.Attributes{ClientURLs: []string{"http://localhost:8081"}}}
 	cluster := &fakeCluster{
+		id:      1,
 		members: map[uint64]*etcdserver.Member{1: &memb1, 2: &memb2},
 	}
 	h := &adminMembersHandler{
@@ -596,6 +598,11 @@ func TestServeAdminMembers(t *testing.T) {
 		if gct := rw.Header().Get("Content-Type"); gct != tt.wct {
 			t.Errorf("#%d: content-type = %s, want %s", i, gct, tt.wct)
 		}
+		gcid := rw.Header().Get("X-Etcd-Cluster-ID")
+		wcid := strconv.FormatUint(cluster.ID(), 16)
+		if gcid != wcid {
+			t.Errorf("#%d: cid = %s, want %s", i, gcid, wcid)
+		}
 		if rw.Body.String() != tt.wbody {
 			t.Errorf("#%d: body = %q, want %q", i, rw.Body.String(), tt.wbody)
 		}
@@ -617,8 +624,9 @@ func TestServeAdminMembersPut(t *testing.T) {
 	req.Header.Set("Content-Type", "application/json")
 	s := &serverRecorder{}
 	h := &adminMembersHandler{
-		server: s,
-		clock:  clockwork.NewFakeClock(),
+		server:      s,
+		clock:       clockwork.NewFakeClock(),
+		clusterInfo: &fakeCluster{id: 1},
 	}
 	rw := httptest.NewRecorder()
 
@@ -641,6 +649,11 @@ func TestServeAdminMembersPut(t *testing.T) {
 	if gct := rw.Header().Get("Content-Type"); gct != wct {
 		t.Errorf("content-type = %s, want %s", gct, wct)
 	}
+	gcid := rw.Header().Get("X-Etcd-Cluster-ID")
+	wcid := strconv.FormatUint(h.clusterInfo.ID(), 16)
+	if gcid != wcid {
+		t.Errorf("cid = %s, want %s", gcid, wcid)
+	}
 	g := rw.Body.String()
 	w := string(wb) + "\n"
 	if g != w {
@@ -659,7 +672,8 @@ func TestServeAdminMembersDelete(t *testing.T) {
 	}
 	s := &serverRecorder{}
 	h := &adminMembersHandler{
-		server: s,
+		server:      s,
+		clusterInfo: &fakeCluster{id: 1},
 	}
 	rw := httptest.NewRecorder()
 
@@ -669,6 +683,11 @@ func TestServeAdminMembersDelete(t *testing.T) {
 	if rw.Code != wcode {
 		t.Errorf("code=%d, want %d", rw.Code, wcode)
 	}
+	gcid := rw.Header().Get("X-Etcd-Cluster-ID")
+	wcid := strconv.FormatUint(h.clusterInfo.ID(), 16)
+	if gcid != wcid {
+		t.Errorf("cid = %s, want %s", gcid, wcid)
+	}
 	g := rw.Body.String()
 	if g != "" {
 		t.Errorf("got body=%q, want %q", g, "")
@@ -768,14 +787,22 @@ func TestServeAdminMembersFail(t *testing.T) {
 	}
 	for i, tt := range tests {
 		h := &adminMembersHandler{
-			server: tt.server,
-			clock:  clockwork.NewFakeClock(),
+			server:      tt.server,
+			clusterInfo: &fakeCluster{id: 1},
+			clock:       clockwork.NewFakeClock(),
 		}
 		rw := httptest.NewRecorder()
 		h.ServeHTTP(rw, tt.req)
 		if rw.Code != tt.wcode {
 			t.Errorf("#%d: code=%d, want %d", i, rw.Code, tt.wcode)
 		}
+		if rw.Code != http.StatusMethodNotAllowed {
+			gcid := rw.Header().Get("X-Etcd-Cluster-ID")
+			wcid := strconv.FormatUint(h.clusterInfo.ID(), 16)
+			if gcid != wcid {
+				t.Errorf("#%d: cid = %s, want %s", i, gcid, wcid)
+			}
+		}
 	}
 }
 
@@ -1101,14 +1128,22 @@ func TestBadServeKeys(t *testing.T) {
 	}
 	for i, tt := range testBadCases {
 		h := &keysHandler{
-			timeout: 0, // context times out immediately
-			server:  tt.server,
+			timeout:     0, // context times out immediately
+			server:      tt.server,
+			clusterInfo: &fakeCluster{id: 1},
 		}
 		rw := httptest.NewRecorder()
 		h.ServeHTTP(rw, tt.req)
 		if rw.Code != tt.wcode {
 			t.Errorf("#%d: got code=%d, want %d", i, rw.Code, tt.wcode)
 		}
+		if rw.Code != http.StatusMethodNotAllowed {
+			gcid := rw.Header().Get("X-Etcd-Cluster-ID")
+			wcid := strconv.FormatUint(h.clusterInfo.ID(), 16)
+			if gcid != wcid {
+				t.Errorf("#%d: cid = %s, want %s", i, gcid, wcid)
+			}
+		}
 		if g := strings.TrimSuffix(rw.Body.String(), "\n"); g != tt.wbody {
 			t.Errorf("#%d: body = %s, want %s", i, g, tt.wbody)
 		}
@@ -1126,9 +1161,10 @@ func TestServeKeysEvent(t *testing.T) {
 		},
 	}
 	h := &keysHandler{
-		timeout: time.Hour,
-		server:  server,
-		timer:   &dummyRaftTimer{},
+		timeout:     time.Hour,
+		server:      server,
+		clusterInfo: &fakeCluster{id: 1},
+		timer:       &dummyRaftTimer{},
 	}
 	rw := httptest.NewRecorder()
 
@@ -1146,6 +1182,11 @@ func TestServeKeysEvent(t *testing.T) {
 	if rw.Code != wcode {
 		t.Errorf("got code=%d, want %d", rw.Code, wcode)
 	}
+	gcid := rw.Header().Get("X-Etcd-Cluster-ID")
+	wcid := strconv.FormatUint(h.clusterInfo.ID(), 16)
+	if gcid != wcid {
+		t.Errorf("cid = %s, want %s", gcid, wcid)
+	}
 	g := rw.Body.String()
 	if g != wbody {
 		t.Errorf("got body=%#v, want %#v", g, wbody)
@@ -1164,9 +1205,10 @@ func TestServeKeysWatch(t *testing.T) {
 		},
 	}
 	h := &keysHandler{
-		timeout: time.Hour,
-		server:  server,
-		timer:   &dummyRaftTimer{},
+		timeout:     time.Hour,
+		server:      server,
+		clusterInfo: &fakeCluster{id: 1},
+		timer:       &dummyRaftTimer{},
 	}
 	go func() {
 		ec <- &store.Event{
@@ -1190,6 +1232,11 @@ func TestServeKeysWatch(t *testing.T) {
 	if rw.Code != wcode {
 		t.Errorf("got code=%d, want %d", rw.Code, wcode)
 	}
+	gcid := rw.Header().Get("X-Etcd-Cluster-ID")
+	wcid := strconv.FormatUint(h.clusterInfo.ID(), 16)
+	if gcid != wcid {
+		t.Errorf("cid = %s, want %s", gcid, wcid)
+	}
 	g := rw.Body.String()
 	if g != wbody {
 		t.Errorf("got body=%#v, want %#v", g, wbody)