-
-
Notifications
You must be signed in to change notification settings - Fork 539
/
Copy pathgeneric.go
150 lines (129 loc) · 4.44 KB
/
generic.go
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
package testcontainers
import (
"context"
"errors"
"fmt"
"strings"
"sync"
"github.com/testcontainers/testcontainers-go/internal/core"
"github.com/testcontainers/testcontainers-go/log"
)
var (
reuseContainerMx sync.Mutex
ErrReuseEmptyName = errors.New("with reuse option a container name mustn't be empty")
)
// 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
Logger log.Logger // provide a container specific Logging - use default global logger if empty
Reuse bool // reuse an existing container if it exists or create a new one. a container name mustn't be empty
}
// Deprecated: will be removed in the future.
// GenericNetworkRequest represents parameters to a generic network
type GenericNetworkRequest struct {
NetworkRequest // embedded request for provider
ProviderType ProviderType // which provider to use, Docker if empty
}
// Deprecated: use network.New instead
// GenericNetwork creates a generic network with parameters
func GenericNetwork(ctx context.Context, req GenericNetworkRequest) (Network, error) {
provider, err := req.ProviderType.GetProvider()
if err != nil {
return nil, err
}
network, err := provider.CreateNetwork(ctx, req.NetworkRequest)
if err != nil {
return nil, fmt.Errorf("%w: failed to create network", err)
}
return network, nil
}
// GenericContainer creates a generic container with parameters
func GenericContainer(ctx context.Context, req GenericContainerRequest) (Container, error) {
if req.Reuse && req.Name == "" {
return nil, ErrReuseEmptyName
}
logger := req.Logger
if logger == nil {
// Ensure there is always a non-nil logger by default
logger = log.Default()
}
provider, err := req.ProviderType.GetProvider(WithLogger(logger))
if err != nil {
return nil, fmt.Errorf("get provider: %w", err)
}
defer provider.Close()
var c Container
if req.Reuse {
// we must protect the reusability of the container in the case it's invoked
// in a parallel execution, via ParallelContainers or t.Parallel()
reuseContainerMx.Lock()
defer reuseContainerMx.Unlock()
c, err = provider.ReuseOrCreateContainer(ctx, req.ContainerRequest)
} else {
c, err = provider.CreateContainer(ctx, req.ContainerRequest)
}
if err != nil {
// At this point `c` might not be nil. Give the caller an opportunity to call Destroy on the container.
// TODO: Remove this debugging.
if strings.Contains(err.Error(), "toomanyrequests") {
// Debugging information for rate limiting.
cfg, err := getDockerConfig()
if err == nil {
fmt.Printf("XXX: too many requests: %+v", cfg)
}
}
return c, fmt.Errorf("create container: %w", err)
}
if req.Started && !c.IsRunning() {
if err := c.Start(ctx); err != nil {
return c, fmt.Errorf("start container: %w", err)
}
}
return c, nil
}
// GenericProvider represents an abstraction for container and network providers
type GenericProvider interface {
ContainerProvider
NetworkProvider
ImageProvider
}
// GenericLabels returns a map of labels that can be used to identify resources
// created by this library. This includes the standard LabelSessionID if the
// reaper is enabled, otherwise this is excluded to prevent resources being
// incorrectly reaped.
func GenericLabels() map[string]string {
return core.DefaultLabels(core.SessionID())
}
// AddGenericLabels adds the generic labels to target.
func AddGenericLabels(target map[string]string) {
for k, v := range GenericLabels() {
target[k] = v
}
}
// Run is a convenience function that creates a new container and starts it.
// It calls the GenericContainer function and returns a concrete DockerContainer type.
func Run(ctx context.Context, img string, opts ...ContainerCustomizer) (*DockerContainer, error) {
req := ContainerRequest{
Image: img,
}
genericContainerReq := GenericContainerRequest{
ContainerRequest: req,
Started: true,
}
for _, opt := range opts {
if err := opt.Customize(&genericContainerReq); err != nil {
return nil, fmt.Errorf("customize: %w", err)
}
}
ctr, err := GenericContainer(ctx, genericContainerReq)
var c *DockerContainer
if ctr != nil {
c = ctr.(*DockerContainer)
}
if err != nil {
return c, fmt.Errorf("generic container: %w", err)
}
return c, nil
}