diff --git a/api/README.md b/api/README.md index d7e038797d..d0cf334fa5 100644 --- a/api/README.md +++ b/api/README.md @@ -10,14 +10,12 @@ Here are the main differences: ``` GET "/images/json" GET "/images/json" -GET "/images/search" GET "/images/get" GET "/images/{name:.*}/get" GET "/images/{name:.*}/history" GET "/images/{name:.*}/json" GET "/containers/{name:.*}/attach/ws" -POST "/auth" POST "/commit" POST "/build" POST "/images/create" diff --git a/api/api.go b/api/api.go index b4c055e177..4330a2160e 100644 --- a/api/api.go +++ b/api/api.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io/ioutil" + "math/rand" "net/http" "runtime" "sort" @@ -14,6 +15,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/swarm/cluster" "github.com/docker/swarm/scheduler" + "github.com/docker/swarm/scheduler/filter" "github.com/gorilla/mux" "github.com/samalba/dockerclient" ) @@ -229,7 +231,7 @@ func proxyContainerAndForceRefresh(c *context, w http.ResponseWriter, r *http.Re return } - if err := proxy(c.tlsConfig, container, w, r); err != nil { + if err := proxy(c.tlsConfig, container.Node.Addr, w, r); err != nil { httpError(w, err.Error(), http.StatusInternalServerError) } @@ -245,7 +247,24 @@ func proxyContainer(c *context, w http.ResponseWriter, r *http.Request) { return } - if err := proxy(c.tlsConfig, container, w, r); err != nil { + if err := proxy(c.tlsConfig, container.Node.Addr, w, r); err != nil { + httpError(w, err.Error(), http.StatusInternalServerError) + } +} + +// Proxy a request to a random node +func proxyRandom(c *context, w http.ResponseWriter, r *http.Request) { + candidates := c.cluster.Nodes() + + healthFilter := &filter.HealthFilter{} + accepted, err := healthFilter.Filter(nil, candidates) + + if err != nil { + httpError(w, err.Error(), http.StatusInternalServerError) + return + } + + if err := proxy(c.tlsConfig, accepted[rand.Intn(len(accepted))].Addr, w, r); err != nil { httpError(w, err.Error(), http.StatusInternalServerError) } } @@ -258,7 +277,7 @@ func proxyHijack(c *context, w http.ResponseWriter, r *http.Request) { return } - if err := hijack(c.tlsConfig, container, w, r); err != nil { + if err := hijack(c.tlsConfig, container.Node.Addr, w, r); err != nil { httpError(w, err.Error(), http.StatusInternalServerError) } } @@ -293,7 +312,7 @@ func createRouter(c *context, enableCors bool) *mux.Router { "/version": getVersion, "/images/json": notImplementedHandler, "/images/viz": notImplementedHandler, - "/images/search": notImplementedHandler, + "/images/search": proxyRandom, "/images/get": notImplementedHandler, "/images/{name:.*}/get": notImplementedHandler, "/images/{name:.*}/history": notImplementedHandler, @@ -309,7 +328,7 @@ func createRouter(c *context, enableCors bool) *mux.Router { "/exec/{execid:.*}/json": proxyContainer, }, "POST": { - "/auth": notImplementedHandler, + "/auth": proxyRandom, "/commit": notImplementedHandler, "/build": notImplementedHandler, "/images/create": notImplementedHandler, diff --git a/api/utils.go b/api/utils.go index 98fe751064..ded0b93340 100644 --- a/api/utils.go +++ b/api/utils.go @@ -51,15 +51,14 @@ func copyHeader(dst, src http.Header) { } } -func proxy(tlsConfig *tls.Config, container *cluster.Container, w http.ResponseWriter, r *http.Request) error { +func proxy(tlsConfig *tls.Config, addr string, w http.ResponseWriter, r *http.Request) error { // Use a new client for each request client, scheme := newClientAndScheme(tlsConfig) // RequestURI may not be sent to client r.RequestURI = "" r.URL.Scheme = scheme - - r.URL.Host = container.Node.Addr + r.URL.Host = addr log.Debugf("[PROXY] --> %s %s", r.Method, r.URL) resp, err := client.Do(r) @@ -74,9 +73,8 @@ func proxy(tlsConfig *tls.Config, container *cluster.Container, w http.ResponseW return nil } -func hijack(tlsConfig *tls.Config, container *cluster.Container, w http.ResponseWriter, r *http.Request) error { - addr := container.Node.Addr - if parts := strings.SplitN(container.Node.Addr, "://", 2); len(parts) == 2 { +func hijack(tlsConfig *tls.Config, addr string, w http.ResponseWriter, r *http.Request) error { + if parts := strings.SplitN(addr, "://", 2); len(parts) == 2 { addr = parts[1] } diff --git a/scheduler/filter/health.go b/scheduler/filter/health.go index e05ba3a356..de94cf767d 100644 --- a/scheduler/filter/health.go +++ b/scheduler/filter/health.go @@ -15,7 +15,7 @@ var ( type HealthFilter struct { } -func (f *HealthFilter) Filter(config *dockerclient.ContainerConfig, nodes []*cluster.Node) ([]*cluster.Node, error) { +func (f *HealthFilter) Filter(_ *dockerclient.ContainerConfig, nodes []*cluster.Node) ([]*cluster.Node, error) { result := []*cluster.Node{} for _, node := range nodes { if node.IsHealthy() {