Browse code

vendor: update buildkit to f5a55a95

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>

Tonis Tiigi authored on 2019/08/07 08:08:45
Showing 41 changed files
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"io/ioutil"
8 8
 	nethttp "net/http"
9 9
 	"runtime"
10
+	"strings"
10 11
 	"time"
11 12
 
12 13
 	"github.com/containerd/containerd/content"
... ...
@@ -43,6 +44,7 @@ import (
43 43
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
44 44
 	"github.com/pkg/errors"
45 45
 	"github.com/sirupsen/logrus"
46
+	bolt "go.etcd.io/bbolt"
46 47
 )
47 48
 
48 49
 const labelCreatedAt = "buildkit/createdat"
... ...
@@ -257,6 +259,47 @@ func (w *Worker) GetRemote(ctx context.Context, ref cache.ImmutableRef, createIf
257 257
 	}, nil
258 258
 }
259 259
 
260
+// PruneCacheMounts removes the current cache snapshots for specified IDs
261
+func (w *Worker) PruneCacheMounts(ctx context.Context, ids []string) error {
262
+	mu := ops.CacheMountsLocker()
263
+	mu.Lock()
264
+	defer mu.Unlock()
265
+
266
+	for _, id := range ids {
267
+		id = "cache-dir:" + id
268
+		sis, err := w.MetadataStore.Search(id)
269
+		if err != nil {
270
+			return err
271
+		}
272
+		for _, si := range sis {
273
+			for _, k := range si.Indexes() {
274
+				if k == id || strings.HasPrefix(k, id+":") {
275
+					if siCached := w.CacheManager.Metadata(si.ID()); siCached != nil {
276
+						si = siCached
277
+					}
278
+					if err := cache.CachePolicyDefault(si); err != nil {
279
+						return err
280
+					}
281
+					si.Queue(func(b *bolt.Bucket) error {
282
+						return si.SetValue(b, k, nil)
283
+					})
284
+					if err := si.Commit(); err != nil {
285
+						return err
286
+					}
287
+					// if ref is unused try to clean it up right away by releasing it
288
+					if mref, err := w.CacheManager.GetMutable(ctx, si.ID()); err == nil {
289
+						go mref.Release(context.TODO())
290
+					}
291
+					break
292
+				}
293
+			}
294
+		}
295
+	}
296
+
297
+	ops.ClearActiveCacheMounts()
298
+	return nil
299
+}
300
+
260 301
 // FromRemote converts a remote snapshot reference to a local one
261 302
 func (w *Worker) FromRemote(ctx context.Context, remote *solver.Remote) (cache.ImmutableRef, error) {
262 303
 	rootfs, err := getLayers(ctx, remote.Descriptors)
... ...
@@ -27,7 +27,7 @@ github.com/imdario/mergo                            7c29201646fa3de8506f70121347
27 27
 golang.org/x/sync                                   e225da77a7e68af35c70ccbf71af2b83e6acac3c
28 28
 
29 29
 # buildkit
30
-github.com/moby/buildkit                            a258bd18b2c55aac4e8a10a3074757d66d45cef6
30
+github.com/moby/buildkit                            f5a55a9516d1c6e2ade9bec22b83259caeed3a84 
31 31
 github.com/tonistiigi/fsutil                        3bbb99cdbd76619ab717299830c60f6f2a533a6b
32 32
 github.com/grpc-ecosystem/grpc-opentracing          8e809c8a86450a29b90dcc9efbf062d0fe6d9746
33 33
 github.com/opentracing/opentracing-go               1361b9cd60be79c4c3a7fa9841b3c132e40066a7
... ...
@@ -1,27 +1,25 @@
1 1
 [![asciicinema example](https://asciinema.org/a/gPEIEo1NzmDTUu2bEPsUboqmU.png)](https://asciinema.org/a/gPEIEo1NzmDTUu2bEPsUboqmU)
2 2
 
3
-
4 3
 ## BuildKit
5 4
 
6 5
 [![GoDoc](https://godoc.org/github.com/moby/buildkit?status.svg)](https://godoc.org/github.com/moby/buildkit/client/llb)
7 6
 [![Build Status](https://travis-ci.org/moby/buildkit.svg?branch=master)](https://travis-ci.org/moby/buildkit)
8 7
 [![Go Report Card](https://goreportcard.com/badge/github.com/moby/buildkit)](https://goreportcard.com/report/github.com/moby/buildkit)
9 8
 
10
-
11 9
 BuildKit is a toolkit for converting source code to build artifacts in an efficient, expressive and repeatable manner.
12 10
 
13 11
 Key features:
14
-- Automatic garbage collection
15
-- Extendable frontend formats
16
-- Concurrent dependency resolution
17
-- Efficient instruction caching
18
-- Build cache import/export
19
-- Nested build job invocations
20
-- Distributable workers
21
-- Multiple output formats
22
-- Pluggable architecture
23
-- Execution without root privileges
24 12
 
13
+-   Automatic garbage collection
14
+-   Extendable frontend formats
15
+-   Concurrent dependency resolution
16
+-   Efficient instruction caching
17
+-   Build cache import/export
18
+-   Nested build job invocations
19
+-   Distributable workers
20
+-   Multiple output formats
21
+-   Pluggable architecture
22
+-   Execution without root privileges
25 23
 
26 24
 Read the proposal from https://github.com/moby/moby/issues/32925
27 25
 
... ...
@@ -33,20 +31,21 @@ Introductory blog post https://blog.mobyproject.org/introducing-buildkit-17e056c
33 33
 
34 34
 BuildKit is used by the following projects:
35 35
 
36
-- [Moby & Docker](https://github.com/moby/moby/pull/37151)
37
-- [img](https://github.com/genuinetools/img)
38
-- [OpenFaaS Cloud](https://github.com/openfaas/openfaas-cloud)
39
-- [container build interface](https://github.com/containerbuilding/cbi)
40
-- [Knative Build Templates](https://github.com/knative/build-templates)
41
-- [vab](https://github.com/stellarproject/vab)
42
-- [Rio](https://github.com/rancher/rio) (on roadmap)
36
+-   [Moby & Docker](https://github.com/moby/moby/pull/37151)
37
+-   [img](https://github.com/genuinetools/img)
38
+-   [OpenFaaS Cloud](https://github.com/openfaas/openfaas-cloud)
39
+-   [container build interface](https://github.com/containerbuilding/cbi)
40
+-   [Knative Build Templates](https://github.com/knative/build-templates)
41
+-   [the Sanic build tool](https://github.com/distributed-containers-inc/sanic)
42
+-   [vab](https://github.com/stellarproject/vab)
43
+-   [Rio](https://github.com/rancher/rio) (on roadmap)
43 44
 
44 45
 ### Quick start
45 46
 
46 47
 Dependencies:
47
-- [runc](https://github.com/opencontainers/runc)
48
-- [containerd](https://github.com/containerd/containerd) (if you want to use containerd worker)
49 48
 
49
+-   [runc](https://github.com/opencontainers/runc)
50
+-   [containerd](https://github.com/containerd/containerd) (if you want to use containerd worker)
50 51
 
51 52
 The following command installs `buildkitd` and `buildctl` to `/usr/local/bin`:
52 53
 
... ...
@@ -58,14 +57,13 @@ You can also use `make binaries-all` to prepare `buildkitd.containerd_only` and
58 58
 
59 59
 #### Starting the buildkitd daemon:
60 60
 
61
-```
61
+```bash
62 62
 buildkitd --debug --root /var/lib/buildkit
63 63
 ```
64 64
 
65 65
 The buildkitd daemon supports two worker backends: OCI (runc) and containerd.
66 66
 
67
-By default, the OCI (runc) worker is used.
68
-You can set `--oci-worker=false --containerd-worker=true` to use the containerd worker.
67
+By default, the OCI (runc) worker is used. You can set `--oci-worker=false --containerd-worker=true` to use the containerd worker.
69 68
 
70 69
 We are open to adding more backends.
71 70
 
... ...
@@ -73,44 +71,46 @@ We are open to adding more backends.
73 73
 
74 74
 BuildKit builds are based on a binary intermediate format called LLB that is used for defining the dependency graph for processes running part of your build. tl;dr: LLB is to Dockerfile what LLVM IR is to C.
75 75
 
76
-- Marshaled as Protobuf messages
77
-- Concurrently executable
78
-- Efficiently cacheable
79
-- Vendor-neutral (i.e. non-Dockerfile languages can be easily implemented)
76
+-   Marshaled as Protobuf messages
77
+-   Concurrently executable
78
+-   Efficiently cacheable
79
+-   Vendor-neutral (i.e. non-Dockerfile languages can be easily implemented)
80 80
 
81 81
 See [`solver/pb/ops.proto`](./solver/pb/ops.proto) for the format definition.
82 82
 
83 83
 Currently, following high-level languages has been implemented for LLB:
84 84
 
85
-- Dockerfile (See [Exploring Dockerfiles](#exploring-dockerfiles))
86
-- [Buildpacks](https://github.com/tonistiigi/buildkit-pack)
87
-- (open a PR to add your own language)
85
+-   Dockerfile (See [Exploring Dockerfiles](#exploring-dockerfiles))
86
+-   [Buildpacks](https://github.com/tonistiigi/buildkit-pack)
87
+-   (open a PR to add your own language)
88 88
 
89 89
 For understanding the basics of LLB, `examples/buildkit*` directory contains scripts that define how to build different configurations of BuildKit itself and its dependencies using the `client` package. Running one of these scripts generates a protobuf definition of a build graph. Note that the script itself does not execute any steps of the build.
90 90
 
91 91
 You can use `buildctl debug dump-llb` to see what data is in this definition. Add `--dot` to generate dot layout.
92 92
 
93 93
 ```bash
94
-go run examples/buildkit0/buildkit.go | buildctl debug dump-llb | jq .
94
+go run examples/buildkit0/buildkit.go \
95
+    | buildctl debug dump-llb \
96
+    | jq .
95 97
 ```
96 98
 
97
-To start building use `buildctl build` command. The example script accepts `--with-containerd` flag to choose if containerd binaries and support should be included in the end result as well. 
99
+To start building use `buildctl build` command. The example script accepts `--with-containerd` flag to choose if containerd binaries and support should be included in the end result as well.
98 100
 
99 101
 ```bash
100
-go run examples/buildkit0/buildkit.go | buildctl build
102
+go run examples/buildkit0/buildkit.go \
103
+    | buildctl build
101 104
 ```
102 105
 
103 106
 `buildctl build` will show interactive progress bar by default while the build job is running. If the path to the trace file is specified, the trace file generated will contain all information about the timing of the individual steps and logs.
104 107
 
105 108
 Different versions of the example scripts show different ways of describing the build definition for this project to show the capabilities of the library. New versions have been added when new features have become available.
106 109
 
107
-- `./examples/buildkit0` - uses only exec operations, defines a full stage per component.
108
-- `./examples/buildkit1` - cloning git repositories has been separated for extra concurrency.
109
-- `./examples/buildkit2` - uses git sources directly instead of running `git clone`, allowing better performance and much safer caching.
110
-- `./examples/buildkit3` - allows using local source files for separate components eg. `./buildkit3 --runc=local | buildctl build --local runc-src=some/local/path`  
111
-- `./examples/dockerfile2llb` - can be used to convert a Dockerfile to LLB for debugging purposes
112
-- `./examples/gobuild` - shows how to use nested invocation to generate LLB for Go package internal dependencies
113
-
110
+-   `./examples/buildkit0` - uses only exec operations, defines a full stage per component.
111
+-   `./examples/buildkit1` - cloning git repositories has been separated for extra concurrency.
112
+-   `./examples/buildkit2` - uses git sources directly instead of running `git clone`, allowing better performance and much safer caching.
113
+-   `./examples/buildkit3` - allows using local source files for separate components eg. `./buildkit3 --runc=local | buildctl build --local runc-src=some/local/path`
114
+-   `./examples/dockerfile2llb` - can be used to convert a Dockerfile to LLB for debugging purposes
115
+-   `./examples/gobuild` - shows how to use nested invocation to generate LLB for Go package internal dependencies
114 116
 
115 117
 #### Exploring Dockerfiles
116 118
 
... ...
@@ -120,9 +120,18 @@ During development, Dockerfile frontend (dockerfile.v0) is also part of the Buil
120 120
 
121 121
 ##### Building a Dockerfile with `buildctl`
122 122
 
123
-```
124
-buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=.
125
-buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=. --opt target=foo --opt build-arg:foo=bar
123
+```bash
124
+buildctl build \
125
+    --frontend=dockerfile.v0 \
126
+    --local context=. \
127
+    --local dockerfile=.
128
+# or
129
+buildctl build \
130
+    --frontend=dockerfile.v0 \
131
+    --local context=. \
132
+    --local dockerfile=. \
133
+    --opt target=foo \
134
+    --opt build-arg:foo=bar
126 135
 ```
127 136
 
128 137
 `--local` exposes local source files from client to the builder. `context` and `dockerfile` are the names Dockerfile frontend looks for build context and Dockerfile location.
... ...
@@ -131,8 +140,9 @@ buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=. -
131 131
 
132 132
 For people familiar with `docker build` command, there is an example wrapper utility in `./examples/build-using-dockerfile` that allows building Dockerfiles with BuildKit using a syntax similar to `docker build`.
133 133
 
134
-```
135
-go build ./examples/build-using-dockerfile && sudo install build-using-dockerfile /usr/local/bin
134
+```bash
135
+go build ./examples/build-using-dockerfile \
136
+    && sudo install build-using-dockerfile /usr/local/bin
136 137
 
137 138
 build-using-dockerfile -t myimage .
138 139
 build-using-dockerfile -t mybuildkit -f ./hack/dockerfiles/test.Dockerfile .
... ...
@@ -145,10 +155,18 @@ docker inspect myimage
145 145
 
146 146
 External versions of the Dockerfile frontend are pushed to https://hub.docker.com/r/docker/dockerfile-upstream and https://hub.docker.com/r/docker/dockerfile and can be used with the gateway frontend. The source for the external frontend is currently located in `./frontend/dockerfile/cmd/dockerfile-frontend` but will move out of this repository in the future ([#163](https://github.com/moby/buildkit/issues/163)). For automatic build from master branch of this repository `docker/dockerfile-upsteam:master` or `docker/dockerfile-upstream:master-experimental` image can be used.
147 147
 
148
+```bash
149
+buildctl build \
150
+    --frontend gateway.v0 \
151
+    --opt source=docker/dockerfile \
152
+    --local context=. \
153
+    --local dockerfile=.
154
+buildctl build \
155
+    --frontend gateway.v0 \
156
+    --opt source=docker/dockerfile \
157
+    --opt context=git://github.com/moby/moby \
158
+    --opt build-arg:APT_MIRROR=cdn-fastly.deb.debian.org
148 159
 ```
149
-buildctl build --frontend gateway.v0 --opt source=docker/dockerfile --local context=. --local dockerfile=.
150
-buildctl build --frontend gateway.v0 --opt source=docker/dockerfile --opt context=git://github.com/moby/moby --opt build-arg:APT_MIRROR=cdn-fastly.deb.debian.org
151
-````
152 160
 
153 161
 ##### Building a Dockerfile with experimental features like `RUN --mount=type=(bind|cache|tmpfs|secret|ssh)`
154 162
 
... ...
@@ -162,29 +180,29 @@ By default, the build result and intermediate cache will only remain internally
162 162
 
163 163
 The containerd worker needs to be used
164 164
 
165
-```
165
+```bash
166 166
 buildctl build ... --output type=image,name=docker.io/username/image
167 167
 ctr --namespace=buildkit images ls
168 168
 ```
169 169
 
170 170
 ##### Push resulting image to registry
171 171
 
172
-```
172
+```bash
173 173
 buildctl build ... --output type=image,name=docker.io/username/image,push=true
174 174
 ```
175 175
 
176 176
 If credentials are required, `buildctl` will attempt to read Docker configuration file.
177 177
 
178
-
179 178
 ##### Exporting build result back to client
180 179
 
181 180
 The local client will copy the files directly to the client. This is useful if BuildKit is being used for building something else than container images.
182 181
 
183
-```
182
+```bash
184 183
 buildctl build ... --output type=local,dest=path/to/output-dir
185 184
 ```
186 185
 
187 186
 To export specific files use multi-stage builds with a scratch stage and copy the needed files into that stage with `COPY --from`.
187
+
188 188
 ```dockerfile
189 189
 ...
190 190
 FROM scratch as testresult
... ...
@@ -193,28 +211,27 @@ COPY --from=builder /usr/src/app/testresult.xml .
193 193
 ...
194 194
 ```
195 195
 
196
-```
196
+```bash
197 197
 buildctl build ... --opt target=testresult --output type=local,dest=path/to/output-dir
198 198
 ```
199 199
 
200 200
 Tar exporter is similar to local exporter but transfers the files through a tarball.
201 201
 
202
-```
202
+```bash
203 203
 buildctl build ... --output type=tar,dest=out.tar
204 204
 buildctl build ... --output type=tar > out.tar
205 205
 ```
206 206
 
207
-
208 207
 ##### Exporting built image to Docker
209 208
 
210
-```
209
+```bash
211 210
 # exported tarball is also compatible with OCI spec
212 211
 buildctl build ... --output type=docker,name=myimage | docker load
213 212
 ```
214 213
 
215 214
 ##### Exporting [OCI Image Format](https://github.com/opencontainers/image-spec) tarball to client
216 215
 
217
-```
216
+```bash
218 217
 buildctl build ... --output type=oci,dest=path/to/output.tar
219 218
 buildctl build ... --output type=oci > output.tar
220 219
 ```
... ...
@@ -223,14 +240,14 @@ buildctl build ... --output type=oci > output.tar
223 223
 
224 224
 #### To/From registry
225 225
 
226
-```
226
+```bash
227 227
 buildctl build ... --export-cache type=registry,ref=localhost:5000/myrepo:buildcache
228 228
 buildctl build ... --import-cache type=registry,ref=localhost:5000/myrepo:buildcache
229 229
 ```
230 230
 
231 231
 #### To/From local filesystem
232 232
 
233
-```
233
+```bash
234 234
 buildctl build ... --export-cache type=local,dest=path/to/output-dir
235 235
 buildctl build ... --import-cache type=local,src=path/to/input-dir
236 236
 ```
... ...
@@ -238,27 +255,29 @@ buildctl build ... --import-cache type=local,src=path/to/input-dir
238 238
 The directory layout conforms to OCI Image Spec v1.0.
239 239
 
240 240
 #### `--export-cache` options
241
-* `mode=min` (default): only export layers for the resulting image
242
-* `mode=max`: export all the layers of all intermediate steps
243
-* `ref=docker.io/user/image:tag`: reference for `registry` cache exporter
244
-* `dest=path/to/output-dir`: directory for `local` cache exporter
241
+
242
+-   `mode=min` (default): only export layers for the resulting image
243
+-   `mode=max`: export all the layers of all intermediate steps
244
+-   `ref=docker.io/user/image:tag`: reference for `registry` cache exporter
245
+-   `dest=path/to/output-dir`: directory for `local` cache exporter
245 246
 
246 247
 #### `--import-cache` options
247
-* `ref=docker.io/user/image:tag`: reference for `registry` cache importer
248
-* `src=path/to/input-dir`: directory for `local` cache importer
249
-* `digest=sha256:deadbeef`: digest of the manifest list to import for `local` cache importer. Defaults to the digest of "latest" tag in `index.json`
248
+
249
+-   `ref=docker.io/user/image:tag`: reference for `registry` cache importer
250
+-   `src=path/to/input-dir`: directory for `local` cache importer
251
+-   `digest=sha256:deadbeef`: digest of the manifest list to import for `local` cache importer. Defaults to the digest of "latest" tag in `index.json`
250 252
 
251 253
 ### Other
252 254
 
253 255
 #### View build cache
254 256
 
255
-```
257
+```bash
256 258
 buildctl du -v
257 259
 ```
258 260
 
259 261
 #### Show enabled workers
260 262
 
261
-```
263
+```bash
262 264
 buildctl debug workers -v
263 265
 ```
264 266
 
... ...
@@ -268,14 +287,14 @@ BuildKit can also be used by running the `buildkitd` daemon inside a Docker cont
268 268
 
269 269
 We provide `buildkitd` container images as [`moby/buildkit`](https://hub.docker.com/r/moby/buildkit/tags/):
270 270
 
271
-* `moby/buildkit:latest`: built from the latest regular [release](https://github.com/moby/buildkit/releases)
272
-* `moby/buildkit:rootless`: same as `latest` but runs as an unprivileged user, see [`docs/rootless.md`](docs/rootless.md)
273
-* `moby/buildkit:master`: built from the master branch
274
-* `moby/buildkit:master-rootless`: same as master but runs as an unprivileged user, see [`docs/rootless.md`](docs/rootless.md)
271
+-   `moby/buildkit:latest`: built from the latest regular [release](https://github.com/moby/buildkit/releases)
272
+-   `moby/buildkit:rootless`: same as `latest` but runs as an unprivileged user, see [`docs/rootless.md`](docs/rootless.md)
273
+-   `moby/buildkit:master`: built from the master branch
274
+-   `moby/buildkit:master-rootless`: same as master but runs as an unprivileged user, see [`docs/rootless.md`](docs/rootless.md)
275 275
 
276 276
 To run daemon in a container:
277 277
 
278
-```
278
+```bash
279 279
 docker run -d --privileged -p 1234:1234 moby/buildkit:latest --addr tcp://0.0.0.0:1234
280 280
 export BUILDKIT_HOST=tcp://0.0.0.0:1234
281 281
 buildctl build --help
... ...
@@ -283,26 +302,50 @@ buildctl build --help
283 283
 
284 284
 To run client and an ephemeral daemon in a single container ("daemonless mode"):
285 285
 
286
+```bash
287
+docker run \
288
+    -it \
289
+    --rm \
290
+    --privileged \
291
+    -v /path/to/dir:/tmp/work \
292
+    --entrypoint buildctl-daemonless.sh \
293
+    moby/buildkit:master \
294
+        build \
295
+        --frontend dockerfile.v0 \
296
+        --local context=/tmp/work \
297
+        --local dockerfile=/tmp/work
286 298
 ```
287
-docker run -it --rm --privileged -v /path/to/dir:/tmp/work --entrypoint buildctl-daemonless.sh moby/buildkit:master build --frontend dockerfile.v0 --local context=/tmp/work --local dockerfile=/tmp/work
288
-```
299
+
289 300
 or
290
-```
291
-docker run -it --rm --security-opt seccomp=unconfined --security-opt apparmor=unconfined -e BUILDKITD_FLAGS=--oci-worker-no-process-sandbox -v /path/to/dir:/tmp/work --entrypoint buildctl-daemonless.sh moby/buildkit:master-rootless build --frontend dockerfile.v0 --local context=/tmp/work --local dockerfile=/tmp/work
292
-```
293 301
 
294
-The images can be also built locally using `./hack/dockerfiles/test.Dockerfile` (or `./hack/dockerfiles/test.buildkit.Dockerfile` if you already have BuildKit).
295
-Run `make images` to build the images as `moby/buildkit:local` and `moby/buildkit:local-rootless`.
302
+```bash
303
+docker run \
304
+    -it \
305
+    --rm \
306
+    --security-opt seccomp=unconfined \
307
+    --security-opt apparmor=unconfined \
308
+    -e BUILDKITD_FLAGS=--oci-worker-no-process-sandbox \
309
+    -v /path/to/dir:/tmp/work \
310
+    --entrypoint buildctl-daemonless.sh \
311
+    moby/buildkit:master-rootless \
312
+        build \
313
+        --frontend \
314
+        dockerfile.v0 \
315
+        --local context=/tmp/work \
316
+        --local dockerfile=/tmp/work
317
+```
318
+
319
+The images can be also built locally using `./hack/dockerfiles/test.Dockerfile` (or `./hack/dockerfiles/test.buildkit.Dockerfile` if you already have BuildKit). Run `make images` to build the images as `moby/buildkit:local` and `moby/buildkit:local-rootless`.
296 320
 
297 321
 #### Connection helpers
298 322
 
299 323
 If you are running `moby/buildkit:master` or `moby/buildkit:master-rootless` as a Docker/Kubernetes container, you can use special `BUILDKIT_HOST` URL for connecting to the BuildKit daemon in the container:
300 324
 
301
-```
325
+```bash
302 326
 export BUILDKIT_HOST=docker-container://<container>
303 327
 ```
304 328
 
305
-```
329
+```bash
306 330
 export BUILDKIT_HOST=kube-pod://<pod>
307 331
 ```
308 332
 
... ...
@@ -310,15 +353,13 @@ export BUILDKIT_HOST=kube-pod://<pod>
310 310
 
311 311
 BuildKit supports opentracing for buildkitd gRPC API and buildctl commands. To capture the trace to [Jaeger](https://github.com/jaegertracing/jaeger), set `JAEGER_TRACE` environment variable to the collection address.
312 312
 
313
-
314
-```
313
+```bash
315 314
 docker run -d -p6831:6831/udp -p16686:16686 jaegertracing/all-in-one:latest
316 315
 export JAEGER_TRACE=0.0.0.0:6831
317 316
 # restart buildkitd and buildctl so they know JAEGER_TRACE
318 317
 # any buildctl command should be traced to http://127.0.0.1:16686/
319 318
 ```
320 319
 
321
-
322 320
 ### Supported runc version
323 321
 
324 322
 During development, BuildKit is tested with the version of runc that is being used by the containerd repository. Please refer to [runc.md](https://github.com/containerd/containerd/blob/v1.2.1/RUNC.md) for more information.
... ...
@@ -329,5 +370,4 @@ Please refer to [`docs/rootless.md`](docs/rootless.md).
329 329
 
330 330
 ### Contributing
331 331
 
332
-Want to contribute to BuildKit? Awesome! You can find information about
333
-contributing to this project in the [CONTRIBUTING.md](/.github/CONTRIBUTING.md)
332
+Want to contribute to BuildKit? Awesome! You can find information about contributing to this project in the [CONTRIBUTING.md](/.github/CONTRIBUTING.md)
... ...
@@ -36,6 +36,7 @@ type Accessor interface {
36 36
 	New(ctx context.Context, s ImmutableRef, opts ...RefOption) (MutableRef, error)
37 37
 	GetMutable(ctx context.Context, id string) (MutableRef, error) // Rebase?
38 38
 	IdentityMapping() *idtools.IdentityMapping
39
+	Metadata(string) *metadata.StorageItem
39 40
 }
40 41
 
41 42
 type Controller interface {
... ...
@@ -124,6 +125,16 @@ func (cm *cacheManager) GetFromSnapshotter(ctx context.Context, id string, opts
124 124
 	return cm.get(ctx, id, true, opts...)
125 125
 }
126 126
 
127
+func (cm *cacheManager) Metadata(id string) *metadata.StorageItem {
128
+	cm.mu.Lock()
129
+	defer cm.mu.Unlock()
130
+	r, ok := cm.records[id]
131
+	if !ok {
132
+		return nil
133
+	}
134
+	return r.Metadata()
135
+}
136
+
127 137
 // get requires manager lock to be taken
128 138
 func (cm *cacheManager) get(ctx context.Context, id string, fromSnapshotter bool, opts ...RefOption) (*immutableRef, error) {
129 139
 	rec, err := cm.getRecord(ctx, id, fromSnapshotter, opts...)
... ...
@@ -250,6 +250,10 @@ func (s *StorageItem) Update(fn func(b *bolt.Bucket) error) error {
250 250
 	return s.storage.Update(s.id, fn)
251 251
 }
252 252
 
253
+func (s *StorageItem) Metadata() *StorageItem {
254
+	return s
255
+}
256
+
253 257
 func (s *StorageItem) Keys() []string {
254 258
 	keys := make([]string, 0, len(s.values))
255 259
 	for k := range s.values {
... ...
@@ -333,6 +337,15 @@ func (s *StorageItem) Indexes() (out []string) {
333 333
 
334 334
 func (s *StorageItem) SetValue(b *bolt.Bucket, key string, v *Value) error {
335 335
 	if v == nil {
336
+		if old, ok := s.values[key]; ok {
337
+			if old.Index != "" {
338
+				b, err := b.Tx().CreateBucketIfNotExists([]byte(indexBucket))
339
+				if err != nil {
340
+					return errors.WithStack(err)
341
+				}
342
+				b.Delete([]byte(indexKey(old.Index, s.ID()))) // ignore error
343
+			}
344
+		}
336 345
 		if err := b.Put([]byte(key), nil); err != nil {
337 346
 			return err
338 347
 		}
... ...
@@ -2,6 +2,7 @@ package cache
2 2
 
3 3
 import (
4 4
 	"context"
5
+	"strings"
5 6
 	"sync"
6 7
 
7 8
 	"github.com/containerd/containerd/mount"
... ...
@@ -429,6 +430,10 @@ func (m *readOnlyMounter) Mount() ([]mount.Mount, error) {
429 429
 		return nil, err
430 430
 	}
431 431
 	for i, m := range mounts {
432
+		if m.Type == "overlay" {
433
+			mounts[i].Options = readonlyOverlay(m.Options)
434
+			continue
435
+		}
432 436
 		opts := make([]string, 0, len(m.Options))
433 437
 		for _, opt := range m.Options {
434 438
 			if opt != "rw" {
... ...
@@ -440,3 +445,23 @@ func (m *readOnlyMounter) Mount() ([]mount.Mount, error) {
440 440
 	}
441 441
 	return mounts, nil
442 442
 }
443
+
444
+func readonlyOverlay(opt []string) []string {
445
+	out := make([]string, 0, len(opt))
446
+	upper := ""
447
+	for _, o := range opt {
448
+		if strings.HasPrefix(o, "upperdir=") {
449
+			upper = strings.TrimPrefix(o, "upperdir=")
450
+		} else if !strings.HasPrefix(o, "workdir=") {
451
+			out = append(out, o)
452
+		}
453
+	}
454
+	if upper != "" {
455
+		for i, o := range out {
456
+			if strings.HasPrefix(o, "lowerdir=") {
457
+				out[i] = "lowerdir=" + upper + ":" + strings.TrimPrefix(o, "lowerdir=")
458
+			}
459
+		}
460
+	}
461
+	return out
462
+}
... ...
@@ -67,8 +67,8 @@ func sortConfig(cc *CacheConfig) {
67 67
 		if ri.Digest != rj.Digest {
68 68
 			return ri.Digest < rj.Digest
69 69
 		}
70
-		if len(ri.Inputs) != len(ri.Inputs) {
71
-			return len(ri.Inputs) < len(ri.Inputs)
70
+		if len(ri.Inputs) != len(rj.Inputs) {
71
+			return len(ri.Inputs) < len(rj.Inputs)
72 72
 		}
73 73
 		for i, inputs := range ri.Inputs {
74 74
 			if len(ri.Inputs[i]) != len(rj.Inputs[i]) {
... ...
@@ -76,7 +76,7 @@ func sortConfig(cc *CacheConfig) {
76 76
 			}
77 77
 			for j := range inputs {
78 78
 				if ri.Inputs[i][j].Selector != rj.Inputs[i][j].Selector {
79
-					return ri.Inputs[i][j].Selector != rj.Inputs[i][j].Selector
79
+					return ri.Inputs[i][j].Selector < rj.Inputs[i][j].Selector
80 80
 				}
81 81
 				return cc.Records[ri.Inputs[i][j].LinkIndex].Digest < cc.Records[rj.Inputs[i][j].LinkIndex].Digest
82 82
 			}
... ...
@@ -46,8 +46,8 @@ type SolveOpt struct {
46 46
 type ExportEntry struct {
47 47
 	Type      string
48 48
 	Attrs     map[string]string
49
-	Output    io.WriteCloser // for ExporterOCI and ExporterDocker
50
-	OutputDir string         // for ExporterLocal
49
+	Output    func(map[string]string) (io.WriteCloser, error) // for ExporterOCI and ExporterDocker
50
+	OutputDir string                                          // for ExporterLocal
51 51
 }
52 52
 
53 53
 type CacheOptionsEntry struct {
... ...
@@ -38,13 +38,13 @@ type Opt struct {
38 38
 }
39 39
 
40 40
 type Controller struct { // TODO: ControlService
41
+	buildCount       int64
41 42
 	opt              Opt
42 43
 	solver           *llbsolver.Solver
43 44
 	cache            solver.CacheManager
44 45
 	gatewayForwarder *controlgateway.GatewayForwarder
45 46
 	throttledGC      func()
46 47
 	gcmu             sync.Mutex
47
-	buildCount       int64
48 48
 }
49 49
 
50 50
 func NewController(opt Opt) (*Controller, error) {
... ...
@@ -101,11 +101,11 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
101 101
 	}
102 102
 
103 103
 	if meta.SecurityMode == pb.SecurityMode_INSECURE {
104
-		//make sysfs rw mount for insecure mode.
105
-		for _, m := range s.Mounts {
106
-			if m.Type == "sysfs" {
107
-				m.Options = []string{"nosuid", "noexec", "nodev", "rw"}
108
-			}
104
+		if err = oci.WithWriteableCgroupfs(ctx, nil, c, s); err != nil {
105
+			return nil, nil, err
106
+		}
107
+		if err = oci.WithWriteableSysfs(ctx, nil, c, s); err != nil {
108
+			return nil, nil, err
109 109
 		}
110 110
 	}
111 111
 
... ...
@@ -236,8 +236,10 @@ func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache.
236 236
 	if err != nil {
237 237
 		return errors.Wrapf(err, "working dir %s points to invalid target", newp)
238 238
 	}
239
-	if err := idtools.MkdirAllAndChown(newp, 0755, identity); err != nil {
240
-		return errors.Wrapf(err, "failed to create working directory %s", newp)
239
+	if _, err := os.Stat(newp); err != nil {
240
+		if err := idtools.MkdirAllAndChown(newp, 0755, identity); err != nil {
241
+			return errors.Wrapf(err, "failed to create working directory %s", newp)
242
+		}
241 243
 	}
242 244
 
243 245
 	if err := setOOMScoreAdj(spec); err != nil {
... ...
@@ -147,7 +147,7 @@ func (e *localExporterInstance) Export(ctx context.Context, inp exporter.Source)
147 147
 		fs = d.FS
148 148
 	}
149 149
 
150
-	w, err := filesync.CopyFileWriter(ctx, e.caller)
150
+	w, err := filesync.CopyFileWriter(ctx, nil, e.caller)
151 151
 	if err != nil {
152 152
 		return nil, err
153 153
 	}
... ...
@@ -34,6 +34,7 @@ const (
34 34
 	keyFilename                = "filename"
35 35
 	keyCacheFrom               = "cache-from"    // for registry only. deprecated in favor of keyCacheImports
36 36
 	keyCacheImports            = "cache-imports" // JSON representation of []CacheOptionsEntry
37
+	keyCacheNS                 = "build-arg:BUILDKIT_CACHE_MOUNT_NS"
37 38
 	defaultDockerfileName      = "Dockerfile"
38 39
 	dockerignoreFilename       = ".dockerignore"
39 40
 	buildArgPrefix             = "build-arg:"
... ...
@@ -322,6 +323,7 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) {
322 322
 					MetaResolver:      c,
323 323
 					BuildArgs:         filter(opts, buildArgPrefix),
324 324
 					Labels:            filter(opts, labelPrefix),
325
+					CacheIDNamespace:  opts[keyCacheNS],
325 326
 					SessionID:         c.BuildOpts().SessionID,
326 327
 					BuildContext:      buildContext,
327 328
 					Excludes:          excludes,
... ...
@@ -461,7 +461,7 @@ type dispatchOpt struct {
461 461
 func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
462 462
 	if ex, ok := cmd.Command.(instructions.SupportsSingleWordExpansion); ok {
463 463
 		err := ex.Expand(func(word string) (string, error) {
464
-			return opt.shlex.ProcessWordWithMap(word, toEnvMap(d.buildArgs, d.image.Config.Env))
464
+			return opt.shlex.ProcessWord(word, d.state.Env())
465 465
 		})
466 466
 		if err != nil {
467 467
 			return err
... ...
@@ -626,14 +626,7 @@ func dispatchRun(d *dispatchState, c *instructions.RunCommand, proxy *llb.ProxyE
626 626
 		args = withShell(d.image, args)
627 627
 	}
628 628
 	env := d.state.Env()
629
-	opt := []llb.RunOption{llb.Args(args)}
630
-	for _, arg := range d.buildArgs {
631
-		if arg.Value != nil {
632
-			env = append(env, fmt.Sprintf("%s=%s", arg.Key, arg.ValueString()))
633
-			opt = append(opt, llb.AddEnv(arg.Key, arg.ValueString()))
634
-		}
635
-	}
636
-	opt = append(opt, dfCmd(c))
629
+	opt := []llb.RunOption{llb.Args(args), dfCmd(c)}
637 630
 	if d.ignoreCache {
638 631
 		opt = append(opt, llb.IgnoreCache)
639 632
 	}
... ...
@@ -647,6 +640,11 @@ func dispatchRun(d *dispatchState, c *instructions.RunCommand, proxy *llb.ProxyE
647 647
 	}
648 648
 	opt = append(opt, runMounts...)
649 649
 
650
+	err = dispatchRunSecurity(d, c)
651
+	if err != nil {
652
+		return err
653
+	}
654
+
650 655
 	shlex := *dopt.shlex
651 656
 	shlex.RawQuotes = true
652 657
 	shlex.SkipUnsetEnv = true
... ...
@@ -656,7 +654,7 @@ func dispatchRun(d *dispatchState, c *instructions.RunCommand, proxy *llb.ProxyE
656 656
 		opt = append(opt, llb.AddExtraHost(h.Host, h.IP))
657 657
 	}
658 658
 	d.state = d.state.Run(opt...).Root()
659
-	return commitToHistory(&d.image, "RUN "+runCommandString(args, d.buildArgs), true, &d.state)
659
+	return commitToHistory(&d.image, "RUN "+runCommandString(args, d.buildArgs, shell.BuildEnvs(env)), true, &d.state)
660 660
 }
661 661
 
662 662
 func dispatchWorkdir(d *dispatchState, c *instructions.WorkdirCommand, commit bool, opt *dispatchOpt) error {
... ...
@@ -927,7 +925,7 @@ func dispatchHealthcheck(d *dispatchState, c *instructions.HealthCheckCommand) e
927 927
 func dispatchExpose(d *dispatchState, c *instructions.ExposeCommand, shlex *shell.Lex) error {
928 928
 	ports := []string{}
929 929
 	for _, p := range c.Ports {
930
-		ps, err := shlex.ProcessWordsWithMap(p, toEnvMap(d.buildArgs, d.image.Config.Env))
930
+		ps, err := shlex.ProcessWords(p, d.state.Env())
931 931
 		if err != nil {
932 932
 			return err
933 933
 		}
... ...
@@ -1000,6 +998,10 @@ func dispatchArg(d *dispatchState, c *instructions.ArgCommand, metaArgs []instru
1000 1000
 		}
1001 1001
 	}
1002 1002
 
1003
+	if buildArg.Value != nil {
1004
+		d.state = d.state.AddEnv(buildArg.Key, *buildArg.Value)
1005
+	}
1006
+
1003 1007
 	d.buildArgs = append(d.buildArgs, buildArg)
1004 1008
 	return commitToHistory(&d.image, commitStr, false, nil)
1005 1009
 }
... ...
@@ -1065,21 +1067,6 @@ func setKVValue(kvpo instructions.KeyValuePairOptional, values map[string]string
1065 1065
 	return kvpo
1066 1066
 }
1067 1067
 
1068
-func toEnvMap(args []instructions.KeyValuePairOptional, env []string) map[string]string {
1069
-	m := shell.BuildEnvs(env)
1070
-
1071
-	for _, arg := range args {
1072
-		// If key already exists, keep previous value.
1073
-		if _, ok := m[arg.Key]; ok {
1074
-			continue
1075
-		}
1076
-		if arg.Value != nil {
1077
-			m[arg.Key] = arg.ValueString()
1078
-		}
1079
-	}
1080
-	return m
1081
-}
1082
-
1083 1068
 func dfCmd(cmd interface{}) llb.ConstraintsOpt {
1084 1069
 	// TODO: add fmt.Stringer to instructions.Command to remove interface{}
1085 1070
 	var cmdStr string
... ...
@@ -1094,10 +1081,14 @@ func dfCmd(cmd interface{}) llb.ConstraintsOpt {
1094 1094
 	})
1095 1095
 }
1096 1096
 
1097
-func runCommandString(args []string, buildArgs []instructions.KeyValuePairOptional) string {
1097
+func runCommandString(args []string, buildArgs []instructions.KeyValuePairOptional, envMap map[string]string) string {
1098 1098
 	var tmpBuildEnv []string
1099 1099
 	for _, arg := range buildArgs {
1100
-		tmpBuildEnv = append(tmpBuildEnv, arg.Key+"="+arg.ValueString())
1100
+		v, ok := envMap[arg.Key]
1101
+		if !ok {
1102
+			v = arg.ValueString()
1103
+		}
1104
+		tmpBuildEnv = append(tmpBuildEnv, arg.Key+"="+v)
1101 1105
 	}
1102 1106
 	if len(tmpBuildEnv) > 0 {
1103 1107
 		tmpBuildEnv = append([]string{fmt.Sprintf("|%d", len(tmpBuildEnv))}, tmpBuildEnv...)
1104 1108
new file mode 100644
... ...
@@ -0,0 +1,11 @@
0
+// +build !dfrunsecurity
1
+
2
+package dockerfile2llb
3
+
4
+import (
5
+	"github.com/moby/buildkit/frontend/dockerfile/instructions"
6
+)
7
+
8
+func dispatchRunSecurity(d *dispatchState, c *instructions.RunCommand) error {
9
+	return nil
10
+}
... ...
@@ -124,6 +124,9 @@ func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*
124 124
 			if mount.CacheSharing == instructions.MountSharingLocked {
125 125
 				sharing = llb.CacheMountLocked
126 126
 			}
127
+			if mount.CacheID == "" {
128
+				mount.CacheID = path.Clean(mount.Target)
129
+			}
127 130
 			mountOpts = append(mountOpts, llb.AsPersistentCacheDir(opt.cacheIDNamespace+"/"+mount.CacheID, sharing))
128 131
 		}
129 132
 		target := mount.Target
... ...
@@ -144,7 +147,9 @@ func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*
144 144
 
145 145
 		out = append(out, llb.AddMount(target, st, mountOpts...))
146 146
 
147
-		d.ctxPaths[path.Join("/", filepath.ToSlash(mount.Source))] = struct{}{}
147
+		if mount.From == "" {
148
+			d.ctxPaths[path.Join("/", filepath.ToSlash(mount.Source))] = struct{}{}
149
+		}
148 150
 	}
149 151
 	return out, nil
150 152
 }
151 153
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+// +build dfrunsecurity
1
+
2
+package dockerfile2llb
3
+
4
+import (
5
+	"github.com/pkg/errors"
6
+
7
+	"github.com/moby/buildkit/frontend/dockerfile/instructions"
8
+	"github.com/moby/buildkit/solver/pb"
9
+)
10
+
11
+func dispatchRunSecurity(d *dispatchState, c *instructions.RunCommand) error {
12
+	security := instructions.GetSecurity(c)
13
+
14
+	for _, sec := range security {
15
+		switch sec {
16
+		case instructions.SecurityInsecure:
17
+			d.state = d.state.Security(pb.SecurityMode_INSECURE)
18
+		case instructions.SecuritySandbox:
19
+			d.state = d.state.Security(pb.SecurityMode_SANDBOX)
20
+		default:
21
+			return errors.Errorf("unsupported security mode %q", sec)
22
+		}
23
+	}
24
+
25
+	return nil
26
+}
... ...
@@ -142,6 +142,8 @@ func parseMount(value string) (*Mount, error) {
142 142
 				if m.Type == "secret" || m.Type == "ssh" {
143 143
 					m.Required = true
144 144
 					continue
145
+				} else {
146
+					return nil, errors.Errorf("unexpected key '%s' for mount type '%s'", key, m.Type)
145 147
 				}
146 148
 			}
147 149
 		}
... ...
@@ -176,6 +178,16 @@ func parseMount(value string) (*Mount, error) {
176 176
 			}
177 177
 			m.ReadOnly = !rw
178 178
 			roAuto = false
179
+		case "required":
180
+			if m.Type == "secret" || m.Type == "ssh" {
181
+				v, err := strconv.ParseBool(value)
182
+				if err != nil {
183
+					return nil, errors.Errorf("invalid value for %s: %s", key, value)
184
+				}
185
+				m.Required = v
186
+			} else {
187
+				return nil, errors.Errorf("unexpected key '%s' for mount type '%s'", key, m.Type)
188
+			}
179 189
 		case "id":
180 190
 			m.CacheID = value
181 191
 		case "sharing":
182 192
new file mode 100644
... ...
@@ -0,0 +1,83 @@
0
+// +build dfrunsecurity
1
+
2
+package instructions
3
+
4
+import (
5
+	"encoding/csv"
6
+	"strings"
7
+
8
+	"github.com/pkg/errors"
9
+)
10
+
11
+const (
12
+	SecurityInsecure = "insecure"
13
+	SecuritySandbox  = "sandbox"
14
+)
15
+
16
+var allowedSecurity = map[string]struct{}{
17
+	SecurityInsecure: {},
18
+	SecuritySandbox:  {},
19
+}
20
+
21
+func isValidSecurity(value string) bool {
22
+	_, ok := allowedSecurity[value]
23
+	return ok
24
+}
25
+
26
+type securityKeyT string
27
+
28
+var securityKey = securityKeyT("dockerfile/run/security")
29
+
30
+func init() {
31
+	parseRunPreHooks = append(parseRunPreHooks, runSecurityPreHook)
32
+	parseRunPostHooks = append(parseRunPostHooks, runSecurityPostHook)
33
+}
34
+
35
+func runSecurityPreHook(cmd *RunCommand, req parseRequest) error {
36
+	st := &securityState{}
37
+	st.flag = req.flags.AddStrings("security")
38
+	cmd.setExternalValue(securityKey, st)
39
+	return nil
40
+}
41
+
42
+func runSecurityPostHook(cmd *RunCommand, req parseRequest) error {
43
+	st := getSecurityState(cmd)
44
+	if st == nil {
45
+		return errors.Errorf("no security state")
46
+	}
47
+
48
+	for _, value := range st.flag.StringValues {
49
+		csvReader := csv.NewReader(strings.NewReader(value))
50
+		fields, err := csvReader.Read()
51
+		if err != nil {
52
+			return errors.Wrap(err, "failed to parse csv security")
53
+		}
54
+
55
+		for _, field := range fields {
56
+			if !isValidSecurity(field) {
57
+				return errors.Errorf("security %q is not valid", field)
58
+			}
59
+
60
+			st.security = append(st.security, field)
61
+		}
62
+	}
63
+
64
+	return nil
65
+}
66
+
67
+func getSecurityState(cmd *RunCommand) *securityState {
68
+	v := cmd.getExternalValue(securityKey)
69
+	if v == nil {
70
+		return nil
71
+	}
72
+	return v.(*securityState)
73
+}
74
+
75
+func GetSecurity(cmd *RunCommand) []string {
76
+	return getSecurityState(cmd).security
77
+}
78
+
79
+type securityState struct {
80
+	flag     *Flag
81
+	security []string
82
+}
... ...
@@ -417,10 +417,7 @@ func BuildEnvs(env []string) map[string]string {
417 417
 			k := e[:i]
418 418
 			v := e[i+1:]
419 419
 
420
-			// If key already exists, keep previous value.
421
-			if _, ok := envs[k]; ok {
422
-				continue
423
-			}
420
+			// overwrite value if key already exists
424 421
 			envs[k] = v
425 422
 		}
426 423
 	}
... ...
@@ -9,12 +9,14 @@ require (
9 9
 	github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58 // indirect
10 10
 	github.com/containerd/cgroups v0.0.0-20190226200435-dbea6f2bd416 // indirect
11 11
 	github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50
12
-	github.com/containerd/containerd v1.3.0-0.20190426060238-3a3f0aac8819
12
+	github.com/containerd/containerd v1.3.0-0.20190507210959-7c1e88399ec0
13 13
 	github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc
14 14
 	github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260 // indirect
15
+	github.com/containerd/go-cni v0.0.0-20190610170741-5a4663dad645
15 16
 	github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3
16 17
 	github.com/containerd/ttrpc v0.0.0-20190411181408-699c4e40d1e7 // indirect
17 18
 	github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd // indirect
19
+	github.com/containernetworking/cni v0.6.1-0.20180218032124-142cde0c766c // indirect
18 20
 	github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
19 21
 	github.com/docker/cli v0.0.0-20190321234815-f40f9c240ab0
20 22
 	github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible
... ...
@@ -41,7 +43,7 @@ require (
41 41
 	github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c
42 42
 	github.com/opencontainers/go-digest v1.0.0-rc1
43 43
 	github.com/opencontainers/image-spec v1.0.1
44
-	github.com/opencontainers/runc v1.0.1-0.20190307181833-2b18fe1d885e
44
+	github.com/opencontainers/runc v1.0.0-rc8
45 45
 	github.com/opencontainers/runtime-spec v0.0.0-20180909173843-eba862dc2470
46 46
 	github.com/opentracing-contrib/go-stdlib v0.0.0-20171029140428-b1a47cfbdd75
47 47
 	github.com/opentracing/opentracing-go v0.0.0-20171003133519-1361b9cd60be
... ...
@@ -40,6 +40,12 @@ type streamWriterCloser struct {
40 40
 
41 41
 func (wc *streamWriterCloser) Write(dt []byte) (int, error) {
42 42
 	if err := wc.ClientStream.SendMsg(&BytesMessage{Data: dt}); err != nil {
43
+		// SendMsg return EOF on remote errors
44
+		if errors.Cause(err) == io.EOF {
45
+			if err := errors.WithStack(wc.ClientStream.RecvMsg(struct{}{})); err != nil {
46
+				return 0, err
47
+			}
48
+		}
43 49
 		return 0, errors.WithStack(err)
44 50
 	}
45 51
 	return len(dt), nil
... ...
@@ -18,11 +18,12 @@ import (
18 18
 )
19 19
 
20 20
 const (
21
-	keyOverrideExcludes = "override-excludes"
22
-	keyIncludePatterns  = "include-patterns"
23
-	keyExcludePatterns  = "exclude-patterns"
24
-	keyFollowPaths      = "followpaths"
25
-	keyDirName          = "dir-name"
21
+	keyOverrideExcludes   = "override-excludes"
22
+	keyIncludePatterns    = "include-patterns"
23
+	keyExcludePatterns    = "exclude-patterns"
24
+	keyFollowPaths        = "followpaths"
25
+	keyDirName            = "dir-name"
26
+	keyExporterMetaPrefix = "exporter-md-"
26 27
 )
27 28
 
28 29
 type fsSyncProvider struct {
... ...
@@ -238,16 +239,16 @@ func NewFSSyncTargetDir(outdir string) session.Attachable {
238 238
 }
239 239
 
240 240
 // NewFSSyncTarget allows writing into an io.WriteCloser
241
-func NewFSSyncTarget(w io.WriteCloser) session.Attachable {
241
+func NewFSSyncTarget(f func(map[string]string) (io.WriteCloser, error)) session.Attachable {
242 242
 	p := &fsSyncTarget{
243
-		outfile: w,
243
+		f: f,
244 244
 	}
245 245
 	return p
246 246
 }
247 247
 
248 248
 type fsSyncTarget struct {
249
-	outdir  string
250
-	outfile io.WriteCloser
249
+	outdir string
250
+	f      func(map[string]string) (io.WriteCloser, error)
251 251
 }
252 252
 
253 253
 func (sp *fsSyncTarget) Register(server *grpc.Server) {
... ...
@@ -258,11 +259,26 @@ func (sp *fsSyncTarget) DiffCopy(stream FileSend_DiffCopyServer) error {
258 258
 	if sp.outdir != "" {
259 259
 		return syncTargetDiffCopy(stream, sp.outdir)
260 260
 	}
261
-	if sp.outfile == nil {
261
+
262
+	if sp.f == nil {
262 263
 		return errors.New("empty outfile and outdir")
263 264
 	}
264
-	defer sp.outfile.Close()
265
-	return writeTargetFile(stream, sp.outfile)
265
+	opts, _ := metadata.FromIncomingContext(stream.Context()) // if no metadata continue with empty object
266
+	md := map[string]string{}
267
+	for k, v := range opts {
268
+		if strings.HasPrefix(k, keyExporterMetaPrefix) {
269
+			md[strings.TrimPrefix(k, keyExporterMetaPrefix)] = strings.Join(v, ",")
270
+		}
271
+	}
272
+	wc, err := sp.f(md)
273
+	if err != nil {
274
+		return err
275
+	}
276
+	if wc == nil {
277
+		return status.Errorf(codes.AlreadyExists, "target already exists")
278
+	}
279
+	defer wc.Close()
280
+	return writeTargetFile(stream, wc)
266 281
 }
267 282
 
268 283
 func CopyToCaller(ctx context.Context, fs fsutil.FS, c session.Caller, progress func(int, bool)) error {
... ...
@@ -281,7 +297,7 @@ func CopyToCaller(ctx context.Context, fs fsutil.FS, c session.Caller, progress
281 281
 	return sendDiffCopy(cc, fs, progress)
282 282
 }
283 283
 
284
-func CopyFileWriter(ctx context.Context, c session.Caller) (io.WriteCloser, error) {
284
+func CopyFileWriter(ctx context.Context, md map[string]string, c session.Caller) (io.WriteCloser, error) {
285 285
 	method := session.MethodURL(_FileSend_serviceDesc.ServiceName, "diffcopy")
286 286
 	if !c.Supports(method) {
287 287
 		return nil, errors.Errorf("method %s not supported by the client", method)
... ...
@@ -289,6 +305,13 @@ func CopyFileWriter(ctx context.Context, c session.Caller) (io.WriteCloser, erro
289 289
 
290 290
 	client := NewFileSendClient(c.Conn())
291 291
 
292
+	opts := make(map[string][]string, len(md))
293
+	for k, v := range md {
294
+		opts[keyExporterMetaPrefix+k] = []string{v}
295
+	}
296
+
297
+	ctx = metadata.NewOutgoingContext(ctx, opts)
298
+
292 299
 	cc, err := client.DiffCopy(ctx)
293 300
 	if err != nil {
294 301
 		return nil, errors.WithStack(err)
... ...
@@ -29,6 +29,7 @@ type llbBridge struct {
29 29
 	builder                   solver.Builder
30 30
 	frontends                 map[string]frontend.Frontend
31 31
 	resolveWorker             func() (worker.Worker, error)
32
+	eachWorker                func(func(worker.Worker) error) error
32 33
 	resolveCacheImporterFuncs map[string]remotecache.ResolveCacheImporterFunc
33 34
 	cms                       map[string]solver.CacheManager
34 35
 	cmsMu                     sync.Mutex
... ...
@@ -91,11 +92,25 @@ func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res *
91 91
 		if err != nil {
92 92
 			return nil, err
93 93
 		}
94
+		dpc := &detectPrunedCacheID{}
94 95
 
95
-		edge, err := Load(req.Definition, ValidateEntitlements(ent), WithCacheSources(cms), RuntimePlatforms(b.platforms), WithValidateCaps())
96
+		edge, err := Load(req.Definition, dpc.Load, ValidateEntitlements(ent), WithCacheSources(cms), RuntimePlatforms(b.platforms), WithValidateCaps())
96 97
 		if err != nil {
97 98
 			return nil, errors.Wrap(err, "failed to load LLB")
98 99
 		}
100
+
101
+		if len(dpc.ids) > 0 {
102
+			ids := make([]string, 0, len(dpc.ids))
103
+			for id := range dpc.ids {
104
+				ids = append(ids, id)
105
+			}
106
+			if err := b.eachWorker(func(w worker.Worker) error {
107
+				return w.PruneCacheMounts(ctx, ids)
108
+			}); err != nil {
109
+				return nil, err
110
+			}
111
+		}
112
+
99 113
 		ref, err := b.builder.Build(ctx, edge)
100 114
 		if err != nil {
101 115
 			return nil, errors.Wrap(err, "failed to build LLB")
... ...
@@ -221,11 +221,13 @@ func (e *execOp) getMountDeps() ([]dep, error) {
221 221
 }
222 222
 
223 223
 func (e *execOp) getRefCacheDir(ctx context.Context, ref cache.ImmutableRef, id string, m *pb.Mount, sharing pb.CacheSharingOpt) (mref cache.MutableRef, err error) {
224
-
225 224
 	key := "cache-dir:" + id
226 225
 	if ref != nil {
227 226
 		key += ":" + ref.ID()
228 227
 	}
228
+	mu := CacheMountsLocker()
229
+	mu.Lock()
230
+	defer mu.Unlock()
229 231
 
230 232
 	if ref, ok := e.cacheMounts[key]; ok {
231 233
 		return ref.clone(), nil
... ...
@@ -792,10 +794,17 @@ type cacheRefs struct {
792 792
 	shares map[string]*cacheRefShare
793 793
 }
794 794
 
795
-func (r *cacheRefs) get(key string, fn func() (cache.MutableRef, error)) (cache.MutableRef, error) {
796
-	r.mu.Lock()
797
-	defer r.mu.Unlock()
795
+// ClearActiveCacheMounts clears shared cache mounts currently in use.
796
+// Caller needs to hold CacheMountsLocker before calling
797
+func ClearActiveCacheMounts() {
798
+	sharedCacheRefs.shares = nil
799
+}
800
+
801
+func CacheMountsLocker() sync.Locker {
802
+	return &sharedCacheRefs.mu
803
+}
798 804
 
805
+func (r *cacheRefs) get(key string, fn func() (cache.MutableRef, error)) (cache.MutableRef, error) {
799 806
 	if r.shares == nil {
800 807
 		r.shares = map[string]*cacheRefShare{}
801 808
 	}
... ...
@@ -39,6 +39,7 @@ type Solver struct {
39 39
 	workerController          *worker.Controller
40 40
 	solver                    *solver.Solver
41 41
 	resolveWorker             ResolveWorkerFunc
42
+	eachWorker                func(func(worker.Worker) error) error
42 43
 	frontends                 map[string]frontend.Frontend
43 44
 	resolveCacheImporterFuncs map[string]remotecache.ResolveCacheImporterFunc
44 45
 	platforms                 []specs.Platform
... ...
@@ -51,6 +52,7 @@ func New(wc *worker.Controller, f map[string]frontend.Frontend, cache solver.Cac
51 51
 	s := &Solver{
52 52
 		workerController:          wc,
53 53
 		resolveWorker:             defaultResolver(wc),
54
+		eachWorker:                allWorkers(wc),
54 55
 		frontends:                 f,
55 56
 		resolveCacheImporterFuncs: resolveCI,
56 57
 		gatewayForwarder:          gatewayForwarder,
... ...
@@ -87,6 +89,7 @@ func (s *Solver) Bridge(b solver.Builder) frontend.FrontendLLBBridge {
87 87
 		builder:                   b,
88 88
 		frontends:                 s.frontends,
89 89
 		resolveWorker:             s.resolveWorker,
90
+		eachWorker:                s.eachWorker,
90 91
 		resolveCacheImporterFuncs: s.resolveCacheImporterFuncs,
91 92
 		cms:                       map[string]solver.CacheManager{},
92 93
 		platforms:                 s.platforms,
... ...
@@ -285,6 +288,20 @@ func defaultResolver(wc *worker.Controller) ResolveWorkerFunc {
285 285
 		return wc.GetDefault()
286 286
 	}
287 287
 }
288
+func allWorkers(wc *worker.Controller) func(func(w worker.Worker) error) error {
289
+	return func(f func(worker.Worker) error) error {
290
+		all, err := wc.List()
291
+		if err != nil {
292
+			return err
293
+		}
294
+		for _, w := range all {
295
+			if err := f(w); err != nil {
296
+				return err
297
+			}
298
+		}
299
+		return nil
300
+	}
301
+}
288 302
 
289 303
 func oneOffProgress(ctx context.Context, id string) func(err error) error {
290 304
 	pw, _, _ := progress.FromContext(ctx)
... ...
@@ -131,6 +131,34 @@ func ValidateEntitlements(ent entitlements.Set) LoadOpt {
131 131
 	}
132 132
 }
133 133
 
134
+type detectPrunedCacheID struct {
135
+	ids map[string]struct{}
136
+}
137
+
138
+func (dpc *detectPrunedCacheID) Load(op *pb.Op, md *pb.OpMetadata, opt *solver.VertexOptions) error {
139
+	if md == nil || !md.IgnoreCache {
140
+		return nil
141
+	}
142
+	switch op := op.Op.(type) {
143
+	case *pb.Op_Exec:
144
+		for _, m := range op.Exec.GetMounts() {
145
+			if m.MountType == pb.MountType_CACHE {
146
+				if m.CacheOpt != nil {
147
+					id := m.CacheOpt.ID
148
+					if id == "" {
149
+						id = m.Dest
150
+					}
151
+					if dpc.ids == nil {
152
+						dpc.ids = map[string]struct{}{}
153
+					}
154
+					dpc.ids[id] = struct{}{}
155
+				}
156
+			}
157
+		}
158
+	}
159
+	return nil
160
+}
161
+
134 162
 func Load(def *pb.Definition, opts ...LoadOpt) (solver.Edge, error) {
135 163
 	return loadLLB(def, func(dgst digest.Digest, pbOp *pb.Op, load func(digest.Digest) (solver.Vertex, error)) (solver.Vertex, error) {
136 164
 		opMetadata := def.Metadata[dgst]
... ...
@@ -40,9 +40,9 @@ func dup(res Result) (Result, Result) {
40 40
 }
41 41
 
42 42
 type splitResult struct {
43
-	Result
44 43
 	released int64
45 44
 	sem      *int64
45
+	Result
46 46
 }
47 47
 
48 48
 func (r *splitResult) Release(ctx context.Context) error {
49 49
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+// +build !386
1
+
2
+package binfmt_misc
3
+
4
+// This file is generated by running make inside the binfmt_misc package.
5
+// Do not edit manually.
6
+
7
+const Binary386 = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xec\xd8\x31\x6e\xc2\x30\x14\x06\xe0\xdf\x8d\xdb\x26\x6a\x07\x1f\x20\xaa\x3a\x74\xe8\x64\xb5\x52\xae\x00\x2c\x88\x8d\x03\x80\x14\xc1\x94\x44\x89\x91\x60\x22\x47\x60\xe0\x20\x8c\x8c\x5c\x80\x13\x70\x19\xf4\xe2\x67\x91\x81\x25\xfb\xfb\xa4\x5f\x16\xcf\xe6\x29\xeb\x7b\xfb\xd1\x74\xac\x94\x42\xf0\x82\x08\xdd\xaf\x83\x8e\x33\x00\x7f\xc6\xd7\x33\x7c\x23\xc2\x2f\x74\xb8\x27\xad\x8e\x29\x27\x00\x14\x4d\x35\x03\x7f\x6f\x7c\x0f\x4a\x02\x80\xf2\xca\x75\x7a\x77\xa4\xb4\x3a\xa6\xa4\x00\x52\xfe\x7f\xc8\x27\xbf\x9f\xcc\xe6\xd4\xef\x42\xb5\xc7\x57\x0a\x21\x84\x10\x42\x08\x21\x84\x10\x62\x88\x33\x0d\xd5\xff\xb7\x6b\x0b\xdb\xac\x1b\x57\xbb\xc5\x12\xb6\x28\x5d\x6e\x57\xc5\xc6\x56\x75\x59\xe5\xb5\xdb\xc1\xba\x7c\xeb\x86\xf4\xfd\x00\xf0\xde\xed\x13\x78\xce\xe7\x19\x3f\xd0\x7c\x7e\xf1\x5c\xff\xc6\x3b\x07\x18\xbf\x2b\x08\x54\xef\x8c\x7a\xf5\xc4\x00\x3f\x4f\xde\xdd\x03\x00\x00\xff\xff\x8d\xf7\xd2\x72\xd0\x10\x00\x00"
0 8
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// +build !386
1
+
2
+package binfmt_misc
3
+
4
+func i386Supported() error {
5
+	return check(Binary386)
6
+}
0 7
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// +build 386
1
+
2
+package binfmt_misc
3
+
4
+func i386Supported() error {
5
+	return nil
6
+}
... ...
@@ -24,6 +24,15 @@ func SupportedPlatforms() []string {
24 24
 		if p := "linux/riscv64"; def != p && riscv64Supported() == nil {
25 25
 			arr = append(arr, p)
26 26
 		}
27
+		if p := "linux/ppc64le"; def != p && ppc64leSupported() == nil {
28
+			arr = append(arr, p)
29
+		}
30
+		if p := "linux/s390x"; def != p && s390xSupported() == nil {
31
+			arr = append(arr, p)
32
+		}
33
+		if p := "linux/386"; def != p && i386Supported() == nil {
34
+			arr = append(arr, p)
35
+		}
27 36
 		if !strings.HasPrefix(def, "linux/arm/") && armSupported() == nil {
28 37
 			arr = append(arr, "linux/arm/v7", "linux/arm/v6")
29 38
 		} else if def == "linux/arm/v7" {
... ...
@@ -55,6 +64,21 @@ func WarnIfUnsupported(pfs []string) {
55 55
 					printPlatfromWarning(p, err)
56 56
 				}
57 57
 			}
58
+			if p == "linux/ppc64le" {
59
+				if err := ppc64leSupported(); err != nil {
60
+					printPlatfromWarning(p, err)
61
+				}
62
+			}
63
+			if p == "linux/s390x" {
64
+				if err := s390xSupported(); err != nil {
65
+					printPlatfromWarning(p, err)
66
+				}
67
+			}
68
+			if p == "linux/386" {
69
+				if err := i386Supported(); err != nil {
70
+					printPlatfromWarning(p, err)
71
+				}
72
+			}
58 73
 			if strings.HasPrefix(p, "linux/arm/v6") || strings.HasPrefix(p, "linux/arm/v7") {
59 74
 				if err := armSupported(); err != nil {
60 75
 					printPlatfromWarning(p, err)
61 76
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+// +build !ppc64le
1
+
2
+package binfmt_misc
3
+
4
+// This file is generated by running make inside the binfmt_misc package.
5
+// Do not edit manually.
6
+
7
+const Binaryppc64le = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xaa\x77\xf5\x71\x63\x62\x64\x64\x80\x01\x26\x06\x51\x06\x10\xaf\x82\x81\x41\x00\xc4\x77\x80\x8a\x2f\x80\xcb\x83\xc4\x2c\x18\x18\x19\x1c\x18\x58\x18\x98\xc1\x6a\x59\x19\x50\x80\x00\x32\xdd\x02\xe5\xb4\xc0\xa5\x19\x61\xa4\x05\x03\x43\x82\x05\x13\x03\x83\x0b\x83\x5e\x71\x46\x71\x49\x51\x49\x62\x12\x83\x5e\x49\x6a\x45\x09\x83\x5e\x6a\x46\x7c\x5a\x51\x62\x6e\x2a\x03\xc5\x80\x1b\x6a\x23\x1b\x94\x0f\xf3\x57\x05\x94\xcf\x83\xa6\x9e\x03\x8d\x2f\x08\xd5\xcf\x84\xf0\x87\x00\xaa\x7f\x50\x01\x0b\x1a\x1f\xa4\x97\x19\x8b\x3a\x98\x7e\x69\x2c\xea\x91\x01\x20\x00\x00\xff\xff\xce\xf7\x15\x75\xa0\x01\x00\x00"
0 8
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// +build !ppc64le
1
+
2
+package binfmt_misc
3
+
4
+func ppc64leSupported() error {
5
+	return check(Binaryppc64le)
6
+}
0 7
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// +build ppc64le
1
+
2
+package binfmt_misc
3
+
4
+func ppc64leSupported() error {
5
+	return nil
6
+}
0 7
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+// +build !s390x
1
+
2
+package binfmt_misc
3
+
4
+// This file is generated by running make inside the binfmt_misc package.
5
+// Do not edit manually.
6
+
7
+const Binarys390x = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xaa\x77\xf5\x71\x63\x62\x62\x64\x80\x03\x26\x06\x31\x06\x06\x06\xb0\x00\x23\x03\x43\x05\x54\xd4\x01\x4a\xcf\x80\xf2\x2c\x18\x18\x19\x1c\x18\x98\x19\x98\xa0\x6a\x59\x19\x90\x00\x23\x1a\xcd\xc0\xc0\xd0\x80\x4a\x0b\x30\x2c\xd7\x64\x60\xe0\x62\x64\x67\x67\xd0\x2b\xce\x28\x2e\x29\x2a\x49\x4c\x62\xd0\x2b\x49\xad\x28\x61\xa0\x1e\xe0\x46\x72\x02\x1b\x9a\x7f\x60\x34\x07\x9a\x1e\x16\x34\x6f\x30\xe3\x30\x1b\xe6\x1f\x41\x34\x71\xb8\x97\x01\x01\x00\x00\xff\xff\x0c\x76\x9a\xe1\x58\x01\x00\x00"
0 8
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// +build !s390x
1
+
2
+package binfmt_misc
3
+
4
+func s390xSupported() error {
5
+	return check(Binarys390x)
6
+}
0 7
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// +build s390x
1
+
2
+package binfmt_misc
3
+
4
+func s390xSupported() error {
5
+	return nil
6
+}
... ...
@@ -72,16 +72,18 @@ func (g *Group) do(ctx context.Context, key string, fn func(ctx context.Context)
72 72
 		g.mu.Lock()
73 73
 		delete(g.m, key)
74 74
 		g.mu.Unlock()
75
+		close(c.cleaned)
75 76
 	}()
76 77
 	g.mu.Unlock()
77 78
 	return c.wait(ctx)
78 79
 }
79 80
 
80 81
 type call struct {
81
-	mu     sync.Mutex
82
-	result interface{}
83
-	err    error
84
-	ready  chan struct{}
82
+	mu      sync.Mutex
83
+	result  interface{}
84
+	err     error
85
+	ready   chan struct{}
86
+	cleaned chan struct{}
85 87
 
86 88
 	ctx  *sharedContext
87 89
 	ctxs []context.Context
... ...
@@ -97,6 +99,7 @@ func newCall(fn func(ctx context.Context) (interface{}, error)) *call {
97 97
 	c := &call{
98 98
 		fn:            fn,
99 99
 		ready:         make(chan struct{}),
100
+		cleaned:       make(chan struct{}),
100 101
 		progressState: newProgressState(),
101 102
 	}
102 103
 	ctx := newContext(c) // newSharedContext
... ...
@@ -127,6 +130,7 @@ func (c *call) wait(ctx context.Context) (v interface{}, err error) {
127 127
 	select {
128 128
 	case <-c.ready: // could return if no error
129 129
 		c.mu.Unlock()
130
+		<-c.cleaned
130 131
 		return nil, errRetry
131 132
 	default:
132 133
 	}
... ...
@@ -3,20 +3,9 @@ package network
3 3
 import (
4 4
 	"io"
5 5
 
6
-	"github.com/moby/buildkit/solver/pb"
7 6
 	specs "github.com/opencontainers/runtime-spec/specs-go"
8 7
 )
9 8
 
10
-// Default returns the default network provider set
11
-func Default() map[pb.NetMode]Provider {
12
-	return map[pb.NetMode]Provider{
13
-		// FIXME: still uses host if no provider configured
14
-		pb.NetMode_UNSET: NewHostProvider(),
15
-		pb.NetMode_HOST:  NewHostProvider(),
16
-		pb.NetMode_NONE:  NewNoneProvider(),
17
-	}
18
-}
19
-
20 9
 // Provider interface for Network
21 10
 type Provider interface {
22 11
 	New() (Namespace, error)
... ...
@@ -28,10 +17,3 @@ type Namespace interface {
28 28
 	// Set the namespace on the spec
29 29
 	Set(*specs.Spec)
30 30
 }
31
-
32
-// NetworkOpts hold network options
33
-type NetworkOpts struct {
34
-	Type          string
35
-	CNIConfigPath string
36
-	CNIPluginPath string
37
-}
... ...
@@ -33,6 +33,7 @@ type Worker interface {
33 33
 	Prune(ctx context.Context, ch chan client.UsageInfo, opt ...client.PruneInfo) error
34 34
 	GetRemote(ctx context.Context, ref cache.ImmutableRef, createIfNeeded bool) (*solver.Remote, error)
35 35
 	FromRemote(ctx context.Context, remote *solver.Remote) (cache.ImmutableRef, error)
36
+	PruneCacheMounts(ctx context.Context, ids []string) error
36 37
 }
37 38
 
38 39
 // Pre-defined label keys