Browse code

Improve docstrings and small cleanup in client

Use client instead of helpers for TLS in integration test

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2018/02/17 03:24:57
Showing 3 changed files
... ...
@@ -42,8 +42,8 @@ For example, to list running containers (the equivalent of "docker ps"):
42 42
 package client // import "github.com/docker/docker/client"
43 43
 
44 44
 import (
45
-	"errors"
46 45
 	"fmt"
46
+	"net"
47 47
 	"net/http"
48 48
 	"net/url"
49 49
 	"os"
... ...
@@ -56,6 +56,7 @@ import (
56 56
 	"github.com/docker/docker/api/types/versions"
57 57
 	"github.com/docker/go-connections/sockets"
58 58
 	"github.com/docker/go-connections/tlsconfig"
59
+	"github.com/pkg/errors"
59 60
 	"golang.org/x/net/context"
60 61
 )
61 62
 
... ...
@@ -103,18 +104,21 @@ func CheckRedirect(req *http.Request, via []*http.Request) error {
103 103
 }
104 104
 
105 105
 // NewEnvClient initializes a new API client based on environment variables.
106
-// Use DOCKER_HOST to set the url to the docker server.
107
-// Use DOCKER_API_VERSION to set the version of the API to reach, leave empty for latest.
108
-// Use DOCKER_CERT_PATH to load the TLS certificates from.
109
-// Use DOCKER_TLS_VERIFY to enable or disable TLS verification, off by default.
110
-// deprecated: use NewClientWithOpts(FromEnv)
106
+// See FromEnv for a list of support environment variables.
107
+//
108
+// Deprecated: use NewClientWithOpts(FromEnv)
111 109
 func NewEnvClient() (*Client, error) {
112 110
 	return NewClientWithOpts(FromEnv)
113 111
 }
114 112
 
115
-// FromEnv enhance the default client with values from environment variables
113
+// FromEnv configures the client with values from environment variables.
114
+//
115
+// Supported environment variables:
116
+// DOCKER_HOST to set the url to the docker server.
117
+// DOCKER_API_VERSION to set the version of the API to reach, leave empty for latest.
118
+// DOCKER_CERT_PATH to load the TLS certificates from.
119
+// DOCKER_TLS_VERIFY to enable or disable TLS verification, off by default.
116 120
 func FromEnv(c *Client) error {
117
-	var httpClient *http.Client
118 121
 	if dockerCertPath := os.Getenv("DOCKER_CERT_PATH"); dockerCertPath != "" {
119 122
 		options := tlsconfig.Options{
120 123
 			CAFile:             filepath.Join(dockerCertPath, "ca.pem"),
... ...
@@ -127,30 +131,58 @@ func FromEnv(c *Client) error {
127 127
 			return err
128 128
 		}
129 129
 
130
-		httpClient = &http.Client{
131
-			Transport: &http.Transport{
132
-				TLSClientConfig: tlsc,
133
-			},
130
+		c.client = &http.Client{
131
+			Transport:     &http.Transport{TLSClientConfig: tlsc},
134 132
 			CheckRedirect: CheckRedirect,
135 133
 		}
136
-		WithHTTPClient(httpClient)(c)
137 134
 	}
138 135
 
139
-	host := os.Getenv("DOCKER_HOST")
140
-	if host != "" {
141
-		// WithHost will create an API client if it doesn't exist
136
+	if host := os.Getenv("DOCKER_HOST"); host != "" {
142 137
 		if err := WithHost(host)(c); err != nil {
143 138
 			return err
144 139
 		}
145 140
 	}
146
-	version := os.Getenv("DOCKER_API_VERSION")
147
-	if version != "" {
141
+
142
+	if version := os.Getenv("DOCKER_API_VERSION"); version != "" {
148 143
 		c.version = version
149 144
 		c.manualOverride = true
150 145
 	}
151 146
 	return nil
152 147
 }
153 148
 
149
+// WithTLSClientConfig applies a tls config to the client transport.
150
+func WithTLSClientConfig(cacertPath, certPath, keyPath string) func(*Client) error {
151
+	return func(c *Client) error {
152
+		opts := tlsconfig.Options{
153
+			CAFile:             cacertPath,
154
+			CertFile:           certPath,
155
+			KeyFile:            keyPath,
156
+			ExclusiveRootPools: true,
157
+		}
158
+		config, err := tlsconfig.Client(opts)
159
+		if err != nil {
160
+			return errors.Wrap(err, "failed to create tls config")
161
+		}
162
+		if transport, ok := c.client.Transport.(*http.Transport); ok {
163
+			transport.TLSClientConfig = config
164
+			return nil
165
+		}
166
+		return errors.Errorf("cannot apply tls config to transport: %T", c.client.Transport)
167
+	}
168
+}
169
+
170
+// WithDialer applies the dialer.DialContext to the client transport. This can be
171
+// used to set the Timeout and KeepAlive settings of the client.
172
+func WithDialer(dialer *net.Dialer) func(*Client) error {
173
+	return func(c *Client) error {
174
+		if transport, ok := c.client.Transport.(*http.Transport); ok {
175
+			transport.DialContext = dialer.DialContext
176
+			return nil
177
+		}
178
+		return errors.Errorf("cannot apply dialer to transport: %T", c.client.Transport)
179
+	}
180
+}
181
+
154 182
 // WithVersion overrides the client version with the specified one
155 183
 func WithVersion(version string) func(*Client) error {
156 184
 	return func(c *Client) error {
... ...
@@ -159,8 +191,7 @@ func WithVersion(version string) func(*Client) error {
159 159
 	}
160 160
 }
161 161
 
162
-// WithHost overrides the client host with the specified one, creating a new
163
-// http client if one doesn't exist
162
+// WithHost overrides the client host with the specified one.
164 163
 func WithHost(host string) func(*Client) error {
165 164
 	return func(c *Client) error {
166 165
 		hostURL, err := ParseHostURL(host)
... ...
@@ -171,17 +202,10 @@ func WithHost(host string) func(*Client) error {
171 171
 		c.proto = hostURL.Scheme
172 172
 		c.addr = hostURL.Host
173 173
 		c.basePath = hostURL.Path
174
-		if c.client == nil {
175
-			client, err := defaultHTTPClient(host)
176
-			if err != nil {
177
-				return err
178
-			}
179
-			return WithHTTPClient(client)(c)
180
-		}
181 174
 		if transport, ok := c.client.Transport.(*http.Transport); ok {
182 175
 			return sockets.ConfigureTransport(transport, c.proto, c.addr)
183 176
 		}
184
-		return fmt.Errorf("cannot apply host to http transport")
177
+		return errors.Errorf("cannot apply host to transport: %T", c.client.Transport)
185 178
 	}
186 179
 }
187 180
 
... ...
@@ -266,7 +290,7 @@ func defaultHTTPClient(host string) (*http.Client, error) {
266 266
 // It won't send any version information if the version number is empty. It is
267 267
 // highly recommended that you set a version or your client may break if the
268 268
 // server is upgraded.
269
-// deprecated: use NewClientWithOpts
269
+// Deprecated: use NewClientWithOpts
270 270
 func NewClient(host string, version string, client *http.Client, httpHeaders map[string]string) (*Client, error) {
271 271
 	return NewClientWithOpts(WithHost(host), WithVersion(version), WithHTTPClient(client), WithHTTPHeaders(httpHeaders))
272 272
 }
... ...
@@ -378,6 +402,7 @@ func (cli *Client) CustomHTTPHeaders() map[string]string {
378 378
 }
379 379
 
380 380
 // SetCustomHTTPHeaders that will be set on every HTTP request made by the client.
381
+// Deprecated: use WithHTTPHeaders when creating the client.
381 382
 func (cli *Client) SetCustomHTTPHeaders(headers map[string]string) {
382 383
 	cli.customHTTPHeaders = headers
383 384
 }
... ...
@@ -2,8 +2,6 @@ package request // import "github.com/docker/docker/integration/internal/request
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"net"
6
-	"net/http"
7 5
 	"testing"
8 6
 	"time"
9 7
 
... ...
@@ -11,8 +9,6 @@ import (
11 11
 
12 12
 	"github.com/docker/docker/client"
13 13
 	"github.com/docker/docker/internal/test/environment"
14
-	"github.com/docker/go-connections/sockets"
15
-	"github.com/docker/go-connections/tlsconfig"
16 14
 	"github.com/stretchr/testify/require"
17 15
 )
18 16
 
... ...
@@ -24,36 +20,6 @@ func NewAPIClient(t *testing.T, ops ...func(*client.Client) error) client.APICli
24 24
 	return clt
25 25
 }
26 26
 
27
-// NewTLSAPIClient returns a docker API client configured with the
28
-// provided TLS settings
29
-func NewTLSAPIClient(t *testing.T, host, cacertPath, certPath, keyPath string) (client.APIClient, error) {
30
-	opts := tlsconfig.Options{
31
-		CAFile:             cacertPath,
32
-		CertFile:           certPath,
33
-		KeyFile:            keyPath,
34
-		ExclusiveRootPools: true,
35
-	}
36
-	config, err := tlsconfig.Client(opts)
37
-	require.Nil(t, err)
38
-	tr := &http.Transport{
39
-		TLSClientConfig: config,
40
-		DialContext: (&net.Dialer{
41
-			KeepAlive: 30 * time.Second,
42
-			Timeout:   30 * time.Second,
43
-		}).DialContext,
44
-	}
45
-	proto, addr, _, err := client.ParseHost(host)
46
-	require.Nil(t, err)
47
-
48
-	sockets.ConfigureTransport(tr, proto, addr)
49
-
50
-	httpClient := &http.Client{
51
-		Transport:     tr,
52
-		CheckRedirect: client.CheckRedirect,
53
-	}
54
-	return client.NewClientWithOpts(client.WithHost(host), client.WithHTTPClient(httpClient))
55
-}
56
-
57 27
 // daemonTime provides the current time on the daemon host
58 28
 func daemonTime(ctx context.Context, t *testing.T, client client.APIClient, testEnv *environment.Execution) time.Time {
59 29
 	if testEnv.IsLocalDaemon() {
... ...
@@ -22,7 +22,6 @@ import (
22 22
 	eventtypes "github.com/docker/docker/api/types/events"
23 23
 	"github.com/docker/docker/client"
24 24
 	"github.com/docker/docker/integration/internal/container"
25
-	"github.com/docker/docker/integration/internal/request"
26 25
 	"github.com/docker/docker/internal/test/environment"
27 26
 	"github.com/docker/docker/pkg/authorization"
28 27
 	"github.com/gotestyourself/gotestyourself/skip"
... ...
@@ -126,7 +125,7 @@ func TestAuthZPluginTLS(t *testing.T) {
126 126
 	ctrl.reqRes.Allow = true
127 127
 	ctrl.resRes.Allow = true
128 128
 
129
-	client, err := request.NewTLSAPIClient(t, testDaemonHTTPSAddr, cacertPath, clientCertPath, clientKeyPath)
129
+	client, err := newTLSAPIClient(testDaemonHTTPSAddr, cacertPath, clientCertPath, clientKeyPath)
130 130
 	require.Nil(t, err)
131 131
 
132 132
 	_, err = client.ServerVersion(context.Background())
... ...
@@ -136,6 +135,17 @@ func TestAuthZPluginTLS(t *testing.T) {
136 136
 	require.Equal(t, "client", ctrl.resUser)
137 137
 }
138 138
 
139
+func newTLSAPIClient(host, cacertPath, certPath, keyPath string) (client.APIClient, error) {
140
+	dialer := &net.Dialer{
141
+		KeepAlive: 30 * time.Second,
142
+		Timeout:   30 * time.Second,
143
+	}
144
+	return client.NewClientWithOpts(
145
+		client.WithTLSClientConfig(cacertPath, certPath, keyPath),
146
+		client.WithDialer(dialer),
147
+		client.WithHost(host))
148
+}
149
+
139 150
 func TestAuthZPluginDenyRequest(t *testing.T) {
140 151
 	defer setupTestV1(t)()
141 152
 	d.Start(t, "--authorization-plugin="+testAuthZPlugin)