Use client instead of helpers for TLS in integration test
Signed-off-by: Daniel Nephin <dnephin@docker.com>
| ... | ... |
@@ -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) |