|
|
@@ -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)
|
|
|
+}
|