diff --git a/api/handlers.go b/api/handlers.go index 792cbad6dd..09a9c0bd41 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -124,9 +124,9 @@ func getImages(c *context, w http.ResponseWriter, r *http.Request) { names := r.Form["names"] // Create a map of engine address to the list of images it holds. - engineImages := make(map[string][]*cluster.Image) + engineImages := make(map[*cluster.Engine][]*cluster.Image) for _, image := range c.cluster.Images() { - engineImages[image.Engine.Addr] = append(engineImages[image.Engine.Addr], image) + engineImages[image.Engine] = append(engineImages[image.Engine], image) } // Look for an engine that has all the images we need. @@ -146,7 +146,7 @@ func getImages(c *context, w http.ResponseWriter, r *http.Request) { // If the engine has all images, stop our search here. if matchedImages == len(names) { - proxy(c.tlsConfig, engine, w, r) + proxy(engine, w, r) return } } @@ -462,7 +462,11 @@ func getContainerJSON(c *context, w http.ResponseWriter, r *http.Request) { return } - client, scheme := newClientAndScheme(c.tlsConfig) + client, scheme := container.Engine.HTTPClientAndScheme() + if client == nil { + httpError(w, "Cannot connect to docker engine", http.StatusInternalServerError) + return + } resp, err := client.Get(scheme + "://" + container.Engine.Addr + "/containers/" + container.Id + "/json") container.Engine.CheckConnectionErr(err) @@ -767,7 +771,11 @@ func postContainersExec(c *context, w http.ResponseWriter, r *http.Request) { return } - client, scheme := newClientAndScheme(c.tlsConfig) + client, scheme := container.Engine.HTTPClientAndScheme() + if client == nil { + httpError(w, "Cannot connect to docker engine", http.StatusInternalServerError) + return + } resp, err := client.Post(scheme+"://"+container.Engine.Addr+"/containers/"+container.Id+"/exec", "application/json", r.Body) container.Engine.CheckConnectionErr(err) @@ -931,7 +939,7 @@ func proxyNetworkDisconnect(c *context, w http.ResponseWriter, r *http.Request) } // request is forwarded to the container's address - err := proxyAsync(c.tlsConfig, engine.Addr, w, r, cb) + err := proxyAsync(engine, w, r, cb) engine.CheckConnectionErr(err) if err != nil { httpError(w, err.Error(), http.StatusNotFound) @@ -974,7 +982,7 @@ func proxyNetworkConnect(c *context, w http.ResponseWriter, r *http.Request) { } // request is forwarded to the container's address - err := proxyAsync(c.tlsConfig, container.Engine.Addr, w, r, cb) + err := proxyAsync(container.Engine, w, r, cb) container.Engine.CheckConnectionErr(err) if err != nil { httpError(w, err.Error(), http.StatusNotFound) @@ -997,7 +1005,7 @@ func proxyContainer(c *context, w http.ResponseWriter, r *http.Request) { r.URL.Path = strings.Replace(r.URL.Path, name, container.Id, 1) } - err = proxy(c.tlsConfig, container.Engine.Addr, w, r) + err = proxy(container.Engine, w, r) container.Engine.CheckConnectionErr(err) if err != nil { httpError(w, err.Error(), http.StatusInternalServerError) @@ -1025,7 +1033,7 @@ func proxyContainerAndForceRefresh(c *context, w http.ResponseWriter, r *http.Re container.Refresh() } - err = proxyAsync(c.tlsConfig, container.Engine.Addr, w, r, cb) + err = proxyAsync(container.Engine, w, r, cb) container.Engine.CheckConnectionErr(err) if err != nil { httpError(w, err.Error(), http.StatusInternalServerError) @@ -1037,7 +1045,7 @@ func proxyImage(c *context, w http.ResponseWriter, r *http.Request) { name := mux.Vars(r)["name"] if image := c.cluster.Image(name); image != nil { - err := proxy(c.tlsConfig, image.Engine.Addr, w, r) + err := proxy(image.Engine, w, r) image.Engine.CheckConnectionErr(err) return } @@ -1051,7 +1059,7 @@ func proxyImageGet(c *context, w http.ResponseWriter, r *http.Request) { for _, image := range c.cluster.Images() { if len(strings.SplitN(name, ":", 2)) == 2 && image.Match(name, true) || len(strings.SplitN(name, ":", 2)) == 1 && image.Match(name, false) { - err := proxy(c.tlsConfig, image.Engine.Addr, w, r) + err := proxy(image.Engine, w, r) image.Engine.CheckConnectionErr(err) return } @@ -1075,7 +1083,7 @@ func proxyImagePush(c *context, w http.ResponseWriter, r *http.Request) { for _, image := range c.cluster.Images() { if tag != "" && image.Match(name, true) || tag == "" && image.Match(name, false) { - err := proxy(c.tlsConfig, image.Engine.Addr, w, r) + err := proxy(image.Engine, w, r) image.Engine.CheckConnectionErr(err) return } @@ -1120,7 +1128,7 @@ func proxyRandom(c *context, w http.ResponseWriter, r *http.Request) { return } - err = proxy(c.tlsConfig, engine.Addr, w, r) + err = proxy(engine, w, r) engine.CheckConnectionErr(err) if err != nil { httpError(w, err.Error(), http.StatusInternalServerError) @@ -1159,7 +1167,7 @@ func postCommit(c *context, w http.ResponseWriter, r *http.Request) { } // proxy commit request to the right node - err = proxyAsync(c.tlsConfig, container.Engine.Addr, w, r, cb) + err = proxyAsync(container.Engine, w, r, cb) container.Engine.CheckConnectionErr(err) if err != nil { httpError(w, err.Error(), http.StatusInternalServerError) diff --git a/api/utils.go b/api/utils.go index aaff32b261..08bb8b2aab 100644 --- a/api/utils.go +++ b/api/utils.go @@ -54,12 +54,6 @@ func sendErrorJSONMessage(w io.Writer, errorCode int, errorMessage string) { json.NewEncoder(w).Encode(message) } -func newClientAndScheme(tlsConfig *tls.Config) (*http.Client, string) { - if tlsConfig != nil { - return &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}}, "https" - } - return &http.Client{}, "http" -} func getContainerFromVars(c *context, vars map[string]string) (string, *cluster.Container, error) { if name, ok := vars["name"]; ok { @@ -102,14 +96,14 @@ func closeIdleConnections(client *http.Client) { } } -func proxyAsync(tlsConfig *tls.Config, addr string, w http.ResponseWriter, r *http.Request, callback func(*http.Response)) error { - // Use a new client for each request - client, scheme := newClientAndScheme(tlsConfig) +func proxyAsync(engine *cluster.Engine, w http.ResponseWriter, r *http.Request, callback func(*http.Response)) error { // RequestURI may not be sent to client r.RequestURI = "" + client, scheme := engine.HTTPClientAndScheme() + r.URL.Scheme = scheme - r.URL.Host = addr + r.URL.Host = engine.Addr log.WithFields(log.Fields{"method": r.Method, "url": r.URL}).Debug("Proxy request") resp, err := client.Do(r) @@ -132,8 +126,8 @@ func proxyAsync(tlsConfig *tls.Config, addr string, w http.ResponseWriter, r *ht return nil } -func proxy(tlsConfig *tls.Config, addr string, w http.ResponseWriter, r *http.Request) error { - return proxyAsync(tlsConfig, addr, w, r, nil) +func proxy(engine *cluster.Engine, w http.ResponseWriter, r *http.Request) error { + return proxyAsync(engine, w, r, nil) } type tlsClientConn struct { diff --git a/cluster/engine.go b/cluster/engine.go index 20e5332707..e4646de818 100644 --- a/cluster/engine.go +++ b/cluster/engine.go @@ -8,6 +8,7 @@ import ( "math" "math/rand" "net" + "net/http" "strings" "sync" "time" @@ -131,6 +132,14 @@ func NewEngine(addr string, overcommitRatio float64, opts *EngineOpts) *Engine { return e } +// HTTPClientAndScheme returns the underlying HTTPClient and the scheme used by the engine +func (e *Engine) HTTPClientAndScheme() (*http.Client, string) { + if dc, ok := e.client.(*dockerclient.DockerClient); ok { + return dc.HTTPClient, dc.URL.Scheme + } + return nil, "" +} + // Connect will initialize a connection to the Docker daemon running on the // host, gather machine specs (memory, cpu, ...) and monitor state changes. func (e *Engine) Connect(config *tls.Config) error {