gitlab.com/jfprevost/gitlab-runner-notlscheck@v11.11.4+incompatible/helpers/docker/official_docker_client.go (about)

     1  package docker_helpers
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"path/filepath"
    10  	"runtime"
    11  	"time"
    12  
    13  	"github.com/docker/docker/api/types"
    14  	"github.com/docker/docker/api/types/container"
    15  	"github.com/docker/docker/api/types/network"
    16  	"github.com/docker/docker/client"
    17  	"github.com/docker/go-connections/tlsconfig"
    18  	"github.com/sirupsen/logrus"
    19  )
    20  
    21  // The default API version used to create a new docker client.
    22  const DefaultAPIVersion = "1.25"
    23  
    24  // IsErrNotFound checks whether a returned error is due to an image or container
    25  // not being found. Proxies the docker implementation.
    26  func IsErrNotFound(err error) bool {
    27  	return client.IsErrNotFound(err)
    28  }
    29  
    30  // type officialDockerClient wraps a "github.com/docker/docker/client".Client,
    31  // giving it the methods it needs to satisfy the docker_helpers.Client interface
    32  type officialDockerClient struct {
    33  	client *client.Client
    34  
    35  	// Close() means "close idle connections held by engine-api's transport"
    36  	Transport *http.Transport
    37  }
    38  
    39  func newOfficialDockerClient(c DockerCredentials, apiVersion string) (*officialDockerClient, error) {
    40  	transport, err := newHTTPTransport(c)
    41  	if err != nil {
    42  		logrus.Errorln("Error creating TLS Docker client:", err)
    43  		return nil, err
    44  	}
    45  	httpClient := &http.Client{Transport: transport}
    46  
    47  	dockerClient, err := client.NewClient(c.Host, apiVersion, httpClient, nil)
    48  	if err != nil {
    49  		transport.CloseIdleConnections()
    50  		logrus.Errorln("Error creating Docker client:", err)
    51  		return nil, err
    52  	}
    53  
    54  	return &officialDockerClient{
    55  		client:    dockerClient,
    56  		Transport: transport,
    57  	}, nil
    58  }
    59  
    60  func wrapError(method string, err error, started time.Time) error {
    61  	if err == nil {
    62  		return nil
    63  	}
    64  
    65  	seconds := int(time.Since(started).Seconds())
    66  
    67  	if _, file, line, ok := runtime.Caller(2); ok {
    68  		return fmt.Errorf("%s (%s:%d:%ds)", err.Error(), filepath.Base(file), line, seconds)
    69  	}
    70  
    71  	return fmt.Errorf("%s (%s:%ds)", err.Error(), method, seconds)
    72  }
    73  
    74  func (c *officialDockerClient) ImageInspectWithRaw(ctx context.Context, imageID string) (types.ImageInspect, []byte, error) {
    75  	started := time.Now()
    76  	image, data, err := c.client.ImageInspectWithRaw(ctx, imageID)
    77  	return image, data, wrapError("ImageInspectWithRaw", err, started)
    78  }
    79  
    80  func (c *officialDockerClient) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (container.ContainerCreateCreatedBody, error) {
    81  	started := time.Now()
    82  	container, err := c.client.ContainerCreate(ctx, config, hostConfig, networkingConfig, containerName)
    83  	return container, wrapError("ContainerCreate", err, started)
    84  }
    85  
    86  func (c *officialDockerClient) ContainerStart(ctx context.Context, containerID string, options types.ContainerStartOptions) error {
    87  	started := time.Now()
    88  	err := c.client.ContainerStart(ctx, containerID, options)
    89  	return wrapError("ContainerCreate", err, started)
    90  }
    91  
    92  func (c *officialDockerClient) ContainerKill(ctx context.Context, containerID string, signal string) error {
    93  	started := time.Now()
    94  	err := c.client.ContainerKill(ctx, containerID, signal)
    95  	return wrapError("ContainerWait", err, started)
    96  }
    97  
    98  func (c *officialDockerClient) ContainerInspect(ctx context.Context, containerID string) (types.ContainerJSON, error) {
    99  	started := time.Now()
   100  	data, err := c.client.ContainerInspect(ctx, containerID)
   101  	return data, wrapError("ContainerInspect", err, started)
   102  }
   103  
   104  func (c *officialDockerClient) ContainerAttach(ctx context.Context, container string, options types.ContainerAttachOptions) (types.HijackedResponse, error) {
   105  	started := time.Now()
   106  	response, err := c.client.ContainerAttach(ctx, container, options)
   107  	return response, wrapError("ContainerAttach", err, started)
   108  }
   109  
   110  func (c *officialDockerClient) ContainerRemove(ctx context.Context, containerID string, options types.ContainerRemoveOptions) error {
   111  	started := time.Now()
   112  	err := c.client.ContainerRemove(ctx, containerID, options)
   113  	return wrapError("ContainerRemove", err, started)
   114  }
   115  
   116  func (c *officialDockerClient) ContainerLogs(ctx context.Context, container string, options types.ContainerLogsOptions) (io.ReadCloser, error) {
   117  	started := time.Now()
   118  	rc, err := c.client.ContainerLogs(ctx, container, options)
   119  	return rc, wrapError("ContainerLogs", err, started)
   120  }
   121  
   122  func (c *officialDockerClient) ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error) {
   123  	started := time.Now()
   124  	resp, err := c.client.ContainerExecCreate(ctx, container, config)
   125  	return resp, wrapError("ContainerExecCreate", err, started)
   126  }
   127  
   128  func (c *officialDockerClient) ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error) {
   129  	started := time.Now()
   130  	resp, err := c.client.ContainerExecAttach(ctx, execID, config)
   131  	return resp, wrapError("ContainerExecAttach", err, started)
   132  }
   133  
   134  func (c *officialDockerClient) NetworkDisconnect(ctx context.Context, networkID string, containerID string, force bool) error {
   135  	started := time.Now()
   136  	err := c.client.NetworkDisconnect(ctx, networkID, containerID, force)
   137  	return wrapError("NetworkDisconnect", err, started)
   138  }
   139  
   140  func (c *officialDockerClient) NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) {
   141  	started := time.Now()
   142  	networks, err := c.client.NetworkList(ctx, options)
   143  	return networks, wrapError("NetworkList", err, started)
   144  }
   145  
   146  func (c *officialDockerClient) Info(ctx context.Context) (types.Info, error) {
   147  	started := time.Now()
   148  	info, err := c.client.Info(ctx)
   149  	return info, wrapError("Info", err, started)
   150  }
   151  
   152  func (c *officialDockerClient) ImageImportBlocking(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) error {
   153  	started := time.Now()
   154  	readCloser, err := c.client.ImageImport(ctx, source, ref, options)
   155  	if err != nil {
   156  		return wrapError("ImageImport", err, started)
   157  	}
   158  	defer readCloser.Close()
   159  
   160  	// TODO: respect the context here
   161  	if _, err := io.Copy(ioutil.Discard, readCloser); err != nil {
   162  		return wrapError("io.Copy: Failed to import image", err, started)
   163  	}
   164  
   165  	return nil
   166  }
   167  
   168  func (c *officialDockerClient) ImagePullBlocking(ctx context.Context, ref string, options types.ImagePullOptions) error {
   169  	started := time.Now()
   170  	readCloser, err := c.client.ImagePull(ctx, ref, options)
   171  	if err != nil {
   172  		return wrapError("ImagePull", err, started)
   173  	}
   174  	defer readCloser.Close()
   175  
   176  	// TODO: respect the context here
   177  	if _, err := io.Copy(ioutil.Discard, readCloser); err != nil {
   178  		return wrapError("io.Copy: Failed to pull image", err, started)
   179  	}
   180  
   181  	return nil
   182  }
   183  
   184  func (c *officialDockerClient) Close() error {
   185  	c.Transport.CloseIdleConnections()
   186  	return nil
   187  }
   188  
   189  // New attempts to create a new Docker client of the specified version. If the
   190  // specified version is empty, it will use the default version.
   191  //
   192  // If no host is given in the DockerCredentials, it will attempt to look up
   193  // details from the environment. If that fails, it will use the default
   194  // connection details for your platform.
   195  func New(c DockerCredentials, apiVersion string) (Client, error) {
   196  	if c.Host == "" {
   197  		c = credentialsFromEnv()
   198  	}
   199  
   200  	// Use the default if nothing is specified by caller *or* environment
   201  	if c.Host == "" {
   202  		c.Host = client.DefaultDockerHost
   203  	}
   204  
   205  	if apiVersion == "" {
   206  		apiVersion = DefaultAPIVersion
   207  	}
   208  
   209  	return newOfficialDockerClient(c, apiVersion)
   210  }
   211  
   212  func newHTTPTransport(c DockerCredentials) (*http.Transport, error) {
   213  	url, err := client.ParseHostURL(c.Host)
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  
   218  	tr := &http.Transport{}
   219  
   220  	if err := configureTransport(tr, url.Scheme, url.Host); err != nil {
   221  		return nil, err
   222  	}
   223  
   224  	// FIXME: is a TLS connection with InsecureSkipVerify == true ever wanted?
   225  	if c.TLSVerify {
   226  		options := tlsconfig.Options{}
   227  
   228  		if c.CertPath != "" {
   229  			options.CAFile = filepath.Join(c.CertPath, "ca.pem")
   230  			options.CertFile = filepath.Join(c.CertPath, "cert.pem")
   231  			options.KeyFile = filepath.Join(c.CertPath, "key.pem")
   232  		}
   233  
   234  		tlsConfig, err := tlsconfig.Client(options)
   235  		if err != nil {
   236  			tr.CloseIdleConnections()
   237  			return nil, err
   238  		}
   239  
   240  		tr.TLSClientConfig = tlsConfig
   241  	}
   242  
   243  	return tr, nil
   244  }