From 2ff3cac653369cca965d65620881b095bd90a891 Mon Sep 17 00:00:00 2001 From: Yicheng Qin Date: Wed, 15 Oct 2014 00:19:27 -0700 Subject: [PATCH 1/4] etcdserver/etcdhttp: store location adjustment Detailed adjustment: /_etcd/machines/* -> /0/members/* /* -> /1/* And it keeps key path returned to user the same as before. --- etcdserver/cluster_store.go | 2 +- etcdserver/cluster_store_test.go | 6 +-- etcdserver/etcdhttp/http.go | 29 +++++++++-- etcdserver/etcdhttp/http_test.go | 84 +++++++++++++++++++++++++++++++- etcdserver/member.go | 4 +- etcdserver/server.go | 4 ++ 6 files changed, 117 insertions(+), 12 deletions(-) diff --git a/etcdserver/cluster_store.go b/etcdserver/cluster_store.go index def0284bf..4c2af8447 100644 --- a/etcdserver/cluster_store.go +++ b/etcdserver/cluster_store.go @@ -77,7 +77,7 @@ func (s *clusterStore) Add(m Member) { func (s *clusterStore) Get() Cluster { c := NewCluster() c.id = s.id - e, err := s.Store.Get(membersKVPrefix, true, true) + e, err := s.Store.Get(membersDir, true, true) if err != nil { if v, ok := err.(*etcdErr.Error); ok && v.ErrorCode == etcdErr.EcodeKeyNotFound { return *c diff --git a/etcdserver/cluster_store_test.go b/etcdserver/cluster_store_test.go index f73424286..0fe6c3b3a 100644 --- a/etcdserver/cluster_store_test.go +++ b/etcdserver/cluster_store_test.go @@ -34,7 +34,7 @@ func TestClusterStoreAdd(t *testing.T) { { name: "Create", params: []interface{}{ - membersKVPrefix + "1/raftAttributes", + membersDir + "/1/raftAttributes", false, `{"PeerURLs":null}`, false, @@ -44,7 +44,7 @@ func TestClusterStoreAdd(t *testing.T) { { name: "Create", params: []interface{}{ - membersKVPrefix + "1/attributes", + membersDir + "/1/attributes", false, `{"Name":"node1","ClientURLs":null}`, false, @@ -113,7 +113,7 @@ func TestClusterStoreDelete(t *testing.T) { cs.Add(newTestMember(1, nil, "node1", nil)) cs.Remove(1) - wdeletes := []string{membersKVPrefix + "1"} + wdeletes := []string{membersDir + "/1"} if !reflect.DeepEqual(st.deletes, wdeletes) { t.Errorf("deletes = %v, want %v", st.deletes, wdeletes) } diff --git a/etcdserver/etcdhttp/http.go b/etcdserver/etcdhttp/http.go index 5e028aebe..4f691344f 100644 --- a/etcdserver/etcdhttp/http.go +++ b/etcdserver/etcdhttp/http.go @@ -113,6 +113,7 @@ func (h serverHandler) serveKeys(w http.ResponseWriter, r *http.Request) { return } + rr.Path = etcdserver.KeysDir + rr.Path resp, err := h.server.Do(ctx, rr) if err != nil { writeError(w, err) @@ -121,14 +122,15 @@ func (h serverHandler) serveKeys(w http.ResponseWriter, r *http.Request) { switch { case resp.Event != nil: - if err := writeEvent(w, resp.Event, h.timer); err != nil { + ev := trimEventPrefix(resp.Event, etcdserver.KeysDir) + if err := writeEvent(w, ev, h.timer); err != nil { // Should never be reached log.Printf("error writing event: %v", err) } case resp.Watcher != nil: ctx, cancel := context.WithTimeout(context.Background(), defaultWatchTimeout) defer cancel() - handleWatch(ctx, w, resp.Watcher, rr.Stream, h.timer) + handleKeyWatch(ctx, w, resp.Watcher, rr.Stream, h.timer) default: writeError(w, errors.New("received response with no Event/Watcher!")) } @@ -444,7 +446,7 @@ func writeEvent(w http.ResponseWriter, ev *store.Event, rt etcdserver.RaftTimer) return json.NewEncoder(w).Encode(ev) } -func handleWatch(ctx context.Context, w http.ResponseWriter, wa store.Watcher, stream bool, rt etcdserver.RaftTimer) { +func handleKeyWatch(ctx context.Context, w http.ResponseWriter, wa store.Watcher, stream bool, rt etcdserver.RaftTimer) { defer wa.Remove() ech := wa.EventChan() var nch <-chan bool @@ -476,6 +478,7 @@ func handleWatch(ctx context.Context, w http.ResponseWriter, wa store.Watcher, s // send to the client in time. Then we simply end streaming. return } + ev = trimEventPrefix(ev, etcdserver.KeysDir) if err := json.NewEncoder(w).Encode(ev); err != nil { // Should never be reached log.Printf("error writing event: %v\n", err) @@ -502,3 +505,23 @@ func allowMethod(w http.ResponseWriter, m string, ms ...string) bool { http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) return false } + +func trimEventPrefix(ev *store.Event, pre string) *store.Event { + if ev == nil { + return nil + } + ev.Node = trimNodeExternPrefix(ev.Node, pre) + ev.PrevNode = trimNodeExternPrefix(ev.PrevNode, pre) + return ev +} + +func trimNodeExternPrefix(n *store.NodeExtern, pre string) *store.NodeExtern { + if n == nil { + return nil + } + n.Key = strings.TrimPrefix(n.Key, pre) + for _, nn := range n.Nodes { + nn = trimNodeExternPrefix(nn, pre) + } + return n +} diff --git a/etcdserver/etcdhttp/http_test.go b/etcdserver/etcdhttp/http_test.go index 287742a87..8c7114397 100644 --- a/etcdserver/etcdhttp/http_test.go +++ b/etcdserver/etcdhttp/http_test.go @@ -1240,7 +1240,7 @@ func TestHandleWatch(t *testing.T) { } tt.doToChan(wa.echan) - handleWatch(tt.getCtx(), rw, wa, false, dummyRaftTimer{}) + handleKeyWatch(tt.getCtx(), rw, wa, false, dummyRaftTimer{}) wcode := http.StatusOK wct := "application/json" @@ -1295,7 +1295,7 @@ func TestHandleWatchStreaming(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) done := make(chan struct{}) go func() { - handleWatch(ctx, rw, wa, true, dummyRaftTimer{}) + handleKeyWatch(ctx, rw, wa, true, dummyRaftTimer{}) close(done) }() @@ -1561,6 +1561,86 @@ func TestServeAdminMembersDelete(t *testing.T) { } } +func TestTrimEventPrefix(t *testing.T) { + pre := "/abc" + tests := []struct { + ev *store.Event + wev *store.Event + }{ + { + nil, + nil, + }, + { + &store.Event{}, + &store.Event{}, + }, + { + &store.Event{Node: &store.NodeExtern{Key: "/abc/def"}}, + &store.Event{Node: &store.NodeExtern{Key: "/def"}}, + }, + { + &store.Event{PrevNode: &store.NodeExtern{Key: "/abc/ghi"}}, + &store.Event{PrevNode: &store.NodeExtern{Key: "/ghi"}}, + }, + { + &store.Event{ + Node: &store.NodeExtern{Key: "/abc/def"}, + PrevNode: &store.NodeExtern{Key: "/abc/ghi"}, + }, + &store.Event{ + Node: &store.NodeExtern{Key: "/def"}, + PrevNode: &store.NodeExtern{Key: "/ghi"}, + }, + }, + } + for i, tt := range tests { + ev := trimEventPrefix(tt.ev, pre) + if !reflect.DeepEqual(ev, tt.wev) { + t.Errorf("#%d: event = %+v, want %+v", i, ev, tt.wev) + } + } +} + +func TestTrimNodeExternPrefix(t *testing.T) { + pre := "/abc" + tests := []struct { + n *store.NodeExtern + wn *store.NodeExtern + }{ + { + nil, + nil, + }, + { + &store.NodeExtern{Key: "/abc/def"}, + &store.NodeExtern{Key: "/def"}, + }, + { + &store.NodeExtern{ + Key: "/abc/def", + Nodes: []*store.NodeExtern{ + {Key: "/abc/def/1"}, + {Key: "/abc/def/2"}, + }, + }, + &store.NodeExtern{ + Key: "/def", + Nodes: []*store.NodeExtern{ + {Key: "/def/1"}, + {Key: "/def/2"}, + }, + }, + }, + } + for i, tt := range tests { + n := trimNodeExternPrefix(tt.n, pre) + if !reflect.DeepEqual(n, tt.wn) { + t.Errorf("#%d: node = %+v, want %+v", i, n, tt.wn) + } + } +} + type fakeCluster struct { members []etcdserver.Member } diff --git a/etcdserver/member.go b/etcdserver/member.go index 2118e039f..25c23c323 100644 --- a/etcdserver/member.go +++ b/etcdserver/member.go @@ -28,8 +28,6 @@ import ( "github.com/coreos/etcd/pkg/types" ) -const membersKVPrefix = "/_etcd/members/" - // RaftAttributes represents the raft related attributes of an etcd member. type RaftAttributes struct { // TODO(philips): ensure these are URLs @@ -71,7 +69,7 @@ func newMember(name string, peerURLs types.URLs, now *time.Time) *Member { } func (m Member) storeKey() string { - return path.Join(membersKVPrefix, idAsHex(m.ID)) + return path.Join(membersDir, idAsHex(m.ID)) } func parseMemberID(key string) uint64 { diff --git a/etcdserver/server.go b/etcdserver/server.go index e81e92de6..ac7a83d74 100644 --- a/etcdserver/server.go +++ b/etcdserver/server.go @@ -47,6 +47,10 @@ const ( DefaultSnapCount = 10000 // TODO: calculate based on heartbeat interval defaultPublishRetryInterval = 5 * time.Second + + AdminDir = "/0" + membersDir = AdminDir + "/members" + KeysDir = "/1" ) var ( From e2b6a4fc4c8c8a35be9170f2fb8ac7881c1bc491 Mon Sep 17 00:00:00 2001 From: Yicheng Qin Date: Tue, 21 Oct 2014 11:47:03 -0700 Subject: [PATCH 2/4] etcdserver: const XXXDir -> StoreXXXPrefix and code clean --- etcdserver/cluster_store.go | 2 +- etcdserver/cluster_store_test.go | 7 ++++--- etcdserver/etcdhttp/http.go | 19 ++++++++++--------- etcdserver/member.go | 2 +- etcdserver/server.go | 8 +++++--- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/etcdserver/cluster_store.go b/etcdserver/cluster_store.go index 4c2af8447..c36655070 100644 --- a/etcdserver/cluster_store.go +++ b/etcdserver/cluster_store.go @@ -77,7 +77,7 @@ func (s *clusterStore) Add(m Member) { func (s *clusterStore) Get() Cluster { c := NewCluster() c.id = s.id - e, err := s.Store.Get(membersDir, true, true) + e, err := s.Store.Get(storeMembersPrefix, true, true) if err != nil { if v, ok := err.(*etcdErr.Error); ok && v.ErrorCode == etcdErr.EcodeKeyNotFound { return *c diff --git a/etcdserver/cluster_store_test.go b/etcdserver/cluster_store_test.go index 0fe6c3b3a..202a4f13b 100644 --- a/etcdserver/cluster_store_test.go +++ b/etcdserver/cluster_store_test.go @@ -17,6 +17,7 @@ package etcdserver import ( + "path" "reflect" "testing" "time" @@ -34,7 +35,7 @@ func TestClusterStoreAdd(t *testing.T) { { name: "Create", params: []interface{}{ - membersDir + "/1/raftAttributes", + path.Join(storeMembersPrefix, "1", "raftAttributes"), false, `{"PeerURLs":null}`, false, @@ -44,7 +45,7 @@ func TestClusterStoreAdd(t *testing.T) { { name: "Create", params: []interface{}{ - membersDir + "/1/attributes", + path.Join(storeMembersPrefix, "1", "attributes"), false, `{"Name":"node1","ClientURLs":null}`, false, @@ -113,7 +114,7 @@ func TestClusterStoreDelete(t *testing.T) { cs.Add(newTestMember(1, nil, "node1", nil)) cs.Remove(1) - wdeletes := []string{membersDir + "/1"} + wdeletes := []string{path.Join(storeMembersPrefix, "1")} if !reflect.DeepEqual(st.deletes, wdeletes) { t.Errorf("deletes = %v, want %v", st.deletes, wdeletes) } diff --git a/etcdserver/etcdhttp/http.go b/etcdserver/etcdhttp/http.go index 4f691344f..cb8f22a64 100644 --- a/etcdserver/etcdhttp/http.go +++ b/etcdserver/etcdhttp/http.go @@ -24,6 +24,7 @@ import ( "log" "net/http" "net/url" + "path" "strconv" "strings" "time" @@ -113,7 +114,7 @@ func (h serverHandler) serveKeys(w http.ResponseWriter, r *http.Request) { return } - rr.Path = etcdserver.KeysDir + rr.Path + rr.Path = path.Join(etcdserver.StoreKeysPrefix, rr.Path) resp, err := h.server.Do(ctx, rr) if err != nil { writeError(w, err) @@ -122,7 +123,7 @@ func (h serverHandler) serveKeys(w http.ResponseWriter, r *http.Request) { switch { case resp.Event != nil: - ev := trimEventPrefix(resp.Event, etcdserver.KeysDir) + ev := trimEventPrefix(resp.Event, etcdserver.StoreKeysPrefix) if err := writeEvent(w, ev, h.timer); err != nil { // Should never be reached log.Printf("error writing event: %v", err) @@ -478,7 +479,7 @@ func handleKeyWatch(ctx context.Context, w http.ResponseWriter, wa store.Watcher // send to the client in time. Then we simply end streaming. return } - ev = trimEventPrefix(ev, etcdserver.KeysDir) + ev = trimEventPrefix(ev, etcdserver.StoreKeysPrefix) if err := json.NewEncoder(w).Encode(ev); err != nil { // Should never be reached log.Printf("error writing event: %v\n", err) @@ -506,22 +507,22 @@ func allowMethod(w http.ResponseWriter, m string, ms ...string) bool { return false } -func trimEventPrefix(ev *store.Event, pre string) *store.Event { +func trimEventPrefix(ev *store.Event, prefix string) *store.Event { if ev == nil { return nil } - ev.Node = trimNodeExternPrefix(ev.Node, pre) - ev.PrevNode = trimNodeExternPrefix(ev.PrevNode, pre) + ev.Node = trimNodeExternPrefix(ev.Node, prefix) + ev.PrevNode = trimNodeExternPrefix(ev.PrevNode, prefix) return ev } -func trimNodeExternPrefix(n *store.NodeExtern, pre string) *store.NodeExtern { +func trimNodeExternPrefix(n *store.NodeExtern, prefix string) *store.NodeExtern { if n == nil { return nil } - n.Key = strings.TrimPrefix(n.Key, pre) + n.Key = strings.TrimPrefix(n.Key, prefix) for _, nn := range n.Nodes { - nn = trimNodeExternPrefix(nn, pre) + nn = trimNodeExternPrefix(nn, prefix) } return n } diff --git a/etcdserver/member.go b/etcdserver/member.go index 25c23c323..d56377dac 100644 --- a/etcdserver/member.go +++ b/etcdserver/member.go @@ -69,7 +69,7 @@ func newMember(name string, peerURLs types.URLs, now *time.Time) *Member { } func (m Member) storeKey() string { - return path.Join(membersDir, idAsHex(m.ID)) + return path.Join(storeMembersPrefix, idAsHex(m.ID)) } func parseMemberID(key string) uint64 { diff --git a/etcdserver/server.go b/etcdserver/server.go index ac7a83d74..89a51a745 100644 --- a/etcdserver/server.go +++ b/etcdserver/server.go @@ -22,6 +22,7 @@ import ( "log" "math/rand" "os" + "path" "strconv" "sync/atomic" "time" @@ -48,9 +49,8 @@ const ( // TODO: calculate based on heartbeat interval defaultPublishRetryInterval = 5 * time.Second - AdminDir = "/0" - membersDir = AdminDir + "/members" - KeysDir = "/1" + StoreAdminPrefix = "/0" + StoreKeysPrefix = "/1" ) var ( @@ -59,6 +59,8 @@ var ( ErrIDRemoved = errors.New("etcdserver: ID removed") ErrIDExists = errors.New("etcdserver: ID exists") ErrIDNotFound = errors.New("etcdserver: ID not found") + + storeMembersPrefix = path.Join(StoreAdminPrefix, "members") ) func init() { From ca73f256157e07a4a40957ff8e1fe810241e8e6a Mon Sep 17 00:00:00 2001 From: Yicheng Qin Date: Tue, 21 Oct 2014 15:04:00 -0700 Subject: [PATCH 3/4] etcdhttp: parseRequest -> parseKeyRequest --- etcdserver/etcdhttp/http.go | 11 +++++----- etcdserver/etcdhttp/http_test.go | 36 ++++++++++++++++---------------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/etcdserver/etcdhttp/http.go b/etcdserver/etcdhttp/http.go index cb8f22a64..4733497c4 100644 --- a/etcdserver/etcdhttp/http.go +++ b/etcdserver/etcdhttp/http.go @@ -108,13 +108,12 @@ func (h serverHandler) serveKeys(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(context.Background(), h.timeout) defer cancel() - rr, err := parseRequest(r, etcdserver.GenID(), clockwork.NewRealClock()) + rr, err := parseKeyRequest(r, etcdserver.GenID(), clockwork.NewRealClock()) if err != nil { writeError(w, err) return } - rr.Path = path.Join(etcdserver.StoreKeysPrefix, rr.Path) resp, err := h.server.Do(ctx, rr) if err != nil { writeError(w, err) @@ -251,10 +250,10 @@ func (h serverHandler) serveRaft(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) } -// parseRequest converts a received http.Request to a server Request, -// performing validation of supplied fields as appropriate. +// parseKeyRequest converts a received http.Request on keysPrefix to +// a server Request, performing validation of supplied fields as appropriate. // If any validation fails, an empty Request and non-nil error is returned. -func parseRequest(r *http.Request, id uint64, clock clockwork.Clock) (etcdserverpb.Request, error) { +func parseKeyRequest(r *http.Request, id uint64, clock clockwork.Clock) (etcdserverpb.Request, error) { emptyReq := etcdserverpb.Request{} err := r.ParseForm() @@ -271,7 +270,7 @@ func parseRequest(r *http.Request, id uint64, clock clockwork.Clock) (etcdserver "incorrect key prefix", ) } - p := r.URL.Path[len(keysPrefix):] + p := path.Join(etcdserver.StoreKeysPrefix, r.URL.Path[len(keysPrefix):]) var pIdx, wIdx uint64 if pIdx, err = getUint64(r.Form, "prevIndex"); err != nil { diff --git a/etcdserver/etcdhttp/http_test.go b/etcdserver/etcdhttp/http_test.go index 8c7114397..98dac7023 100644 --- a/etcdserver/etcdhttp/http_test.go +++ b/etcdserver/etcdhttp/http_test.go @@ -211,7 +211,7 @@ func TestBadParseRequest(t *testing.T) { }, } for i, tt := range tests { - got, err := parseRequest(tt.in, 1234, clockwork.NewFakeClock()) + got, err := parseKeyRequest(tt.in, 1234, clockwork.NewFakeClock()) if err == nil { t.Errorf("#%d: unexpected nil error!", i) continue @@ -244,7 +244,7 @@ func TestGoodParseRequest(t *testing.T) { etcdserverpb.Request{ ID: 1234, Method: "GET", - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), }, }, { @@ -258,7 +258,7 @@ func TestGoodParseRequest(t *testing.T) { ID: 1234, Method: "PUT", Val: "some_value", - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), }, }, { @@ -272,7 +272,7 @@ func TestGoodParseRequest(t *testing.T) { ID: 1234, Method: "PUT", PrevIndex: 98765, - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), }, }, { @@ -286,7 +286,7 @@ func TestGoodParseRequest(t *testing.T) { ID: 1234, Method: "PUT", Recursive: true, - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), }, }, { @@ -300,7 +300,7 @@ func TestGoodParseRequest(t *testing.T) { ID: 1234, Method: "PUT", Sorted: true, - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), }, }, { @@ -310,7 +310,7 @@ func TestGoodParseRequest(t *testing.T) { ID: 1234, Method: "GET", Wait: true, - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), }, }, { @@ -319,7 +319,7 @@ func TestGoodParseRequest(t *testing.T) { etcdserverpb.Request{ ID: 1234, Method: "GET", - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), Expiration: 0, }, }, @@ -329,7 +329,7 @@ func TestGoodParseRequest(t *testing.T) { etcdserverpb.Request{ ID: 1234, Method: "GET", - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), Expiration: fc.Now().Add(5678 * time.Second).UnixNano(), }, }, @@ -339,7 +339,7 @@ func TestGoodParseRequest(t *testing.T) { etcdserverpb.Request{ ID: 1234, Method: "GET", - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), Expiration: fc.Now().UnixNano(), }, }, @@ -350,7 +350,7 @@ func TestGoodParseRequest(t *testing.T) { ID: 1234, Method: "GET", Dir: true, - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), }, }, { @@ -360,7 +360,7 @@ func TestGoodParseRequest(t *testing.T) { ID: 1234, Method: "GET", Dir: false, - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), }, }, { @@ -374,7 +374,7 @@ func TestGoodParseRequest(t *testing.T) { ID: 1234, Method: "PUT", PrevExist: boolp(true), - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), }, }, { @@ -388,7 +388,7 @@ func TestGoodParseRequest(t *testing.T) { ID: 1234, Method: "PUT", PrevExist: boolp(false), - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), }, }, // mix various fields @@ -408,7 +408,7 @@ func TestGoodParseRequest(t *testing.T) { PrevExist: boolp(true), PrevValue: "previous value", Val: "some value", - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), }, }, // query parameters should be used if given @@ -422,7 +422,7 @@ func TestGoodParseRequest(t *testing.T) { ID: 1234, Method: "PUT", PrevValue: "woof", - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), }, }, // but form values should take precedence over query parameters @@ -438,13 +438,13 @@ func TestGoodParseRequest(t *testing.T) { ID: 1234, Method: "PUT", PrevValue: "miaow", - Path: "/foo", + Path: path.Join(etcdserver.StoreKeysPrefix, "/foo"), }, }, } for i, tt := range tests { - got, err := parseRequest(tt.in, 1234, fc) + got, err := parseKeyRequest(tt.in, 1234, fc) if err != nil { t.Errorf("#%d: err = %v, want %v", i, err, nil) } From 06b196e34503fc88bfe8a69c377497ec528a9d1f Mon Sep 17 00:00:00 2001 From: Yicheng Qin Date: Tue, 21 Oct 2014 15:29:43 -0700 Subject: [PATCH 4/4] etcdhttp: writeEvent -> writeKeyEvent --- etcdserver/etcdhttp/http.go | 12 ++++++------ etcdserver/etcdhttp/http_test.go | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/etcdserver/etcdhttp/http.go b/etcdserver/etcdhttp/http.go index 4733497c4..b5be1110b 100644 --- a/etcdserver/etcdhttp/http.go +++ b/etcdserver/etcdhttp/http.go @@ -122,8 +122,7 @@ func (h serverHandler) serveKeys(w http.ResponseWriter, r *http.Request) { switch { case resp.Event != nil: - ev := trimEventPrefix(resp.Event, etcdserver.StoreKeysPrefix) - if err := writeEvent(w, ev, h.timer); err != nil { + if err := writeKeyEvent(w, resp.Event, h.timer); err != nil { // Should never be reached log.Printf("error writing event: %v", err) } @@ -427,10 +426,10 @@ func writeError(w http.ResponseWriter, err error) { } } -// writeEvent serializes a single Event and writes the resulting -// JSON to the given ResponseWriter, along with the appropriate -// headers -func writeEvent(w http.ResponseWriter, ev *store.Event, rt etcdserver.RaftTimer) error { +// writeKeyEvent trims the prefix of key path in a single Event under +// StoreKeysPrefix, serializes it and writes the resulting JSON to the given +// ResponseWriter, along with the appropriate headers. +func writeKeyEvent(w http.ResponseWriter, ev *store.Event, rt etcdserver.RaftTimer) error { if ev == nil { return errors.New("cannot write empty Event!") } @@ -443,6 +442,7 @@ func writeEvent(w http.ResponseWriter, ev *store.Event, rt etcdserver.RaftTimer) w.WriteHeader(http.StatusCreated) } + ev = trimEventPrefix(ev, etcdserver.StoreKeysPrefix) return json.NewEncoder(w).Encode(ev) } diff --git a/etcdserver/etcdhttp/http_test.go b/etcdserver/etcdhttp/http_test.go index 98dac7023..659aa71ff 100644 --- a/etcdserver/etcdhttp/http_test.go +++ b/etcdserver/etcdhttp/http_test.go @@ -526,7 +526,7 @@ func (drt dummyRaftTimer) Term() uint64 { return uint64(5) } func TestWriteEvent(t *testing.T) { // nil event should not panic rw := httptest.NewRecorder() - writeEvent(rw, nil, dummyRaftTimer{}) + writeKeyEvent(rw, nil, dummyRaftTimer{}) h := rw.Header() if len(h) > 0 { t.Fatalf("unexpected non-empty headers: %#v", h) @@ -569,7 +569,7 @@ func TestWriteEvent(t *testing.T) { for i, tt := range tests { rw := httptest.NewRecorder() - writeEvent(rw, tt.ev, dummyRaftTimer{}) + writeKeyEvent(rw, tt.ev, dummyRaftTimer{}) if gct := rw.Header().Get("Content-Type"); gct != "application/json" { t.Errorf("case %d: bad Content-Type: got %q, want application/json", i, gct) }