Skip to content

Commit f6c2fad

Browse files
committed
Rely on docker/cli to get APIClient and registry credentials
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent df1d8fe commit f6c2fad

Some content is hidden

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

78 files changed

+1155
-5843
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ lint-all:
1111
@echo "Running lint in all modules..."
1212
$(call for-all-modules,make lint)
1313

14+
tidy-all:
15+
@echo "Running lint in all modules..."
16+
$(call for-all-modules,go mod tidy)
17+
1418
tidy-all:
1519
@echo "Running tidy in all modules..."
1620
$(call for-all-modules,go mod tidy)

client/client.go

Lines changed: 15 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,17 @@ import (
55
"fmt"
66
"io"
77
"log/slog"
8-
"maps"
9-
"path/filepath"
108
"time"
119

12-
"github.com/docker/docker/client"
13-
dockercontext "github.com/docker/go-sdk/context"
14-
)
15-
16-
const (
17-
// Headers used for docker client requests.
18-
headerUserAgent = "User-Agent"
19-
20-
// TLS certificate files.
21-
tlsCACertFile = "ca.pem"
22-
tlsCertFile = "cert.pem"
23-
tlsKeyFile = "key.pem"
10+
"github.com/docker/cli/cli/command"
11+
"github.com/docker/cli/cli/flags"
2412
)
2513

2614
var (
2715
defaultLogger = slog.New(slog.NewTextHandler(io.Discard, nil))
2816

2917
defaultUserAgent = "docker-go-sdk/" + Version()
3018

31-
defaultOpts = []client.Opt{client.FromEnv, client.WithAPIVersionNegotiation()}
32-
3319
defaultHealthCheck = func(ctx context.Context) func(c SDKClient) error {
3420
return func(c SDKClient) error {
3521
var pingErr error
@@ -71,112 +57,28 @@ func New(ctx context.Context, options ...ClientOption) (SDKClient, error) {
7157
log: defaultLogger,
7258
healthCheck: defaultHealthCheck,
7359
}
74-
for _, opt := range options {
75-
if err := opt.Apply(c); err != nil {
76-
return nil, fmt.Errorf("apply option: %w", err)
77-
}
78-
}
7960

80-
if err := c.init(); err != nil {
81-
return nil, fmt.Errorf("load config: %w", err)
82-
}
83-
84-
if err := c.healthCheck(ctx)(c); err != nil {
85-
return nil, fmt.Errorf("health check: %w", err)
86-
}
87-
88-
return c, nil
89-
}
90-
91-
// init initializes the client.
92-
// This method is safe for concurrent use by multiple goroutines.
93-
func (c *sdkClient) init() error {
94-
if c.APIClient != nil || c.err != nil {
95-
return c.err
96-
}
97-
98-
// Set the default values for the client:
99-
// - log
100-
// - dockerHost
101-
// - currentContext
102-
if c.err = c.defaultValues(); c.err != nil {
103-
return fmt.Errorf("default values: %w", c.err)
104-
}
105-
106-
if c.cfg, c.err = newConfig(c.dockerHost); c.err != nil {
107-
return c.err
108-
}
109-
110-
opts := make([]client.Opt, len(defaultOpts), len(defaultOpts)+len(c.dockerOpts))
111-
copy(opts, defaultOpts)
112-
113-
// Add all collected Docker options
114-
opts = append(opts, c.dockerOpts...)
115-
116-
if c.cfg.TLSVerify {
117-
// For further information see:
118-
// https://docs.docker.com/engine/security/protect-access/#use-tls-https-to-protect-the-docker-daemon-socket
119-
opts = append(opts, client.WithTLSClientConfig(
120-
filepath.Join(c.cfg.CertPath, tlsCACertFile),
121-
filepath.Join(c.cfg.CertPath, tlsCertFile),
122-
filepath.Join(c.cfg.CertPath, tlsKeyFile),
123-
))
124-
}
125-
if c.cfg.Host != "" {
126-
// apply the host from the config if it is set
127-
opts = append(opts, client.WithHost(c.cfg.Host))
128-
}
129-
130-
httpHeaders := make(map[string]string)
131-
maps.Copy(httpHeaders, c.extraHeaders)
132-
133-
// Append the SDK headers last.
134-
httpHeaders[headerUserAgent] = defaultUserAgent
135-
136-
opts = append(opts, client.WithHTTPHeaders(httpHeaders))
137-
138-
api, err := client.NewClientWithOpts(opts...)
61+
cli, err := command.NewDockerCli(command.WithUserAgent(defaultUserAgent))
13962
if err != nil {
140-
return fmt.Errorf("new client: %w", err)
63+
return nil, err
14164
}
142-
c.APIClient = api
143-
return nil
144-
}
14565

146-
// defaultValues sets the default values for the client.
147-
// If no logger is provided, the default one is used.
148-
// If no docker host is provided and no docker context is provided, the current docker host and context are used.
149-
// If no docker host is provided but a docker context is provided, the docker host from the context is used.
150-
// If a docker host is provided, it is used as is.
151-
func (c *sdkClient) defaultValues() error {
152-
if c.log == nil {
153-
c.log = defaultLogger
66+
err = cli.Initialize(flags.NewClientOptions())
67+
if err != nil {
68+
return nil, err
15469
}
70+
c.APIClient = cli.Client()
71+
c.config = cli.ConfigFile()
15572

156-
if c.dockerHost == "" && c.dockerContext == "" {
157-
currentDockerHost, err := dockercontext.CurrentDockerHost()
158-
if err != nil {
159-
return fmt.Errorf("current docker host: %w", err)
160-
}
161-
currentContext, err := dockercontext.Current()
162-
if err != nil {
163-
return fmt.Errorf("current context: %w", err)
73+
for _, opt := range options {
74+
if err := opt.Apply(c); err != nil {
75+
return nil, fmt.Errorf("apply option: %w", err)
16476
}
165-
166-
c.dockerHost = currentDockerHost
167-
c.dockerContext = currentContext
168-
169-
return nil
17077
}
17178

172-
if c.dockerContext != "" {
173-
dockerHost, err := dockercontext.DockerHostFromContext(c.dockerContext)
174-
if err != nil {
175-
return fmt.Errorf("docker host from context: %w", err)
176-
}
177-
178-
c.dockerHost = dockerHost
79+
if err := c.healthCheck(ctx)(c); err != nil {
80+
return nil, fmt.Errorf("health check: %w", err)
17981
}
18082

181-
return nil
83+
return c, nil
18284
}

client/client_test.go

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,13 @@ package client_test
22

33
import (
44
"context"
5-
"path/filepath"
65
"testing"
76

87
"github.com/stretchr/testify/require"
98

10-
dockerclient "github.com/docker/docker/client"
119
"github.com/docker/go-sdk/client"
12-
dockercontext "github.com/docker/go-sdk/context"
1310
)
1411

15-
var noopHealthCheck = func(_ context.Context) func(c client.SDKClient) error {
16-
return func(_ client.SDKClient) error {
17-
return nil
18-
}
19-
}
20-
2112
func TestNew(t *testing.T) {
2213
t.Run("success", func(t *testing.T) {
2314
cli, err := client.New(context.Background())
@@ -60,75 +51,4 @@ func TestNew(t *testing.T) {
6051
require.NoError(t, cli.Close())
6152
require.NoError(t, cli.Close())
6253
})
63-
64-
t.Run("success/tls-verify", func(t *testing.T) {
65-
t.Setenv("DOCKER_TLS_VERIFY", "1")
66-
t.Setenv("DOCKER_CERT_PATH", filepath.Join("testdata", "certificates"))
67-
68-
cli, err := client.New(context.Background())
69-
require.Error(t, err)
70-
require.Nil(t, cli)
71-
})
72-
73-
t.Run("success/apply-option", func(t *testing.T) {
74-
cli, err := client.New(context.Background(), client.FromDockerOpt(dockerclient.WithHost("tcp://foobar:2375")))
75-
require.NoError(t, err)
76-
require.NotNil(t, cli)
77-
})
78-
79-
t.Run("error", func(t *testing.T) {
80-
cli, err := client.New(context.Background(), client.FromDockerOpt(dockerclient.WithHost("foobar")))
81-
require.Error(t, err)
82-
require.Nil(t, cli)
83-
})
84-
85-
t.Run("healthcheck/nil", func(t *testing.T) {
86-
cli, err := client.New(context.Background(), client.WithHealthCheck(nil))
87-
require.ErrorContains(t, err, "health check is nil")
88-
require.Nil(t, cli)
89-
})
90-
91-
t.Run("healthcheck/noop", func(t *testing.T) {
92-
cli, err := client.New(context.Background(), client.WithHealthCheck(noopHealthCheck))
93-
require.NoError(t, err)
94-
require.NotNil(t, cli)
95-
})
96-
97-
t.Run("healthcheck/info", func(t *testing.T) {
98-
t.Setenv(dockercontext.EnvOverrideHost, "tcp://foobar:2375") // this URL is parseable, although not reachable
99-
100-
infoHealthCheck := func(ctx context.Context) func(c client.SDKClient) error {
101-
return func(c client.SDKClient) error {
102-
_, err := c.Info(ctx)
103-
return err
104-
}
105-
}
106-
107-
cli, err := client.New(context.Background(), client.WithHealthCheck(infoHealthCheck))
108-
require.Error(t, err)
109-
require.Nil(t, cli)
110-
})
111-
112-
t.Run("docker-host/precedence", func(t *testing.T) {
113-
t.Run("env-var-wins", func(t *testing.T) {
114-
t.Setenv(dockercontext.EnvOverrideHost, "tcp://foobar:2375") // this URL is parseable, although not reachable
115-
cli, err := client.New(context.Background())
116-
require.Error(t, err)
117-
require.Nil(t, cli)
118-
})
119-
120-
t.Run("context-wins/found", func(t *testing.T) {
121-
t.Setenv(dockercontext.EnvOverrideContext, dockercontext.DefaultContextName)
122-
cli, err := client.New(context.Background(), client.WithHealthCheck(noopHealthCheck))
123-
require.NoError(t, err)
124-
require.NotNil(t, cli)
125-
})
126-
127-
t.Run("context-wins/not-found", func(t *testing.T) {
128-
t.Setenv(dockercontext.EnvOverrideContext, "foocontext") // this context does not exist
129-
cli, err := client.New(context.Background())
130-
require.Error(t, err)
131-
require.Nil(t, cli)
132-
})
133-
})
13454
}

0 commit comments

Comments
 (0)