Browse Source

Merge pull request #3533 from xiang90/proxy

proxy: expose proxy configuration
Xiang Li 10 years ago
parent
commit
06180be154
2 changed files with 88 additions and 1 deletions
  1. 43 1
      proxy/proxy.go
  2. 45 0
      proxy/proxy_test.go

+ 43 - 1
proxy/proxy.go

@@ -15,7 +15,9 @@
 package proxy
 
 import (
+	"encoding/json"
 	"net/http"
+	"strings"
 	"time"
 )
 
@@ -40,10 +42,16 @@ type GetProxyURLs func() []string
 // which will proxy requests to an etcd cluster.
 // The handler will periodically update its view of the cluster.
 func NewHandler(t *http.Transport, urlsFunc GetProxyURLs, failureWait time.Duration, refreshInterval time.Duration) http.Handler {
-	return &reverseProxy{
+	p := &reverseProxy{
 		director:  newDirector(urlsFunc, failureWait, refreshInterval),
 		transport: t,
 	}
+
+	mux := http.NewServeMux()
+	mux.Handle("/", p)
+	mux.HandleFunc("/v2/config/local/proxy", p.configHandler)
+
+	return mux
 }
 
 // NewReadonlyHandler wraps the given HTTP handler to allow only GET requests
@@ -62,3 +70,37 @@ func readonlyHandlerFunc(next http.Handler) func(http.ResponseWriter, *http.Requ
 		next.ServeHTTP(w, req)
 	}
 }
+
+func (p *reverseProxy) configHandler(w http.ResponseWriter, r *http.Request) {
+	if !allowMethod(w, r.Method, "GET") {
+		return
+	}
+
+	eps := p.director.endpoints()
+	epstr := make([]string, len(eps))
+	for i, e := range eps {
+		epstr[i] = e.URL.String()
+	}
+
+	proxyConfig := struct {
+		Endpoints []string `json:"endpoints"`
+	}{
+		Endpoints: epstr,
+	}
+
+	json.NewEncoder(w).Encode(proxyConfig)
+}
+
+// allowMethod verifies that the given method is one of the allowed methods,
+// and if not, it writes an error to w.  A boolean is returned indicating
+// whether or not the method is allowed.
+func allowMethod(w http.ResponseWriter, m string, ms ...string) bool {
+	for _, meth := range ms {
+		if m == meth {
+			return true
+		}
+	}
+	w.Header().Set("Allow", strings.Join(ms, ","))
+	http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
+	return false
+}

+ 45 - 0
proxy/proxy_test.go

@@ -15,9 +15,12 @@
 package proxy
 
 import (
+	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
+	"net/url"
 	"testing"
+	"time"
 )
 
 func TestReadonlyHandler(t *testing.T) {
@@ -51,3 +54,45 @@ func TestReadonlyHandler(t *testing.T) {
 		}
 	}
 }
+
+func TestConfigHandlerGET(t *testing.T) {
+	var err error
+	us := make([]*url.URL, 3)
+	us[0], err = url.Parse("http://example1.com")
+	if err != nil {
+		t.Fatal(err)
+	}
+	us[1], err = url.Parse("http://example2.com")
+	if err != nil {
+		t.Fatal(err)
+	}
+	us[2], err = url.Parse("http://example3.com")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	rp := reverseProxy{
+		director: &director{
+			ep: []*endpoint{
+				newEndpoint(*us[0], 1*time.Second),
+				newEndpoint(*us[1], 1*time.Second),
+				newEndpoint(*us[2], 1*time.Second),
+			},
+		},
+	}
+
+	req, _ := http.NewRequest("GET", "http://example.com//v2/config/local/proxy", nil)
+	rr := httptest.NewRecorder()
+	rp.configHandler(rr, req)
+
+	wbody := "{\"endpoints\":[\"http://example1.com\",\"http://example2.com\",\"http://example3.com\"]}\n"
+
+	body, err := ioutil.ReadAll(rr.Body)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if string(body) != wbody {
+		t.Errorf("body = %s, want %s", string(body), wbody)
+	}
+}