|
@@ -3,12 +3,13 @@ package lib
|
|
|
import (
|
|
|
"crypto/tls"
|
|
|
"fmt"
|
|
|
+ "net"
|
|
|
"net/http"
|
|
|
"net/url"
|
|
|
+ "os"
|
|
|
+ "path/filepath"
|
|
|
"strings"
|
|
|
-
|
|
|
- "github.com/docker/docker/pkg/sockets"
|
|
|
- "github.com/docker/docker/pkg/tlsconfig"
|
|
|
+ "time"
|
|
|
)
|
|
|
|
|
|
// Client is the API client that performs all operations
|
|
@@ -32,11 +33,35 @@ type Client struct {
|
|
|
customHTTPHeaders map[string]string
|
|
|
}
|
|
|
|
|
|
+// NewEnvClient initializes a new API client based on environment variables.
|
|
|
+// Use DOCKER_HOST to set the url to the docker server.
|
|
|
+// Use DOCKER_API_VERSION to set the version of the API to reach, leave empty for latest.
|
|
|
+// Use DOCKER_CERT_PATH to load the tls certificates from.
|
|
|
+func NewEnvClient() (*Client, error) {
|
|
|
+ var transport *http.Transport
|
|
|
+ if dockerCertPath := os.Getenv("DOCKER_CERT_PATH"); dockerCertPath != "" {
|
|
|
+ tlsc := &tls.Config{}
|
|
|
+
|
|
|
+ cert, err := tls.LoadX509KeyPair(filepath.Join(dockerCertPath, "cert.pem"), filepath.Join(dockerCertPath, "key.pem"))
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("Error loading x509 key pair: %s", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ tlsc.Certificates = append(tlsc.Certificates, cert)
|
|
|
+ tlsc.InsecureSkipVerify = os.Getenv("DOCKER_TLS_VERIFY") == ""
|
|
|
+ transport = &http.Transport{
|
|
|
+ TLSClientConfig: tlsc,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return NewClient(os.Getenv("DOCKER_HOST"), os.Getenv("DOCKER_API_VERSION"), transport, nil)
|
|
|
+}
|
|
|
+
|
|
|
// NewClient initializes a new API client for the given host and API version.
|
|
|
// It won't send any version information if the version number is empty.
|
|
|
-// It uses the tlsOptions to decide whether to use a secure connection or not.
|
|
|
+// It uses the transport to create a new http client.
|
|
|
// It also initializes the custom http headers to add to each request.
|
|
|
-func NewClient(host string, version string, tlsOptions *tlsconfig.Options, httpHeaders map[string]string) (*Client, error) {
|
|
|
+func NewClient(host string, version string, transport *http.Transport, httpHeaders map[string]string) (*Client, error) {
|
|
|
var (
|
|
|
basePath string
|
|
|
tlsConfig *tls.Config
|
|
@@ -54,20 +79,10 @@ func NewClient(host string, version string, tlsOptions *tlsconfig.Options, httpH
|
|
|
basePath = parsed.Path
|
|
|
}
|
|
|
|
|
|
- if tlsOptions != nil {
|
|
|
+ transport = configureTransport(transport, proto, addr)
|
|
|
+ if transport.TLSClientConfig != nil {
|
|
|
scheme = "https"
|
|
|
- var err error
|
|
|
- tlsConfig, err = tlsconfig.Client(*tlsOptions)
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // The transport is created here for reuse during the client session.
|
|
|
- transport := &http.Transport{
|
|
|
- TLSClientConfig: tlsConfig,
|
|
|
}
|
|
|
- sockets.ConfigureTCPTransport(transport, proto, addr)
|
|
|
|
|
|
return &Client{
|
|
|
proto: proto,
|
|
@@ -103,3 +118,24 @@ func (cli *Client) getAPIPath(p string, query url.Values) string {
|
|
|
func (cli *Client) ClientVersion() string {
|
|
|
return cli.version
|
|
|
}
|
|
|
+
|
|
|
+func configureTransport(tr *http.Transport, proto, addr string) *http.Transport {
|
|
|
+ if tr == nil {
|
|
|
+ tr = &http.Transport{}
|
|
|
+ }
|
|
|
+
|
|
|
+ // Why 32? See https://github.com/docker/docker/pull/8035.
|
|
|
+ timeout := 32 * time.Second
|
|
|
+ if proto == "unix" {
|
|
|
+ // No need for compression in local communications.
|
|
|
+ tr.DisableCompression = true
|
|
|
+ tr.Dial = func(_, _ string) (net.Conn, error) {
|
|
|
+ return net.DialTimeout(proto, addr, timeout)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ tr.Proxy = http.ProxyFromEnvironment
|
|
|
+ tr.Dial = (&net.Dialer{Timeout: timeout}).Dial
|
|
|
+ }
|
|
|
+
|
|
|
+ return tr
|
|
|
+}
|