helpers/docker/official_docker_client.go (98 lines of code) (raw):
package docker_helpers
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"path/filepath"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/docker/go-connections/tlsconfig"
"golang.org/x/net/context"
)
// IsErrNotFound checks whether a returned error is due to an image or container
// not being found. Proxies the docker implementation.
func IsErrNotFound(err error) bool {
return client.IsErrNotFound(err)
}
// type officialDockerClient wraps a "github.com/docker/docker/client".Client,
// giving it the methods it needs to satisfy the docker_helpers.Client interface
type officialDockerClient struct {
*client.Client
// Close() means "close idle connections held by engine-api's transport"
Transport *http.Transport
}
func newOfficialDockerClient(c DockerCredentials, apiVersion string) (*officialDockerClient, error) {
transport, err := newHTTPTransport(c)
if err != nil {
logrus.Errorln("Error creating TLS Docker client:", err)
return nil, err
}
httpClient := &http.Client{Transport: transport}
dockerClient, err := client.NewClient(c.Host, apiVersion, httpClient, nil)
if err != nil {
transport.CloseIdleConnections()
logrus.Errorln("Error creating Docker client:", err)
return nil, err
}
return &officialDockerClient{
Client: dockerClient,
Transport: transport,
}, nil
}
func (c *officialDockerClient) ImageImportBlocking(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) error {
readCloser, err := c.ImageImport(ctx, source, ref, options)
if err != nil {
return err
}
defer readCloser.Close()
// TODO: respect the context here
if _, err := io.Copy(ioutil.Discard, readCloser); err != nil {
return fmt.Errorf("Failed to import image: %s", err)
}
return nil
}
func (c *officialDockerClient) ImagePullBlocking(ctx context.Context, ref string, options types.ImagePullOptions) error {
readCloser, err := c.ImagePull(ctx, ref, options)
if err != nil {
return err
}
defer readCloser.Close()
// TODO: respect the context here
if _, err := io.Copy(ioutil.Discard, readCloser); err != nil {
return fmt.Errorf("Failed to pull image: %s: %s", ref, err)
}
return nil
}
func (c *officialDockerClient) Close() error {
c.Transport.CloseIdleConnections()
return nil
}
// New attempts to create a new Docker client of the specified version.
//
// If no host is given in the DockerCredentials, it will attempt to look up
// details from the environment. If that fails, it will use the default
// connection details for your platform.
func New(c DockerCredentials, apiVersion string) (Client, error) {
if c.Host == "" {
c = credentialsFromEnv()
}
// Use the default if nothing is specified by caller *or* environment
if c.Host == "" {
c.Host = client.DefaultDockerHost
}
return newOfficialDockerClient(c, apiVersion)
}
func newHTTPTransport(c DockerCredentials) (*http.Transport, error) {
proto, addr, _, err := client.ParseHost(c.Host)
if err != nil {
return nil, err
}
tr := &http.Transport{}
if err := configureTransport(tr, proto, addr); err != nil {
return nil, err
}
// FIXME: is a TLS connection with InsecureSkipVerify == true ever wanted?
if c.TLSVerify {
options := tlsconfig.Options{}
if c.CertPath != "" {
options.CAFile = filepath.Join(c.CertPath, "ca.pem")
options.CertFile = filepath.Join(c.CertPath, "cert.pem")
options.KeyFile = filepath.Join(c.CertPath, "key.pem")
}
tlsConfig, err := tlsconfig.Client(options)
if err != nil {
tr.CloseIdleConnections()
return nil, err
}
tr.TLSClientConfig = tlsConfig
}
return tr, nil
}