-
Notifications
You must be signed in to change notification settings - Fork 84
Expand file tree
/
Copy pathdocker.go
More file actions
115 lines (95 loc) · 2.41 KB
/
docker.go
File metadata and controls
115 lines (95 loc) · 2.41 KB
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
package dockerexec
import (
"context"
"encoding/hex"
"io"
"math/rand"
"time"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/client"
"github.com/pkg/errors"
"go.uber.org/zap"
)
type Options struct {
BuildContext string
Debug bool
Dockerfile string
Image string
Logger *zap.Logger
}
func New(opts *Options) (*Docker, error) {
// Negotiate API version with the daemon to avoid hard-coded mismatches across environments.
c, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return nil, err
}
logger := opts.Logger
if logger == nil {
logger = zap.NewNop()
}
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
d := &Docker{
client: c,
buildContext: opts.BuildContext,
debug: opts.Debug,
dockerfile: opts.Dockerfile,
image: opts.Image,
logger: logger,
rnd: rnd,
}
if err := d.buildOrPullImage(context.Background()); err != nil {
return nil, err
}
return d, nil
}
type Docker struct {
client *client.Client
buildContext string // used to build the image
debug bool // when true, the container will not be removed
dockerfile string // used to build the image
image string
logger *zap.Logger
rnd *rand.Rand
}
func (d *Docker) CommandContext(ctx context.Context, program string, args ...string) *Cmd {
return &Cmd{
Path: program,
Args: args,
ctx: ctx,
docker: d,
name: d.containerUniqueName(),
logger: d.logger,
}
}
func (d *Docker) containerUniqueName() string {
var hash [4]byte
_, _ = d.rnd.Read(hash[:])
return "runme-runner-" + hex.EncodeToString(hash[:])
}
func (d *Docker) buildOrPullImage(ctx context.Context) error {
if d.buildContext != "" {
return d.buildImage(ctx)
}
return d.pullImage(ctx)
}
func (d *Docker) buildImage(context.Context) error {
return errors.New("not implemented")
}
func (d *Docker) pullImage(ctx context.Context) error {
filters := filters.NewArgs(filters.Arg("reference", d.image))
result, err := d.client.ImageList(ctx, image.ListOptions{Filters: filters})
if err != nil {
return errors.WithStack(err)
}
if len(result) > 0 {
return nil
}
resp, err := d.client.ImagePull(ctx, d.image, image.PullOptions{})
if err != nil {
return errors.WithStack(err)
}
defer resp.Close()
_, _ = io.Copy(io.Discard, resp)
return nil
}