forked from hashicorp/vault-testing-stepwise
-
Notifications
You must be signed in to change notification settings - Fork 0
/
runner.go
125 lines (109 loc) · 3.78 KB
/
runner.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
package docker
import (
"context"
"fmt"
"io/ioutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/strslice"
docker "github.com/docker/docker/client"
"github.com/docker/docker/pkg/archive"
)
// Runner manages the lifecycle of the Docker container
type Runner struct {
dockerAPI *docker.Client
ContainerConfig *container.Config
ContainerName string
NetName string
IP string
CopyFromTo map[string]string
}
// Start is responsible for executing the Vault container. It consists of
// pulling the specified Vault image, creating the container, and copies the
// plugin binary into the container file system before starting the container
// itself.
func (d *Runner) Start(ctx context.Context) (*types.ContainerJSON, error) {
hostConfig := &container.HostConfig{
PublishAllPorts: true,
AutoRemove: true,
}
networkingConfig := &network.NetworkingConfig{}
switch d.NetName {
case "":
case "host":
hostConfig.NetworkMode = "host"
default:
es := &network.EndpointSettings{
Aliases: []string{d.ContainerName},
}
if len(d.IP) != 0 {
es.IPAMConfig = &network.EndpointIPAMConfig{
IPv4Address: d.IP,
}
}
networkingConfig.EndpointsConfig = map[string]*network.EndpointSettings{
d.NetName: es,
}
}
// Best-effort pull. ImageCreate here will use a matching image from the local
// Docker library, or if not found pull the matching image from docker hub. If
// not found on docker hub, returns an error. The response must be read in
// order for the local image to be used.
resp, err := d.dockerAPI.ImageCreate(ctx, d.ContainerConfig.Image, types.ImageCreateOptions{})
if err != nil {
return nil, err
}
if resp != nil {
_, _ = ioutil.ReadAll(resp)
}
cfg := *d.ContainerConfig
hostConfig.CapAdd = strslice.StrSlice{"IPC_LOCK", "NET_ADMIN"}
cfg.Hostname = d.ContainerName
fullName := d.ContainerName
container, err := d.dockerAPI.ContainerCreate(ctx, &cfg, hostConfig, networkingConfig, nil, fullName)
if err != nil {
return nil, fmt.Errorf("container create failed: %v", err)
}
// copies the plugin binary into the Docker file system. This copy is only
// allowed before the container is started
for from, to := range d.CopyFromTo {
if err := copyToContainer(ctx, d.dockerAPI, container.ID, from, to); err != nil {
_ = d.dockerAPI.ContainerRemove(ctx, container.ID, types.ContainerRemoveOptions{})
return nil, err
}
}
err = d.dockerAPI.ContainerStart(ctx, container.ID, types.ContainerStartOptions{})
if err != nil {
_ = d.dockerAPI.ContainerRemove(ctx, container.ID, types.ContainerRemoveOptions{})
return nil, fmt.Errorf("container start failed: %v", err)
}
inspect, err := d.dockerAPI.ContainerInspect(ctx, container.ID)
if err != nil {
_ = d.dockerAPI.ContainerRemove(ctx, container.ID, types.ContainerRemoveOptions{})
return nil, err
}
return &inspect, nil
}
func copyToContainer(ctx context.Context, d *docker.Client, containerID, from, to string) error {
srcInfo, err := archive.CopyInfoSourcePath(from, false)
if err != nil {
return fmt.Errorf("error copying from source %q: %v", from, err)
}
srcArchive, err := archive.TarResource(srcInfo)
if err != nil {
return fmt.Errorf("error creating tar from source %q: %v", from, err)
}
defer srcArchive.Close()
dstInfo := archive.CopyInfo{Path: to}
dstDir, content, err := archive.PrepareArchiveCopy(srcArchive, srcInfo, dstInfo)
if err != nil {
return fmt.Errorf("error preparing copy from %q -> %q: %v", from, to, err)
}
defer content.Close()
err = d.CopyToContainer(ctx, containerID, dstDir, content, types.CopyToContainerOptions{})
if err != nil {
return fmt.Errorf("error copying from %q -> %q: %v", from, to, err)
}
return nil
}