github.com/alloyci/alloy-runner@v1.0.1-0.20180222164613-925503ccafd6/helpers/docker/official_docker_client.go (about) 1 package docker_helpers 2 3 import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "net/http" 8 "path/filepath" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/api/types" 12 "github.com/docker/docker/client" 13 "github.com/docker/go-connections/tlsconfig" 14 "golang.org/x/net/context" 15 ) 16 17 // IsErrNotFound checks whether a returned error is due to an image or container 18 // not being found. Proxies the docker implementation. 19 func IsErrNotFound(err error) bool { 20 return client.IsErrNotFound(err) 21 } 22 23 // type officialDockerClient wraps a "github.com/docker/docker/client".Client, 24 // giving it the methods it needs to satisfy the docker_helpers.Client interface 25 type officialDockerClient struct { 26 *client.Client 27 28 // Close() means "close idle connections held by engine-api's transport" 29 Transport *http.Transport 30 } 31 32 func newOfficialDockerClient(c DockerCredentials, apiVersion string) (*officialDockerClient, error) { 33 transport, err := newHTTPTransport(c) 34 if err != nil { 35 logrus.Errorln("Error creating TLS Docker client:", err) 36 return nil, err 37 } 38 httpClient := &http.Client{Transport: transport} 39 40 dockerClient, err := client.NewClient(c.Host, apiVersion, httpClient, nil) 41 if err != nil { 42 transport.CloseIdleConnections() 43 logrus.Errorln("Error creating Docker client:", err) 44 return nil, err 45 } 46 47 return &officialDockerClient{ 48 Client: dockerClient, 49 Transport: transport, 50 }, nil 51 } 52 53 func (c *officialDockerClient) ImageImportBlocking(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) error { 54 readCloser, err := c.ImageImport(ctx, source, ref, options) 55 if err != nil { 56 return err 57 } 58 defer readCloser.Close() 59 60 // TODO: respect the context here 61 if _, err := io.Copy(ioutil.Discard, readCloser); err != nil { 62 return fmt.Errorf("Failed to import image: %s", err) 63 } 64 65 return nil 66 } 67 68 func (c *officialDockerClient) ImagePullBlocking(ctx context.Context, ref string, options types.ImagePullOptions) error { 69 readCloser, err := c.ImagePull(ctx, ref, options) 70 if err != nil { 71 return err 72 } 73 defer readCloser.Close() 74 75 // TODO: respect the context here 76 if _, err := io.Copy(ioutil.Discard, readCloser); err != nil { 77 return fmt.Errorf("Failed to pull image: %s: %s", ref, err) 78 } 79 80 return nil 81 } 82 83 func (c *officialDockerClient) Close() error { 84 c.Transport.CloseIdleConnections() 85 return nil 86 } 87 88 // New attempts to create a new Docker client of the specified version. 89 // 90 // If no host is given in the DockerCredentials, it will attempt to look up 91 // details from the environment. If that fails, it will use the default 92 // connection details for your platform. 93 func New(c DockerCredentials, apiVersion string) (Client, error) { 94 if c.Host == "" { 95 c = credentialsFromEnv() 96 } 97 98 // Use the default if nothing is specified by caller *or* environment 99 if c.Host == "" { 100 c.Host = client.DefaultDockerHost 101 } 102 103 return newOfficialDockerClient(c, apiVersion) 104 } 105 106 func newHTTPTransport(c DockerCredentials) (*http.Transport, error) { 107 proto, addr, _, err := client.ParseHost(c.Host) 108 if err != nil { 109 return nil, err 110 } 111 112 tr := &http.Transport{} 113 114 if err := configureTransport(tr, proto, addr); err != nil { 115 return nil, err 116 } 117 118 // FIXME: is a TLS connection with InsecureSkipVerify == true ever wanted? 119 if c.TLSVerify { 120 options := tlsconfig.Options{} 121 122 if c.CertPath != "" { 123 options.CAFile = filepath.Join(c.CertPath, "ca.pem") 124 options.CertFile = filepath.Join(c.CertPath, "cert.pem") 125 options.KeyFile = filepath.Join(c.CertPath, "key.pem") 126 } 127 128 tlsConfig, err := tlsconfig.Client(options) 129 if err != nil { 130 tr.CloseIdleConnections() 131 return nil, err 132 } 133 134 tr.TLSClientConfig = tlsConfig 135 } 136 137 return tr, nil 138 }