Clean vendor dependencies
This commit is contained in:
2
vendor/github.com/testcontainers/testcontainers-go/.gitignore
generated
vendored
2
vendor/github.com/testcontainers/testcontainers-go/.gitignore
generated
vendored
@ -1,2 +0,0 @@
|
||||
debug.test
|
||||
vendor
|
19
vendor/github.com/testcontainers/testcontainers-go/.travis.yml
generated
vendored
19
vendor/github.com/testcontainers/testcontainers-go/.travis.yml
generated
vendored
@ -1,19 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.11.4
|
||||
|
||||
install: true
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
|
||||
script:
|
||||
- go mod verify
|
||||
- go mod tidy
|
||||
- go fmt ./...
|
||||
- go vet ./...
|
||||
- go test ./...
|
||||
|
21
vendor/github.com/testcontainers/testcontainers-go/LICENSE
generated
vendored
21
vendor/github.com/testcontainers/testcontainers-go/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017-2019 Gianluca Arbezzano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
118
vendor/github.com/testcontainers/testcontainers-go/README.md
generated
vendored
118
vendor/github.com/testcontainers/testcontainers-go/README.md
generated
vendored
@ -1,118 +0,0 @@
|
||||
[](https://travis-ci.org/testcontainers/testcontainers-go)
|
||||
|
||||
When I was working on a Zipkin PR I discovered a nice Java library called
|
||||
[testcontainers](https://www.testcontainers.org/).
|
||||
|
||||
It provides an easy and clean API over the go docker sdk to run, terminate and
|
||||
connect to containers in your tests.
|
||||
|
||||
I found myself comfortable programmatically writing the containers I need to run
|
||||
an integration/smoke tests. So I started porting this library in Go.
|
||||
|
||||
|
||||
This is the API I have defined:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
)
|
||||
|
||||
func TestNginxLatestReturn(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
req := testcontainers.ContainerRequest{
|
||||
Image: "nginx",
|
||||
ExposedPorts: []string{"80/tcp"},
|
||||
WaitingFor: wait.ForHTTP("/"),
|
||||
}
|
||||
nginxC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: req,
|
||||
Started: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer nginxC.Terminate(ctx)
|
||||
ip, err := nginxC.Host(ctx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
port, err := nginxC.MappedPort(ctx, "80")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
resp, err := http.Get(fmt.Sprintf("http://%s:%s", ip, port.Port()))
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Errorf("Expected status code %d. Got %d.", http.StatusOK, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
```
|
||||
This is a simple example, you can create one container in my case using the
|
||||
`nginx` image. You can get its IP `ip, err := nginxC.GetContainerIpAddress(ctx)` and you
|
||||
can use it to make a GET: `resp, err := http.Get(fmt.Sprintf("http://%s", ip))`
|
||||
|
||||
To clean your environment you can defer the container termination `defer
|
||||
nginxC.Terminate(ctx, t)`. `t` is `*testing.T` and it is used to notify is the
|
||||
`defer` failed marking the test as failed.
|
||||
|
||||
|
||||
## Build from Dockerfile
|
||||
|
||||
Testcontainers-go gives you the ability to build and image and run a container from a Dockerfile.
|
||||
|
||||
You can do so by specifiying a `Context` (the filepath to the build context on your local filesystem)
|
||||
and optionally a `Dockerfile` (defaults to "Dockerfile") like so:
|
||||
|
||||
```go
|
||||
req := ContainerRequest{
|
||||
FromDockerfile: testcontainers.FromDockerfile{
|
||||
Context: "/path/to/build/context",
|
||||
Dockerfile: "CustomDockerfile",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Dynamic Build Context
|
||||
|
||||
If you would like to send a build context that you created in code (maybe you have a dynamic Dockerfile), you can
|
||||
send the build context as an `io.Reader` since the Docker Daemon accepts is as a tar file, you can use the [tar](https://golang.org/pkg/archive/tar/) package to create your context.
|
||||
|
||||
|
||||
To do this you would use the `ContextArchive` attribute in the `FromDockerfile` struct.
|
||||
|
||||
```go
|
||||
var buf bytes.Buffer
|
||||
tarWriter := tar.NewWriter(&buf)
|
||||
// ... add some files
|
||||
if err := tarWriter.Close(); err != nil {
|
||||
// do something with err
|
||||
}
|
||||
reader := bytes.NewReader(buf.Bytes())
|
||||
fromDockerfile := testcontainers.FromDockerfile{
|
||||
ContextArchive: reader,
|
||||
}
|
||||
```
|
||||
|
||||
**Please Note** if you specify a `ContextArchive` this will cause testcontainers to ignore the path passed
|
||||
in to `Context`
|
||||
|
||||
## Sending a CMD to a Container
|
||||
|
||||
If you would like to send a CMD (command) to a container, you can pass it in to the container request via the `Cmd` field...
|
||||
|
||||
```go
|
||||
req := ContainerRequest{
|
||||
Image: "alpine",
|
||||
WaitingFor: wait.ForAll(
|
||||
wait.ForLog("command override!"),
|
||||
),
|
||||
Cmd: []string{"echo", "command override!"},
|
||||
}
|
||||
```
|
162
vendor/github.com/testcontainers/testcontainers-go/container.go
generated
vendored
162
vendor/github.com/testcontainers/testcontainers-go/container.go
generated
vendored
@ -1,162 +0,0 @@
|
||||
package testcontainers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
)
|
||||
|
||||
// DeprecatedContainer shows methods that were supported before, but are now deprecated
|
||||
// Deprecated: Use Container
|
||||
type DeprecatedContainer interface {
|
||||
GetHostEndpoint(ctx context.Context, port string) (string, string, error)
|
||||
GetIPAddress(ctx context.Context) (string, error)
|
||||
LivenessCheckPorts(ctx context.Context) (nat.PortSet, error)
|
||||
Terminate(ctx context.Context) error
|
||||
}
|
||||
|
||||
// ContainerProvider allows the creation of containers on an arbitrary system
|
||||
type ContainerProvider interface {
|
||||
CreateContainer(context.Context, ContainerRequest) (Container, error) // create a container without starting it
|
||||
RunContainer(context.Context, ContainerRequest) (Container, error) // create a container and start it
|
||||
}
|
||||
|
||||
// Container allows getting info about and controlling a single container instance
|
||||
type Container interface {
|
||||
GetContainerID() string // get the container id from the provider
|
||||
Endpoint(context.Context, string) (string, error) // get proto://ip:port string for the first exposed port
|
||||
PortEndpoint(context.Context, nat.Port, string) (string, error) // get proto://ip:port string for the given exposed port
|
||||
Host(context.Context) (string, error) // get host where the container port is exposed
|
||||
MappedPort(context.Context, nat.Port) (nat.Port, error) // get externally mapped port for a container port
|
||||
Ports(context.Context) (nat.PortMap, error) // get all exposed ports
|
||||
SessionID() string // get session id
|
||||
Start(context.Context) error // start the container
|
||||
Terminate(context.Context) error // terminate the container
|
||||
Logs(context.Context) (io.ReadCloser, error) // Get logs of the container
|
||||
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
|
||||
type ImageBuildInfo interface {
|
||||
GetContext() (io.Reader, error) // the path to the build context
|
||||
GetDockerfile() string // the relative path to the Dockerfile, including the fileitself
|
||||
ShouldBuildImage() bool // return true if the image needs to be built
|
||||
}
|
||||
|
||||
// FromDockerfile represents the parameters needed to build an image from a Dockerfile
|
||||
// rather than using a pre-built one
|
||||
type FromDockerfile struct {
|
||||
Context string // the path to the context of of the docker build
|
||||
ContextArchive io.Reader // the tar archive file to send to docker that contains the build context
|
||||
Dockerfile string // the path from the context to the Dockerfile for the image, defaults to "Dockerfile"
|
||||
}
|
||||
|
||||
// ContainerRequest represents the parameters used to get a running container
|
||||
type ContainerRequest struct {
|
||||
FromDockerfile
|
||||
Image string
|
||||
Env map[string]string
|
||||
ExposedPorts []string // allow specifying protocol info
|
||||
Cmd []string
|
||||
Labels map[string]string
|
||||
BindMounts map[string]string
|
||||
RegistryCred string
|
||||
WaitingFor wait.Strategy
|
||||
Name string // for specifying container name
|
||||
Privileged bool // for starting privileged container
|
||||
Networks []string // for specifying network names
|
||||
NetworkAliases map[string][]string // for specifying network aliases
|
||||
SkipReaper bool // indicates whether we skip setting up a reaper for this
|
||||
}
|
||||
|
||||
// ProviderType is an enum for the possible providers
|
||||
type ProviderType int
|
||||
|
||||
// possible provider types
|
||||
const (
|
||||
ProviderDocker ProviderType = iota // Docker is default = 0
|
||||
)
|
||||
|
||||
// GetProvider provides the provider implementation for a certain type
|
||||
func (t ProviderType) GetProvider() (GenericProvider, error) {
|
||||
switch t {
|
||||
case ProviderDocker:
|
||||
provider, err := NewDockerProvider()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create Docker provider")
|
||||
}
|
||||
return provider, nil
|
||||
}
|
||||
return nil, errors.New("unknown provider")
|
||||
}
|
||||
|
||||
// Validate ensures that the ContainerRequest does not have invalid paramters configured to it
|
||||
// ex. make sure you are not specifying both an image as well as a context
|
||||
func (c *ContainerRequest) Validate() error {
|
||||
|
||||
validationMethods := []func() error{
|
||||
c.validateContextAndImage,
|
||||
c.validateContexOrImageIsSpecified,
|
||||
}
|
||||
|
||||
var err error
|
||||
for _, validationMethod := range validationMethods {
|
||||
err = validationMethod()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetContext retrieve the build context for the request
|
||||
func (c *ContainerRequest) GetContext() (io.Reader, error) {
|
||||
if c.ContextArchive != nil {
|
||||
return c.ContextArchive, nil
|
||||
}
|
||||
|
||||
buildContext, err := archive.TarWithOptions(c.Context, &archive.TarOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buildContext, nil
|
||||
}
|
||||
|
||||
// GetDockerfile returns the Dockerfile from the ContainerRequest, defaults to "Dockerfile"
|
||||
func (c *ContainerRequest) GetDockerfile() string {
|
||||
f := c.FromDockerfile.Dockerfile
|
||||
if f == "" {
|
||||
return "Dockerfile"
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (c *ContainerRequest) ShouldBuildImage() bool {
|
||||
return c.FromDockerfile.Context != "" || c.FromDockerfile.ContextArchive != nil
|
||||
}
|
||||
|
||||
func (c *ContainerRequest) validateContextAndImage() error {
|
||||
if c.FromDockerfile.Context != "" && c.Image != "" {
|
||||
return errors.New("you cannot specify both an Image and Context in a ContainerRequest")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ContainerRequest) validateContexOrImageIsSpecified() error {
|
||||
if c.FromDockerfile.Context == "" && c.FromDockerfile.ContextArchive == nil && c.Image == "" {
|
||||
return errors.New("you must specify either a build context or an image")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
612
vendor/github.com/testcontainers/testcontainers-go/docker.go
generated
vendored
612
vendor/github.com/testcontainers/testcontainers-go/docker.go
generated
vendored
@ -1,612 +0,0 @@
|
||||
package testcontainers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
)
|
||||
|
||||
// Implement interfaces
|
||||
var _ Container = (*DockerContainer)(nil)
|
||||
|
||||
// DockerContainer represents a container started using Docker
|
||||
type DockerContainer struct {
|
||||
// Container ID from Docker
|
||||
ID string
|
||||
WaitingFor wait.Strategy
|
||||
|
||||
// Cache to retrieve container infromation without re-fetching them from dockerd
|
||||
raw *types.ContainerJSON
|
||||
provider *DockerProvider
|
||||
sessionID uuid.UUID
|
||||
terminationSignal chan bool
|
||||
skipReaper bool
|
||||
}
|
||||
|
||||
func (c *DockerContainer) GetContainerID() string {
|
||||
return c.ID
|
||||
}
|
||||
|
||||
// Endpoint gets proto://host:port string for the first exposed port
|
||||
// Will returns just host:port if proto is ""
|
||||
func (c *DockerContainer) Endpoint(ctx context.Context, proto string) (string, error) {
|
||||
ports, err := c.Ports(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// get first port
|
||||
var firstPort nat.Port
|
||||
for p := range ports {
|
||||
firstPort = p
|
||||
break
|
||||
}
|
||||
|
||||
return c.PortEndpoint(ctx, firstPort, proto)
|
||||
}
|
||||
|
||||
// PortEndpoint gets proto://host:port string for the given exposed port
|
||||
// Will returns just host:port if proto is ""
|
||||
func (c *DockerContainer) PortEndpoint(ctx context.Context, port nat.Port, proto string) (string, error) {
|
||||
host, err := c.Host(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
outerPort, err := c.MappedPort(ctx, port)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
protoFull := ""
|
||||
if proto != "" {
|
||||
protoFull = fmt.Sprintf("%s://", proto)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s%s:%s", protoFull, host, outerPort.Port()), nil
|
||||
}
|
||||
|
||||
// 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
|
||||
func (c *DockerContainer) Host(ctx context.Context) (string, error) {
|
||||
host, err := c.provider.daemonHost()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return host, nil
|
||||
}
|
||||
|
||||
// MappedPort gets externally mapped port for a container port
|
||||
func (c *DockerContainer) MappedPort(ctx context.Context, port nat.Port) (nat.Port, error) {
|
||||
ports, err := c.Ports(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for k, p := range ports {
|
||||
if k.Port() != port.Port() {
|
||||
continue
|
||||
}
|
||||
if port.Proto() != "" && k.Proto() != port.Proto() {
|
||||
continue
|
||||
}
|
||||
return nat.NewPort(k.Proto(), p[0].HostPort)
|
||||
}
|
||||
|
||||
return "", errors.New("port not found")
|
||||
}
|
||||
|
||||
// Ports gets the exposed ports for the container.
|
||||
func (c *DockerContainer) Ports(ctx context.Context) (nat.PortMap, error) {
|
||||
inspect, err := c.inspectContainer(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return inspect.NetworkSettings.Ports, nil
|
||||
}
|
||||
|
||||
// SessionID gets the current session id
|
||||
func (c *DockerContainer) SessionID() string {
|
||||
return c.sessionID.String()
|
||||
}
|
||||
|
||||
// Start will start an already created container
|
||||
func (c *DockerContainer) Start(ctx context.Context) error {
|
||||
if err := c.provider.client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if a Wait Strategy has been specified, wait before returning
|
||||
if c.WaitingFor != nil {
|
||||
if err := c.WaitingFor.WaitUntilReady(ctx, c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Terminate is used to kill the container. It is usally triggered by as defer function.
|
||||
func (c *DockerContainer) Terminate(ctx context.Context) error {
|
||||
err := c.provider.client.ContainerRemove(ctx, c.GetContainerID(), types.ContainerRemoveOptions{
|
||||
RemoveVolumes: true,
|
||||
Force: true,
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
c.sessionID = uuid.UUID{}
|
||||
c.raw = nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *DockerContainer) inspectContainer(ctx context.Context) (*types.ContainerJSON, error) {
|
||||
if c.raw != nil {
|
||||
return c.raw, nil
|
||||
}
|
||||
inspect, err := c.provider.client.ContainerInspect(ctx, c.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.raw = &inspect
|
||||
|
||||
return c.raw, nil
|
||||
}
|
||||
|
||||
// Logs will fetch both STDOUT and STDERR from the current container. Returns a
|
||||
// ReadCloser and leaves it up to the caller to extract what it wants.
|
||||
func (c *DockerContainer) Logs(ctx context.Context) (io.ReadCloser, error) {
|
||||
options := types.ContainerLogsOptions{
|
||||
ShowStdout: true,
|
||||
ShowStderr: true,
|
||||
}
|
||||
return c.provider.client.ContainerLogs(ctx, c.ID, options)
|
||||
}
|
||||
|
||||
// Name gets the name of the container.
|
||||
func (c *DockerContainer) Name(ctx context.Context) (string, error) {
|
||||
inspect, err := c.inspectContainer(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return inspect.Name, nil
|
||||
}
|
||||
|
||||
// Networks gets the names of the networks the container is attached to.
|
||||
func (c *DockerContainer) Networks(ctx context.Context) ([]string, error) {
|
||||
inspect, err := c.inspectContainer(ctx)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
networks := inspect.NetworkSettings.Networks
|
||||
|
||||
n := []string{}
|
||||
|
||||
for k := range networks {
|
||||
n = append(n, k)
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// NetworkAliases gets the aliases of the container for the networks it is attached to.
|
||||
func (c *DockerContainer) NetworkAliases(ctx context.Context) (map[string][]string, error) {
|
||||
inspect, err := c.inspectContainer(ctx)
|
||||
if err != nil {
|
||||
return map[string][]string{}, err
|
||||
}
|
||||
|
||||
networks := inspect.NetworkSettings.Networks
|
||||
|
||||
a := map[string][]string{}
|
||||
|
||||
for k := range networks {
|
||||
a[k] = networks[k].Aliases
|
||||
}
|
||||
|
||||
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
|
||||
Driver string
|
||||
Name string
|
||||
provider *DockerProvider
|
||||
terminationSignal chan bool
|
||||
}
|
||||
|
||||
// Remove is used to remove the network. It is usually triggered by as defer function.
|
||||
func (n *DockerNetwork) Remove(_ context.Context) error {
|
||||
if n.terminationSignal != nil {
|
||||
n.terminationSignal <- true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DockerProvider implements the ContainerProvider interface
|
||||
type DockerProvider struct {
|
||||
client *client.Client
|
||||
hostCache string
|
||||
}
|
||||
|
||||
var _ ContainerProvider = (*DockerProvider)(nil)
|
||||
|
||||
// NewDockerProvider creates a Docker provider with the EnvClient
|
||||
func NewDockerProvider() (*DockerProvider, error) {
|
||||
client, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.NegotiateAPIVersion(context.Background())
|
||||
p := &DockerProvider{
|
||||
client: client,
|
||||
}
|
||||
return p, 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) {
|
||||
repo := uuid.NewV4()
|
||||
tag := uuid.NewV4()
|
||||
|
||||
repoTag := fmt.Sprintf("%s:%s", repo, tag)
|
||||
|
||||
buildContext, err := img.GetContext()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
buildOptions := types.ImageBuildOptions{
|
||||
Dockerfile: img.GetDockerfile(),
|
||||
Context: buildContext,
|
||||
Tags: []string{repoTag},
|
||||
}
|
||||
|
||||
resp, err := p.client.ImageBuild(ctx, buildContext, buildOptions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp.Body.Close()
|
||||
|
||||
return repoTag, nil
|
||||
}
|
||||
|
||||
// CreateContainer fulfills a request for a container without starting it
|
||||
func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerRequest) (Container, error) {
|
||||
exposedPortSet, exposedPortMap, err := nat.ParsePortSpecs(req.ExposedPorts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
env := []string{}
|
||||
for envKey, envVar := range req.Env {
|
||||
env = append(env, envKey+"="+envVar)
|
||||
}
|
||||
|
||||
if req.Labels == nil {
|
||||
req.Labels = make(map[string]string)
|
||||
}
|
||||
|
||||
sessionID := uuid.NewV4()
|
||||
|
||||
var termSignal chan bool
|
||||
if !req.SkipReaper {
|
||||
r, err := NewReaper(ctx, sessionID.String(), p)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "creating reaper failed")
|
||||
}
|
||||
termSignal, err = r.Connect()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "connecting to reaper failed")
|
||||
}
|
||||
for k, v := range r.Labels() {
|
||||
if _, ok := req.Labels[k]; !ok {
|
||||
req.Labels[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = req.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tag string
|
||||
if req.ShouldBuildImage() {
|
||||
tag, err = p.BuildImage(ctx, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
tag = req.Image
|
||||
_, _, err = p.client.ImageInspectWithRaw(ctx, tag)
|
||||
if err != nil {
|
||||
if client.IsErrNotFound(err) {
|
||||
pullOpt := types.ImagePullOptions{}
|
||||
if req.RegistryCred != "" {
|
||||
pullOpt.RegistryAuth = req.RegistryCred
|
||||
}
|
||||
var pull io.ReadCloser
|
||||
err := backoff.Retry(func() error {
|
||||
var err error
|
||||
pull, err = p.client.ImagePull(ctx, tag, pullOpt)
|
||||
return err
|
||||
}, backoff.NewExponentialBackOff())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer pull.Close()
|
||||
|
||||
// download of docker image finishes at EOF of the pull request
|
||||
_, err = ioutil.ReadAll(pull)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dockerInput := &container.Config{
|
||||
Image: tag,
|
||||
Env: env,
|
||||
ExposedPorts: exposedPortSet,
|
||||
Labels: req.Labels,
|
||||
Cmd: req.Cmd,
|
||||
}
|
||||
|
||||
// prepare mounts
|
||||
bindMounts := []mount.Mount{}
|
||||
for hostPath, innerPath := range req.BindMounts {
|
||||
bindMounts = append(bindMounts, mount.Mount{
|
||||
Type: mount.TypeBind,
|
||||
Source: hostPath,
|
||||
Target: innerPath,
|
||||
})
|
||||
}
|
||||
|
||||
hostConfig := &container.HostConfig{
|
||||
PortBindings: exposedPortMap,
|
||||
Mounts: bindMounts,
|
||||
AutoRemove: true,
|
||||
Privileged: req.Privileged,
|
||||
}
|
||||
|
||||
endpointConfigs := map[string]*network.EndpointSettings{}
|
||||
for _, n := range req.Networks {
|
||||
nw, err := p.GetNetwork(ctx, NetworkRequest{
|
||||
Name: n,
|
||||
})
|
||||
if err == nil {
|
||||
endpointSetting := network.EndpointSettings{
|
||||
Aliases: req.NetworkAliases[n],
|
||||
NetworkID: nw.ID,
|
||||
}
|
||||
endpointConfigs[n] = &endpointSetting
|
||||
}
|
||||
}
|
||||
networkingConfig := network.NetworkingConfig{
|
||||
EndpointsConfig: endpointConfigs,
|
||||
}
|
||||
|
||||
resp, err := p.client.ContainerCreate(ctx, dockerInput, hostConfig, &networkingConfig, req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &DockerContainer{
|
||||
ID: resp.ID,
|
||||
WaitingFor: req.WaitingFor,
|
||||
sessionID: sessionID,
|
||||
provider: p,
|
||||
terminationSignal: termSignal,
|
||||
skipReaper: req.SkipReaper,
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// RunContainer takes a RequestContainer as input and it runs a container via the docker sdk
|
||||
func (p *DockerProvider) RunContainer(ctx context.Context, req ContainerRequest) (Container, error) {
|
||||
c, err := p.CreateContainer(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := c.Start(ctx); err != nil {
|
||||
return c, errors.Wrap(err, "could not start container")
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
func (p *DockerProvider) daemonHost() (string, error) {
|
||||
if p.hostCache != "" {
|
||||
return p.hostCache, nil
|
||||
}
|
||||
|
||||
host, exists := os.LookupEnv("TC_HOST")
|
||||
if exists {
|
||||
p.hostCache = host
|
||||
return p.hostCache, nil
|
||||
}
|
||||
|
||||
// infer from Docker host
|
||||
url, err := url.Parse(p.client.DaemonHost())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
switch url.Scheme {
|
||||
case "http", "https", "tcp":
|
||||
p.hostCache = url.Hostname()
|
||||
case "unix", "npipe":
|
||||
if inAContainer() {
|
||||
ip, err := getGatewayIp()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
p.hostCache = ip
|
||||
} else {
|
||||
p.hostCache = "localhost"
|
||||
}
|
||||
default:
|
||||
return "", errors.New("Could not determine host through env or docker host")
|
||||
}
|
||||
|
||||
return p.hostCache, nil
|
||||
}
|
||||
|
||||
// CreateNetwork returns the object representing a new network identified by its name
|
||||
func (p *DockerProvider) CreateNetwork(ctx context.Context, req NetworkRequest) (Network, error) {
|
||||
if req.Labels == nil {
|
||||
req.Labels = make(map[string]string)
|
||||
}
|
||||
|
||||
nc := types.NetworkCreate{
|
||||
Driver: req.Driver,
|
||||
CheckDuplicate: req.CheckDuplicate,
|
||||
Internal: req.Internal,
|
||||
EnableIPv6: req.EnableIPv6,
|
||||
Attachable: req.Attachable,
|
||||
Labels: req.Labels,
|
||||
}
|
||||
|
||||
sessionID := uuid.NewV4()
|
||||
|
||||
var termSignal chan bool
|
||||
if !req.SkipReaper {
|
||||
r, err := NewReaper(ctx, sessionID.String(), p)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "creating network reaper failed")
|
||||
}
|
||||
termSignal, err = r.Connect()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "connecting to network reaper failed")
|
||||
}
|
||||
for k, v := range r.Labels() {
|
||||
if _, ok := req.Labels[k]; !ok {
|
||||
req.Labels[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response, err := p.client.NetworkCreate(ctx, req.Name, nc)
|
||||
if err != nil {
|
||||
return &DockerNetwork{}, err
|
||||
}
|
||||
|
||||
n := &DockerNetwork{
|
||||
ID: response.ID,
|
||||
Driver: req.Driver,
|
||||
Name: req.Name,
|
||||
terminationSignal: termSignal,
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// 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{
|
||||
Verbose: true,
|
||||
})
|
||||
if err != nil {
|
||||
return types.NetworkResource{}, err
|
||||
}
|
||||
|
||||
return networkResource, err
|
||||
}
|
||||
|
||||
func inAContainer() bool {
|
||||
// see https://github.com/testcontainers/testcontainers-java/blob/3ad8d80e2484864e554744a4800a81f6b7982168/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java#L15
|
||||
if _, err := os.Stat("/.dockerenv"); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getGatewayIp() (string, error) {
|
||||
// see https://github.com/testcontainers/testcontainers-java/blob/3ad8d80e2484864e554744a4800a81f6b7982168/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java#L27
|
||||
cmd := exec.Command("sh", "-c", "ip route|awk '/default/ { print $3 }'")
|
||||
stdout, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", errors.New("Failed to detect docker host")
|
||||
}
|
||||
ip := strings.TrimSpace(string(stdout))
|
||||
if len(ip) == 0 {
|
||||
return "", errors.New("Failed to parse default gateway IP")
|
||||
}
|
||||
return string(ip), nil
|
||||
}
|
41
vendor/github.com/testcontainers/testcontainers-go/generic.go
generated
vendored
41
vendor/github.com/testcontainers/testcontainers-go/generic.go
generated
vendored
@ -1,41 +0,0 @@
|
||||
package testcontainers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// GenericContainerRequest represents parameters to a generic container
|
||||
type GenericContainerRequest struct {
|
||||
ContainerRequest // embedded request for provider
|
||||
Started bool // whether to auto-start the container
|
||||
ProviderType ProviderType // which provider to use, Docker if empty
|
||||
}
|
||||
|
||||
// GenericContainer creates a generic container with parameters
|
||||
func GenericContainer(ctx context.Context, req GenericContainerRequest) (Container, error) {
|
||||
provider, err := req.ProviderType.GetProvider()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, err := provider.CreateContainer(ctx, req.ContainerRequest)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create container")
|
||||
}
|
||||
|
||||
if req.Started {
|
||||
if err := c.Start(ctx); err != nil {
|
||||
return c, errors.Wrap(err, "failed to start container")
|
||||
}
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// GenericProvider represents an abstraction for container and network providers
|
||||
type GenericProvider interface {
|
||||
ContainerProvider
|
||||
NetworkProvider
|
||||
}
|
36
vendor/github.com/testcontainers/testcontainers-go/go.mod
generated
vendored
36
vendor/github.com/testcontainers/testcontainers-go/go.mod
generated
vendored
@ -1,36 +0,0 @@
|
||||
module github.com/testcontainers/testcontainers-go
|
||||
|
||||
replace github.com/docker/docker => github.com/docker/engine v0.0.0-20190717161051-705d9623b7c1
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
|
||||
github.com/Microsoft/go-winio v0.4.11 // indirect
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible // indirect
|
||||
github.com/docker/docker v0.7.3-0.20190506211059-b20a14b54661
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/docker/go-units v0.3.3 // indirect
|
||||
github.com/go-redis/redis v6.15.6+incompatible
|
||||
github.com/go-sql-driver/mysql v1.4.1
|
||||
github.com/gogo/protobuf v1.2.0 // indirect
|
||||
github.com/gorilla/context v1.1.1 // indirect
|
||||
github.com/gorilla/mux v1.6.2 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
|
||||
github.com/onsi/ginkgo v1.8.0 // indirect
|
||||
github.com/onsi/gomega v1.5.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/opencontainers/runc v0.1.1 // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/sirupsen/logrus v1.2.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb // indirect
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c // indirect
|
||||
google.golang.org/grpc v1.17.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
gotest.tools v0.0.0-20181223230014-1083505acf35 // indirect
|
||||
)
|
||||
|
||||
go 1.13
|
109
vendor/github.com/testcontainers/testcontainers-go/go.sum
generated
vendored
109
vendor/github.com/testcontainers/testcontainers-go/go.sum
generated
vendored
@ -1,109 +0,0 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
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/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible h1:dvc1KSkIYTVjZgHf/CTC2diTYC8PzhaA5sFISRfNVrE=
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/engine v0.0.0-20190717161051-705d9623b7c1 h1:pKV3lCoWunXtXfyRUcqYflvdaiFU3BMxHw5izMsYDhY=
|
||||
github.com/docker/engine v0.0.0-20190717161051-705d9623b7c1/go.mod h1:3CPr2caMgTHxxIAZgEMd3uLYPDlRvPqCpyeRf6ncPcY=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4=
|
||||
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-redis/redis v6.15.5+incompatible h1:pLky8I0rgiblWfa8C1EV7fPEUv0aH6vKRaYHc/YRHVk=
|
||||
github.com/go-redis/redis v6.15.5+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-redis/redis v6.15.6+incompatible h1:H9evprGPLI8+ci7fxQx6WNZHJSb7be8FqJQRhdQZ5Sg=
|
||||
github.com/go-redis/redis v6.15.6+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE=
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=
|
||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb h1:pf3XwC90UUdNPYWZdFjhGBE7DUFuK3Ct1zWmZ65QN30=
|
||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180810170437-e96c4e24768d/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.17.0 h1:TRJYBgMclJvGYn2rIMjj+h9KtMt5r1Ij7ODVRIZkwhk=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gotest.tools v0.0.0-20181223230014-1083505acf35 h1:zpdCK+REwbk+rqjJmHhiCN6iBIigrZ39glqSF0P3KF0=
|
||||
gotest.tools v0.0.0-20181223230014-1083505acf35/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
31
vendor/github.com/testcontainers/testcontainers-go/network.go
generated
vendored
31
vendor/github.com/testcontainers/testcontainers-go/network.go
generated
vendored
@ -1,31 +0,0 @@
|
||||
package testcontainers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
// NetworkProvider allows the creation of networks on an arbitrary system
|
||||
type NetworkProvider interface {
|
||||
CreateNetwork(context.Context, NetworkRequest) (Network, error) // create a network
|
||||
GetNetwork(context.Context, NetworkRequest) (types.NetworkResource, error) // get a network
|
||||
}
|
||||
|
||||
// Network allows getting info about a single network instance
|
||||
type Network interface {
|
||||
Remove(context.Context) error // removes the network
|
||||
}
|
||||
|
||||
// NetworkRequest represents the parameters used to get a network
|
||||
type NetworkRequest struct {
|
||||
Driver string
|
||||
CheckDuplicate bool
|
||||
Internal bool
|
||||
EnableIPv6 bool
|
||||
Name string
|
||||
Labels map[string]string
|
||||
Attachable bool
|
||||
|
||||
SkipReaper bool // indicates whether we skip setting up a reaper for this
|
||||
}
|
118
vendor/github.com/testcontainers/testcontainers-go/reaper.go
generated
vendored
118
vendor/github.com/testcontainers/testcontainers-go/reaper.go
generated
vendored
@ -1,118 +0,0 @@
|
||||
package testcontainers
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// TestcontainerLabel is used as a base for docker labels
|
||||
const (
|
||||
TestcontainerLabel = "org.testcontainers.golang"
|
||||
TestcontainerLabelSessionID = TestcontainerLabel + ".sessionId"
|
||||
TestcontainerLabelIsReaper = TestcontainerLabel + ".reaper"
|
||||
ReaperDefaultImage = "quay.io/testcontainers/ryuk:0.2.2"
|
||||
)
|
||||
|
||||
// ReaperProvider represents a provider for the reaper to run itself with
|
||||
// The ContainerProvider interface should usually satisfy this as well, so it is pluggable
|
||||
type ReaperProvider interface {
|
||||
RunContainer(ctx context.Context, req ContainerRequest) (Container, error)
|
||||
}
|
||||
|
||||
// Reaper is used to start a sidecar container that cleans up resources
|
||||
type Reaper struct {
|
||||
Provider ReaperProvider
|
||||
SessionID string
|
||||
Endpoint string
|
||||
}
|
||||
|
||||
// NewReaper creates a Reaper with a sessionID to identify containers and a provider to use
|
||||
func NewReaper(ctx context.Context, sessionID string, provider ReaperProvider) (*Reaper, error) {
|
||||
r := &Reaper{
|
||||
Provider: provider,
|
||||
SessionID: sessionID,
|
||||
}
|
||||
|
||||
// TODO: reuse reaper if there already is one
|
||||
|
||||
req := ContainerRequest{
|
||||
Image: ReaperDefaultImage,
|
||||
ExposedPorts: []string{"8080"},
|
||||
Labels: map[string]string{
|
||||
TestcontainerLabel: "true",
|
||||
TestcontainerLabelIsReaper: "true",
|
||||
},
|
||||
SkipReaper: true,
|
||||
BindMounts: map[string]string{
|
||||
"/var/run/docker.sock": "/var/run/docker.sock",
|
||||
},
|
||||
}
|
||||
|
||||
c, err := provider.RunContainer(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
endpoint, err := c.PortEndpoint(ctx, "8080", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.Endpoint = endpoint
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Connect runs a goroutine which can be terminated by sending true into the returned channel
|
||||
func (r *Reaper) Connect() (chan bool, error) {
|
||||
conn, err := net.DialTimeout("tcp", r.Endpoint, 10*time.Second)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Connecting to Ryuk on "+r.Endpoint+" failed")
|
||||
}
|
||||
|
||||
terminationSignal := make(chan bool)
|
||||
go func(conn net.Conn) {
|
||||
sock := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
|
||||
defer conn.Close()
|
||||
|
||||
labelFilters := []string{}
|
||||
for l, v := range r.Labels() {
|
||||
labelFilters = append(labelFilters, fmt.Sprintf("label=%s=%s", l, v))
|
||||
}
|
||||
|
||||
retryLimit := 3
|
||||
for retryLimit > 0 {
|
||||
retryLimit--
|
||||
|
||||
sock.WriteString(strings.Join(labelFilters, "&"))
|
||||
sock.WriteString("\n")
|
||||
if err := sock.Flush(); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
resp, err := sock.ReadString('\n')
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if resp == "ACK\n" {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
<-terminationSignal
|
||||
}(conn)
|
||||
return terminationSignal, nil
|
||||
}
|
||||
|
||||
// Labels returns the container labels to use so that this Reaper cleans them up
|
||||
func (r *Reaper) Labels() map[string]string {
|
||||
return map[string]string{
|
||||
TestcontainerLabel: "true",
|
||||
TestcontainerLabelSessionID: r.SessionID,
|
||||
}
|
||||
}
|
112
vendor/github.com/testcontainers/testcontainers-go/wait/host_port.go
generated
vendored
112
vendor/github.com/testcontainers/testcontainers-go/wait/host_port.go
generated
vendored
@ -1,112 +0,0 @@
|
||||
package wait
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-connections/nat"
|
||||
)
|
||||
|
||||
// Implement interface
|
||||
var _ Strategy = (*HostPortStrategy)(nil)
|
||||
|
||||
type HostPortStrategy struct {
|
||||
Port nat.Port
|
||||
// all WaitStrategies should have a startupTimeout to avoid waiting infinitely
|
||||
startupTimeout time.Duration
|
||||
}
|
||||
|
||||
// NewHostPortStrategy constructs a default host port strategy
|
||||
func NewHostPortStrategy(port nat.Port) *HostPortStrategy {
|
||||
return &HostPortStrategy{
|
||||
Port: port,
|
||||
startupTimeout: defaultStartupTimeout(),
|
||||
}
|
||||
}
|
||||
|
||||
// fluent builders for each property
|
||||
// since go has neither covariance nor generics, the return type must be the type of the concrete implementation
|
||||
// this is true for all properties, even the "shared" ones like startupTimeout
|
||||
|
||||
// ForListeningPort is a helper similar to those in Wait.java
|
||||
// https://github.com/testcontainers/testcontainers-java/blob/1d85a3834bd937f80aad3a4cec249c027f31aeb4/core/src/main/java/org/testcontainers/containers/wait/strategy/Wait.java
|
||||
func ForListeningPort(port nat.Port) *HostPortStrategy {
|
||||
return NewHostPortStrategy(port)
|
||||
}
|
||||
|
||||
func (hp *HostPortStrategy) WithStartupTimeout(startupTimeout time.Duration) *HostPortStrategy {
|
||||
hp.startupTimeout = startupTimeout
|
||||
return hp
|
||||
}
|
||||
|
||||
// WaitUntilReady implements Strategy.WaitUntilReady
|
||||
func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) (err error) {
|
||||
// limit context to startupTimeout
|
||||
ctx, cancelContext := context.WithTimeout(ctx, hp.startupTimeout)
|
||||
defer cancelContext()
|
||||
|
||||
ipAddress, err := target.Host(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
port, err := target.MappedPort(ctx, hp.Port)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
proto := port.Proto()
|
||||
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)
|
||||
defer conn.Close()
|
||||
if err != nil {
|
||||
if v, ok := err.(*net.OpError); ok {
|
||||
if v2, ok := (v.Err).(*os.SyscallError); ok {
|
||||
if v2.Err == syscall.ECONNREFUSED {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
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)
|
||||
}
|
147
vendor/github.com/testcontainers/testcontainers-go/wait/http.go
generated
vendored
147
vendor/github.com/testcontainers/testcontainers-go/wait/http.go
generated
vendored
@ -1,147 +0,0 @@
|
||||
package wait
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-connections/nat"
|
||||
)
|
||||
|
||||
// Implement interface
|
||||
var _ Strategy = (*HTTPStrategy)(nil)
|
||||
|
||||
type HTTPStrategy struct {
|
||||
// all Strategies should have a startupTimeout to avoid waiting infinitely
|
||||
startupTimeout time.Duration
|
||||
|
||||
// additional properties
|
||||
Port nat.Port
|
||||
Path string
|
||||
StatusCodeMatcher func(status int) bool
|
||||
UseTLS bool
|
||||
AllowInsecure bool
|
||||
}
|
||||
|
||||
// NewHTTPStrategy constructs a HTTP strategy waiting on port 80 and status code 200
|
||||
func NewHTTPStrategy(path string) *HTTPStrategy {
|
||||
return &HTTPStrategy{
|
||||
startupTimeout: defaultStartupTimeout(),
|
||||
Port: "80/tcp",
|
||||
Path: path,
|
||||
StatusCodeMatcher: defaultStatusCodeMatcher,
|
||||
UseTLS: false,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func defaultStatusCodeMatcher(status int) bool {
|
||||
return status == http.StatusOK
|
||||
}
|
||||
|
||||
// fluent builders for each property
|
||||
// since go has neither covariance nor generics, the return type must be the type of the concrete implementation
|
||||
// this is true for all properties, even the "shared" ones like startupTimeout
|
||||
|
||||
func (ws *HTTPStrategy) WithStartupTimeout(startupTimeout time.Duration) *HTTPStrategy {
|
||||
ws.startupTimeout = startupTimeout
|
||||
return ws
|
||||
}
|
||||
|
||||
func (ws *HTTPStrategy) WithPort(port nat.Port) *HTTPStrategy {
|
||||
ws.Port = port
|
||||
return ws
|
||||
}
|
||||
|
||||
func (ws *HTTPStrategy) WithStatusCodeMatcher(statusCodeMatcher func(status int) bool) *HTTPStrategy {
|
||||
ws.StatusCodeMatcher = statusCodeMatcher
|
||||
return ws
|
||||
}
|
||||
|
||||
func (ws *HTTPStrategy) WithTLS(useTLS bool) *HTTPStrategy {
|
||||
ws.UseTLS = useTLS
|
||||
return ws
|
||||
}
|
||||
|
||||
func (ws *HTTPStrategy) WithAllowInsecure(allowInsecure bool) *HTTPStrategy {
|
||||
ws.AllowInsecure = allowInsecure
|
||||
return ws
|
||||
}
|
||||
|
||||
// ForHTTP is a convenience method similar to Wait.java
|
||||
// https://github.com/testcontainers/testcontainers-java/blob/1d85a3834bd937f80aad3a4cec249c027f31aeb4/core/src/main/java/org/testcontainers/containers/wait/strategy/Wait.java
|
||||
func ForHTTP(path string) *HTTPStrategy {
|
||||
return NewHTTPStrategy(path)
|
||||
}
|
||||
|
||||
// WaitUntilReady implements Strategy.WaitUntilReady
|
||||
func (ws *HTTPStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) (err error) {
|
||||
// limit context to startupTimeout
|
||||
ctx, cancelContext := context.WithTimeout(ctx, ws.startupTimeout)
|
||||
defer cancelContext()
|
||||
|
||||
ipAddress, err := target.Host(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
port, err := target.MappedPort(ctx, ws.Port)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if port.Proto() != "tcp" {
|
||||
return errors.New("Cannot use HTTP client on non-TCP ports")
|
||||
}
|
||||
|
||||
portNumber := port.Int()
|
||||
portString := strconv.Itoa(portNumber)
|
||||
|
||||
address := net.JoinHostPort(ipAddress, portString)
|
||||
|
||||
var proto string
|
||||
if ws.UseTLS {
|
||||
proto = "https"
|
||||
} else {
|
||||
proto = "http"
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s://%s%s", proto, address, ws.Path)
|
||||
|
||||
tripper := http.DefaultTransport
|
||||
|
||||
if ws.AllowInsecure {
|
||||
tripper.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
}
|
||||
|
||||
client := http.Client{Timeout: ws.startupTimeout, Transport: tripper}
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
Retry:
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
break Retry
|
||||
default:
|
||||
resp, err := client.Do(req)
|
||||
if err != nil || !ws.StatusCodeMatcher(resp.StatusCode) {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
break Retry
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
104
vendor/github.com/testcontainers/testcontainers-go/wait/log.go
generated
vendored
104
vendor/github.com/testcontainers/testcontainers-go/wait/log.go
generated
vendored
@ -1,104 +0,0 @@
|
||||
package wait
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Implement interface
|
||||
var _ Strategy = (*LogStrategy)(nil)
|
||||
|
||||
// LogStrategy will wait until a given log entry shows up in the docker logs
|
||||
type LogStrategy struct {
|
||||
// all Strategies should have a startupTimeout to avoid waiting infinitely
|
||||
startupTimeout time.Duration
|
||||
|
||||
// additional properties
|
||||
Log string
|
||||
PollInterval time.Duration
|
||||
Occurrence int
|
||||
}
|
||||
|
||||
// NewLogStrategy constructs a HTTP strategy waiting on port 80 and status code 200
|
||||
func NewLogStrategy(log string) *LogStrategy {
|
||||
return &LogStrategy{
|
||||
startupTimeout: defaultStartupTimeout(),
|
||||
Log: log,
|
||||
PollInterval: 100 * time.Millisecond,
|
||||
Occurrence: 1,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// fluent builders for each property
|
||||
// since go has neither covariance nor generics, the return type must be the type of the concrete implementation
|
||||
// this is true for all properties, even the "shared" ones like startupTimeout
|
||||
|
||||
// WithStartupTimeout can be used to change the default startup timeout
|
||||
func (ws *LogStrategy) WithStartupTimeout(startupTimeout time.Duration) *LogStrategy {
|
||||
ws.startupTimeout = startupTimeout
|
||||
return ws
|
||||
}
|
||||
|
||||
// WithPollInterval can be used to override the default polling interval of 100 milliseconds
|
||||
func (ws *LogStrategy) WithPollInterval(pollInterval time.Duration) *LogStrategy {
|
||||
ws.PollInterval = pollInterval
|
||||
return ws
|
||||
}
|
||||
|
||||
func (ws *LogStrategy) WithOccurrence(o int) *LogStrategy {
|
||||
// the number of occurence needs to be positive
|
||||
if o <= 0 {
|
||||
o = 1
|
||||
}
|
||||
ws.Occurrence = o
|
||||
return ws
|
||||
}
|
||||
|
||||
// ForLog is the default construction for the fluid interface.
|
||||
//
|
||||
// For Example:
|
||||
// wait.
|
||||
// ForLog("some text").
|
||||
// WithPollInterval(1 * time.Second)
|
||||
func ForLog(log string) *LogStrategy {
|
||||
return NewLogStrategy(log)
|
||||
}
|
||||
|
||||
// WaitUntilReady implements Strategy.WaitUntilReady
|
||||
func (ws *LogStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) (err error) {
|
||||
// limit context to startupTimeout
|
||||
ctx, cancelContext := context.WithTimeout(ctx, ws.startupTimeout)
|
||||
defer cancelContext()
|
||||
currentOccurence := 0
|
||||
|
||||
LOOP:
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
reader, err := target.Logs(ctx)
|
||||
|
||||
if err != nil {
|
||||
time.Sleep(ws.PollInterval)
|
||||
continue
|
||||
}
|
||||
b, err := ioutil.ReadAll(reader)
|
||||
logs := string(b)
|
||||
if strings.Contains(logs, ws.Log) {
|
||||
currentOccurence++
|
||||
if ws.Occurrence == 0 || currentOccurence >= ws.Occurrence-1 {
|
||||
break LOOP
|
||||
}
|
||||
} else {
|
||||
time.Sleep(ws.PollInterval)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
47
vendor/github.com/testcontainers/testcontainers-go/wait/multi.go
generated
vendored
47
vendor/github.com/testcontainers/testcontainers-go/wait/multi.go
generated
vendored
@ -1,47 +0,0 @@
|
||||
package wait
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Implement interface
|
||||
var _ Strategy = (*MultiStrategy)(nil)
|
||||
|
||||
type MultiStrategy struct {
|
||||
// all Strategies should have a startupTimeout to avoid waiting infinitely
|
||||
startupTimeout time.Duration
|
||||
|
||||
// additional properties
|
||||
Strategies []Strategy
|
||||
}
|
||||
|
||||
func (ms *MultiStrategy) WithStartupTimeout(startupTimeout time.Duration) *MultiStrategy {
|
||||
ms.startupTimeout = startupTimeout
|
||||
return ms
|
||||
}
|
||||
|
||||
func ForAll(strategies ...Strategy) *MultiStrategy {
|
||||
return &MultiStrategy{
|
||||
startupTimeout: defaultStartupTimeout(),
|
||||
Strategies: strategies,
|
||||
}
|
||||
}
|
||||
|
||||
func (ms *MultiStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) (err error) {
|
||||
ctx, cancelContext := context.WithTimeout(ctx, ms.startupTimeout)
|
||||
defer cancelContext()
|
||||
|
||||
if len(ms.Strategies) == 0 {
|
||||
return fmt.Errorf("no wait strategy supplied")
|
||||
}
|
||||
|
||||
for _, strategy := range ms.Strategies {
|
||||
err := strategy.WaitUntilReady(ctx, target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
24
vendor/github.com/testcontainers/testcontainers-go/wait/wait.go
generated
vendored
24
vendor/github.com/testcontainers/testcontainers-go/wait/wait.go
generated
vendored
@ -1,24 +0,0 @@
|
||||
package wait
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-connections/nat"
|
||||
)
|
||||
|
||||
type Strategy interface {
|
||||
WaitUntilReady(context.Context, StrategyTarget) error
|
||||
}
|
||||
|
||||
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 {
|
||||
return 60 * time.Second
|
||||
}
|
Reference in New Issue
Block a user