Skip to content

Commit

Permalink
Merge pull request #373 from mdelapenya/docker-host-support
Browse files Browse the repository at this point in the history
feat: support reading DOCKER_HOST from testcontainers props file
  • Loading branch information
mdelapenya committed Nov 6, 2021
2 parents 1b9fe0b + 59a295c commit cad4370
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 3 deletions.
65 changes: 62 additions & 3 deletions docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"net/url"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"time"
Expand All @@ -25,6 +26,7 @@ import (
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/go-connections/nat"
"github.com/google/uuid"
"github.com/magiconair/properties"
"github.com/moby/term"
"github.com/pkg/errors"

Expand Down Expand Up @@ -514,19 +516,76 @@ type DockerProvider struct {

var _ ContainerProvider = (*DockerProvider)(nil)

// or through Decode
type TestContainersConfig struct {
Host string `properties:"docker.host,default="`
TLSVerify int `properties:"docker.tls.verify,default=0"`
CertPath string `properties:"docker.cert.path,default="`
}

// NewDockerProvider creates a Docker provider with the EnvClient
func NewDockerProvider() (*DockerProvider, error) {
client, err := client.NewEnvClient()
tcConfig := readTCPropsFile()
host := tcConfig.Host

opts := []client.Opt{client.FromEnv}
if host != "" {
opts = append(opts, client.WithHost(host))

// for further informacion, read https://docs.docker.com/engine/security/protect-access/
if tcConfig.TLSVerify == 1 {
cacertPath := path.Join(tcConfig.CertPath, "ca.pem")
certPath := path.Join(tcConfig.CertPath, "cert.pem")
keyPath := path.Join(tcConfig.CertPath, "key.pem")

opts = append(opts, client.WithTLSClientConfig(cacertPath, certPath, keyPath))
}
}

c, err := client.NewClientWithOpts(opts...)
if err != nil {
return nil, err
}
client.NegotiateAPIVersion(context.Background())

_, err = c.Ping(context.TODO())
if err != nil {
// fallback to environment
c, err = client.NewClientWithOpts(client.FromEnv)
if err != nil {
return nil, err
}
}

c.NegotiateAPIVersion(context.Background())
p := &DockerProvider{
client: client,
client: c,
}
return p, nil
}

// readTCPropsFile reads from testcontainers properties file, if it exists
func readTCPropsFile() TestContainersConfig {
home, err := os.UserHomeDir()
if err != nil {
return TestContainersConfig{}
}

tcProp := path.Join(home, ".testcontainers.properties")
// init from a file
properties, err := properties.LoadFile(tcProp, properties.UTF8)
if err != nil {
return TestContainersConfig{}
}

var cfg TestContainersConfig
if err := properties.Decode(&cfg); err != nil {
fmt.Printf("invalid testcontainers properties file, returning an empty Testcontainers configuration: %v\n", err)
return TestContainersConfig{}
}

return cfg
}

// BuildImage will build and image from context and Dockerfile, then return the tag
func (p *DockerProvider) BuildImage(ctx context.Context, img ImageBuildInfo) (string, error) {
repo := uuid.New()
Expand Down
123 changes: 123 additions & 0 deletions docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import (
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"strings"
"testing"
"time"

"github.com/Flaque/filet"
"github.com/stretchr/testify/assert"

"github.com/docker/docker/errdefs"
Expand Down Expand Up @@ -1187,6 +1189,127 @@ func TestEntrypoint(t *testing.T) {
defer c.Terminate(ctx)
}

func TestReadTCPropsFile(t *testing.T) {
t.Run("HOME is not set", func(t *testing.T) {
oldHome := os.Getenv("HOME")
os.Unsetenv("HOME")
defer func() {
os.Setenv("HOME", oldHome)
}()

config := readTCPropsFile()

assert.Empty(t, config, "TC props file should not exist")
})

t.Run("HOME does not contain TC props file", func(t *testing.T) {
oldHome := os.Getenv("HOME")
tmpDir := filet.TmpDir(t, "")
os.Setenv("HOME", tmpDir)
defer func() {
os.Setenv("HOME", oldHome)
filet.CleanUp(t)
}()

config := readTCPropsFile()

assert.Empty(t, config, "TC props file should not exist")
})

t.Run("HOME contains TC properties file", func(t *testing.T) {
oldHome := os.Getenv("HOME")

tests := []struct {
content string
expectedHost string
expectedTLSVerify int
expectedCertPath string
}{
{
"docker.host = tcp:https://127.0.0.1:33293",
"tcp:https://127.0.0.1:33293",
0,
"",
},
{
"docker.host = tcp:https://127.0.0.1:33293",
"tcp:https://127.0.0.1:33293",
0,
"",
},
{
`docker.host = tcp:https://127.0.0.1:33293
docker.host = tcp:https://127.0.0.1:4711
`,
"tcp:https://127.0.0.1:4711",
0,
"",
},
{`docker.host = tcp:https://127.0.0.1:33293
docker.host = tcp:https://127.0.0.1:4711
docker.host = tcp:https://127.0.0.1:1234
docker.tls.verify = 1
`,
"tcp:https://127.0.0.1:1234",
1,
"",
},
{
"",
"",
0,
"",
},
{
`foo = bar
docker.host = tcp:https://127.0.0.1:1234
`,
"tcp:https://127.0.0.1:1234",
0,
"",
},
{
"docker.host=tcp:https://127.0.0.1:33293",
"tcp:https://127.0.0.1:33293",
0,
"",
},
{
`#docker.host=tcp:https://127.0.0.1:33293`,
"",
0,
"",
},
{
`#docker.host = tcp:https://127.0.0.1:33293
docker.host = tcp:https://127.0.0.1:4711
docker.host = tcp:https://127.0.0.1:1234
docker.cert.path=/tmp/certs`,
"tcp:https://127.0.0.1:1234",
0,
"/tmp/certs",
},
}
for _, tt := range tests {
tmpDir := filet.TmpDir(t, "")
os.Setenv("HOME", tmpDir)

defer func() {
os.Setenv("HOME", oldHome)
filet.CleanUp(t)
}()

_ = filet.File(t, path.Join(tmpDir, ".testcontainers.properties"), tt.content)

config := readTCPropsFile()

assert.Equal(t, tt.expectedHost, config.Host, "Hosts do not match")
assert.Equal(t, tt.expectedTLSVerify, config.TLSVerify, "TLS verifies do not match")
assert.Equal(t, tt.expectedCertPath, config.CertPath, "Cert paths do not match")
}
})
}

func ExampleDockerProvider_CreateContainer() {
ctx := context.Background()
req := ContainerRequest{
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ module github.com/testcontainers/testcontainers-go
go 1.13

require (
github.com/Flaque/filet v0.0.0-20201012163910-45f684403088 // indirect
github.com/Microsoft/hcsshim v0.8.16 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/docker/docker v20.10.9+incompatible
github.com/docker/go-connections v0.4.0
github.com/go-redis/redis v6.15.9+incompatible
github.com/go-sql-driver/mysql v1.6.0
github.com/google/uuid v1.3.0
github.com/magiconair/properties v1.8.5 // indirect
github.com/moby/sys/mount v0.2.0 // indirect
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Flaque/filet v0.0.0-20201012163910-45f684403088 h1:PnnQln5IGbhLeJOi6hVs+lCeF+B1dRfFKPGXUAez0Ww=
github.com/Flaque/filet v0.0.0-20201012163910-45f684403088/go.mod h1:TK+jB3mBs+8ZMWhU5BqZKnZWJ1MrLo8etNVg51ueTBo=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
Expand Down Expand Up @@ -363,6 +365,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
Expand Down Expand Up @@ -485,6 +489,7 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
Expand Down

0 comments on commit cad4370

Please sign in to comment.