Merge pull request #1238 from yuce/1235-remove-endpoints

Removes /id and /hosts endpoints. Adds local ID to /status
This commit is contained in:
Yuce Tekol 2018-05-11 16:57:29 +03:00 committed by GitHub
commit beef74a31e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 41 additions and 54 deletions

View file

@ -142,12 +142,20 @@ If the node is being added to a cluster which contains no data (for example, dur
In order to remove a node from a cluster, your cluster must be configured to have a [cluster replicas](../configuration/#cluster-replicas) value of at least 2; if you're removing a node that no longer exists (for example a node that has died), there must be at least one additional replica of the data owned by the dead node in order for the cluster to correctly rebalance itself.
To remove node `localhost:10102` from a cluster having coordinator `localhost:10101`, first determine the ID of the node to be removed. If the node to be removed is still available, you can find the ID by issuing an `/id` request to the node:
To remove node `localhost:10102` from a cluster having coordinator `localhost:10101`, first determine the ID of the node to be removed. If the node to be removed is still available, you can find the ID by issuing a `/status` request to the node. The node's ID is in the `localID` field:
``` request
curl localhost:10102/id
curl localhost:10101/status
```
``` response
40a891fa-243b-4d71-ae24-4f5c78a0f4b1
{
"state":"NORMAL",
"nodes":[
{"id":"24824777-62ec-4151-9fbd-67e4676e317d","uri":{"scheme":"http","host":"localhost","port":10101}}
{"id":"40a891fa-243b-4d71-ae24-4f5c78a0f4b1","uri":{"scheme":"http","host":"localhost","port":10102}}
{"id":"9fab09cc-3c26-4202-9622-d167c84684d9","uri":{"scheme":"http","host":"localhost","port":10103}}
],
"localID": "40a891fa-243b-4d71-ae24-4f5c78a0f4b1"
}
```
If the node to be removed is no longer available, you can get the IDs of the nodes in the cluster by issuing a `/status` request to any available node:
@ -161,7 +169,8 @@ curl localhost:10101/status
{"id":"24824777-62ec-4151-9fbd-67e4676e317d","uri":{"scheme":"http","host":"localhost","port":10101}}
{"id":"40a891fa-243b-4d71-ae24-4f5c78a0f4b1","uri":{"scheme":"http","host":"localhost","port":10102}}
{"id":"9fab09cc-3c26-4202-9622-d167c84684d9","uri":{"scheme":"http","host":"localhost","port":10103}}
]
],
"localID": "40a891fa-243b-4d71-ae24-4f5c78a0f4b1"
}
```

View file

@ -166,19 +166,6 @@ curl localhost:10101/index/repository/frame/stats/field/pullrequests \
{}
```
### List hosts
`GET /hosts`
Returns the hosts in the cluster.
``` request
curl -XGET localhost:10101/hosts
```
``` response
[{"host":":10101"}]
```
### Get version
`GET /version`

View file

@ -121,8 +121,6 @@ func NewRouter(handler *Handler) *mux.Router {
router.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux).Methods("GET")
router.Handle("/debug/vars", expvar.Handler()).Methods("GET")
router.HandleFunc("/fragment/data", handler.handleGetFragmentData).Methods("GET").Name("GetFragmentData")
router.HandleFunc("/hosts", handler.handleGetHosts).Methods("GET")
router.HandleFunc("/id", handler.handleGetID).Methods("GET")
router.HandleFunc("/schema", handler.handleGetSchema).Methods("GET")
router.HandleFunc("/slices/max", handler.handleGetSlicesMax).Methods("GET") // TODO: deprecate, but it's being used by the client (for backups)
router.HandleFunc("/status", handler.handleGetStatus).Methods("GET")
@ -245,8 +243,9 @@ func (h *Handler) handleGetSchema(w http.ResponseWriter, r *http.Request) {
// handleGetStatus handles GET /status requests.
func (h *Handler) handleGetStatus(w http.ResponseWriter, r *http.Request) {
status := getStatusResponse{
State: h.API.State(),
Nodes: h.API.Hosts(r.Context()),
State: h.API.State(),
Nodes: h.API.Hosts(r.Context()),
LocalID: h.API.LocalID(),
}
if err := json.NewEncoder(w).Encode(status); err != nil {
h.Logger.Printf("write status response error: %s", err)
@ -265,8 +264,9 @@ type getSchemaResponse struct {
}
type getStatusResponse struct {
State string `json:"state"`
Nodes []*Node `json:"nodes"`
State string `json:"state"`
Nodes []*Node `json:"nodes"`
LocalID string `json:"localID"`
}
// handlePostQuery handles /query requests.
@ -1188,14 +1188,6 @@ func (h *Handler) handlePostFrameRestore(w http.ResponseWriter, r *http.Request)
}
}
// handleGetHosts handles /hosts requests.
func (h *Handler) handleGetHosts(w http.ResponseWriter, r *http.Request) {
hosts := h.API.Hosts(r.Context())
if err := json.NewEncoder(w).Encode(hosts); err != nil {
h.Logger.Printf("write version response error: %s", err)
}
}
// handleGetVersion handles /version requests.
func (h *Handler) handleGetVersion(w http.ResponseWriter, r *http.Request) {
err := json.NewEncoder(w).Encode(struct {
@ -1623,13 +1615,6 @@ func (h *Handler) handlePostClusterMessage(w http.ResponseWriter, r *http.Reques
}
}
func (h *Handler) handleGetID(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte(h.API.LocalID()))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
type defaultClusterMessageResponse struct{}
type queryValidationSpec struct {

View file

@ -150,7 +150,7 @@ func TestHandler_Status(t *testing.T) {
h.ServeHTTP(w, test.MustNewHTTPRequest("GET", "/status", nil))
if w.Code != http.StatusOK {
t.Fatalf("unexpected status code: %d", w.Code)
} else if body := w.Body.String(); body != `{"state":"NORMAL","nodes":[{"id":"node0","uri":{"scheme":"http","host":"host0"},"isCoordinator":false}]}`+"\n" {
} else if body := w.Body.String(); body != `{"state":"NORMAL","nodes":[{"id":"node0","uri":{"scheme":"http","host":"host0"},"isCoordinator":false}],"localID":"node0"}`+"\n" {
t.Fatalf("unexpected body: %s", body)
}
}

View file

@ -16,6 +16,7 @@ package server_test
import (
"context"
"encoding/json"
"fmt"
"net/http"
"reflect"
@ -443,6 +444,19 @@ func TestClusterResize_RemoveNode(t *testing.T) {
m0 := cluster[0]
m1 := cluster[1]
mustNodeID := func(baseURL string) string {
body := test.MustDo("GET", fmt.Sprintf("%s/status", baseURL), "").Body
var resp map[string]interface{}
err := json.Unmarshal([]byte(body), &resp)
if err != nil {
panic(err)
}
if localID, ok := resp["localID"].(string); ok {
return localID
}
panic("localID should be a string")
}
t.Run("ErrorRemoveInvalidNode", func(t *testing.T) {
resp := test.MustDo("POST", m0.URL()+fmt.Sprintf("/cluster/resize/remove-node"), `{"id": "invalid-node-id"}`)
expBody := "removing node: finding node to remove: node with provided ID does not exist"
@ -454,10 +468,8 @@ func TestClusterResize_RemoveNode(t *testing.T) {
})
t.Run("ErrorRemoveCoordinator", func(t *testing.T) {
resp := test.MustDo("GET", m0.URL()+fmt.Sprintf("/id"), "")
nodeID := resp.Body
resp = test.MustDo("POST", m0.URL()+fmt.Sprintf("/cluster/resize/remove-node"), fmt.Sprintf(`{"id": "%s"}`, nodeID))
nodeID := mustNodeID(m0.URL())
resp := test.MustDo("POST", m0.URL()+fmt.Sprintf("/cluster/resize/remove-node"), fmt.Sprintf(`{"id": "%s"}`, nodeID))
expBody := "removing node: calling node leave: coordinator cannot be removed; first, make a different node the new coordinator."
if resp.StatusCode != http.StatusInternalServerError {
@ -468,13 +480,9 @@ func TestClusterResize_RemoveNode(t *testing.T) {
})
t.Run("ErrorRemoveOnNonCoordinator", func(t *testing.T) {
resp := test.MustDo("GET", m0.URL()+fmt.Sprintf("/id"), "")
coordinatorNodeID := resp.Body
resp = test.MustDo("GET", m1.URL()+fmt.Sprintf("/id"), "")
nodeID := resp.Body
resp = test.MustDo("POST", m1.URL()+fmt.Sprintf("/cluster/resize/remove-node"), fmt.Sprintf(`{"id": "%s"}`, nodeID))
coordinatorNodeID := mustNodeID(m0.URL())
nodeID := mustNodeID(m1.URL())
resp := test.MustDo("POST", m1.URL()+fmt.Sprintf("/cluster/resize/remove-node"), fmt.Sprintf(`{"id": "%s"}`, nodeID))
expBody := fmt.Sprintf("removing node: calling node leave: node removal requests are only valid on the coordinator node: %s", coordinatorNodeID)
if resp.StatusCode != http.StatusInternalServerError {
@ -505,10 +513,8 @@ func TestClusterResize_RemoveNode(t *testing.T) {
t.Fatal(err)
}
resp := test.MustDo("GET", m1.URL()+fmt.Sprintf("/id"), "")
nodeID := resp.Body
resp = test.MustDo("POST", m0.URL()+fmt.Sprintf("/cluster/resize/remove-node"), fmt.Sprintf(`{"id": "%s"}`, nodeID))
nodeID := mustNodeID(m1.URL())
resp := test.MustDo("POST", m0.URL()+fmt.Sprintf("/cluster/resize/remove-node"), fmt.Sprintf(`{"id": "%s"}`, nodeID))
expBody := "not enough data to perform resize"
if resp.StatusCode != http.StatusInternalServerError {
t.Fatalf("expected StatusCode %d but got %d", http.StatusInternalServerError, resp.StatusCode)