options.go 4.9 KB

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