Skip to content

Commit

Permalink
Merge pull request #114 from nikolayk812/46-host-port-wait-strategy-i…
Browse files Browse the repository at this point in the history
…nside-container

#46 host port waiting strategy inside container
  • Loading branch information
gianarb committed Nov 20, 2019
2 parents d199160 + 26574fd commit cb2a3aa
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 2 deletions.
1 change: 1 addition & 0 deletions container.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type Container interface {
Name(context.Context) (string, error) // get container name
Networks(context.Context) ([]string, error) // get container networks
NetworkAliases(context.Context) (map[string][]string, error) // get container network aliases for a network
Exec(ctx context.Context, cmd []string) (int, error)
}

// ImageBuildInfo defines what is needed to build an image
Expand Down
36 changes: 36 additions & 0 deletions docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"os"
"os/exec"
"strings"
"time"

"github.com/cenkalti/backoff"
"github.com/docker/docker/api/types"
Expand Down Expand Up @@ -230,6 +231,41 @@ func (c *DockerContainer) NetworkAliases(ctx context.Context) (map[string][]stri
return a, nil
}

func (c *DockerContainer) Exec(ctx context.Context, cmd []string) (int, error) {
cli := c.provider.client
response, err := cli.ContainerExecCreate(ctx, c.ID, types.ExecConfig{
Cmd: cmd,
Detach: false,
})
if err != nil {
return 0, err
}

err = cli.ContainerExecStart(ctx, response.ID, types.ExecStartCheck{
Detach: false,
})
if err != nil {
return 0, err
}

var exitCode int
for {
execResp, err := cli.ContainerExecInspect(ctx, response.ID)
if err != nil {
return 0, err
}

if !execResp.Running {
exitCode = execResp.ExitCode
break
}

time.Sleep(100 * time.Millisecond)
}

return exitCode, nil
}

// DockerNetwork represents a network started using Docker
type DockerNetwork struct {
ID string // Network ID from Docker
Expand Down
1 change: 0 additions & 1 deletion docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,6 @@ func TestContainerCreationWithName(t *testing.T) {
}

func TestContainerCreationAndWaitForListeningPortLongEnough(t *testing.T) {
t.Skip("Wait needs to be fixed")
ctx := context.Background()

nginxPort := "80/tcp"
Expand Down
27 changes: 26 additions & 1 deletion wait/host_port.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package wait

import (
"context"
"fmt"
"github.com/pkg/errors"
"net"
"os"
"strconv"
Expand Down Expand Up @@ -63,8 +65,8 @@ func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyT
portNumber := port.Int()
portString := strconv.Itoa(portNumber)

//external check
dialer := net.Dialer{}

address := net.JoinHostPort(ipAddress, portString)
for {
conn, err := dialer.DialContext(ctx, proto, address)
Expand All @@ -83,5 +85,28 @@ func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyT
break
}

//internal check
command := buildInternalCheckCommand(hp.Port.Int())
for {
exitCode, err := target.Exec(ctx, []string{"/bin/bash", "-c", command})
if err != nil {
return errors.Wrapf(err, "host port waiting failed")
}

if exitCode == 0 {
break
}
}

return nil
}

func buildInternalCheckCommand(internalPort int) string {
command := `(
cat /proc/net/tcp{,6} | awk '{print $2}' | grep -i :%x ||
nc -vz -w 1 localhost %d ||
/bin/bash -c '</dev/tcp/localhost/%d'
)
`
return "true && " + fmt.Sprintf(command, internalPort, internalPort, internalPort)
}
4 changes: 4 additions & 0 deletions wait/log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ func (st noopStrategyTarget) Logs(ctx context.Context) (io.ReadCloser, error) {
return st.ioReaderCloser, nil
}

func (st noopStrategyTarget) Exec(ctx context.Context, cmd []string) (int, error) {
return 0, nil
}

func TestWaitForLog(t *testing.T) {
target := noopStrategyTarget{
ioReaderCloser: ioutil.NopCloser(bytes.NewReader([]byte("dude"))),
Expand Down
1 change: 1 addition & 0 deletions wait/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type StrategyTarget interface {
Host(context.Context) (string, error)
MappedPort(context.Context, nat.Port) (nat.Port, error)
Logs(context.Context) (io.ReadCloser, error)
Exec(ctx context.Context, cmd []string) (int, error)
}

func defaultStartupTimeout() time.Duration {
Expand Down

0 comments on commit cb2a3aa

Please sign in to comment.