-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathcontainer.go
120 lines (109 loc) · 2.59 KB
/
container.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
package buildkit
import (
"context"
"os"
"strings"
"github.com/docker/cli/cli/config"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/auth/authprovider"
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
log "github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
"github.com/gitpod-io/dazzle/pkg/test"
"github.com/gitpod-io/dazzle/pkg/test/runner"
)
// NewExecutor creates a new buildkit-backed executor
func NewExecutor(cl *client.Client, ref string, cfg *ociv1.Image) *Executor {
return &Executor{
cl: cl,
ref: ref,
cfg: cfg,
}
}
// Executor runs tests in containers using buildkit
type Executor struct {
cl *client.Client
ref string
cfg *ociv1.Image
}
// Run executes the test
func (b *Executor) Run(ctx context.Context, spec *test.Spec) (rr *test.RunResult, err error) {
rb, err := runner.GetRunner("linux_amd64")
if err != nil {
return
}
espec, err := runner.Args(spec)
if err != nil {
return
}
state := llb.Image(b.ref)
if user := b.cfg.Config.User; user != "" {
state = state.User(user)
log.WithField("user", user).Debug("running test as user")
}
for _, e := range b.cfg.Config.Env {
segs := strings.Split(e, "=")
state = state.AddEnv(segs[0], segs[1])
}
def, err := state.
File(llb.Mkdir("/dazzle", 0755)).
File(llb.Mkfile("/dazzle/runner", 0777, rb)).
Run(llb.Args(append([]string{"/dazzle/runner"}, espec...)), llb.IgnoreCache).
Root().
Marshal(ctx)
if err != nil {
return
}
log.WithField("args", espec).Debug("running test using buildkit")
var (
cctx, cancel = context.WithCancel(ctx)
ch = make(chan *client.SolveStatus)
eg, bctx = errgroup.WithContext(cctx)
rchan = make(chan []byte, 1)
)
defer cancel()
eg.Go(func() error {
dockerConfig := config.LoadDefaultConfigFile(os.Stderr)
_, err := b.cl.Solve(bctx, def, client.SolveOpt{
Session: []session.Attachable{
authprovider.NewDockerAuthProvider(dockerConfig),
},
}, ch)
if err != nil {
return err
}
return nil
})
eg.Go(func() error {
var b []byte
defer func() {
rchan <- b
}()
for {
select {
case cs, ok := <-ch:
if !ok {
return nil
}
for _, l := range cs.Logs {
b = append(b, l.Data...)
}
case <-ctx.Done():
return nil
}
}
})
err = eg.Wait()
if err != nil {
log.WithError(err).Info("ignored error group error")
}
buf := <-rchan
log.WithField("buf", string(buf)).Debug("received test run output")
res, err := runner.UnmarshalRunResult(buf)
if err != nil {
return
}
return res, nil
}