mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
4e2c0f385c
Signed-off-by: David Calavera <david.calavera@gmail.com>
142 lines
4.2 KiB
Go
142 lines
4.2 KiB
Go
package lib
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Client is the API client that performs all operations
|
|
// against a docker server.
|
|
type Client struct {
|
|
// proto holds the client protocol i.e. unix.
|
|
proto string
|
|
// addr holds the client address.
|
|
addr string
|
|
// basePath holds the path to prepend to the requests
|
|
basePath string
|
|
// scheme holds the scheme of the client i.e. https.
|
|
scheme string
|
|
// tlsConfig holds the tls configuration to use in hijacked requests.
|
|
tlsConfig *tls.Config
|
|
// httpClient holds the client transport instance. Exported to keep the old code running.
|
|
httpClient *http.Client
|
|
// version of the server to talk to.
|
|
version string
|
|
// custom http headers configured by users
|
|
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.
|
|
// Use DOCKER_TLS_VERIFY to enable or disable TLS verification, off by default.
|
|
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 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, transport *http.Transport, httpHeaders map[string]string) (*Client, error) {
|
|
var (
|
|
basePath string
|
|
tlsConfig *tls.Config
|
|
scheme = "http"
|
|
protoAddrParts = strings.SplitN(host, "://", 2)
|
|
proto, addr = protoAddrParts[0], protoAddrParts[1]
|
|
)
|
|
|
|
if proto == "tcp" {
|
|
parsed, err := url.Parse("tcp://" + addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
addr = parsed.Host
|
|
basePath = parsed.Path
|
|
}
|
|
|
|
transport = configureTransport(transport, proto, addr)
|
|
if transport.TLSClientConfig != nil {
|
|
scheme = "https"
|
|
}
|
|
|
|
return &Client{
|
|
proto: proto,
|
|
addr: addr,
|
|
basePath: basePath,
|
|
scheme: scheme,
|
|
tlsConfig: tlsConfig,
|
|
httpClient: &http.Client{Transport: transport},
|
|
version: version,
|
|
customHTTPHeaders: httpHeaders,
|
|
}, nil
|
|
}
|
|
|
|
// getAPIPath returns the versioned request path to call the api.
|
|
// It appends the query parameters to the path if they are not empty.
|
|
func (cli *Client) getAPIPath(p string, query url.Values) string {
|
|
var apiPath string
|
|
if cli.version != "" {
|
|
v := strings.TrimPrefix(cli.version, "v")
|
|
apiPath = fmt.Sprintf("%s/v%s%s", cli.basePath, v, p)
|
|
} else {
|
|
apiPath = fmt.Sprintf("%s%s", cli.basePath, p)
|
|
}
|
|
if len(query) > 0 {
|
|
apiPath += "?" + query.Encode()
|
|
}
|
|
return apiPath
|
|
}
|
|
|
|
// ClientVersion returns the version string associated with this
|
|
// instance of the Client. Note that this value can be changed
|
|
// via the DOCKER_API_VERSION env var.
|
|
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
|
|
}
|