From 215cb39fd099b45ce0ed1bb75583c78977f856fd Mon Sep 17 00:00:00 2001 From: Viktor Stanchev Date: Fri, 29 Nov 2024 01:59:17 +0000 Subject: [PATCH 01/10] avoid double lock in DockerProvider.DaemonHost() --- docker.go | 20 +++++++++++++------- reaper.go | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/docker.go b/docker.go index 296fe6743c..fc29fb9b5b 100644 --- a/docker.go +++ b/docker.go @@ -1027,7 +1027,7 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque defer p.Close() var defaultNetwork string - defaultNetwork, err = p.ensureDefaultNetwork(ctx) + defaultNetwork, err = p.ensureDefaultNetwork(ctx, false) if err != nil { return nil, fmt.Errorf("ensure default network: %w", err) } @@ -1498,7 +1498,7 @@ func (p *DockerProvider) daemonHostLocked(ctx context.Context) (string, error) { p.hostCache = daemonURL.Hostname() case "unix", "npipe": if core.InAContainer() { - ip, err := p.GetGatewayIP(ctx) + ip, err := p.getGatewayIPMaybeLocked(ctx, true) if err != nil { ip, err = core.DefaultGatewayIP() if err != nil { @@ -1522,7 +1522,7 @@ func (p *DockerProvider) CreateNetwork(ctx context.Context, req NetworkRequest) // defer the close of the Docker client connection the soonest defer p.Close() - if _, err = p.ensureDefaultNetwork(ctx); err != nil { + if _, err = p.ensureDefaultNetwork(ctx, false); err != nil { return nil, fmt.Errorf("ensure default network: %w", err) } @@ -1593,8 +1593,12 @@ func (p *DockerProvider) GetNetwork(ctx context.Context, req NetworkRequest) (ne } func (p *DockerProvider) GetGatewayIP(ctx context.Context) (string, error) { + return p.getGatewayIPMaybeLocked(ctx, false) +} + +func (p *DockerProvider) getGatewayIPMaybeLocked(ctx context.Context, locked bool) (string, error) { // Use a default network as defined in the DockerProvider - defaultNetwork, err := p.ensureDefaultNetwork(ctx) + defaultNetwork, err := p.ensureDefaultNetwork(ctx, locked) if err != nil { return "", fmt.Errorf("ensure default network: %w", err) } @@ -1621,9 +1625,11 @@ func (p *DockerProvider) GetGatewayIP(ctx context.Context) (string, error) { // ensureDefaultNetwork ensures that defaultNetwork is set and creates // it if it does not exist, returning its value. // It is safe to call this method concurrently. -func (p *DockerProvider) ensureDefaultNetwork(ctx context.Context) (string, error) { - p.mtx.Lock() - defer p.mtx.Unlock() +func (p *DockerProvider) ensureDefaultNetwork(ctx context.Context, locked bool) (string, error) { + if !locked { + p.mtx.Lock() + defer p.mtx.Unlock() + } if p.defaultNetwork != "" { // Already set. diff --git a/reaper.go b/reaper.go index 1d97a36ffa..57327958a0 100644 --- a/reaper.go +++ b/reaper.go @@ -408,7 +408,7 @@ func (r *reaperSpawner) newReaper(ctx context.Context, sessionID string, provide // Attach reaper container to a requested network if it is specified if p, ok := provider.(*DockerProvider); ok { - defaultNetwork, err := p.ensureDefaultNetwork(ctx) + defaultNetwork, err := p.ensureDefaultNetwork(ctx, false) if err != nil { return nil, fmt.Errorf("ensure default network: %w", err) } From fd013f23889e8bd98caad60fd9abf397bb0ec359 Mon Sep 17 00:00:00 2001 From: Viktor Stanchev Date: Fri, 29 Nov 2024 19:12:58 +0000 Subject: [PATCH 02/10] cleaner structure --- docker.go | 31 +++++++++++++++++-------------- reaper.go | 2 +- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/docker.go b/docker.go index fc29fb9b5b..bf5d0f2c50 100644 --- a/docker.go +++ b/docker.go @@ -1027,7 +1027,7 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque defer p.Close() var defaultNetwork string - defaultNetwork, err = p.ensureDefaultNetwork(ctx, false) + defaultNetwork, err = p.ensureDefaultNetwork(ctx) if err != nil { return nil, fmt.Errorf("ensure default network: %w", err) } @@ -1498,7 +1498,11 @@ func (p *DockerProvider) daemonHostLocked(ctx context.Context) (string, error) { p.hostCache = daemonURL.Hostname() case "unix", "npipe": if core.InAContainer() { - ip, err := p.getGatewayIPMaybeLocked(ctx, true) + defaultNetwork, err := p.ensureDefaultNetworkLocked(ctx) + if err != nil { + return "", fmt.Errorf("ensure default network: %w", err) + } + ip, err := p.getGatewayIP(ctx, defaultNetwork) if err != nil { ip, err = core.DefaultGatewayIP() if err != nil { @@ -1522,7 +1526,7 @@ func (p *DockerProvider) CreateNetwork(ctx context.Context, req NetworkRequest) // defer the close of the Docker client connection the soonest defer p.Close() - if _, err = p.ensureDefaultNetwork(ctx, false); err != nil { + if _, err = p.ensureDefaultNetwork(ctx); err != nil { return nil, fmt.Errorf("ensure default network: %w", err) } @@ -1593,16 +1597,14 @@ func (p *DockerProvider) GetNetwork(ctx context.Context, req NetworkRequest) (ne } func (p *DockerProvider) GetGatewayIP(ctx context.Context) (string, error) { - return p.getGatewayIPMaybeLocked(ctx, false) -} - -func (p *DockerProvider) getGatewayIPMaybeLocked(ctx context.Context, locked bool) (string, error) { - // Use a default network as defined in the DockerProvider - defaultNetwork, err := p.ensureDefaultNetwork(ctx, locked) + defaultNetwork, err := p.ensureDefaultNetwork(ctx) if err != nil { return "", fmt.Errorf("ensure default network: %w", err) } + return p.getGatewayIP(ctx, defaultNetwork) +} +func (p *DockerProvider) getGatewayIP(ctx context.Context, defaultNetwork string) (string, error) { nw, err := p.GetNetwork(ctx, NetworkRequest{Name: defaultNetwork}) if err != nil { return "", err @@ -1625,12 +1627,13 @@ func (p *DockerProvider) getGatewayIPMaybeLocked(ctx context.Context, locked boo // ensureDefaultNetwork ensures that defaultNetwork is set and creates // it if it does not exist, returning its value. // It is safe to call this method concurrently. -func (p *DockerProvider) ensureDefaultNetwork(ctx context.Context, locked bool) (string, error) { - if !locked { - p.mtx.Lock() - defer p.mtx.Unlock() - } +func (p *DockerProvider) ensureDefaultNetwork(ctx context.Context) (string, error) { + p.mtx.Lock() + defer p.mtx.Unlock() + return p.ensureDefaultNetworkLocked(ctx) +} +func (p *DockerProvider) ensureDefaultNetworkLocked(ctx context.Context) (string, error) { if p.defaultNetwork != "" { // Already set. return p.defaultNetwork, nil diff --git a/reaper.go b/reaper.go index 57327958a0..1d97a36ffa 100644 --- a/reaper.go +++ b/reaper.go @@ -408,7 +408,7 @@ func (r *reaperSpawner) newReaper(ctx context.Context, sessionID string, provide // Attach reaper container to a requested network if it is specified if p, ok := provider.(*DockerProvider); ok { - defaultNetwork, err := p.ensureDefaultNetwork(ctx, false) + defaultNetwork, err := p.ensureDefaultNetwork(ctx) if err != nil { return nil, fmt.Errorf("ensure default network: %w", err) } From 1162bcb0880513430cd1835cbbf20495114c731a Mon Sep 17 00:00:00 2001 From: Viktor Stanchev Date: Fri, 29 Nov 2024 19:14:44 +0000 Subject: [PATCH 03/10] put comment back --- docker.go | 1 + 1 file changed, 1 insertion(+) diff --git a/docker.go b/docker.go index bf5d0f2c50..addb614929 100644 --- a/docker.go +++ b/docker.go @@ -1597,6 +1597,7 @@ func (p *DockerProvider) GetNetwork(ctx context.Context, req NetworkRequest) (ne } func (p *DockerProvider) GetGatewayIP(ctx context.Context) (string, error) { + // Use a default network as defined in the DockerProvider defaultNetwork, err := p.ensureDefaultNetwork(ctx) if err != nil { return "", fmt.Errorf("ensure default network: %w", err) From f83199b1a2c4afd4a2e783d80b71c7291317fda2 Mon Sep 17 00:00:00 2001 From: Viktor Stanchev Date: Fri, 29 Nov 2024 19:43:56 +0000 Subject: [PATCH 04/10] add regression test --- docker_test.go | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/docker_test.go b/docker_test.go index 3fa686632f..429c562e02 100644 --- a/docker_test.go +++ b/docker_test.go @@ -19,12 +19,14 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/image" + "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/strslice" "github.com/docker/docker/client" "github.com/docker/docker/errdefs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/testcontainers/testcontainers-go/exec" "github.com/testcontainers/testcontainers-go/wait" ) @@ -35,6 +37,7 @@ const ( nginxAlpineImage = "nginx:alpine" nginxDefaultPort = "80/tcp" nginxHighPort = "8080/tcp" + golangImage = "golang" daemonMaxVersion = "1.41" ) @@ -46,6 +49,72 @@ func init() { } } +func TestWithinContainerStage1(t *testing.T) { + if providerType != ProviderDocker { + t.Skip("This is a docker-specific test.") + } + dir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + req := ContainerRequest{ + Image: golangImage, + WorkingDir: dir, + HostConfigModifier: func(hc *container.HostConfig) { + hc.Mounts = append(hc.Mounts, mount.Mount{ + Type: "bind", + Source: dir, + Target: dir, + }, mount.Mount{ + Type: "bind", + Source: "/var/run", + Target: "/var/run", + }) + }, + Entrypoint: []string{"sleep", "100"}, + } + container, err := GenericContainer(context.Background(), GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + t.Fatal(err) + } + // The timeout is necessary because when TestWithinContainersStage2 fails, it hangs forever instead of erroring + exitCode, outputReader, err := container.Exec(context.Background(), []string{"go", "test", "-v", "-run", "^TestWithinContainerStage2$", "-timeout", "10s"}, exec.Multiplexed()) + if err != nil { + t.Fatal(err) + } + + outputStr, err := io.ReadAll(outputReader) + if err != nil { + t.Fatalf("failed to read output: %s", err) + } + t.Logf("%s", outputStr) + + if exitCode != 0 { + t.Fatalf("exit code %d, output: %s", exitCode, outputStr) + } +} + +// Regression test for deadlock #2897 +func TestWithinContainerStage2(t *testing.T) { + req := ContainerRequest{ + Image: nginxImage, + } + container, err := GenericContainer(context.Background(), GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + t.Fatal(err) + } + _, err = container.Host(context.Background()) + if err != nil { + t.Fatal(err) + } +} + func TestContainerWithHostNetworkOptions(t *testing.T) { if os.Getenv("XDG_RUNTIME_DIR") != "" { t.Skip("Skipping test that requires host network access when running in a container") From d9c908c6219f1972864f0b531e21c9de1e0310a9 Mon Sep 17 00:00:00 2001 From: Viktor Stanchev Date: Fri, 29 Nov 2024 19:45:49 +0000 Subject: [PATCH 05/10] use require --- docker_test.go | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/docker_test.go b/docker_test.go index 429c562e02..daea4c582f 100644 --- a/docker_test.go +++ b/docker_test.go @@ -54,9 +54,7 @@ func TestWithinContainerStage1(t *testing.T) { t.Skip("This is a docker-specific test.") } dir, err := os.Getwd() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) req := ContainerRequest{ Image: golangImage, WorkingDir: dir, @@ -77,14 +75,10 @@ func TestWithinContainerStage1(t *testing.T) { ContainerRequest: req, Started: true, }) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // The timeout is necessary because when TestWithinContainersStage2 fails, it hangs forever instead of erroring exitCode, outputReader, err := container.Exec(context.Background(), []string{"go", "test", "-v", "-run", "^TestWithinContainerStage2$", "-timeout", "10s"}, exec.Multiplexed()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) outputStr, err := io.ReadAll(outputReader) if err != nil { @@ -106,13 +100,9 @@ func TestWithinContainerStage2(t *testing.T) { ContainerRequest: req, Started: true, }) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = container.Host(context.Background()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } func TestContainerWithHostNetworkOptions(t *testing.T) { From a290906f0e011368338f6a96c40af9a845075b65 Mon Sep 17 00:00:00 2001 From: Viktor Stanchev Date: Sat, 30 Nov 2024 20:56:08 -0500 Subject: [PATCH 06/10] test improvements --- docker_test.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/docker_test.go b/docker_test.go index daea4c582f..ffbb87c691 100644 --- a/docker_test.go +++ b/docker_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "errors" + "flag" "fmt" "io" "log" @@ -50,6 +51,7 @@ func init() { } func TestWithinContainerStage1(t *testing.T) { + // TODO: remove this skip check when context rework is merged. if providerType != ProviderDocker { t.Skip("This is a docker-specific test.") } @@ -77,22 +79,24 @@ func TestWithinContainerStage1(t *testing.T) { }) require.NoError(t, err) // The timeout is necessary because when TestWithinContainersStage2 fails, it hangs forever instead of erroring - exitCode, outputReader, err := container.Exec(context.Background(), []string{"go", "test", "-v", "-run", "^TestWithinContainerStage2$", "-timeout", "10s"}, exec.Multiplexed()) + exitCode, outputReader, err := container.Exec(context.Background(), []string{"go", "test", "-v", "-run", "^TestWithinContainerStage2$", "-timeout", "20s", "-stage2"}, exec.Multiplexed()) require.NoError(t, err) - outputStr, err := io.ReadAll(outputReader) - if err != nil { - t.Fatalf("failed to read output: %s", err) - } - t.Logf("%s", outputStr) + outputBytes, err := io.ReadAll(outputReader) + require.NoError(t, err, "failed to read output") + t.Logf("%s", outputBytes) - if exitCode != 0 { - t.Fatalf("exit code %d, output: %s", exitCode, outputStr) - } + require.Zero(t, exitCode, "non-zero exit code, output: %s", outputBytes) } +var stage2 = flag.Bool("stage2", false, "Run TestWithinContainerStage2") + // Regression test for deadlock #2897 func TestWithinContainerStage2(t *testing.T) { + if !*stage2 { + t.Skip("Skipping test that requires stage2") + } + req := ContainerRequest{ Image: nginxImage, } From 1ad63a39cea03aac156371873b16022d5c4d2a41 Mon Sep 17 00:00:00 2001 From: Viktor Stanchev Date: Sun, 1 Dec 2024 08:31:09 -0500 Subject: [PATCH 07/10] better error output --- docker_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker_test.go b/docker_test.go index ffbb87c691..2ea4dd094b 100644 --- a/docker_test.go +++ b/docker_test.go @@ -86,7 +86,7 @@ func TestWithinContainerStage1(t *testing.T) { require.NoError(t, err, "failed to read output") t.Logf("%s", outputBytes) - require.Zero(t, exitCode, "non-zero exit code, output: %s", outputBytes) + require.Zero(t, exitCode, "non-zero exit code from stage 2") } var stage2 = flag.Bool("stage2", false, "Run TestWithinContainerStage2") From 1ef4fa25b02e49c7a17edc45bf55abd9ca637ec3 Mon Sep 17 00:00:00 2001 From: Viktor Stanchev Date: Mon, 2 Dec 2024 08:35:16 -0500 Subject: [PATCH 08/10] try to fix rootless mode --- docker_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docker_test.go b/docker_test.go index 2ea4dd094b..2cb9d8d965 100644 --- a/docker_test.go +++ b/docker_test.go @@ -55,6 +55,7 @@ func TestWithinContainerStage1(t *testing.T) { if providerType != ProviderDocker { t.Skip("This is a docker-specific test.") } + socketPath := MustExtractDockerSocket(context.Background()) dir, err := os.Getwd() require.NoError(t, err) req := ContainerRequest{ @@ -67,8 +68,8 @@ func TestWithinContainerStage1(t *testing.T) { Target: dir, }, mount.Mount{ Type: "bind", - Source: "/var/run", - Target: "/var/run", + Source: socketPath, + Target: socketPath, }) }, Entrypoint: []string{"sleep", "100"}, From 4e1beb5491dd8af61e4607c1b4a549439a4a3688 Mon Sep 17 00:00:00 2001 From: Viktor Stanchev Date: Tue, 3 Dec 2024 20:42:37 -0500 Subject: [PATCH 09/10] pass on XDG_RUNTIME_DIR --- docker_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker_test.go b/docker_test.go index 2cb9d8d965..ef7b79c2b2 100644 --- a/docker_test.go +++ b/docker_test.go @@ -61,6 +61,9 @@ func TestWithinContainerStage1(t *testing.T) { req := ContainerRequest{ Image: golangImage, WorkingDir: dir, + Env: map[string]string{ + "XDG_RUNTIME_DIR": os.Getenv("XDG_RUNTIME_DIR"), + }, HostConfigModifier: func(hc *container.HostConfig) { hc.Mounts = append(hc.Mounts, mount.Mount{ Type: "bind", From 547a532f0fbc6f5d9c896d34d1dbe484f884979d Mon Sep 17 00:00:00 2001 From: Steven Hartland Date: Wed, 18 Dec 2024 23:27:32 +0000 Subject: [PATCH 10/10] fix: DaemonHost locking test Fix the DaemonHost locking test by implementing a way to change the location of the file the core library tests for. --- docker_test.go | 103 +++++++++++++---------------------- internal/core/docker_host.go | 7 ++- 2 files changed, 43 insertions(+), 67 deletions(-) diff --git a/docker_test.go b/docker_test.go index ef7b79c2b2..b8a0388a4c 100644 --- a/docker_test.go +++ b/docker_test.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "errors" - "flag" "fmt" "io" "log" @@ -20,14 +19,13 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/image" - "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/strslice" "github.com/docker/docker/client" "github.com/docker/docker/errdefs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/testcontainers/testcontainers-go/exec" + "github.com/testcontainers/testcontainers-go/internal/core" "github.com/testcontainers/testcontainers-go/wait" ) @@ -50,69 +48,6 @@ func init() { } } -func TestWithinContainerStage1(t *testing.T) { - // TODO: remove this skip check when context rework is merged. - if providerType != ProviderDocker { - t.Skip("This is a docker-specific test.") - } - socketPath := MustExtractDockerSocket(context.Background()) - dir, err := os.Getwd() - require.NoError(t, err) - req := ContainerRequest{ - Image: golangImage, - WorkingDir: dir, - Env: map[string]string{ - "XDG_RUNTIME_DIR": os.Getenv("XDG_RUNTIME_DIR"), - }, - HostConfigModifier: func(hc *container.HostConfig) { - hc.Mounts = append(hc.Mounts, mount.Mount{ - Type: "bind", - Source: dir, - Target: dir, - }, mount.Mount{ - Type: "bind", - Source: socketPath, - Target: socketPath, - }) - }, - Entrypoint: []string{"sleep", "100"}, - } - container, err := GenericContainer(context.Background(), GenericContainerRequest{ - ContainerRequest: req, - Started: true, - }) - require.NoError(t, err) - // The timeout is necessary because when TestWithinContainersStage2 fails, it hangs forever instead of erroring - exitCode, outputReader, err := container.Exec(context.Background(), []string{"go", "test", "-v", "-run", "^TestWithinContainerStage2$", "-timeout", "20s", "-stage2"}, exec.Multiplexed()) - require.NoError(t, err) - - outputBytes, err := io.ReadAll(outputReader) - require.NoError(t, err, "failed to read output") - t.Logf("%s", outputBytes) - - require.Zero(t, exitCode, "non-zero exit code from stage 2") -} - -var stage2 = flag.Bool("stage2", false, "Run TestWithinContainerStage2") - -// Regression test for deadlock #2897 -func TestWithinContainerStage2(t *testing.T) { - if !*stage2 { - t.Skip("Skipping test that requires stage2") - } - - req := ContainerRequest{ - Image: nginxImage, - } - container, err := GenericContainer(context.Background(), GenericContainerRequest{ - ContainerRequest: req, - Started: true, - }) - require.NoError(t, err) - _, err = container.Host(context.Background()) - require.NoError(t, err) -} - func TestContainerWithHostNetworkOptions(t *testing.T) { if os.Getenv("XDG_RUNTIME_DIR") != "" { t.Skip("Skipping test that requires host network access when running in a container") @@ -2192,3 +2127,39 @@ func TestCustomPrefixTrailingSlashIsProperlyRemovedIfPresent(t *testing.T) { dockerContainer := c.(*DockerContainer) require.Equal(t, fmt.Sprintf("%s%s", hubPrefixWithTrailingSlash, dockerImage), dockerContainer.Image) } + +// TODO: remove this skip check when context rework is merged alongside [core.DockerEnvFile] removal. +func Test_Provider_DaemonHost_Issue2897(t *testing.T) { + ctx := context.Background() + provider, err := NewDockerProvider() + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, provider.Close()) + }) + + orig := core.DockerEnvFile + core.DockerEnvFile = filepath.Join(t.TempDir(), ".dockerenv") + t.Cleanup(func() { + core.DockerEnvFile = orig + }) + + f, err := os.Create(core.DockerEnvFile) + require.NoError(t, err) + require.NoError(t, f.Close()) + t.Cleanup(func() { + require.NoError(t, os.Remove(f.Name())) + }) + + errCh := make(chan error, 1) + go func() { + _, err := provider.DaemonHost(ctx) + errCh <- err + }() + + select { + case <-time.After(1 * time.Second): + t.Fatal("timeout waiting for DaemonHost") + case err := <-errCh: + require.NoError(t, err) + } +} diff --git a/internal/core/docker_host.go b/internal/core/docker_host.go index 3088a3742b..765626da57 100644 --- a/internal/core/docker_host.go +++ b/internal/core/docker_host.go @@ -309,10 +309,15 @@ func testcontainersHostFromProperties(ctx context.Context) (string, error) { return "", ErrTestcontainersHostNotSetInProperties } +// DockerEnvFile is the file that is created when running inside a container. +// It's a variable to allow testing. +// TODO: Remove this once context rework is done, which eliminates need for the default network creation. +var DockerEnvFile = "/.dockerenv" + // InAContainer returns true if the code is running inside a container // See https://github.com/docker/docker/blob/a9fa38b1edf30b23cae3eade0be48b3d4b1de14b/daemon/initlayer/setup_unix.go#L25 func InAContainer() bool { - return inAContainer("/.dockerenv") + return inAContainer(DockerEnvFile) } func inAContainer(path string) bool {