client.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package client
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/url"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. "github.com/docker/engine-api/client/transport"
  10. "github.com/docker/go-connections/tlsconfig"
  11. )
  12. // Client is the API client that performs all operations
  13. // against a docker server.
  14. type Client struct {
  15. // proto holds the client protocol i.e. unix.
  16. proto string
  17. // addr holds the client address.
  18. addr string
  19. // basePath holds the path to prepend to the requests.
  20. basePath string
  21. // transport is the interface to sends request with, it implements transport.Client.
  22. transport transport.Client
  23. // version of the server to talk to.
  24. version string
  25. // custom http headers configured by users.
  26. customHTTPHeaders map[string]string
  27. }
  28. // NewEnvClient initializes a new API client based on environment variables.
  29. // Use DOCKER_HOST to set the url to the docker server.
  30. // Use DOCKER_API_VERSION to set the version of the API to reach, leave empty for latest.
  31. // Use DOCKER_CERT_PATH to load the tls certificates from.
  32. // Use DOCKER_TLS_VERIFY to enable or disable TLS verification, off by default.
  33. func NewEnvClient() (*Client, error) {
  34. var client *http.Client
  35. if dockerCertPath := os.Getenv("DOCKER_CERT_PATH"); dockerCertPath != "" {
  36. options := tlsconfig.Options{
  37. CAFile: filepath.Join(dockerCertPath, "ca.pem"),
  38. CertFile: filepath.Join(dockerCertPath, "cert.pem"),
  39. KeyFile: filepath.Join(dockerCertPath, "key.pem"),
  40. InsecureSkipVerify: os.Getenv("DOCKER_TLS_VERIFY") == "",
  41. }
  42. tlsc, err := tlsconfig.Client(options)
  43. if err != nil {
  44. return nil, err
  45. }
  46. client = &http.Client{
  47. Transport: &http.Transport{
  48. TLSClientConfig: tlsc,
  49. },
  50. }
  51. }
  52. host := os.Getenv("DOCKER_HOST")
  53. if host == "" {
  54. host = DefaultDockerHost
  55. }
  56. return NewClient(host, os.Getenv("DOCKER_API_VERSION"), client, nil)
  57. }
  58. // NewClient initializes a new API client for the given host and API version.
  59. // It won't send any version information if the version number is empty.
  60. // It uses the given http client as transport.
  61. // It also initializes the custom http headers to add to each request.
  62. func NewClient(host string, version string, client *http.Client, httpHeaders map[string]string) (*Client, error) {
  63. proto, addr, basePath, err := ParseHost(host)
  64. if err != nil {
  65. return nil, err
  66. }
  67. transport, err := transport.NewTransportWithHTTP(proto, addr, client)
  68. if err != nil {
  69. return nil, err
  70. }
  71. return &Client{
  72. proto: proto,
  73. addr: addr,
  74. basePath: basePath,
  75. transport: transport,
  76. version: version,
  77. customHTTPHeaders: httpHeaders,
  78. }, nil
  79. }
  80. // getAPIPath returns the versioned request path to call the api.
  81. // It appends the query parameters to the path if they are not empty.
  82. func (cli *Client) getAPIPath(p string, query url.Values) string {
  83. var apiPath string
  84. if cli.version != "" {
  85. v := strings.TrimPrefix(cli.version, "v")
  86. apiPath = fmt.Sprintf("%s/v%s%s", cli.basePath, v, p)
  87. } else {
  88. apiPath = fmt.Sprintf("%s%s", cli.basePath, p)
  89. }
  90. u := &url.URL{
  91. Path: apiPath,
  92. }
  93. if len(query) > 0 {
  94. u.RawQuery = query.Encode()
  95. }
  96. return u.String()
  97. }
  98. // ClientVersion returns the version string associated with this
  99. // instance of the Client. Note that this value can be changed
  100. // via the DOCKER_API_VERSION env var.
  101. func (cli *Client) ClientVersion() string {
  102. return cli.version
  103. }
  104. // ParseHost verifies that the given host strings is valid.
  105. func ParseHost(host string) (string, string, string, error) {
  106. protoAddrParts := strings.SplitN(host, "://", 2)
  107. if len(protoAddrParts) == 1 {
  108. return "", "", "", fmt.Errorf("unable to parse docker host `%s`", host)
  109. }
  110. var basePath string
  111. proto, addr := protoAddrParts[0], protoAddrParts[1]
  112. if proto == "tcp" {
  113. parsed, err := url.Parse("tcp://" + addr)
  114. if err != nil {
  115. return "", "", "", err
  116. }
  117. addr = parsed.Host
  118. basePath = parsed.Path
  119. }
  120. return proto, addr, basePath, nil
  121. }