summaryrefslogtreecommitdiff
path: root/vendor/github.com/testcontainers/testcontainers-go/provider.go
blob: d2347b7f3b30003982694414dd53596b38e964f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package testcontainers

import (
	"context"
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/testcontainers/testcontainers-go/internal/config"
	"github.com/testcontainers/testcontainers-go/internal/core"
	"github.com/testcontainers/testcontainers-go/log"
)

// possible provider types
const (
	ProviderDefault ProviderType = iota // default will auto-detect provider from DOCKER_HOST environment variable
	ProviderDocker
	ProviderPodman
)

type (
	// ProviderType is an enum for the possible providers
	ProviderType int

	// GenericProviderOptions defines options applicable to all providers
	GenericProviderOptions struct {
		Logger         log.Logger
		defaultNetwork string
	}

	// GenericProviderOption defines a common interface to modify GenericProviderOptions
	// These options can be passed to GetProvider in a variadic way to customize the returned GenericProvider instance
	GenericProviderOption interface {
		ApplyGenericTo(opts *GenericProviderOptions)
	}

	// GenericProviderOptionFunc is a shorthand to implement the GenericProviderOption interface
	GenericProviderOptionFunc func(opts *GenericProviderOptions)

	// DockerProviderOptions defines options applicable to DockerProvider
	DockerProviderOptions struct {
		defaultBridgeNetworkName string
		*GenericProviderOptions
	}

	// DockerProviderOption defines a common interface to modify DockerProviderOptions
	// These can be passed to NewDockerProvider in a variadic way to customize the returned DockerProvider instance
	DockerProviderOption interface {
		ApplyDockerTo(opts *DockerProviderOptions)
	}

	// DockerProviderOptionFunc is a shorthand to implement the DockerProviderOption interface
	DockerProviderOptionFunc func(opts *DockerProviderOptions)
)

func (f DockerProviderOptionFunc) ApplyDockerTo(opts *DockerProviderOptions) {
	f(opts)
}

func Generic2DockerOptions(opts ...GenericProviderOption) []DockerProviderOption {
	converted := make([]DockerProviderOption, 0, len(opts))
	for _, o := range opts {
		switch c := o.(type) {
		case DockerProviderOption:
			converted = append(converted, c)
		default:
			converted = append(converted, DockerProviderOptionFunc(func(opts *DockerProviderOptions) {
				o.ApplyGenericTo(opts.GenericProviderOptions)
			}))
		}
	}

	return converted
}

func WithDefaultBridgeNetwork(bridgeNetworkName string) DockerProviderOption {
	return DockerProviderOptionFunc(func(opts *DockerProviderOptions) {
		opts.defaultBridgeNetworkName = bridgeNetworkName
	})
}

func (f GenericProviderOptionFunc) ApplyGenericTo(opts *GenericProviderOptions) {
	f(opts)
}

// ContainerProvider allows the creation of containers on an arbitrary system
type ContainerProvider interface {
	Close() error                                                                // close the provider
	CreateContainer(context.Context, ContainerRequest) (Container, error)        // create a container without starting it
	ReuseOrCreateContainer(context.Context, ContainerRequest) (Container, error) // reuses a container if it exists or creates a container without starting
	RunContainer(context.Context, ContainerRequest) (Container, error)           // create a container and start it
	Health(context.Context) error
	Config() TestcontainersConfig
}

// GetProvider provides the provider implementation for a certain type
func (t ProviderType) GetProvider(opts ...GenericProviderOption) (GenericProvider, error) {
	opt := &GenericProviderOptions{
		Logger: log.Default(),
	}

	for _, o := range opts {
		o.ApplyGenericTo(opt)
	}

	pt := t
	if pt == ProviderDefault && strings.Contains(os.Getenv("DOCKER_HOST"), "podman.sock") {
		pt = ProviderPodman
	}

	switch pt {
	case ProviderDefault, ProviderDocker:
		providerOptions := append(Generic2DockerOptions(opts...), WithDefaultBridgeNetwork(Bridge))
		provider, err := NewDockerProvider(providerOptions...)
		if err != nil {
			return nil, fmt.Errorf("%w, failed to create Docker provider", err)
		}
		return provider, nil
	case ProviderPodman:
		providerOptions := append(Generic2DockerOptions(opts...), WithDefaultBridgeNetwork(Podman))
		provider, err := NewDockerProvider(providerOptions...)
		if err != nil {
			return nil, fmt.Errorf("%w, failed to create Docker provider", err)
		}
		return provider, nil
	}
	return nil, errors.New("unknown provider")
}

// NewDockerProvider creates a Docker provider with the EnvClient
func NewDockerProvider(provOpts ...DockerProviderOption) (*DockerProvider, error) {
	o := &DockerProviderOptions{
		GenericProviderOptions: &GenericProviderOptions{
			Logger: log.Default(),
		},
	}

	for idx := range provOpts {
		provOpts[idx].ApplyDockerTo(o)
	}

	ctx := context.Background()
	c, err := NewDockerClientWithOpts(ctx)
	if err != nil {
		return nil, err
	}

	return &DockerProvider{
		DockerProviderOptions: o,
		host:                  core.MustExtractDockerHost(ctx),
		client:                c,
		config:                config.Read(),
	}, nil
}