github.com/adityamillind98/moby@v23.0.0-rc.4+incompatible/client/options.go (about)

     1  package client
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"net/http"
     7  	"os"
     8  	"path/filepath"
     9  	"time"
    10  
    11  	"github.com/docker/go-connections/sockets"
    12  	"github.com/docker/go-connections/tlsconfig"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  // Opt is a configuration option to initialize a client
    17  type Opt func(*Client) error
    18  
    19  // FromEnv configures the client with values from environment variables.
    20  //
    21  // FromEnv uses the following environment variables:
    22  //
    23  // DOCKER_HOST (EnvOverrideHost) to set the URL to the docker server.
    24  //
    25  // DOCKER_API_VERSION (EnvOverrideAPIVersion) to set the version of the API to
    26  // use, leave empty for latest.
    27  //
    28  // DOCKER_CERT_PATH (EnvOverrideCertPath) to specify the directory from which to
    29  // load the TLS certificates (ca.pem, cert.pem, key.pem).
    30  //
    31  // DOCKER_TLS_VERIFY (EnvTLSVerify) to enable or disable TLS verification (off by
    32  // default).
    33  func FromEnv(c *Client) error {
    34  	ops := []Opt{
    35  		WithTLSClientConfigFromEnv(),
    36  		WithHostFromEnv(),
    37  		WithVersionFromEnv(),
    38  	}
    39  	for _, op := range ops {
    40  		if err := op(c); err != nil {
    41  			return err
    42  		}
    43  	}
    44  	return nil
    45  }
    46  
    47  // WithDialContext applies the dialer to the client transport. This can be
    48  // used to set the Timeout and KeepAlive settings of the client.
    49  func WithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) Opt {
    50  	return func(c *Client) error {
    51  		if transport, ok := c.client.Transport.(*http.Transport); ok {
    52  			transport.DialContext = dialContext
    53  			return nil
    54  		}
    55  		return errors.Errorf("cannot apply dialer to transport: %T", c.client.Transport)
    56  	}
    57  }
    58  
    59  // WithHost overrides the client host with the specified one.
    60  func WithHost(host string) Opt {
    61  	return func(c *Client) error {
    62  		hostURL, err := ParseHostURL(host)
    63  		if err != nil {
    64  			return err
    65  		}
    66  		c.host = host
    67  		c.proto = hostURL.Scheme
    68  		c.addr = hostURL.Host
    69  		c.basePath = hostURL.Path
    70  		if transport, ok := c.client.Transport.(*http.Transport); ok {
    71  			return sockets.ConfigureTransport(transport, c.proto, c.addr)
    72  		}
    73  		return errors.Errorf("cannot apply host to transport: %T", c.client.Transport)
    74  	}
    75  }
    76  
    77  // WithHostFromEnv overrides the client host with the host specified in the
    78  // DOCKER_HOST (EnvOverrideHost) environment variable. If DOCKER_HOST is not set,
    79  // or set to an empty value, the host is not modified.
    80  func WithHostFromEnv() Opt {
    81  	return func(c *Client) error {
    82  		if host := os.Getenv(EnvOverrideHost); host != "" {
    83  			return WithHost(host)(c)
    84  		}
    85  		return nil
    86  	}
    87  }
    88  
    89  // WithHTTPClient overrides the client http client with the specified one
    90  func WithHTTPClient(client *http.Client) Opt {
    91  	return func(c *Client) error {
    92  		if client != nil {
    93  			c.client = client
    94  		}
    95  		return nil
    96  	}
    97  }
    98  
    99  // WithTimeout configures the time limit for requests made by the HTTP client
   100  func WithTimeout(timeout time.Duration) Opt {
   101  	return func(c *Client) error {
   102  		c.client.Timeout = timeout
   103  		return nil
   104  	}
   105  }
   106  
   107  // WithHTTPHeaders overrides the client default http headers
   108  func WithHTTPHeaders(headers map[string]string) Opt {
   109  	return func(c *Client) error {
   110  		c.customHTTPHeaders = headers
   111  		return nil
   112  	}
   113  }
   114  
   115  // WithScheme overrides the client scheme with the specified one
   116  func WithScheme(scheme string) Opt {
   117  	return func(c *Client) error {
   118  		c.scheme = scheme
   119  		return nil
   120  	}
   121  }
   122  
   123  // WithTLSClientConfig applies a tls config to the client transport.
   124  func WithTLSClientConfig(cacertPath, certPath, keyPath string) Opt {
   125  	return func(c *Client) error {
   126  		opts := tlsconfig.Options{
   127  			CAFile:             cacertPath,
   128  			CertFile:           certPath,
   129  			KeyFile:            keyPath,
   130  			ExclusiveRootPools: true,
   131  		}
   132  		config, err := tlsconfig.Client(opts)
   133  		if err != nil {
   134  			return errors.Wrap(err, "failed to create tls config")
   135  		}
   136  		if transport, ok := c.client.Transport.(*http.Transport); ok {
   137  			transport.TLSClientConfig = config
   138  			return nil
   139  		}
   140  		return errors.Errorf("cannot apply tls config to transport: %T", c.client.Transport)
   141  	}
   142  }
   143  
   144  // WithTLSClientConfigFromEnv configures the client's TLS settings with the
   145  // settings in the DOCKER_CERT_PATH and DOCKER_TLS_VERIFY environment variables.
   146  // If DOCKER_CERT_PATH is not set or empty, TLS configuration is not modified.
   147  //
   148  // WithTLSClientConfigFromEnv uses the following environment variables:
   149  //
   150  // DOCKER_CERT_PATH (EnvOverrideCertPath) to specify the directory from which to
   151  // load the TLS certificates (ca.pem, cert.pem, key.pem).
   152  //
   153  // DOCKER_TLS_VERIFY (EnvTLSVerify) to enable or disable TLS verification (off by
   154  // default).
   155  func WithTLSClientConfigFromEnv() Opt {
   156  	return func(c *Client) error {
   157  		dockerCertPath := os.Getenv(EnvOverrideCertPath)
   158  		if dockerCertPath == "" {
   159  			return nil
   160  		}
   161  		options := tlsconfig.Options{
   162  			CAFile:             filepath.Join(dockerCertPath, "ca.pem"),
   163  			CertFile:           filepath.Join(dockerCertPath, "cert.pem"),
   164  			KeyFile:            filepath.Join(dockerCertPath, "key.pem"),
   165  			InsecureSkipVerify: os.Getenv(EnvTLSVerify) == "",
   166  		}
   167  		tlsc, err := tlsconfig.Client(options)
   168  		if err != nil {
   169  			return err
   170  		}
   171  
   172  		c.client = &http.Client{
   173  			Transport:     &http.Transport{TLSClientConfig: tlsc},
   174  			CheckRedirect: CheckRedirect,
   175  		}
   176  		return nil
   177  	}
   178  }
   179  
   180  // WithVersion overrides the client version with the specified one. If an empty
   181  // version is specified, the value will be ignored to allow version negotiation.
   182  func WithVersion(version string) Opt {
   183  	return func(c *Client) error {
   184  		if version != "" {
   185  			c.version = version
   186  			c.manualOverride = true
   187  		}
   188  		return nil
   189  	}
   190  }
   191  
   192  // WithVersionFromEnv overrides the client version with the version specified in
   193  // the DOCKER_API_VERSION environment variable. If DOCKER_API_VERSION is not set,
   194  // the version is not modified.
   195  func WithVersionFromEnv() Opt {
   196  	return func(c *Client) error {
   197  		return WithVersion(os.Getenv(EnvOverrideAPIVersion))(c)
   198  	}
   199  }
   200  
   201  // WithAPIVersionNegotiation enables automatic API version negotiation for the client.
   202  // With this option enabled, the client automatically negotiates the API version
   203  // to use when making requests. API version negotiation is performed on the first
   204  // request; subsequent requests will not re-negotiate.
   205  func WithAPIVersionNegotiation() Opt {
   206  	return func(c *Client) error {
   207  		c.negotiateVersion = true
   208  		return nil
   209  	}
   210  }