Skip to content

Commit 339bfde

Browse files
committed
internal/core: add docker context inspect to host lookup strategies
This fixes the user-facing panic, covers additional tests that should be reported as non-fatal, and most importantly includes `docker context inxpect` in the docker host resolution strategies. Fixes #2952
1 parent 9b60a58 commit 339bfde

File tree

2 files changed

+36
-5
lines changed

2 files changed

+36
-5
lines changed

internal/core/client.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package core
22

33
import (
44
"context"
5+
"fmt"
56
"path/filepath"
67

78
"github.com/docker/docker/client"
@@ -14,7 +15,10 @@ import (
1415
func NewClient(ctx context.Context, ops ...client.Opt) (*client.Client, error) {
1516
tcConfig := config.Read()
1617

17-
dockerHost := MustExtractDockerHost(ctx)
18+
dockerHost, err := extractDockerHost(ctx)
19+
if err != nil {
20+
return nil, fmt.Errorf("extract docker host: %w", err)
21+
}
1822

1923
opts := []client.Opt{client.FromEnv, client.WithAPIVersionNegotiation()}
2024
if dockerHost != "" {

internal/core/docker_host.go

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ var (
2828
ErrSocketNotFoundInPath = errors.New("docker socket not found in " + DockerSocketPath)
2929
// ErrTestcontainersHostNotSetInProperties this error is specific to Testcontainers
3030
ErrTestcontainersHostNotSetInProperties = errors.New("tc.host not set in ~/.testcontainers.properties")
31+
ErrDockerSocketNotSetInDockerContext = errors.New("socket not found in docker context")
3132
)
3233

3334
var (
@@ -73,7 +74,7 @@ var dockerHostCheck = func(ctx context.Context, host string) error {
7374
return nil
7475
}
7576

76-
// MustExtractDockerHost Extracts the docker host from the different alternatives, caching the result to avoid unnecessary
77+
// MustExtractDockerHost extracts the docker host from the different alternatives, caching the result to avoid unnecessary
7778
// calculations. Use this function to get the actual Docker host. This function does not consider Windows containers at the moment.
7879
// The possible alternatives are:
7980
//
@@ -118,13 +119,26 @@ func MustExtractDockerSocket(ctx context.Context) string {
118119
return dockerSocketPathCache
119120
}
120121

121-
// extractDockerHost Extracts the docker host from the different alternatives, without caching the result.
122-
// This internal method is handy for testing purposes.
122+
// ExtractDockerHost Extracts the docker host from the different alternatives, without caching the result.
123+
// Use this function to get the actual Docker host. This function does not consider Windows containers at the moment.
124+
// The possible alternatives are:
125+
//
126+
// 1. Docker host from the "tc.host" property in the ~/.testcontainers.properties file.
127+
// 2. DOCKER_HOST environment variable.
128+
// 3. Docker host from context.
129+
// 4. Docker host from the default docker socket path, without the unix schema.
130+
// 5. Docker host from the "docker.host" property in the ~/.testcontainers.properties file.
131+
// 6. Rootless docker socket path.
132+
func ExtractDockerHost(ctx context.Context) (string, error) {
133+
return extractDockerHost(ctx)
134+
}
135+
123136
func extractDockerHost(ctx context.Context) (string, error) {
124137
dockerHostFns := []func(context.Context) (string, error){
125138
testcontainersHostFromProperties,
126139
dockerHostFromEnv,
127140
dockerHostFromContext,
141+
dockerHostFromDockerContext,
128142
dockerSocketPath,
129143
dockerHostFromProperties,
130144
rootlessDockerSocketPath,
@@ -227,12 +241,14 @@ func isHostNotSet(err error) bool {
227241
case errors.Is(err, ErrTestcontainersHostNotSetInProperties),
228242
errors.Is(err, ErrDockerHostNotSet),
229243
errors.Is(err, ErrDockerSocketNotSetInContext),
244+
errors.Is(err, ErrDockerSocketNotSetInDockerContext),
230245
errors.Is(err, ErrDockerSocketNotSetInProperties),
231246
errors.Is(err, ErrSocketNotFoundInPath),
232247
errors.Is(err, ErrXDGRuntimeDirNotSet),
233248
errors.Is(err, ErrRootlessDockerNotFoundHomeRunDir),
234249
errors.Is(err, ErrRootlessDockerNotFoundHomeDesktopDir),
235-
errors.Is(err, ErrRootlessDockerNotFoundRunDir):
250+
errors.Is(err, ErrRootlessDockerNotFoundRunDir),
251+
errors.Is(err, ErrRootlessDockerNotFound):
236252
return true
237253
default:
238254
return false
@@ -262,6 +278,17 @@ func dockerHostFromContext(ctx context.Context) (string, error) {
262278
return "", ErrDockerSocketNotSetInContext
263279
}
264280

281+
// dockerHostFromDockerContext returns the docker host from the DOCKER_CONTEXT environment variable, if it's not empty
282+
func dockerHostFromDockerContext(_ context.Context) (string, error) {
283+
// exec `docker context inspect -f='{{.Endpoints.docker.Host}}'`
284+
cmd := exec.Command("docker", "context", "inspect", "-f", "{{.Endpoints.docker.Host}}")
285+
output, err := cmd.CombinedOutput()
286+
if err != nil {
287+
return "", fmt.Errorf("%w: %w", ErrDockerSocketNotSetInDockerContext, err)
288+
}
289+
return strings.TrimSpace(string(output)), nil
290+
}
291+
265292
// dockerHostFromProperties returns the docker host from the ~/.testcontainers.properties file, if it's not empty
266293
func dockerHostFromProperties(_ context.Context) (string, error) {
267294
cfg := config.Read()

0 commit comments

Comments
 (0)