From 9fb8074f581aaa3f58d6e855a6c733768b732868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Mon, 30 Jan 2023 21:29:13 +0100 Subject: [PATCH] chore: extract docker host calculation to an internal package (#796) --- docker.go | 7 +-- internal/testcontainersdocker/docker_host.go | 40 ++++++++++++++++ .../testcontainersdocker/docker_host_test.go | 47 +++++++++++++++++++ reaper.go | 40 ++-------------- reaper_test.go | 44 +---------------- 5 files changed, 97 insertions(+), 81 deletions(-) create mode 100644 internal/testcontainersdocker/docker_host.go create mode 100644 internal/testcontainersdocker/docker_host_test.go diff --git a/docker.go b/docker.go index fde7f99850..1bb0408cef 100644 --- a/docker.go +++ b/docker.go @@ -34,6 +34,7 @@ import ( specs "github.com/opencontainers/image-spec/specs-go/v1" tcexec "github.com/testcontainers/testcontainers-go/exec" + "github.com/testcontainers/testcontainers-go/internal/testcontainersdocker" "github.com/testcontainers/testcontainers-go/wait" ) @@ -983,7 +984,7 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque // the reaper does not need to start a reaper for itself isReaperContainer := strings.EqualFold(req.Image, reaperImage(reaperOpts.ImageName)) if !req.SkipReaper && !isReaperContainer { - r, err := newReaper(context.WithValue(ctx, dockerHostContextKey, p.host), sessionID.String(), p, req.ReaperOptions...) + r, err := newReaper(context.WithValue(ctx, testcontainersdocker.DockerHostContextKey, p.host), sessionID.String(), p, req.ReaperOptions...) if err != nil { return nil, fmt.Errorf("%w: creating reaper failed", err) } @@ -1200,7 +1201,7 @@ func (p *DockerProvider) ReuseOrCreateContainer(ctx context.Context, req Contain sessionID := sessionID() var termSignal chan bool if !req.SkipReaper { - r, err := newReaper(context.WithValue(ctx, dockerHostContextKey, p.host), sessionID.String(), p, req.ReaperOptions...) + r, err := newReaper(context.WithValue(ctx, testcontainersdocker.DockerHostContextKey, p.host), sessionID.String(), p, req.ReaperOptions...) if err != nil { return nil, fmt.Errorf("%w: creating reaper failed", err) } @@ -1355,7 +1356,7 @@ func (p *DockerProvider) CreateNetwork(ctx context.Context, req NetworkRequest) var termSignal chan bool if !req.SkipReaper { sessionID := sessionID() - r, err := newReaper(context.WithValue(ctx, dockerHostContextKey, p.host), sessionID.String(), p, req.ReaperOptions...) + r, err := newReaper(context.WithValue(ctx, testcontainersdocker.DockerHostContextKey, p.host), sessionID.String(), p, req.ReaperOptions...) if err != nil { return nil, fmt.Errorf("%w: creating network reaper failed", err) } diff --git a/internal/testcontainersdocker/docker_host.go b/internal/testcontainersdocker/docker_host.go new file mode 100644 index 0000000000..a9ee3cff2b --- /dev/null +++ b/internal/testcontainersdocker/docker_host.go @@ -0,0 +1,40 @@ +package testcontainersdocker + +import ( + "context" + "net/url" + "os" +) + +type dockerHostContext string + +var DockerHostContextKey = dockerHostContext("docker_host") + +// Extracts the docker host from the context, or returns the default value +func ExtractDockerHost(ctx context.Context) (dockerHostPath string) { + if dockerHostPath = os.Getenv("TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE"); dockerHostPath != "" { + return dockerHostPath + } + + dockerHostPath = "/var/run/docker.sock" + + var hostRawURL string + if h, ok := ctx.Value(DockerHostContextKey).(string); !ok || h == "" { + return dockerHostPath + } else { + hostRawURL = h + } + var hostURL *url.URL + if u, err := url.Parse(hostRawURL); err != nil { + return dockerHostPath + } else { + hostURL = u + } + + switch hostURL.Scheme { + case "unix": + return hostURL.Path + default: + return dockerHostPath + } +} diff --git a/internal/testcontainersdocker/docker_host_test.go b/internal/testcontainersdocker/docker_host_test.go new file mode 100644 index 0000000000..4c6ae69cb6 --- /dev/null +++ b/internal/testcontainersdocker/docker_host_test.go @@ -0,0 +1,47 @@ +package testcontainersdocker + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_ExtractDockerHost(t *testing.T) { + t.Run("Docker Host as environment variable", func(t *testing.T) { + t.Setenv("TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE", "/path/to/docker.sock") + host := ExtractDockerHost(context.Background()) + + assert.Equal(t, "/path/to/docker.sock", host) + }) + + t.Run("Default Docker Host", func(t *testing.T) { + host := ExtractDockerHost(context.Background()) + + assert.Equal(t, "/var/run/docker.sock", host) + }) + + t.Run("Malformed Docker Host is passed in context", func(t *testing.T) { + ctx := context.Background() + + host := ExtractDockerHost(context.WithValue(ctx, DockerHostContextKey, "path-to-docker-sock")) + + assert.Equal(t, "/var/run/docker.sock", host) + }) + + t.Run("Malformed Schema Docker Host is passed in context", func(t *testing.T) { + ctx := context.Background() + + host := ExtractDockerHost(context.WithValue(ctx, DockerHostContextKey, "http://path to docker sock")) + + assert.Equal(t, "/var/run/docker.sock", host) + }) + + t.Run("Unix Docker Host is passed in context", func(t *testing.T) { + ctx := context.Background() + + host := ExtractDockerHost(context.WithValue(ctx, DockerHostContextKey, "unix:///this/is/a/sample.sock")) + + assert.Equal(t, "/this/is/a/sample.sock", host) + }) +} diff --git a/reaper.go b/reaper.go index c9cce215b6..fffd13cde1 100644 --- a/reaper.go +++ b/reaper.go @@ -5,14 +5,13 @@ import ( "context" "fmt" "net" - "net/url" - "os" "strings" "sync" "time" "github.com/docker/go-connections/nat" + "github.com/testcontainers/testcontainers-go/internal/testcontainersdocker" "github.com/testcontainers/testcontainers-go/wait" ) @@ -24,12 +23,9 @@ const ( ReaperDefaultImage = "docker.io/testcontainers/ryuk:0.3.4" ) -type reaperContextKey string - var ( - dockerHostContextKey = reaperContextKey("docker_host") - reaper *Reaper // We would like to create reaper only once - mutex sync.Mutex + reaper *Reaper // We would like to create reaper only once + mutex sync.Mutex ) // ReaperProvider represents a provider for the reaper to run itself with @@ -54,7 +50,7 @@ func newReaper(ctx context.Context, sessionID string, provider ReaperProvider, o return reaper, nil } - dockerHost := extractDockerHost(ctx) + dockerHost := testcontainersdocker.ExtractDockerHost(ctx) // Otherwise create a new one reaper = &Reaper{ @@ -181,34 +177,6 @@ func (r *Reaper) Labels() map[string]string { } } -func extractDockerHost(ctx context.Context) (dockerHostPath string) { - if dockerHostPath = os.Getenv("TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE"); dockerHostPath != "" { - return dockerHostPath - } - - dockerHostPath = "/var/run/docker.sock" - - var hostRawURL string - if h, ok := ctx.Value(dockerHostContextKey).(string); !ok || h == "" { - return dockerHostPath - } else { - hostRawURL = h - } - var hostURL *url.URL - if u, err := url.Parse(hostRawURL); err != nil { - return dockerHostPath - } else { - hostURL = u - } - - switch hostURL.Scheme { - case "unix": - return hostURL.Path - default: - return dockerHostPath - } -} - func reaperImage(reaperImageName string) string { if reaperImageName == "" { return ReaperDefaultImage diff --git a/reaper_test.go b/reaper_test.go index d17d905b79..db6ebe477e 100644 --- a/reaper_test.go +++ b/reaper_test.go @@ -7,6 +7,7 @@ import ( "github.com/docker/go-connections/nat" "github.com/stretchr/testify/assert" + "github.com/testcontainers/testcontainers-go/internal/testcontainersdocker" "github.com/testcontainers/testcontainers-go/wait" ) @@ -88,7 +89,7 @@ func Test_NewReaper(t *testing.T) { return req }), config: TestContainersConfig{}, - ctx: context.WithValue(context.TODO(), dockerHostContextKey, "unix:///value/in/context.sock"), + ctx: context.WithValue(context.TODO(), testcontainersdocker.DockerHostContextKey, "unix:///value/in/context.sock"), }, { name: "with registry credentials", @@ -123,47 +124,6 @@ func Test_NewReaper(t *testing.T) { } } -func Test_ExtractDockerHost(t *testing.T) { - defer func() { reaper = nil }() - - t.Run("Docker Host as environment variable", func(t *testing.T) { - t.Setenv("TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE", "/path/to/docker.sock") - host := extractDockerHost(context.Background()) - - assert.Equal(t, "/path/to/docker.sock", host) - }) - - t.Run("Default Docker Host", func(t *testing.T) { - host := extractDockerHost(context.Background()) - - assert.Equal(t, "/var/run/docker.sock", host) - }) - - t.Run("Malformed Docker Host is passed in context", func(t *testing.T) { - ctx := context.Background() - - host := extractDockerHost(context.WithValue(ctx, dockerHostContextKey, "path-to-docker-sock")) - - assert.Equal(t, "/var/run/docker.sock", host) - }) - - t.Run("Malformed Schema Docker Host is passed in context", func(t *testing.T) { - ctx := context.Background() - - host := extractDockerHost(context.WithValue(ctx, dockerHostContextKey, "http://path to docker sock")) - - assert.Equal(t, "/var/run/docker.sock", host) - }) - - t.Run("Unix Docker Host is passed in context", func(t *testing.T) { - ctx := context.Background() - - host := extractDockerHost(context.WithValue(ctx, dockerHostContextKey, "unix:///this/is/a/sample.sock")) - - assert.Equal(t, "/this/is/a/sample.sock", host) - }) -} - func Test_ReaperForNetwork(t *testing.T) { defer func() { reaper = nil }()