Skip to content

Commit

Permalink
Merge branch 'main' into wait-for-available-ports
Browse files Browse the repository at this point in the history
* main:
  chore(deps): bump github.com/docker/docker from v26.1.4 to v27.0.2 (testcontainers#2593)
  fix: Rename TC_HOST environment variable to TESTCONTAINERS_HOST_OVERRIDE (testcontainers#2536)
  chore: test cleanups (testcontainers#2608)
  chore(ci): pass docker install type to the nightly build payload (testcontainers#2612)
  chore: run rootless mode in nighlty builds (testcontainers#2611)
  chore(deps): bump github.com/hashicorp/go-retryablehttp (testcontainers#2605)
  chore: improve log handling when container is stopping (testcontainers#2601)
  • Loading branch information
mdelapenya committed Jul 2, 2024
2 parents b0c17a8 + 989b422 commit 97b02f2
Show file tree
Hide file tree
Showing 103 changed files with 500 additions and 550 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/docker-moby-latest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,25 @@ on:

jobs:
test_latest_moby:
strategy:
matrix:
rootless-docker: [true, false]
name: "Core tests using latest moby/moby"
runs-on: 'ubuntu-latest'
continue-on-error: true
steps:
- name: Set the Docker Install type
run: |
echo "docker_install_type=${{ matrix.rootless-docker == true && 'Rootless' || 'Rootful' }}" >> "$GITHUB_ENV"
- name: Setup rootless Docker
if: ${{ matrix.rootless-docker }}
uses: ScribeMD/rootless-docker@6bd157a512c2fafa4e0243a8aa87d964eb890886 # v0.2.2

- name: Remove Docker root socket
if: ${{ matrix.rootless-docker }}
run: sudo rm -rf /var/run/docker.sock

- name: Check out code into the Go module directory
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4

Expand Down Expand Up @@ -39,6 +55,7 @@ jobs:
cat <<EOF > ./payload-slack-content.json
{
"tc_project": "testcontainers-go",
"tc_docker_install_type": "${docker_install_type}",
"tc_github_action_url": "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/attempts/${GITHUB_RUN_ATTEMPT}",
"tc_github_action_status": "FAILED",
"tc_slack_channel_id": "${{ secrets.SLACK_DOCKER_LATEST_CHANNEL_ID }}"
Expand Down
122 changes: 63 additions & 59 deletions docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package testcontainers
import (
"archive/tar"
"bufio"
"bytes"
"context"
"encoding/base64"
"encoding/binary"
Expand All @@ -12,6 +11,7 @@ import (
"fmt"
"io"
"io/fs"
"net"
"net/url"
"os"
"path/filepath"
Expand Down Expand Up @@ -156,7 +156,7 @@ func (c *DockerContainer) PortEndpoint(ctx context.Context, port nat.Port, proto

// Host gets host (ip or name) of the docker daemon where the container port is exposed
// Warning: this is based on your Docker host setting. Will fail if using an SSH tunnel
// You can use the "TC_HOST" env variable to set this yourself
// You can use the "TESTCONTAINERS_HOST_OVERRIDE" env variable to set this yourself
func (c *DockerContainer) Host(ctx context.Context) (string, error) {
host, err := c.provider.DaemonHost(ctx)
if err != nil {
Expand Down Expand Up @@ -507,7 +507,7 @@ func (c *DockerContainer) Exec(ctx context.Context, cmd []string, options ...tce
return 0, nil, err
}

hijack, err := cli.ContainerExecAttach(ctx, response.ID, types.ExecStartCheck{})
hijack, err := cli.ContainerExecAttach(ctx, response.ID, container.ExecAttachOptions{})
if err != nil {
return 0, nil, err
}
Expand Down Expand Up @@ -596,7 +596,7 @@ func (c *DockerContainer) CopyDirToContainer(ctx context.Context, hostDirPath st
// create the directory under its parent
parent := filepath.Dir(containerParentPath)

err = c.provider.client.CopyToContainer(ctx, c.ID, parent, buff, types.CopyToContainerOptions{})
err = c.provider.client.CopyToContainer(ctx, c.ID, parent, buff, container.CopyToContainerOptions{})
if err != nil {
return err
}
Expand Down Expand Up @@ -654,7 +654,7 @@ func (c *DockerContainer) copyToContainer(ctx context.Context, fileContent func(
return err
}

err = c.provider.client.CopyToContainer(ctx, c.ID, "/", buffer, types.CopyToContainerOptions{})
err = c.provider.client.CopyToContainer(ctx, c.ID, "/", buffer, container.CopyToContainerOptions{})
if err != nil {
return err
}
Expand Down Expand Up @@ -742,57 +742,59 @@ func (c *DockerContainer) startLogProduction(ctx context.Context, opts ...LogPro
c.logProductionError <- r.Close()
return
default:
h := make([]byte, 8)
_, err := io.ReadFull(r, h)
if err != nil {
// proper type matching requires https://go-review.googlesource.com/c/go/+/250357/ (go 1.16)
if strings.Contains(err.Error(), "use of closed network connection") {
now := time.Now()
since = fmt.Sprintf("%d.%09d", now.Unix(), int64(now.Nanosecond()))
goto BEGIN
}
if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) {
// Probably safe to continue here
continue
}
}
h := make([]byte, 8)
_, err := io.ReadFull(r, h)
if err != nil {
switch {
case err == io.EOF:
// No more logs coming
case errors.Is(err, net.ErrClosed):
now := time.Now()
since = fmt.Sprintf("%d.%09d", now.Unix(), int64(now.Nanosecond()))
goto BEGIN
case errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled):
// Probably safe to continue here
continue
default:
_, _ = fmt.Fprintf(os.Stderr, "container log error: %+v. %s", err, logStoppedForOutOfSyncMessage)
// if we would continue here, the next header-read will result into random data...
return
}
return
}

count := binary.BigEndian.Uint32(h[4:])
if count == 0 {
continue
}
logType := h[0]
if logType > 2 {
_, _ = fmt.Fprintf(os.Stderr, "received invalid log type: %d", logType)
// sometimes docker returns logType = 3 which is an undocumented log type, so treat it as stdout
logType = 1
}
count := binary.BigEndian.Uint32(h[4:])
if count == 0 {
continue
}
logType := h[0]
if logType > 2 {
_, _ = fmt.Fprintf(os.Stderr, "received invalid log type: %d", logType)
// sometimes docker returns logType = 3 which is an undocumented log type, so treat it as stdout
logType = 1
}

// a map of the log type --> int representation in the header, notice the first is blank, this is stdin, but the go docker client doesn't allow following that in logs
logTypes := []string{"", StdoutLog, StderrLog}
// a map of the log type --> int representation in the header, notice the first is blank, this is stdin, but the go docker client doesn't allow following that in logs
logTypes := []string{"", StdoutLog, StderrLog}

b := make([]byte, count)
_, err = io.ReadFull(r, b)
if err != nil {
// TODO: add-logger: use logger to log out this error
_, _ = fmt.Fprintf(os.Stderr, "error occurred reading log with known length %s", err.Error())
if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) {
// Probably safe to continue here
continue
}
// we can not continue here as the next read most likely will not be the next header
_, _ = fmt.Fprintln(os.Stderr, logStoppedForOutOfSyncMessage)
return
}
for _, c := range c.consumers {
c.Accept(Log{
LogType: logTypes[logType],
Content: b,
})
b := make([]byte, count)
_, err = io.ReadFull(r, b)
if err != nil {
// TODO: add-logger: use logger to log out this error
_, _ = fmt.Fprintf(os.Stderr, "error occurred reading log with known length %s", err.Error())
if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) {
// Probably safe to continue here
continue
}
// we can not continue here as the next read most likely will not be the next header
_, _ = fmt.Fprintln(os.Stderr, logStoppedForOutOfSyncMessage)
return
}
for _, c := range c.consumers {
c.Accept(Log{
LogType: logTypes[logType],
Content: b,
})
}
}
}()
Expand Down Expand Up @@ -881,6 +883,9 @@ var _ ContainerProvider = (*DockerProvider)(nil)
// BuildImage will build and image from context and Dockerfile, then return the tag
func (p *DockerProvider) BuildImage(ctx context.Context, img ImageBuildInfo) (string, error) {
buildOptions, err := img.BuildOptions()
if err != nil {
return "", err
}

var buildError error
var resp types.ImageBuildResponse
Expand Down Expand Up @@ -912,8 +917,7 @@ func (p *DockerProvider) BuildImage(ctx context.Context, img ImageBuildInfo) (st

// need to read the response from Docker, I think otherwise the image
// might not finish building before continuing to execute here
buf := new(bytes.Buffer)
_, err = buf.ReadFrom(resp.Body)
_, err = io.Copy(io.Discard, resp.Body)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -1337,7 +1341,7 @@ func (p *DockerProvider) Config() TestcontainersConfig {

// DaemonHost gets the host or ip of the Docker daemon where ports are exposed on
// Warning: this is based on your Docker host setting. Will fail if using an SSH tunnel
// You can use the "TC_HOST" env variable to set this yourself
// You can use the "TESTCONTAINERS_HOST_OVERRIDE" env variable to set this yourself
func (p *DockerProvider) DaemonHost(ctx context.Context) (string, error) {
return daemonHost(ctx, p)
}
Expand All @@ -1347,7 +1351,7 @@ func daemonHost(ctx context.Context, p *DockerProvider) (string, error) {
return p.hostCache, nil
}

host, exists := os.LookupEnv("TC_HOST")
host, exists := os.LookupEnv("TESTCONTAINERS_HOST_OVERRIDE")
if exists {
p.hostCache = host
return p.hostCache, nil
Expand Down Expand Up @@ -1405,7 +1409,7 @@ func (p *DockerProvider) CreateNetwork(ctx context.Context, req NetworkRequest)

tcConfig := p.Config().Config

nc := types.NetworkCreate{
nc := network.CreateOptions{
Driver: req.Driver,
Internal: req.Internal,
EnableIPv6: req.EnableIPv6,
Expand Down Expand Up @@ -1460,12 +1464,12 @@ func (p *DockerProvider) CreateNetwork(ctx context.Context, req NetworkRequest)
}

// GetNetwork returns the object representing the network identified by its name
func (p *DockerProvider) GetNetwork(ctx context.Context, req NetworkRequest) (types.NetworkResource, error) {
networkResource, err := p.client.NetworkInspect(ctx, req.Name, types.NetworkInspectOptions{
func (p *DockerProvider) GetNetwork(ctx context.Context, req NetworkRequest) (network.Inspect, error) {
networkResource, err := p.client.NetworkInspect(ctx, req.Name, network.InspectOptions{
Verbose: true,
})
if err != nil {
return types.NetworkResource{}, err
return network.Inspect{}, err
}

return networkResource, err
Expand Down Expand Up @@ -1501,7 +1505,7 @@ func (p *DockerProvider) GetGatewayIP(ctx context.Context) (string, error) {

func (p *DockerProvider) getDefaultNetwork(ctx context.Context, cli client.APIClient) (string, error) {
// Get list of available networks
networkResources, err := cli.NetworkList(ctx, types.NetworkListOptions{})
networkResources, err := cli.NetworkList(ctx, network.ListOptions{})
if err != nil {
return "", err
}
Expand All @@ -1522,7 +1526,7 @@ func (p *DockerProvider) getDefaultNetwork(ctx context.Context, cli client.APICl

// Create a bridge network for the container communications
if !reaperNetworkExists {
_, err = cli.NetworkCreate(ctx, reaperNetwork, types.NetworkCreate{
_, err = cli.NetworkCreate(ctx, reaperNetwork, network.CreateOptions{
Driver: Bridge,
Attachable: true,
Labels: core.DefaultLabels(core.SessionID()),
Expand Down
2 changes: 1 addition & 1 deletion docker_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ var (
var _ client.SystemAPIClient = &DockerClient{}

// Events returns a channel to listen to events that happen to the docker daemon.
func (c *DockerClient) Events(ctx context.Context, options types.EventsOptions) (<-chan events.Message, <-chan error) {
func (c *DockerClient) Events(ctx context.Context, options events.ListOptions) (<-chan events.Message, <-chan error) {
return c.Client.Events(ctx, options)
}

Expand Down
3 changes: 1 addition & 2 deletions docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"github.com/docker/docker/api/types/strslice"
"github.com/docker/docker/client"
"github.com/docker/docker/errdefs"
"github.com/docker/go-units"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -1713,7 +1712,7 @@ func TestDockerContainerResources(t *testing.T) {

ctx := context.Background()

expected := []*units.Ulimit{
expected := []*container.Ulimit{
{
Name: "memlock",
Hard: -1,
Expand Down
2 changes: 1 addition & 1 deletion docs/features/networking.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ It is normally advisable to use `Host` and `MappedPort` together when constructi
<!--/codeinclude-->

!!! info
Setting the `TC_HOST` environment variable overrides the host of the docker daemon where the container port is exposed. For example, `TC_HOST=172.17.0.1`.
Setting the `TESTCONTAINERS_HOST_OVERRIDE` environment variable overrides the host of the docker daemon where the container port is exposed. For example, `TESTCONTAINERS_HOST_OVERRIDE=172.17.0.1`.

## Exposing host ports to the container

Expand Down
2 changes: 1 addition & 1 deletion docs/system_requirements/using_podman.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
_Testcontainers for Go_ supports the use of Podman (rootless or rootful) instead of Docker.

In most scenarios no special setup is required in _Testcontainers for Go_.
_Testcontainers for Go_ will automatically discover the socket based on the `DOCKER_HOST` or the `TC_HOST` environment variables.
_Testcontainers for Go_ will automatically discover the socket based on the `DOCKER_HOST` environment variables.
Alternatively you can configure the host with a `.testcontainers.properties` file.
The discovered Docker host is taken into account when starting a reaper container.
The discovered socket is used to detect the use of Podman.
Expand Down
4 changes: 2 additions & 2 deletions examples/nginx/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ require (
github.com/containerd/errdefs v0.1.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/cpuguy83/dockercfg v0.3.1 // indirect
github.com/distribution/reference v0.5.0 // indirect
github.com/docker/docker v26.1.4+incompatible // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/docker v27.0.2+incompatible // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
Expand Down
8 changes: 4 additions & 4 deletions examples/nginx/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v26.1.4+incompatible h1:vuTpXDuoga+Z38m1OZHzl7NKisKWaWlhjQk7IDPSLsU=
github.com/docker/docker v26.1.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v27.0.2+incompatible h1:mNhCtgXNV1fIRns102grG7rdzIsGGCq1OlOD0KunZos=
github.com/docker/docker v27.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
Expand Down
4 changes: 2 additions & 2 deletions examples/toxiproxy/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ require (
github.com/containerd/log v0.1.0 // indirect
github.com/cpuguy83/dockercfg v0.3.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/distribution/reference v0.5.0 // indirect
github.com/docker/docker v26.1.4+incompatible // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/docker v27.0.2+incompatible // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
Expand Down
8 changes: 4 additions & 4 deletions examples/toxiproxy/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v26.1.4+incompatible h1:vuTpXDuoga+Z38m1OZHzl7NKisKWaWlhjQk7IDPSLsU=
github.com/docker/docker v26.1.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v27.0.2+incompatible h1:mNhCtgXNV1fIRns102grG7rdzIsGGCq1OlOD0KunZos=
github.com/docker/docker v27.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
Expand Down
6 changes: 3 additions & 3 deletions exec/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import (
"bytes"
"io"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/stdcopy"
)

// ProcessOptions defines options applicable to the reader processor
type ProcessOptions struct {
ExecConfig types.ExecConfig
ExecConfig container.ExecOptions
Reader io.Reader
}

Expand All @@ -21,7 +21,7 @@ type ProcessOptions struct {
// - attach stderr: true
func NewProcessOptions(cmd []string) *ProcessOptions {
return &ProcessOptions{
ExecConfig: types.ExecConfig{
ExecConfig: container.ExecOptions{
Cmd: cmd,
Detach: false,
AttachStdout: true,
Expand Down
Loading

0 comments on commit 97b02f2

Please sign in to comment.