Skip to content

Commit a20380c

Browse files
authored
Merge pull request moby#5731 from jsternberg/remove-docker-api-dependency
testutil: copy slim version of the docker client into testutil
2 parents bd6820a + 0a7f949 commit a20380c

File tree

214 files changed

+255
-26105
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

214 files changed

+255
-26105
lines changed

go.mod

-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ require (
162162
github.com/kylelemons/godebug v1.1.0 // indirect
163163
github.com/moby/sys/mount v0.3.4 // indirect
164164
github.com/moby/sys/sequential v0.6.0 // indirect
165-
github.com/moby/term v0.5.2 // indirect
166165
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
167166
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 // indirect
168167
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect

go.sum

-4
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0
1515
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0/go.mod h1:oDrbWx4ewMylP7xHivfgixbfGBT6APAwsSoHRKotnIc=
1616
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.5.0 h1:mlmW46Q0B79I+Aj4azKC6xDMFN9a9SyZWESlGWYXbFs=
1717
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.5.0/go.mod h1:PXe2h+LKcWTX9afWdZoHyODqR4fBa5boUM/8uJfZ0Jo=
18-
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
19-
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
2018
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
2119
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
2220
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 h1:kYRSnvJju5gYVyhkij+RTJ/VR6QIUaCfWeaFm2ycsjQ=
@@ -294,8 +292,6 @@ github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
294292
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
295293
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
296294
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
297-
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
298-
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
299295
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
300296
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
301297
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=

vendor/github.com/docker/docker/client/client.go renamed to util/testutil/dockerd/client/client.go

+9-226
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,16 @@
1-
/*
2-
Package client is a Go client for the Docker Engine API.
3-
4-
For more information about the Engine API, see the documentation:
5-
https://docs.docker.com/reference/api/engine/
6-
7-
# Usage
8-
9-
You use the library by constructing a client object using [NewClientWithOpts]
10-
and calling methods on it. The client can be configured from environment
11-
variables by passing the [FromEnv] option, or configured manually by passing any
12-
of the other available [Opts].
13-
14-
For example, to list running containers (the equivalent of "docker ps"):
15-
16-
package main
17-
18-
import (
19-
"context"
20-
"fmt"
21-
22-
"github.com/docker/docker/api/types/container"
23-
"github.com/docker/docker/client"
24-
)
25-
26-
func main() {
27-
cli, err := client.NewClientWithOpts(client.FromEnv)
28-
if err != nil {
29-
panic(err)
30-
}
31-
32-
containers, err := cli.ContainerList(context.Background(), container.ListOptions{})
33-
if err != nil {
34-
panic(err)
35-
}
36-
37-
for _, ctr := range containers {
38-
fmt.Printf("%s %s\n", ctr.ID, ctr.Image)
39-
}
40-
}
41-
*/
42-
package client // import "github.com/docker/docker/client"
1+
package client
432

443
import (
454
"context"
465
"crypto/tls"
476
"net"
487
"net/http"
498
"net/url"
50-
"path"
519
"strings"
52-
"sync"
53-
"sync/atomic"
5410
"time"
5511

56-
"github.com/docker/docker/api"
57-
"github.com/docker/docker/api/types"
58-
"github.com/docker/docker/api/types/versions"
5912
"github.com/docker/go-connections/sockets"
6013
"github.com/pkg/errors"
61-
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
62-
"go.opentelemetry.io/otel/trace"
6314
)
6415

6516
// DummyHost is a hostname used for local communication.
@@ -92,12 +43,8 @@ import (
9243
// [Go stdlib]: https://github.com/golang/go/blob/6244b1946bc2101b01955468f1be502dbadd6807/src/net/http/transport.go#L558-L569
9344
const DummyHost = "api.moby.localhost"
9445

95-
// fallbackAPIVersion is the version to fallback to if API-version negotiation
96-
// fails. This version is the highest version of the API before API-version
97-
// negotiation was introduced. If negotiation fails (or no API version was
98-
// included in the API response), we assume the API server uses the most
99-
// recent version before negotiation was introduced.
100-
const fallbackAPIVersion = "1.24"
46+
// DefaultVersion is the pinned version of the docker API we utilize.
47+
const DefaultVersion = "1.47"
10148

10249
// Client is the API client that performs all operations
10350
// against a docker server.
@@ -116,29 +63,6 @@ type Client struct {
11663
client *http.Client
11764
// version of the server to talk to.
11865
version string
119-
// userAgent is the User-Agent header to use for HTTP requests. It takes
120-
// precedence over User-Agent headers set in customHTTPHeaders, and other
121-
// header variables. When set to an empty string, the User-Agent header
122-
// is removed, and no header is sent.
123-
userAgent *string
124-
// custom HTTP headers configured by users.
125-
customHTTPHeaders map[string]string
126-
// manualOverride is set to true when the version was set by users.
127-
manualOverride bool
128-
129-
// negotiateVersion indicates if the client should automatically negotiate
130-
// the API version to use when making requests. API version negotiation is
131-
// performed on the first request, after which negotiated is set to "true"
132-
// so that subsequent requests do not re-negotiate.
133-
negotiateVersion bool
134-
135-
// negotiated indicates that API version negotiation took place
136-
negotiated atomic.Bool
137-
138-
// negotiateLock is used to single-flight the version negotiation process
139-
negotiateLock sync.Mutex
140-
141-
tp trace.TracerProvider
14266

14367
// When the client transport is an *http.Transport (default) we need to do some extra things (like closing idle connections).
14468
// Store the original transport as the http.Client transport will be wrapped with tracing libs.
@@ -196,7 +120,7 @@ func NewClientWithOpts(ops ...Opt) (*Client, error) {
196120
}
197121
c := &Client{
198122
host: DefaultDockerHost,
199-
version: api.DefaultVersion,
123+
version: DefaultVersion,
200124
client: client,
201125
proto: hostURL.Scheme,
202126
addr: hostURL.Host,
@@ -226,15 +150,6 @@ func NewClientWithOpts(ops ...Opt) (*Client, error) {
226150
c.scheme = "http"
227151
}
228152
}
229-
230-
c.client.Transport = otelhttp.NewTransport(
231-
c.client.Transport,
232-
otelhttp.WithTracerProvider(c.tp),
233-
otelhttp.WithSpanNameFormatter(func(_ string, req *http.Request) string {
234-
return req.Method + " " + req.URL.Path
235-
}),
236-
)
237-
238153
return c, nil
239154
}
240155

@@ -246,17 +161,17 @@ func (cli *Client) tlsConfig() *tls.Config {
246161
}
247162

248163
func defaultHTTPClient(hostURL *url.URL) (*http.Client, error) {
249-
transport := &http.Transport{}
250164
// Necessary to prevent long-lived processes using the
251165
// client from leaking connections due to idle connections
252166
// not being released.
253167
// TODO: see if we can also address this from the server side,
254168
// or in go-connections.
255169
// see: https://github.com/moby/moby/issues/45539
256-
transport.MaxIdleConns = 6
257-
transport.IdleConnTimeout = 30 * time.Second
258-
err := sockets.ConfigureTransport(transport, hostURL.Scheme, hostURL.Host)
259-
if err != nil {
170+
transport := &http.Transport{
171+
MaxIdleConns: 6,
172+
IdleConnTimeout: 30 * time.Second,
173+
}
174+
if err := sockets.ConfigureTransport(transport, hostURL.Scheme, hostURL.Host); err != nil {
260175
return nil, err
261176
}
262177
return &http.Client{
@@ -274,138 +189,6 @@ func (cli *Client) Close() error {
274189
return nil
275190
}
276191

277-
// checkVersion manually triggers API version negotiation (if configured).
278-
// This allows for version-dependent code to use the same version as will
279-
// be negotiated when making the actual requests, and for which cases
280-
// we cannot do the negotiation lazily.
281-
func (cli *Client) checkVersion(ctx context.Context) error {
282-
if !cli.manualOverride && cli.negotiateVersion && !cli.negotiated.Load() {
283-
// Ensure exclusive write access to version and negotiated fields
284-
cli.negotiateLock.Lock()
285-
defer cli.negotiateLock.Unlock()
286-
287-
// May have been set during last execution of critical zone
288-
if cli.negotiated.Load() {
289-
return nil
290-
}
291-
292-
ping, err := cli.Ping(ctx)
293-
if err != nil {
294-
return err
295-
}
296-
cli.negotiateAPIVersionPing(ping)
297-
}
298-
return nil
299-
}
300-
301-
// getAPIPath returns the versioned request path to call the API.
302-
// It appends the query parameters to the path if they are not empty.
303-
func (cli *Client) getAPIPath(ctx context.Context, p string, query url.Values) string {
304-
var apiPath string
305-
_ = cli.checkVersion(ctx)
306-
if cli.version != "" {
307-
v := strings.TrimPrefix(cli.version, "v")
308-
apiPath = path.Join(cli.basePath, "/v"+v, p)
309-
} else {
310-
apiPath = path.Join(cli.basePath, p)
311-
}
312-
return (&url.URL{Path: apiPath, RawQuery: query.Encode()}).String()
313-
}
314-
315-
// ClientVersion returns the API version used by this client.
316-
func (cli *Client) ClientVersion() string {
317-
return cli.version
318-
}
319-
320-
// NegotiateAPIVersion queries the API and updates the version to match the API
321-
// version. NegotiateAPIVersion downgrades the client's API version to match the
322-
// APIVersion if the ping version is lower than the default version. If the API
323-
// version reported by the server is higher than the maximum version supported
324-
// by the client, it uses the client's maximum version.
325-
//
326-
// If a manual override is in place, either through the "DOCKER_API_VERSION"
327-
// ([EnvOverrideAPIVersion]) environment variable, or if the client is initialized
328-
// with a fixed version ([WithVersion]), no negotiation is performed.
329-
//
330-
// If the API server's ping response does not contain an API version, or if the
331-
// client did not get a successful ping response, it assumes it is connected with
332-
// an old daemon that does not support API version negotiation, in which case it
333-
// downgrades to the latest version of the API before version negotiation was
334-
// added (1.24).
335-
func (cli *Client) NegotiateAPIVersion(ctx context.Context) {
336-
if !cli.manualOverride {
337-
// Avoid concurrent modification of version-related fields
338-
cli.negotiateLock.Lock()
339-
defer cli.negotiateLock.Unlock()
340-
341-
ping, err := cli.Ping(ctx)
342-
if err != nil {
343-
// FIXME(thaJeztah): Ping returns an error when failing to connect to the API; we should not swallow the error here, and instead returning it.
344-
return
345-
}
346-
cli.negotiateAPIVersionPing(ping)
347-
}
348-
}
349-
350-
// NegotiateAPIVersionPing downgrades the client's API version to match the
351-
// APIVersion in the ping response. If the API version in pingResponse is higher
352-
// than the maximum version supported by the client, it uses the client's maximum
353-
// version.
354-
//
355-
// If a manual override is in place, either through the "DOCKER_API_VERSION"
356-
// ([EnvOverrideAPIVersion]) environment variable, or if the client is initialized
357-
// with a fixed version ([WithVersion]), no negotiation is performed.
358-
//
359-
// If the API server's ping response does not contain an API version, we assume
360-
// we are connected with an old daemon without API version negotiation support,
361-
// and downgrade to the latest version of the API before version negotiation was
362-
// added (1.24).
363-
func (cli *Client) NegotiateAPIVersionPing(pingResponse types.Ping) {
364-
if !cli.manualOverride {
365-
// Avoid concurrent modification of version-related fields
366-
cli.negotiateLock.Lock()
367-
defer cli.negotiateLock.Unlock()
368-
369-
cli.negotiateAPIVersionPing(pingResponse)
370-
}
371-
}
372-
373-
// negotiateAPIVersionPing queries the API and updates the version to match the
374-
// API version from the ping response.
375-
func (cli *Client) negotiateAPIVersionPing(pingResponse types.Ping) {
376-
// default to the latest version before versioning headers existed
377-
if pingResponse.APIVersion == "" {
378-
pingResponse.APIVersion = fallbackAPIVersion
379-
}
380-
381-
// if the client is not initialized with a version, start with the latest supported version
382-
if cli.version == "" {
383-
cli.version = api.DefaultVersion
384-
}
385-
386-
// if server version is lower than the client version, downgrade
387-
if versions.LessThan(pingResponse.APIVersion, cli.version) {
388-
cli.version = pingResponse.APIVersion
389-
}
390-
391-
// Store the results, so that automatic API version negotiation (if enabled)
392-
// won't be performed on the next request.
393-
if cli.negotiateVersion {
394-
cli.negotiated.Store(true)
395-
}
396-
}
397-
398-
// DaemonHost returns the host address used by the client
399-
func (cli *Client) DaemonHost() string {
400-
return cli.host
401-
}
402-
403-
// HTTPClient returns a copy of the HTTP client bound to the server
404-
func (cli *Client) HTTPClient() *http.Client {
405-
c := *cli.client
406-
return &c
407-
}
408-
409192
// ParseHostURL parses a url string, validates the string is a host url, and
410193
// returns the parsed URL
411194
func ParseHostURL(host string) (*url.URL, error) {

vendor/github.com/docker/docker/client/client_unix.go renamed to util/testutil/dockerd/client/client_unix.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//go:build !windows
22

3-
package client // import "github.com/docker/docker/client"
3+
package client
44

55
// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST
66
// (EnvOverrideHost) environment variable is unset or empty.

vendor/github.com/docker/docker/client/client_windows.go renamed to util/testutil/dockerd/client/client_windows.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package client // import "github.com/docker/docker/client"
1+
package client
22

33
// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST
44
// (EnvOverrideHost) environment variable is unset or empty.
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package client
2+
3+
import (
4+
"github.com/pkg/errors"
5+
)
6+
7+
// ErrorConnectionFailed returns an error with host in the error message when connection to docker daemon failed.
8+
func ErrorConnectionFailed(host string) error {
9+
if host == "" {
10+
return errors.New("Cannot connect to the Docker daemon. Is the docker daemon running on this host?")
11+
}
12+
return errors.Errorf("Cannot connect to the Docker daemon at %s. Is the docker daemon running?", host)
13+
}

0 commit comments

Comments
 (0)