commit
d9b35470a1
|
@ -11,6 +11,7 @@ import (
|
|||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -27,7 +28,10 @@ import (
|
|||
"github.com/coreos/etcd/third_party/code.google.com/p/go.net/context"
|
||||
)
|
||||
|
||||
const keysPrefix = "/v2/keys"
|
||||
const (
|
||||
keysPrefix = "/v2/keys"
|
||||
machinesPrefix = "/v2/machines"
|
||||
)
|
||||
|
||||
type Peers map[int64][]string
|
||||
|
||||
|
@ -36,7 +40,12 @@ func (ps Peers) Pick(id int64) string {
|
|||
if len(addrs) == 0 {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("http://%s", addrs[rand.Intn(len(addrs))])
|
||||
return addScheme(addrs[rand.Intn(len(addrs))])
|
||||
}
|
||||
|
||||
// TODO: improve this when implementing TLS
|
||||
func addScheme(addr string) string {
|
||||
return fmt.Sprintf("http://%s", addr)
|
||||
}
|
||||
|
||||
// Set parses command line sets of names to ips formatted like:
|
||||
|
@ -138,6 +147,9 @@ func httpPost(url string, data []byte) bool {
|
|||
type Handler struct {
|
||||
Timeout time.Duration
|
||||
Server *etcdserver.Server
|
||||
// TODO: dynamic configuration may make this outdated. take care of it.
|
||||
// TODO: dynamic configuration may introduce race also.
|
||||
Peers Peers
|
||||
}
|
||||
|
||||
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -156,6 +168,8 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
h.serveRaft(ctx, w, r)
|
||||
case strings.HasPrefix(r.URL.Path, keysPrefix):
|
||||
h.serveKeys(ctx, w, r)
|
||||
case strings.HasPrefix(r.URL.Path, machinesPrefix):
|
||||
h.serveMachines(w, r)
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
|
@ -188,6 +202,23 @@ func (h Handler) serveKeys(ctx context.Context, w http.ResponseWriter, r *http.R
|
|||
}
|
||||
}
|
||||
|
||||
// serveMachines responds address list in the format '0.0.0.0, 1.1.1.1'.
|
||||
// TODO: rethink the format of machine list because it is not json format.
|
||||
func (h Handler) serveMachines(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" && r.Method != "HEAD" {
|
||||
allow(w, "GET", "HEAD")
|
||||
return
|
||||
}
|
||||
urls := make([]string, 0)
|
||||
for _, addrs := range h.Peers {
|
||||
for _, addr := range addrs {
|
||||
urls = append(urls, addScheme(addr))
|
||||
}
|
||||
}
|
||||
sort.Strings(urls)
|
||||
w.Write([]byte(strings.Join(urls, ", ")))
|
||||
}
|
||||
|
||||
func (h Handler) serveRaft(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
|
@ -320,3 +351,9 @@ func waitForEvent(ctx context.Context, w http.ResponseWriter, wa store.Watcher)
|
|||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
// allow writes response for the case that Method Not Allowed
|
||||
func allow(w http.ResponseWriter, m ...string) {
|
||||
w.Header().Set("Allow", strings.Join(m, ","))
|
||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
|
|
|
@ -347,3 +347,47 @@ func TestWaitForEventCancelledContext(t *testing.T) {
|
|||
t.Fatalf("nil err returned with cancelled context!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestV2MachinesEndpoint(t *testing.T) {
|
||||
tests := []struct {
|
||||
method string
|
||||
wcode int
|
||||
}{
|
||||
{"GET", http.StatusOK},
|
||||
{"HEAD", http.StatusOK},
|
||||
{"POST", http.StatusMethodNotAllowed},
|
||||
}
|
||||
|
||||
h := Handler{Peers: Peers{}}
|
||||
s := httptest.NewServer(h)
|
||||
defer s.Close()
|
||||
|
||||
for _, tt := range tests {
|
||||
req, _ := http.NewRequest(tt.method, s.URL+machinesPrefix, nil)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != tt.wcode {
|
||||
t.Errorf("StatusCode = %d, expected %d", resp.StatusCode, tt.wcode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeMachines(t *testing.T) {
|
||||
peers := Peers{}
|
||||
peers.Set("0xBEEF0=localhost:8080&0xBEEF1=localhost:8081&0xBEEF2=localhost:8082")
|
||||
h := Handler{Peers: peers}
|
||||
|
||||
writer := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "", nil)
|
||||
h.serveMachines(writer, req)
|
||||
w := "http://localhost:8080, http://localhost:8081, http://localhost:8082"
|
||||
if g := writer.Body.String(); g != w {
|
||||
t.Errorf("body = %s, want %s", g, w)
|
||||
}
|
||||
if writer.Code != http.StatusOK {
|
||||
t.Errorf("header = %d, want %d", writer.Code, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue