Browse code

builder: vendor buildkit to 39404586a50d1b9d0fb1c578cf0f4de7bdb7afe5

Signed-off-by: Tibor Vass <tibor@docker.com>

Tibor Vass authored on 2018/09/22 05:43:26
Showing 49 changed files
... ...
@@ -22,7 +22,7 @@ import (
22 22
 	"github.com/moby/buildkit/frontend/gateway"
23 23
 	"github.com/moby/buildkit/frontend/gateway/forwarder"
24 24
 	"github.com/moby/buildkit/snapshot/blobmapping"
25
-	"github.com/moby/buildkit/solver/boltdbcachestorage"
25
+	"github.com/moby/buildkit/solver/bboltcachestorage"
26 26
 	"github.com/moby/buildkit/worker"
27 27
 	"github.com/pkg/errors"
28 28
 )
... ...
@@ -122,7 +122,7 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
122 122
 		return nil, err
123 123
 	}
124 124
 
125
-	cacheStorage, err := boltdbcachestorage.NewStore(filepath.Join(opt.Root, "cache.db"))
125
+	cacheStorage, err := bboltcachestorage.NewStore(filepath.Join(opt.Root, "cache.db"))
126 126
 	if err != nil {
127 127
 		return nil, err
128 128
 	}
... ...
@@ -137,8 +137,12 @@ func (w *Worker) GCPolicy() []client.PruneInfo {
137 137
 }
138 138
 
139 139
 // LoadRef loads a reference by ID
140
-func (w *Worker) LoadRef(id string) (cache.ImmutableRef, error) {
141
-	return w.CacheManager.Get(context.TODO(), id)
140
+func (w *Worker) LoadRef(id string, hidden bool) (cache.ImmutableRef, error) {
141
+	var opts []cache.RefOption
142
+	if hidden {
143
+		opts = append(opts, cache.NoUpdateLastUsed)
144
+	}
145
+	return w.CacheManager.Get(context.TODO(), id, opts...)
142 146
 }
143 147
 
144 148
 // ResolveOp converts a LLB vertex into a LLB operation
... ...
@@ -26,7 +26,7 @@ github.com/imdario/mergo v0.3.6
26 26
 golang.org/x/sync 1d60e4601c6fd243af51cc01ddf169918a5407ca
27 27
 
28 28
 # buildkit
29
-github.com/moby/buildkit d88354f7856a1fafef6f23bc9c5a538c246f4023
29
+github.com/moby/buildkit 39404586a50d1b9d0fb1c578cf0f4de7bdb7afe5
30 30
 github.com/tonistiigi/fsutil b19464cd1b6a00773b4f2eb7acf9c30426f9df42
31 31
 github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
32 32
 github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
33 33
deleted file mode 100644
... ...
@@ -1,27 +0,0 @@
1
-package cache
2
-
3
-import (
4
-	"context"
5
-	"errors"
6
-	"time"
7
-)
8
-
9
-// GCPolicy defines policy for garbage collection
10
-type GCPolicy struct {
11
-	MaxSize         uint64
12
-	MaxKeepDuration time.Duration
13
-}
14
-
15
-// // CachePolicy defines policy for keeping a resource in cache
16
-// type CachePolicy struct {
17
-// 	Priority int
18
-// 	LastUsed time.Time
19
-// }
20
-//
21
-// func defaultCachePolicy() CachePolicy {
22
-// 	return CachePolicy{Priority: 10, LastUsed: time.Now()}
23
-// }
24
-
25
-func (cm *cacheManager) GC(ctx context.Context) error {
26
-	return errors.New("GC not implemented")
27
-}
... ...
@@ -25,7 +25,6 @@ var (
25 25
 
26 26
 type ManagerOpt struct {
27 27
 	Snapshotter     snapshot.SnapshotterBase
28
-	GCPolicy        GCPolicy
29 28
 	MetadataStore   *metadata.Store
30 29
 	PruneRefChecker ExternalRefCheckerFunc
31 30
 }
... ...
@@ -40,7 +39,6 @@ type Accessor interface {
40 40
 type Controller interface {
41 41
 	DiskUsage(ctx context.Context, info client.DiskUsageInfo) ([]*client.UsageInfo, error)
42 42
 	Prune(ctx context.Context, ch chan client.UsageInfo, info ...client.PruneInfo) error
43
-	GC(ctx context.Context) error
44 43
 }
45 44
 
46 45
 type Manager interface {
... ...
@@ -128,17 +126,24 @@ func (cm *cacheManager) get(ctx context.Context, id string, fromSnapshotter bool
128 128
 	rec.mu.Lock()
129 129
 	defer rec.mu.Unlock()
130 130
 
131
+	triggerUpdate := true
132
+	for _, o := range opts {
133
+		if o == NoUpdateLastUsed {
134
+			triggerUpdate = false
135
+		}
136
+	}
137
+
131 138
 	if rec.mutable {
132 139
 		if len(rec.refs) != 0 {
133 140
 			return nil, errors.Wrapf(ErrLocked, "%s is locked", id)
134 141
 		}
135 142
 		if rec.equalImmutable != nil {
136
-			return rec.equalImmutable.ref(), nil
143
+			return rec.equalImmutable.ref(triggerUpdate), nil
137 144
 		}
138
-		return rec.mref().commit(ctx)
145
+		return rec.mref(triggerUpdate).commit(ctx)
139 146
 	}
140 147
 
141
-	return rec.ref(), nil
148
+	return rec.ref(triggerUpdate), nil
142 149
 }
143 150
 
144 151
 // getRecord returns record for id. Requires manager lock.
... ...
@@ -166,8 +171,8 @@ func (cm *cacheManager) getRecord(ctx context.Context, id string, fromSnapshotte
166 166
 		rec := &cacheRecord{
167 167
 			mu:           &sync.Mutex{},
168 168
 			cm:           cm,
169
-			refs:         make(map[Mountable]struct{}),
170
-			parent:       mutable.Parent(),
169
+			refs:         make(map[ref]struct{}),
170
+			parent:       mutable.parentRef(false),
171 171
 			md:           md,
172 172
 			equalMutable: &mutableRef{cacheRecord: mutable},
173 173
 		}
... ...
@@ -183,7 +188,7 @@ func (cm *cacheManager) getRecord(ctx context.Context, id string, fromSnapshotte
183 183
 
184 184
 	var parent ImmutableRef
185 185
 	if info.Parent != "" {
186
-		parent, err = cm.get(ctx, info.Parent, fromSnapshotter, opts...)
186
+		parent, err = cm.get(ctx, info.Parent, fromSnapshotter, append(opts, NoUpdateLastUsed)...)
187 187
 		if err != nil {
188 188
 			return nil, err
189 189
 		}
... ...
@@ -198,7 +203,7 @@ func (cm *cacheManager) getRecord(ctx context.Context, id string, fromSnapshotte
198 198
 		mu:      &sync.Mutex{},
199 199
 		mutable: info.Kind != snapshots.KindCommitted,
200 200
 		cm:      cm,
201
-		refs:    make(map[Mountable]struct{}),
201
+		refs:    make(map[ref]struct{}),
202 202
 		parent:  parent,
203 203
 		md:      md,
204 204
 	}
... ...
@@ -229,7 +234,7 @@ func (cm *cacheManager) New(ctx context.Context, s ImmutableRef, opts ...RefOpti
229 229
 	var parentID string
230 230
 	if s != nil {
231 231
 		var err error
232
-		parent, err = cm.Get(ctx, s.ID())
232
+		parent, err = cm.Get(ctx, s.ID(), NoUpdateLastUsed)
233 233
 		if err != nil {
234 234
 			return nil, err
235 235
 		}
... ...
@@ -252,7 +257,7 @@ func (cm *cacheManager) New(ctx context.Context, s ImmutableRef, opts ...RefOpti
252 252
 		mu:      &sync.Mutex{},
253 253
 		mutable: true,
254 254
 		cm:      cm,
255
-		refs:    make(map[Mountable]struct{}),
255
+		refs:    make(map[ref]struct{}),
256 256
 		parent:  parent,
257 257
 		md:      md,
258 258
 	}
... ...
@@ -269,7 +274,7 @@ func (cm *cacheManager) New(ctx context.Context, s ImmutableRef, opts ...RefOpti
269 269
 
270 270
 	cm.records[id] = rec // TODO: save to db
271 271
 
272
-	return rec.mref(), nil
272
+	return rec.mref(true), nil
273 273
 }
274 274
 func (cm *cacheManager) GetMutable(ctx context.Context, id string) (MutableRef, error) {
275 275
 	cm.mu.Lock()
... ...
@@ -301,7 +306,7 @@ func (cm *cacheManager) GetMutable(ctx context.Context, id string) (MutableRef,
301 301
 		rec.equalImmutable = nil
302 302
 	}
303 303
 
304
-	return rec.mref(), nil
304
+	return rec.mref(true), nil
305 305
 }
306 306
 
307 307
 func (cm *cacheManager) Prune(ctx context.Context, ch chan client.UsageInfo, opts ...client.PruneInfo) error {
... ...
@@ -669,7 +674,7 @@ func (cm *cacheManager) DiskUsage(ctx context.Context, opt client.DiskUsageInfo)
669 669
 		if d.Size == sizeUnknown {
670 670
 			func(d *client.UsageInfo) {
671 671
 				eg.Go(func() error {
672
-					ref, err := cm.Get(ctx, d.ID)
672
+					ref, err := cm.Get(ctx, d.ID, NoUpdateLastUsed)
673 673
 					if err != nil {
674 674
 						d.Size = 0
675 675
 						return nil
... ...
@@ -700,7 +705,7 @@ func IsNotFound(err error) bool {
700 700
 	return errors.Cause(err) == errNotFound
701 701
 }
702 702
 
703
-type RefOption func(withMetadata) error
703
+type RefOption interface{}
704 704
 
705 705
 type cachePolicy int
706 706
 
... ...
@@ -713,6 +718,10 @@ type withMetadata interface {
713 713
 	Metadata() *metadata.StorageItem
714 714
 }
715 715
 
716
+type noUpdateLastUsed struct{}
717
+
718
+var NoUpdateLastUsed noUpdateLastUsed
719
+
716 720
 func HasCachePolicyRetain(m withMetadata) bool {
717 721
 	return getCachePolicy(m.Metadata()) == cachePolicyRetain
718 722
 }
... ...
@@ -750,8 +759,10 @@ func initializeMetadata(m withMetadata, opts ...RefOption) error {
750 750
 	}
751 751
 
752 752
 	for _, opt := range opts {
753
-		if err := opt(m); err != nil {
754
-			return err
753
+		if fn, ok := opt.(func(withMetadata) error); ok {
754
+			if err := fn(m); err != nil {
755
+				return err
756
+			}
755 757
 		}
756 758
 	}
757 759
 
... ...
@@ -3,10 +3,10 @@ package cache
3 3
 import (
4 4
 	"time"
5 5
 
6
-	"github.com/boltdb/bolt"
7 6
 	"github.com/moby/buildkit/cache/metadata"
8 7
 	"github.com/moby/buildkit/client"
9 8
 	"github.com/pkg/errors"
9
+	bolt "go.etcd.io/bbolt"
10 10
 )
11 11
 
12 12
 const sizeUnknown int64 = -1
... ...
@@ -6,9 +6,9 @@ import (
6 6
 	"strings"
7 7
 	"sync"
8 8
 
9
-	"github.com/boltdb/bolt"
10 9
 	"github.com/pkg/errors"
11 10
 	"github.com/sirupsen/logrus"
11
+	bolt "go.etcd.io/bbolt"
12 12
 )
13 13
 
14 14
 const (
... ...
@@ -38,12 +38,16 @@ type Mountable interface {
38 38
 	Mount(ctx context.Context, readonly bool) (snapshot.Mountable, error)
39 39
 }
40 40
 
41
+type ref interface {
42
+	updateLastUsed() bool
43
+}
44
+
41 45
 type cacheRecord struct {
42 46
 	cm *cacheManager
43 47
 	mu *sync.Mutex // the mutex is shared by records sharing data
44 48
 
45 49
 	mutable bool
46
-	refs    map[Mountable]struct{}
50
+	refs    map[ref]struct{}
47 51
 	parent  ImmutableRef
48 52
 	md      *metadata.StorageItem
49 53
 
... ...
@@ -61,15 +65,15 @@ type cacheRecord struct {
61 61
 }
62 62
 
63 63
 // hold ref lock before calling
64
-func (cr *cacheRecord) ref() *immutableRef {
65
-	ref := &immutableRef{cacheRecord: cr}
64
+func (cr *cacheRecord) ref(triggerLastUsed bool) *immutableRef {
65
+	ref := &immutableRef{cacheRecord: cr, triggerLastUsed: triggerLastUsed}
66 66
 	cr.refs[ref] = struct{}{}
67 67
 	return ref
68 68
 }
69 69
 
70 70
 // hold ref lock before calling
71
-func (cr *cacheRecord) mref() *mutableRef {
72
-	ref := &mutableRef{cacheRecord: cr}
71
+func (cr *cacheRecord) mref(triggerLastUsed bool) *mutableRef {
72
+	ref := &mutableRef{cacheRecord: cr, triggerLastUsed: triggerLastUsed}
73 73
 	cr.refs[ref] = struct{}{}
74 74
 	return ref
75 75
 }
... ...
@@ -116,13 +120,17 @@ func (cr *cacheRecord) Size(ctx context.Context) (int64, error) {
116 116
 }
117 117
 
118 118
 func (cr *cacheRecord) Parent() ImmutableRef {
119
+	return cr.parentRef(true)
120
+}
121
+
122
+func (cr *cacheRecord) parentRef(hidden bool) ImmutableRef {
119 123
 	if cr.parent == nil {
120 124
 		return nil
121 125
 	}
122 126
 	p := cr.parent.(*immutableRef)
123 127
 	p.mu.Lock()
124 128
 	defer p.mu.Unlock()
125
-	return p.ref()
129
+	return p.ref(hidden)
126 130
 }
127 131
 
128 132
 func (cr *cacheRecord) Mount(ctx context.Context, readonly bool) (snapshot.Mountable, error) {
... ...
@@ -188,15 +196,17 @@ func (cr *cacheRecord) ID() string {
188 188
 
189 189
 type immutableRef struct {
190 190
 	*cacheRecord
191
+	triggerLastUsed bool
191 192
 }
192 193
 
193 194
 type mutableRef struct {
194 195
 	*cacheRecord
196
+	triggerLastUsed bool
195 197
 }
196 198
 
197 199
 func (sr *immutableRef) Clone() ImmutableRef {
198 200
 	sr.mu.Lock()
199
-	ref := sr.ref()
201
+	ref := sr.ref(false)
200 202
 	sr.mu.Unlock()
201 203
 	return ref
202 204
 }
... ...
@@ -211,11 +221,33 @@ func (sr *immutableRef) Release(ctx context.Context) error {
211 211
 	return sr.release(ctx)
212 212
 }
213 213
 
214
+func (sr *immutableRef) updateLastUsed() bool {
215
+	return sr.triggerLastUsed
216
+}
217
+
218
+func (sr *immutableRef) updateLastUsedNow() bool {
219
+	if !sr.triggerLastUsed {
220
+		return false
221
+	}
222
+	for r := range sr.refs {
223
+		if r.updateLastUsed() {
224
+			return false
225
+		}
226
+	}
227
+	return true
228
+}
229
+
214 230
 func (sr *immutableRef) release(ctx context.Context) error {
215 231
 	delete(sr.refs, sr)
216 232
 
217
-	if len(sr.refs) == 0 {
233
+	if sr.updateLastUsedNow() {
218 234
 		updateLastUsed(sr.md)
235
+		if sr.equalMutable != nil {
236
+			sr.equalMutable.triggerLastUsed = true
237
+		}
238
+	}
239
+
240
+	if len(sr.refs) == 0 {
219 241
 		if sr.viewMount != nil { // TODO: release viewMount earlier if possible
220 242
 			if err := sr.cm.Snapshotter.Remove(ctx, sr.view); err != nil {
221 243
 				return err
... ...
@@ -273,6 +305,10 @@ func (cr *cacheRecord) finalize(ctx context.Context, commit bool) error {
273 273
 	return cr.md.Commit()
274 274
 }
275 275
 
276
+func (sr *mutableRef) updateLastUsed() bool {
277
+	return sr.triggerLastUsed
278
+}
279
+
276 280
 func (sr *mutableRef) commit(ctx context.Context) (ImmutableRef, error) {
277 281
 	if !sr.mutable || len(sr.refs) == 0 {
278 282
 		return nil, errors.Wrapf(errInvalid, "invalid mutable ref")
... ...
@@ -280,13 +316,12 @@ func (sr *mutableRef) commit(ctx context.Context) (ImmutableRef, error) {
280 280
 
281 281
 	id := identity.NewID()
282 282
 	md, _ := sr.cm.md.Get(id)
283
-
284 283
 	rec := &cacheRecord{
285 284
 		mu:           sr.mu,
286 285
 		cm:           sr.cm,
287
-		parent:       sr.Parent(),
286
+		parent:       sr.parentRef(false),
288 287
 		equalMutable: sr,
289
-		refs:         make(map[Mountable]struct{}),
288
+		refs:         make(map[ref]struct{}),
290 289
 		md:           md,
291 290
 	}
292 291
 
... ...
@@ -312,11 +347,15 @@ func (sr *mutableRef) commit(ctx context.Context) (ImmutableRef, error) {
312 312
 		return nil, err
313 313
 	}
314 314
 
315
-	ref := rec.ref()
315
+	ref := rec.ref(true)
316 316
 	sr.equalImmutable = ref
317 317
 	return ref, nil
318 318
 }
319 319
 
320
+func (sr *mutableRef) updatesLastUsed() bool {
321
+	return sr.triggerLastUsed
322
+}
323
+
320 324
 func (sr *mutableRef) Commit(ctx context.Context) (ImmutableRef, error) {
321 325
 	sr.cm.mu.Lock()
322 326
 	defer sr.cm.mu.Unlock()
... ...
@@ -342,6 +381,10 @@ func (sr *mutableRef) release(ctx context.Context) error {
342 342
 	if getCachePolicy(sr.md) != cachePolicyRetain {
343 343
 		if sr.equalImmutable != nil {
344 344
 			if getCachePolicy(sr.equalImmutable.md) == cachePolicyRetain {
345
+				if sr.updateLastUsed() {
346
+					updateLastUsed(sr.md)
347
+					sr.triggerLastUsed = false
348
+				}
345 349
 				return nil
346 350
 			}
347 351
 			if err := sr.equalImmutable.remove(ctx, false); err != nil {
... ...
@@ -355,7 +398,10 @@ func (sr *mutableRef) release(ctx context.Context) error {
355 355
 		}
356 356
 		return sr.remove(ctx, true)
357 357
 	} else {
358
-		updateLastUsed(sr.md)
358
+		if sr.updateLastUsed() {
359
+			updateLastUsed(sr.md)
360
+			sr.triggerLastUsed = false
361
+		}
359 362
 	}
360 363
 	return nil
361 364
 }
... ...
@@ -25,12 +25,11 @@ type ClientOpt interface{}
25 25
 func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error) {
26 26
 	gopts := []grpc.DialOption{
27 27
 		grpc.WithDialer(dialer),
28
-		grpc.FailOnNonTempDialError(true),
29 28
 	}
30 29
 	needWithInsecure := true
31 30
 	for _, o := range opts {
32
-		if _, ok := o.(*withBlockOpt); ok {
33
-			gopts = append(gopts, grpc.WithBlock(), grpc.FailOnNonTempDialError(true))
31
+		if _, ok := o.(*withFailFast); ok {
32
+			gopts = append(gopts, grpc.FailOnNonTempDialError(true))
34 33
 		}
35 34
 		if credInfo, ok := o.(*withCredentials); ok {
36 35
 			opt, err := loadCredentials(credInfo)
... ...
@@ -52,7 +51,6 @@ func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error
52 52
 	if address == "" {
53 53
 		address = appdefaults.Address
54 54
 	}
55
-
56 55
 	conn, err := grpc.DialContext(ctx, address, gopts...)
57 56
 	if err != nil {
58 57
 		return nil, errors.Wrapf(err, "failed to dial %q . make sure buildkitd is running", address)
... ...
@@ -71,10 +69,10 @@ func (c *Client) Close() error {
71 71
 	return c.conn.Close()
72 72
 }
73 73
 
74
-type withBlockOpt struct{}
74
+type withFailFast struct{}
75 75
 
76
-func WithBlock() ClientOpt {
77
-	return &withBlockOpt{}
76
+func WithFailFast() ClientOpt {
77
+	return &withFailFast{}
78 78
 }
79 79
 
80 80
 type withCredentials struct {
... ...
@@ -2,6 +2,7 @@ package llb
2 2
 
3 3
 import (
4 4
 	_ "crypto/sha256"
5
+	"fmt"
5 6
 	"net"
6 7
 	"sort"
7 8
 
... ...
@@ -61,6 +62,7 @@ type ExecOp struct {
61 61
 	constraints Constraints
62 62
 	isValidated bool
63 63
 	secrets     []SecretInfo
64
+	ssh         []SSHInfo
64 65
 }
65 66
 
66 67
 func (e *ExecOp) AddMount(target string, source Output, opt ...MountOption) Output {
... ...
@@ -130,6 +132,17 @@ func (e *ExecOp) Marshal(c *Constraints) (digest.Digest, []byte, *pb.OpMetadata,
130 130
 		return e.mounts[i].target < e.mounts[j].target
131 131
 	})
132 132
 
133
+	if len(e.ssh) > 0 {
134
+		for i, s := range e.ssh {
135
+			if s.Target == "" {
136
+				e.ssh[i].Target = fmt.Sprintf("/run/buildkit/ssh_agent.%d", i)
137
+			}
138
+		}
139
+		if _, ok := e.meta.Env.Get("SSH_AUTH_SOCK"); !ok {
140
+			e.meta.Env = e.meta.Env.AddOrReplace("SSH_AUTH_SOCK", e.ssh[0].Target)
141
+		}
142
+	}
143
+
133 144
 	meta := &pb.Meta{
134 145
 		Args: e.meta.Args,
135 146
 		Env:  e.meta.Env.ToArray(),
... ...
@@ -264,6 +277,21 @@ func (e *ExecOp) Marshal(c *Constraints) (digest.Digest, []byte, *pb.OpMetadata,
264 264
 		peo.Mounts = append(peo.Mounts, pm)
265 265
 	}
266 266
 
267
+	for _, s := range e.ssh {
268
+		pm := &pb.Mount{
269
+			Dest:      s.Target,
270
+			MountType: pb.MountType_SSH,
271
+			SSHOpt: &pb.SSHOpt{
272
+				ID:       s.ID,
273
+				Uid:      uint32(s.UID),
274
+				Gid:      uint32(s.GID),
275
+				Mode:     uint32(s.Mode),
276
+				Optional: s.Optional,
277
+			},
278
+		}
279
+		peo.Mounts = append(peo.Mounts, pm)
280
+	}
281
+
267 282
 	dt, err := pop.Marshal()
268 283
 	if err != nil {
269 284
 		return "", nil, nil, err
... ...
@@ -432,6 +460,56 @@ func AddMount(dest string, mountState State, opts ...MountOption) RunOption {
432 432
 	})
433 433
 }
434 434
 
435
+func AddSSHSocket(opts ...SSHOption) RunOption {
436
+	return runOptionFunc(func(ei *ExecInfo) {
437
+		s := &SSHInfo{
438
+			Mode: 0600,
439
+		}
440
+		for _, opt := range opts {
441
+			opt.SetSSHOption(s)
442
+		}
443
+		ei.SSH = append(ei.SSH, *s)
444
+	})
445
+}
446
+
447
+type SSHOption interface {
448
+	SetSSHOption(*SSHInfo)
449
+}
450
+
451
+type sshOptionFunc func(*SSHInfo)
452
+
453
+func (fn sshOptionFunc) SetSSHOption(si *SSHInfo) {
454
+	fn(si)
455
+}
456
+
457
+func SSHID(id string) SSHOption {
458
+	return sshOptionFunc(func(si *SSHInfo) {
459
+		si.ID = id
460
+	})
461
+}
462
+
463
+func SSHSocketOpt(target string, uid, gid, mode int) SSHOption {
464
+	return sshOptionFunc(func(si *SSHInfo) {
465
+		si.Target = target
466
+		si.UID = uid
467
+		si.GID = gid
468
+		si.Mode = mode
469
+	})
470
+}
471
+
472
+var SSHOptional = sshOptionFunc(func(si *SSHInfo) {
473
+	si.Optional = true
474
+})
475
+
476
+type SSHInfo struct {
477
+	ID       string
478
+	Target   string
479
+	Mode     int
480
+	UID      int
481
+	GID      int
482
+	Optional bool
483
+}
484
+
435 485
 func AddSecret(dest string, opts ...SecretOption) RunOption {
436 486
 	return runOptionFunc(func(ei *ExecInfo) {
437 487
 		s := &SecretInfo{ID: dest, Target: dest, Mode: 0400}
... ...
@@ -498,6 +576,7 @@ type ExecInfo struct {
498 498
 	ReadonlyRootFS bool
499 499
 	ProxyEnv       *ProxyEnv
500 500
 	Secrets        []SecretInfo
501
+	SSH            []SSHInfo
501 502
 }
502 503
 
503 504
 type MountInfo struct {
... ...
@@ -7,12 +7,14 @@ import (
7 7
 	digest "github.com/opencontainers/go-digest"
8 8
 )
9 9
 
10
+// WithMetaResolver adds a metadata resolver to an image
10 11
 func WithMetaResolver(mr ImageMetaResolver) ImageOption {
11 12
 	return imageOptionFunc(func(ii *ImageInfo) {
12 13
 		ii.metaResolver = mr
13 14
 	})
14 15
 }
15 16
 
17
+// ImageMetaResolver can resolve image config metadata from a reference
16 18
 type ImageMetaResolver interface {
17 19
 	ResolveImageConfig(ctx context.Context, ref string, opt gw.ResolveImageConfigOpt) (digest.Digest, []byte, error)
18 20
 }
... ...
@@ -196,6 +196,7 @@ func (s State) Run(ro ...RunOption) ExecState {
196 196
 		exec.AddMount(m.Target, m.Source, m.Opts...)
197 197
 	}
198 198
 	exec.secrets = ei.Secrets
199
+	exec.ssh = ei.SSH
199 200
 
200 201
 	return ExecState{
201 202
 		State: s.WithOutput(exec.Output()),
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	"github.com/pkg/errors"
12 12
 )
13 13
 
14
+// WorkerInfo contains information about a worker
14 15
 type WorkerInfo struct {
15 16
 	ID        string
16 17
 	Labels    map[string]string
... ...
@@ -18,6 +19,7 @@ type WorkerInfo struct {
18 18
 	GCPolicy  []PruneInfo
19 19
 }
20 20
 
21
+// ListWorkers lists all active workers
21 22
 func (c *Client) ListWorkers(ctx context.Context, opts ...ListWorkersOption) ([]*WorkerInfo, error) {
22 23
 	info := &ListWorkersInfo{}
23 24
 	for _, o := range opts {
... ...
@@ -44,10 +46,12 @@ func (c *Client) ListWorkers(ctx context.Context, opts ...ListWorkersOption) ([]
44 44
 	return wi, nil
45 45
 }
46 46
 
47
+// ListWorkersOption is an option for a worker list query
47 48
 type ListWorkersOption interface {
48 49
 	SetListWorkersOption(*ListWorkersInfo)
49 50
 }
50 51
 
52
+// ListWorkersInfo is a payload for worker list query
51 53
 type ListWorkersInfo struct {
52 54
 	Filter []string
53 55
 }
... ...
@@ -127,7 +127,7 @@ func (c *Controller) Prune(req *controlapi.PruneRequest, stream controlapi.Contr
127 127
 				ReleaseUnreferenced() error
128 128
 			}); ok {
129 129
 				if err := c.ReleaseUnreferenced(); err != nil {
130
-					logrus.Errorf("failed to release cache metadata: %+v")
130
+					logrus.Errorf("failed to release cache metadata: %+v", err)
131 131
 				}
132 132
 			}
133 133
 		}
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	"strconv"
12 12
 	"strings"
13 13
 	"syscall"
14
+	"time"
14 15
 
15 16
 	"github.com/containerd/containerd/contrib/seccomp"
16 17
 	"github.com/containerd/containerd/mount"
... ...
@@ -88,7 +89,7 @@ func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Ex
88 88
 		Command:      cmd,
89 89
 		Log:          filepath.Join(root, "runc-log.json"),
90 90
 		LogFormat:    runc.JSON,
91
-		PdeathSignal: syscall.SIGKILL,
91
+		PdeathSignal: syscall.SIGKILL, // this can still leak the process
92 92
 		Setpgid:      true,
93 93
 		// we don't execute runc with --rootless=(true|false) explicitly,
94 94
 		// so as to support non-runc runtimes
... ...
@@ -220,16 +221,43 @@ func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache.
220 220
 		return err
221 221
 	}
222 222
 
223
-	forwardIO, err := newForwardIO(stdin, stdout, stderr)
224
-	if err != nil {
225
-		return errors.Wrap(err, "creating new forwarding IO")
226
-	}
227
-	defer forwardIO.Close()
223
+	// runCtx/killCtx is used for extra check in case the kill command blocks
224
+	runCtx, cancelRun := context.WithCancel(context.Background())
225
+	defer cancelRun()
226
+
227
+	done := make(chan struct{})
228
+	go func() {
229
+		for {
230
+			select {
231
+			case <-ctx.Done():
232
+				killCtx, timeout := context.WithTimeout(context.Background(), 7*time.Second)
233
+				if err := w.runc.Kill(killCtx, id, int(syscall.SIGKILL), nil); err != nil {
234
+					logrus.Errorf("failed to kill runc %s: %+v", id, err)
235
+					select {
236
+					case <-killCtx.Done():
237
+						timeout()
238
+						cancelRun()
239
+						return
240
+					default:
241
+					}
242
+				}
243
+				timeout()
244
+				select {
245
+				case <-time.After(50 * time.Millisecond):
246
+				case <-done:
247
+					return
248
+				}
249
+			case <-done:
250
+				return
251
+			}
252
+		}
253
+	}()
228 254
 
229 255
 	logrus.Debugf("> creating %s %v", id, meta.Args)
230
-	status, err := w.runc.Run(ctx, id, bundle, &runc.CreateOpts{
231
-		IO: forwardIO,
256
+	status, err := w.runc.Run(runCtx, id, bundle, &runc.CreateOpts{
257
+		IO: &forwardIO{stdin: stdin, stdout: stdout, stderr: stderr},
232 258
 	})
259
+	close(done)
233 260
 	if err != nil {
234 261
 		return err
235 262
 	}
... ...
@@ -242,57 +270,11 @@ func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache.
242 242
 }
243 243
 
244 244
 type forwardIO struct {
245
-	stdin, stdout, stderr *os.File
246
-	toRelease             []io.Closer
247
-	toClose               []io.Closer
248
-}
249
-
250
-func newForwardIO(stdin io.ReadCloser, stdout, stderr io.WriteCloser) (f *forwardIO, err error) {
251
-	fio := &forwardIO{}
252
-	defer func() {
253
-		if err != nil {
254
-			fio.Close()
255
-		}
256
-	}()
257
-	if stdin != nil {
258
-		fio.stdin, err = fio.readCloserToFile(stdin)
259
-		if err != nil {
260
-			return nil, err
261
-		}
262
-	}
263
-	if stdout != nil {
264
-		fio.stdout, err = fio.writeCloserToFile(stdout)
265
-		if err != nil {
266
-			return nil, err
267
-		}
268
-	}
269
-	if stderr != nil {
270
-		fio.stderr, err = fio.writeCloserToFile(stderr)
271
-		if err != nil {
272
-			return nil, err
273
-		}
274
-	}
275
-	return fio, nil
245
+	stdin          io.ReadCloser
246
+	stdout, stderr io.WriteCloser
276 247
 }
277 248
 
278 249
 func (s *forwardIO) Close() error {
279
-	s.CloseAfterStart()
280
-	var err error
281
-	for _, cl := range s.toClose {
282
-		if err1 := cl.Close(); err == nil {
283
-			err = err1
284
-		}
285
-	}
286
-	s.toClose = nil
287
-	return err
288
-}
289
-
290
-// release releases active FDs if the process doesn't need them any more
291
-func (s *forwardIO) CloseAfterStart() error {
292
-	for _, cl := range s.toRelease {
293
-		cl.Close()
294
-	}
295
-	s.toRelease = nil
296 250
 	return nil
297 251
 }
298 252
 
... ...
@@ -302,46 +284,6 @@ func (s *forwardIO) Set(cmd *exec.Cmd) {
302 302
 	cmd.Stderr = s.stderr
303 303
 }
304 304
 
305
-func (s *forwardIO) readCloserToFile(rc io.ReadCloser) (*os.File, error) {
306
-	if f, ok := rc.(*os.File); ok {
307
-		return f, nil
308
-	}
309
-	pr, pw, err := os.Pipe()
310
-	if err != nil {
311
-		return nil, err
312
-	}
313
-	s.toClose = append(s.toClose, pw)
314
-	s.toRelease = append(s.toRelease, pr)
315
-	go func() {
316
-		_, err := io.Copy(pw, rc)
317
-		if err1 := pw.Close(); err == nil {
318
-			err = err1
319
-		}
320
-		_ = err
321
-	}()
322
-	return pr, nil
323
-}
324
-
325
-func (s *forwardIO) writeCloserToFile(wc io.WriteCloser) (*os.File, error) {
326
-	if f, ok := wc.(*os.File); ok {
327
-		return f, nil
328
-	}
329
-	pr, pw, err := os.Pipe()
330
-	if err != nil {
331
-		return nil, err
332
-	}
333
-	s.toClose = append(s.toClose, pr)
334
-	s.toRelease = append(s.toRelease, pw)
335
-	go func() {
336
-		_, err := io.Copy(wc, pr)
337
-		if err1 := pw.Close(); err == nil {
338
-			err = err1
339
-		}
340
-		_ = err
341
-	}()
342
-	return pw, nil
343
-}
344
-
345 305
 func (s *forwardIO) Stdin() io.WriteCloser {
346 306
 	return nil
347 307
 }
... ...
@@ -23,6 +23,7 @@ import (
23 23
 	"github.com/moby/buildkit/frontend/dockerfile/shell"
24 24
 	gw "github.com/moby/buildkit/frontend/gateway/client"
25 25
 	"github.com/moby/buildkit/solver/pb"
26
+	"github.com/moby/buildkit/util/system"
26 27
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
27 28
 	"github.com/pkg/errors"
28 29
 	"golang.org/x/sync/errgroup"
... ...
@@ -133,8 +134,12 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
133 133
 			}
134 134
 			ds.platform = &p
135 135
 		}
136
+		allDispatchStates.addState(ds)
136 137
 
137
-		total := 1
138
+		total := 0
139
+		if ds.stage.BaseName != emptyImageName && ds.base == nil {
140
+			total = 1
141
+		}
138 142
 		for _, cmd := range ds.stage.Commands {
139 143
 			switch cmd.(type) {
140 144
 			case *instructions.AddCommand, *instructions.CopyCommand, *instructions.RunCommand:
... ...
@@ -143,7 +148,6 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
143 143
 		}
144 144
 		ds.cmdTotal = total
145 145
 
146
-		allDispatchStates.addState(ds)
147 146
 		if opt.IgnoreCache != nil {
148 147
 			if len(opt.IgnoreCache) == 0 {
149 148
 				ds.ignoreCache = true
... ...
@@ -215,10 +219,15 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
215 215
 					d.stage.BaseName = reference.TagNameOnly(ref).String()
216 216
 					var isScratch bool
217 217
 					if metaResolver != nil && reachable && !d.unregistered {
218
+						prefix := "["
219
+						if opt.PrefixPlatform && platform != nil {
220
+							prefix += platforms.Format(*platform) + " "
221
+						}
222
+						prefix += "internal]"
218 223
 						dgst, dt, err := metaResolver.ResolveImageConfig(ctx, d.stage.BaseName, gw.ResolveImageConfigOpt{
219 224
 							Platform:    platform,
220 225
 							ResolveMode: opt.ImageResolveMode.String(),
221
-							LogName:     fmt.Sprintf("[internal] load metadata for %s", d.stage.BaseName),
226
+							LogName:     fmt.Sprintf("%s load metadata for %s", prefix, d.stage.BaseName),
222 227
 						})
223 228
 						if err == nil { // handle the error while builder is actually running
224 229
 							var img Image
... ...
@@ -242,6 +251,13 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
242 242
 							_ = ref
243 243
 							if len(img.RootFS.DiffIDs) == 0 {
244 244
 								isScratch = true
245
+								// schema1 images can't return diffIDs so double check :(
246
+								for _, h := range img.History {
247
+									if !h.EmptyLayer {
248
+										isScratch = false
249
+										break
250
+									}
251
+								}
245 252
 							}
246 253
 						}
247 254
 					}
... ...
@@ -274,6 +290,11 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
274 274
 			d.image = clone(d.base.image)
275 275
 		}
276 276
 
277
+		// make sure that PATH is always set
278
+		if _, ok := shell.BuildEnvs(d.image.Config.Env)["PATH"]; !ok {
279
+			d.image.Config.Env = append(d.image.Config.Env, "PATH="+system.DefaultPathEnv)
280
+		}
281
+
277 282
 		// initialize base metadata from image conf
278 283
 		for _, env := range d.image.Config.Env {
279 284
 			k, v := parseKeyValue(env)
... ...
@@ -689,16 +710,17 @@ func dispatchCopy(d *dispatchState, c instructions.SourcesAndDest, sourceState l
689 689
 		args = append(args[:1], append([]string{"--unpack"}, args[1:]...)...)
690 690
 	}
691 691
 
692
-	runOpt := []llb.RunOption{llb.Args(args), llb.Dir("/dest"), llb.ReadonlyRootFS(), dfCmd(cmdToPrint), llb.WithCustomName(prefixCommand(d, uppercaseCmd(processCmdEnv(opt.shlex, cmdToPrint.String(), d.state.Env())), d.prefixPlatform, d.state.GetPlatform()))}
692
+	platform := opt.targetPlatform
693
+	if d.platform != nil {
694
+		platform = *d.platform
695
+	}
696
+
697
+	runOpt := []llb.RunOption{llb.Args(args), llb.Dir("/dest"), llb.ReadonlyRootFS(), dfCmd(cmdToPrint), llb.WithCustomName(prefixCommand(d, uppercaseCmd(processCmdEnv(opt.shlex, cmdToPrint.String(), d.state.Env())), d.prefixPlatform, &platform))}
693 698
 	if d.ignoreCache {
694 699
 		runOpt = append(runOpt, llb.IgnoreCache)
695 700
 	}
696 701
 	run := img.Run(append(runOpt, mounts...)...)
697
-	d.state = run.AddMount("/dest", d.state).Platform(opt.targetPlatform)
698
-
699
-	if d.platform != nil {
700
-		d.state = d.state.Platform(*d.platform)
701
-	}
702
+	d.state = run.AddMount("/dest", d.state).Platform(platform)
702 703
 
703 704
 	return commitToHistory(&d.image, commitMessage.String(), true, &d.state)
704 705
 }
... ...
@@ -78,9 +78,12 @@ func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*
78 78
 			}
79 79
 			mountOpts = append(mountOpts, llb.AsPersistentCacheDir(opt.cacheIDNamespace+"/"+mount.CacheID, sharing))
80 80
 		}
81
-		target := path.Join("/", mount.Target)
81
+		target := mount.Target
82
+		if !filepath.IsAbs(filepath.Clean(mount.Target)) {
83
+			target = filepath.Join("/", d.state.GetDir(), mount.Target)
84
+		}
82 85
 		if target == "/" {
83
-			return nil, errors.Errorf("invalid mount target %q", mount.Target)
86
+			return nil, errors.Errorf("invalid mount target %q", target)
84 87
 		}
85 88
 		if src := path.Join("/", mount.Source); src != "/" {
86 89
 			mountOpts = append(mountOpts, llb.SourcePath(src))
... ...
@@ -29,6 +29,7 @@ type HealthConfig struct {
29 29
 	Retries int `json:",omitempty"`
30 30
 }
31 31
 
32
+// ImageConfig is a docker compatible config for an image
32 33
 type ImageConfig struct {
33 34
 	specs.ImageConfig
34 35
 
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"google.golang.org/grpc/metadata"
8 8
 )
9 9
 
10
+// Hijack hijacks session to a connection.
10 11
 func Hijack(stream controlapi.Control_SessionServer) (net.Conn, <-chan struct{}, map[string][]string) {
11 12
 	md, _ := metadata.FromIncomingContext(stream.Context())
12 13
 	c, closeCh := streamToConn(stream)
13 14
new file mode 100644
... ...
@@ -0,0 +1,61 @@
0
+package sshforward
1
+
2
+import (
3
+	io "io"
4
+
5
+	context "golang.org/x/net/context"
6
+	"golang.org/x/sync/errgroup"
7
+	"google.golang.org/grpc"
8
+)
9
+
10
+func Copy(ctx context.Context, conn io.ReadWriteCloser, stream grpc.Stream) error {
11
+	g, ctx := errgroup.WithContext(ctx)
12
+
13
+	g.Go(func() (retErr error) {
14
+		p := &BytesMessage{}
15
+		for {
16
+			if err := stream.RecvMsg(p); err != nil {
17
+				if err == io.EOF {
18
+					return nil
19
+				}
20
+				conn.Close()
21
+				return err
22
+			}
23
+			select {
24
+			case <-ctx.Done():
25
+				conn.Close()
26
+				return ctx.Err()
27
+			default:
28
+			}
29
+			if _, err := conn.Write(p.Data); err != nil {
30
+				conn.Close()
31
+				return err
32
+			}
33
+			p.Data = p.Data[:0]
34
+		}
35
+	})
36
+
37
+	g.Go(func() (retErr error) {
38
+		for {
39
+			buf := make([]byte, 32*1024)
40
+			n, err := conn.Read(buf)
41
+			switch {
42
+			case err == io.EOF:
43
+				return nil
44
+			case err != nil:
45
+				return err
46
+			}
47
+			select {
48
+			case <-ctx.Done():
49
+				return ctx.Err()
50
+			default:
51
+			}
52
+			p := &BytesMessage{Data: buf[:n]}
53
+			if err := stream.SendMsg(p); err != nil {
54
+				return err
55
+			}
56
+		}
57
+	})
58
+
59
+	return g.Wait()
60
+}
0 61
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+package sshforward
1
+
2
+//go:generate protoc --gogoslick_out=plugins=grpc:. ssh.proto
0 3
new file mode 100644
... ...
@@ -0,0 +1,113 @@
0
+package sshforward
1
+
2
+import (
3
+	"io/ioutil"
4
+	"net"
5
+	"os"
6
+	"path/filepath"
7
+
8
+	"github.com/moby/buildkit/session"
9
+	context "golang.org/x/net/context"
10
+	"golang.org/x/sync/errgroup"
11
+	"google.golang.org/grpc/metadata"
12
+)
13
+
14
+// DefaultID is the default ssh ID
15
+const DefaultID = "default"
16
+
17
+const KeySSHID = "buildkit.ssh.id"
18
+
19
+type server struct {
20
+	caller session.Caller
21
+}
22
+
23
+func (s *server) run(ctx context.Context, l net.Listener, id string) error {
24
+	eg, ctx := errgroup.WithContext(ctx)
25
+
26
+	eg.Go(func() error {
27
+		<-ctx.Done()
28
+		return ctx.Err()
29
+	})
30
+
31
+	eg.Go(func() error {
32
+		for {
33
+			conn, err := l.Accept()
34
+			if err != nil {
35
+				return err
36
+			}
37
+
38
+			client := NewSSHClient(s.caller.Conn())
39
+
40
+			opts := make(map[string][]string)
41
+			opts[KeySSHID] = []string{id}
42
+			ctx = metadata.NewOutgoingContext(ctx, opts)
43
+
44
+			stream, err := client.ForwardAgent(ctx)
45
+			if err != nil {
46
+				conn.Close()
47
+				return err
48
+			}
49
+
50
+			go Copy(ctx, conn, stream)
51
+		}
52
+	})
53
+
54
+	return eg.Wait()
55
+}
56
+
57
+type SocketOpt struct {
58
+	ID   string
59
+	UID  int
60
+	GID  int
61
+	Mode int
62
+}
63
+
64
+func MountSSHSocket(ctx context.Context, c session.Caller, opt SocketOpt) (sockPath string, closer func() error, err error) {
65
+	dir, err := ioutil.TempDir("", ".buildkit-ssh-sock")
66
+	if err != nil {
67
+		return "", nil, err
68
+	}
69
+
70
+	defer func() {
71
+		if err != nil {
72
+			os.RemoveAll(dir)
73
+		}
74
+	}()
75
+
76
+	sockPath = filepath.Join(dir, "ssh_auth_sock")
77
+
78
+	l, err := net.Listen("unix", sockPath)
79
+	if err != nil {
80
+		return "", nil, err
81
+	}
82
+
83
+	if err := os.Chown(sockPath, opt.UID, opt.GID); err != nil {
84
+		l.Close()
85
+		return "", nil, err
86
+	}
87
+	if err := os.Chmod(sockPath, os.FileMode(opt.Mode)); err != nil {
88
+		l.Close()
89
+		return "", nil, err
90
+	}
91
+
92
+	s := &server{caller: c}
93
+
94
+	id := opt.ID
95
+	if id == "" {
96
+		id = DefaultID
97
+	}
98
+
99
+	go s.run(ctx, l, id) // erroring per connection allowed
100
+
101
+	return sockPath, func() error {
102
+		err := l.Close()
103
+		os.RemoveAll(sockPath)
104
+		return err
105
+	}, nil
106
+}
107
+
108
+func CheckSSHID(ctx context.Context, c session.Caller, id string) error {
109
+	client := NewSSHClient(c.Conn())
110
+	_, err := client.CheckAgent(ctx, &CheckAgentRequest{ID: id})
111
+	return err
112
+}
0 113
new file mode 100644
... ...
@@ -0,0 +1,816 @@
0
+// Code generated by protoc-gen-gogo. DO NOT EDIT.
1
+// source: ssh.proto
2
+
3
+/*
4
+Package sshforward is a generated protocol buffer package.
5
+
6
+It is generated from these files:
7
+	ssh.proto
8
+
9
+It has these top-level messages:
10
+	BytesMessage
11
+	CheckAgentRequest
12
+	CheckAgentResponse
13
+*/
14
+package sshforward
15
+
16
+import proto "github.com/gogo/protobuf/proto"
17
+import fmt "fmt"
18
+import math "math"
19
+
20
+import bytes "bytes"
21
+
22
+import strings "strings"
23
+import reflect "reflect"
24
+
25
+import context "golang.org/x/net/context"
26
+import grpc "google.golang.org/grpc"
27
+
28
+import io "io"
29
+
30
+// Reference imports to suppress errors if they are not otherwise used.
31
+var _ = proto.Marshal
32
+var _ = fmt.Errorf
33
+var _ = math.Inf
34
+
35
+// This is a compile-time assertion to ensure that this generated file
36
+// is compatible with the proto package it is being compiled against.
37
+// A compilation error at this line likely means your copy of the
38
+// proto package needs to be updated.
39
+const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
40
+
41
+// BytesMessage contains a chunk of byte data
42
+type BytesMessage struct {
43
+	Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
44
+}
45
+
46
+func (m *BytesMessage) Reset()                    { *m = BytesMessage{} }
47
+func (*BytesMessage) ProtoMessage()               {}
48
+func (*BytesMessage) Descriptor() ([]byte, []int) { return fileDescriptorSsh, []int{0} }
49
+
50
+func (m *BytesMessage) GetData() []byte {
51
+	if m != nil {
52
+		return m.Data
53
+	}
54
+	return nil
55
+}
56
+
57
+type CheckAgentRequest struct {
58
+	ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
59
+}
60
+
61
+func (m *CheckAgentRequest) Reset()                    { *m = CheckAgentRequest{} }
62
+func (*CheckAgentRequest) ProtoMessage()               {}
63
+func (*CheckAgentRequest) Descriptor() ([]byte, []int) { return fileDescriptorSsh, []int{1} }
64
+
65
+func (m *CheckAgentRequest) GetID() string {
66
+	if m != nil {
67
+		return m.ID
68
+	}
69
+	return ""
70
+}
71
+
72
+type CheckAgentResponse struct {
73
+}
74
+
75
+func (m *CheckAgentResponse) Reset()                    { *m = CheckAgentResponse{} }
76
+func (*CheckAgentResponse) ProtoMessage()               {}
77
+func (*CheckAgentResponse) Descriptor() ([]byte, []int) { return fileDescriptorSsh, []int{2} }
78
+
79
+func init() {
80
+	proto.RegisterType((*BytesMessage)(nil), "moby.sshforward.v1.BytesMessage")
81
+	proto.RegisterType((*CheckAgentRequest)(nil), "moby.sshforward.v1.CheckAgentRequest")
82
+	proto.RegisterType((*CheckAgentResponse)(nil), "moby.sshforward.v1.CheckAgentResponse")
83
+}
84
+func (this *BytesMessage) Equal(that interface{}) bool {
85
+	if that == nil {
86
+		return this == nil
87
+	}
88
+
89
+	that1, ok := that.(*BytesMessage)
90
+	if !ok {
91
+		that2, ok := that.(BytesMessage)
92
+		if ok {
93
+			that1 = &that2
94
+		} else {
95
+			return false
96
+		}
97
+	}
98
+	if that1 == nil {
99
+		return this == nil
100
+	} else if this == nil {
101
+		return false
102
+	}
103
+	if !bytes.Equal(this.Data, that1.Data) {
104
+		return false
105
+	}
106
+	return true
107
+}
108
+func (this *CheckAgentRequest) Equal(that interface{}) bool {
109
+	if that == nil {
110
+		return this == nil
111
+	}
112
+
113
+	that1, ok := that.(*CheckAgentRequest)
114
+	if !ok {
115
+		that2, ok := that.(CheckAgentRequest)
116
+		if ok {
117
+			that1 = &that2
118
+		} else {
119
+			return false
120
+		}
121
+	}
122
+	if that1 == nil {
123
+		return this == nil
124
+	} else if this == nil {
125
+		return false
126
+	}
127
+	if this.ID != that1.ID {
128
+		return false
129
+	}
130
+	return true
131
+}
132
+func (this *CheckAgentResponse) Equal(that interface{}) bool {
133
+	if that == nil {
134
+		return this == nil
135
+	}
136
+
137
+	that1, ok := that.(*CheckAgentResponse)
138
+	if !ok {
139
+		that2, ok := that.(CheckAgentResponse)
140
+		if ok {
141
+			that1 = &that2
142
+		} else {
143
+			return false
144
+		}
145
+	}
146
+	if that1 == nil {
147
+		return this == nil
148
+	} else if this == nil {
149
+		return false
150
+	}
151
+	return true
152
+}
153
+func (this *BytesMessage) GoString() string {
154
+	if this == nil {
155
+		return "nil"
156
+	}
157
+	s := make([]string, 0, 5)
158
+	s = append(s, "&sshforward.BytesMessage{")
159
+	s = append(s, "Data: "+fmt.Sprintf("%#v", this.Data)+",\n")
160
+	s = append(s, "}")
161
+	return strings.Join(s, "")
162
+}
163
+func (this *CheckAgentRequest) GoString() string {
164
+	if this == nil {
165
+		return "nil"
166
+	}
167
+	s := make([]string, 0, 5)
168
+	s = append(s, "&sshforward.CheckAgentRequest{")
169
+	s = append(s, "ID: "+fmt.Sprintf("%#v", this.ID)+",\n")
170
+	s = append(s, "}")
171
+	return strings.Join(s, "")
172
+}
173
+func (this *CheckAgentResponse) GoString() string {
174
+	if this == nil {
175
+		return "nil"
176
+	}
177
+	s := make([]string, 0, 4)
178
+	s = append(s, "&sshforward.CheckAgentResponse{")
179
+	s = append(s, "}")
180
+	return strings.Join(s, "")
181
+}
182
+func valueToGoStringSsh(v interface{}, typ string) string {
183
+	rv := reflect.ValueOf(v)
184
+	if rv.IsNil() {
185
+		return "nil"
186
+	}
187
+	pv := reflect.Indirect(rv).Interface()
188
+	return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv)
189
+}
190
+
191
+// Reference imports to suppress errors if they are not otherwise used.
192
+var _ context.Context
193
+var _ grpc.ClientConn
194
+
195
+// This is a compile-time assertion to ensure that this generated file
196
+// is compatible with the grpc package it is being compiled against.
197
+const _ = grpc.SupportPackageIsVersion4
198
+
199
+// Client API for SSH service
200
+
201
+type SSHClient interface {
202
+	CheckAgent(ctx context.Context, in *CheckAgentRequest, opts ...grpc.CallOption) (*CheckAgentResponse, error)
203
+	ForwardAgent(ctx context.Context, opts ...grpc.CallOption) (SSH_ForwardAgentClient, error)
204
+}
205
+
206
+type sSHClient struct {
207
+	cc *grpc.ClientConn
208
+}
209
+
210
+func NewSSHClient(cc *grpc.ClientConn) SSHClient {
211
+	return &sSHClient{cc}
212
+}
213
+
214
+func (c *sSHClient) CheckAgent(ctx context.Context, in *CheckAgentRequest, opts ...grpc.CallOption) (*CheckAgentResponse, error) {
215
+	out := new(CheckAgentResponse)
216
+	err := grpc.Invoke(ctx, "/moby.sshforward.v1.SSH/CheckAgent", in, out, c.cc, opts...)
217
+	if err != nil {
218
+		return nil, err
219
+	}
220
+	return out, nil
221
+}
222
+
223
+func (c *sSHClient) ForwardAgent(ctx context.Context, opts ...grpc.CallOption) (SSH_ForwardAgentClient, error) {
224
+	stream, err := grpc.NewClientStream(ctx, &_SSH_serviceDesc.Streams[0], c.cc, "/moby.sshforward.v1.SSH/ForwardAgent", opts...)
225
+	if err != nil {
226
+		return nil, err
227
+	}
228
+	x := &sSHForwardAgentClient{stream}
229
+	return x, nil
230
+}
231
+
232
+type SSH_ForwardAgentClient interface {
233
+	Send(*BytesMessage) error
234
+	Recv() (*BytesMessage, error)
235
+	grpc.ClientStream
236
+}
237
+
238
+type sSHForwardAgentClient struct {
239
+	grpc.ClientStream
240
+}
241
+
242
+func (x *sSHForwardAgentClient) Send(m *BytesMessage) error {
243
+	return x.ClientStream.SendMsg(m)
244
+}
245
+
246
+func (x *sSHForwardAgentClient) Recv() (*BytesMessage, error) {
247
+	m := new(BytesMessage)
248
+	if err := x.ClientStream.RecvMsg(m); err != nil {
249
+		return nil, err
250
+	}
251
+	return m, nil
252
+}
253
+
254
+// Server API for SSH service
255
+
256
+type SSHServer interface {
257
+	CheckAgent(context.Context, *CheckAgentRequest) (*CheckAgentResponse, error)
258
+	ForwardAgent(SSH_ForwardAgentServer) error
259
+}
260
+
261
+func RegisterSSHServer(s *grpc.Server, srv SSHServer) {
262
+	s.RegisterService(&_SSH_serviceDesc, srv)
263
+}
264
+
265
+func _SSH_CheckAgent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
266
+	in := new(CheckAgentRequest)
267
+	if err := dec(in); err != nil {
268
+		return nil, err
269
+	}
270
+	if interceptor == nil {
271
+		return srv.(SSHServer).CheckAgent(ctx, in)
272
+	}
273
+	info := &grpc.UnaryServerInfo{
274
+		Server:     srv,
275
+		FullMethod: "/moby.sshforward.v1.SSH/CheckAgent",
276
+	}
277
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
278
+		return srv.(SSHServer).CheckAgent(ctx, req.(*CheckAgentRequest))
279
+	}
280
+	return interceptor(ctx, in, info, handler)
281
+}
282
+
283
+func _SSH_ForwardAgent_Handler(srv interface{}, stream grpc.ServerStream) error {
284
+	return srv.(SSHServer).ForwardAgent(&sSHForwardAgentServer{stream})
285
+}
286
+
287
+type SSH_ForwardAgentServer interface {
288
+	Send(*BytesMessage) error
289
+	Recv() (*BytesMessage, error)
290
+	grpc.ServerStream
291
+}
292
+
293
+type sSHForwardAgentServer struct {
294
+	grpc.ServerStream
295
+}
296
+
297
+func (x *sSHForwardAgentServer) Send(m *BytesMessage) error {
298
+	return x.ServerStream.SendMsg(m)
299
+}
300
+
301
+func (x *sSHForwardAgentServer) Recv() (*BytesMessage, error) {
302
+	m := new(BytesMessage)
303
+	if err := x.ServerStream.RecvMsg(m); err != nil {
304
+		return nil, err
305
+	}
306
+	return m, nil
307
+}
308
+
309
+var _SSH_serviceDesc = grpc.ServiceDesc{
310
+	ServiceName: "moby.sshforward.v1.SSH",
311
+	HandlerType: (*SSHServer)(nil),
312
+	Methods: []grpc.MethodDesc{
313
+		{
314
+			MethodName: "CheckAgent",
315
+			Handler:    _SSH_CheckAgent_Handler,
316
+		},
317
+	},
318
+	Streams: []grpc.StreamDesc{
319
+		{
320
+			StreamName:    "ForwardAgent",
321
+			Handler:       _SSH_ForwardAgent_Handler,
322
+			ServerStreams: true,
323
+			ClientStreams: true,
324
+		},
325
+	},
326
+	Metadata: "ssh.proto",
327
+}
328
+
329
+func (m *BytesMessage) Marshal() (dAtA []byte, err error) {
330
+	size := m.Size()
331
+	dAtA = make([]byte, size)
332
+	n, err := m.MarshalTo(dAtA)
333
+	if err != nil {
334
+		return nil, err
335
+	}
336
+	return dAtA[:n], nil
337
+}
338
+
339
+func (m *BytesMessage) MarshalTo(dAtA []byte) (int, error) {
340
+	var i int
341
+	_ = i
342
+	var l int
343
+	_ = l
344
+	if len(m.Data) > 0 {
345
+		dAtA[i] = 0xa
346
+		i++
347
+		i = encodeVarintSsh(dAtA, i, uint64(len(m.Data)))
348
+		i += copy(dAtA[i:], m.Data)
349
+	}
350
+	return i, nil
351
+}
352
+
353
+func (m *CheckAgentRequest) Marshal() (dAtA []byte, err error) {
354
+	size := m.Size()
355
+	dAtA = make([]byte, size)
356
+	n, err := m.MarshalTo(dAtA)
357
+	if err != nil {
358
+		return nil, err
359
+	}
360
+	return dAtA[:n], nil
361
+}
362
+
363
+func (m *CheckAgentRequest) MarshalTo(dAtA []byte) (int, error) {
364
+	var i int
365
+	_ = i
366
+	var l int
367
+	_ = l
368
+	if len(m.ID) > 0 {
369
+		dAtA[i] = 0xa
370
+		i++
371
+		i = encodeVarintSsh(dAtA, i, uint64(len(m.ID)))
372
+		i += copy(dAtA[i:], m.ID)
373
+	}
374
+	return i, nil
375
+}
376
+
377
+func (m *CheckAgentResponse) Marshal() (dAtA []byte, err error) {
378
+	size := m.Size()
379
+	dAtA = make([]byte, size)
380
+	n, err := m.MarshalTo(dAtA)
381
+	if err != nil {
382
+		return nil, err
383
+	}
384
+	return dAtA[:n], nil
385
+}
386
+
387
+func (m *CheckAgentResponse) MarshalTo(dAtA []byte) (int, error) {
388
+	var i int
389
+	_ = i
390
+	var l int
391
+	_ = l
392
+	return i, nil
393
+}
394
+
395
+func encodeVarintSsh(dAtA []byte, offset int, v uint64) int {
396
+	for v >= 1<<7 {
397
+		dAtA[offset] = uint8(v&0x7f | 0x80)
398
+		v >>= 7
399
+		offset++
400
+	}
401
+	dAtA[offset] = uint8(v)
402
+	return offset + 1
403
+}
404
+func (m *BytesMessage) Size() (n int) {
405
+	var l int
406
+	_ = l
407
+	l = len(m.Data)
408
+	if l > 0 {
409
+		n += 1 + l + sovSsh(uint64(l))
410
+	}
411
+	return n
412
+}
413
+
414
+func (m *CheckAgentRequest) Size() (n int) {
415
+	var l int
416
+	_ = l
417
+	l = len(m.ID)
418
+	if l > 0 {
419
+		n += 1 + l + sovSsh(uint64(l))
420
+	}
421
+	return n
422
+}
423
+
424
+func (m *CheckAgentResponse) Size() (n int) {
425
+	var l int
426
+	_ = l
427
+	return n
428
+}
429
+
430
+func sovSsh(x uint64) (n int) {
431
+	for {
432
+		n++
433
+		x >>= 7
434
+		if x == 0 {
435
+			break
436
+		}
437
+	}
438
+	return n
439
+}
440
+func sozSsh(x uint64) (n int) {
441
+	return sovSsh(uint64((x << 1) ^ uint64((int64(x) >> 63))))
442
+}
443
+func (this *BytesMessage) String() string {
444
+	if this == nil {
445
+		return "nil"
446
+	}
447
+	s := strings.Join([]string{`&BytesMessage{`,
448
+		`Data:` + fmt.Sprintf("%v", this.Data) + `,`,
449
+		`}`,
450
+	}, "")
451
+	return s
452
+}
453
+func (this *CheckAgentRequest) String() string {
454
+	if this == nil {
455
+		return "nil"
456
+	}
457
+	s := strings.Join([]string{`&CheckAgentRequest{`,
458
+		`ID:` + fmt.Sprintf("%v", this.ID) + `,`,
459
+		`}`,
460
+	}, "")
461
+	return s
462
+}
463
+func (this *CheckAgentResponse) String() string {
464
+	if this == nil {
465
+		return "nil"
466
+	}
467
+	s := strings.Join([]string{`&CheckAgentResponse{`,
468
+		`}`,
469
+	}, "")
470
+	return s
471
+}
472
+func valueToStringSsh(v interface{}) string {
473
+	rv := reflect.ValueOf(v)
474
+	if rv.IsNil() {
475
+		return "nil"
476
+	}
477
+	pv := reflect.Indirect(rv).Interface()
478
+	return fmt.Sprintf("*%v", pv)
479
+}
480
+func (m *BytesMessage) Unmarshal(dAtA []byte) error {
481
+	l := len(dAtA)
482
+	iNdEx := 0
483
+	for iNdEx < l {
484
+		preIndex := iNdEx
485
+		var wire uint64
486
+		for shift := uint(0); ; shift += 7 {
487
+			if shift >= 64 {
488
+				return ErrIntOverflowSsh
489
+			}
490
+			if iNdEx >= l {
491
+				return io.ErrUnexpectedEOF
492
+			}
493
+			b := dAtA[iNdEx]
494
+			iNdEx++
495
+			wire |= (uint64(b) & 0x7F) << shift
496
+			if b < 0x80 {
497
+				break
498
+			}
499
+		}
500
+		fieldNum := int32(wire >> 3)
501
+		wireType := int(wire & 0x7)
502
+		if wireType == 4 {
503
+			return fmt.Errorf("proto: BytesMessage: wiretype end group for non-group")
504
+		}
505
+		if fieldNum <= 0 {
506
+			return fmt.Errorf("proto: BytesMessage: illegal tag %d (wire type %d)", fieldNum, wire)
507
+		}
508
+		switch fieldNum {
509
+		case 1:
510
+			if wireType != 2 {
511
+				return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType)
512
+			}
513
+			var byteLen int
514
+			for shift := uint(0); ; shift += 7 {
515
+				if shift >= 64 {
516
+					return ErrIntOverflowSsh
517
+				}
518
+				if iNdEx >= l {
519
+					return io.ErrUnexpectedEOF
520
+				}
521
+				b := dAtA[iNdEx]
522
+				iNdEx++
523
+				byteLen |= (int(b) & 0x7F) << shift
524
+				if b < 0x80 {
525
+					break
526
+				}
527
+			}
528
+			if byteLen < 0 {
529
+				return ErrInvalidLengthSsh
530
+			}
531
+			postIndex := iNdEx + byteLen
532
+			if postIndex > l {
533
+				return io.ErrUnexpectedEOF
534
+			}
535
+			m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...)
536
+			if m.Data == nil {
537
+				m.Data = []byte{}
538
+			}
539
+			iNdEx = postIndex
540
+		default:
541
+			iNdEx = preIndex
542
+			skippy, err := skipSsh(dAtA[iNdEx:])
543
+			if err != nil {
544
+				return err
545
+			}
546
+			if skippy < 0 {
547
+				return ErrInvalidLengthSsh
548
+			}
549
+			if (iNdEx + skippy) > l {
550
+				return io.ErrUnexpectedEOF
551
+			}
552
+			iNdEx += skippy
553
+		}
554
+	}
555
+
556
+	if iNdEx > l {
557
+		return io.ErrUnexpectedEOF
558
+	}
559
+	return nil
560
+}
561
+func (m *CheckAgentRequest) Unmarshal(dAtA []byte) error {
562
+	l := len(dAtA)
563
+	iNdEx := 0
564
+	for iNdEx < l {
565
+		preIndex := iNdEx
566
+		var wire uint64
567
+		for shift := uint(0); ; shift += 7 {
568
+			if shift >= 64 {
569
+				return ErrIntOverflowSsh
570
+			}
571
+			if iNdEx >= l {
572
+				return io.ErrUnexpectedEOF
573
+			}
574
+			b := dAtA[iNdEx]
575
+			iNdEx++
576
+			wire |= (uint64(b) & 0x7F) << shift
577
+			if b < 0x80 {
578
+				break
579
+			}
580
+		}
581
+		fieldNum := int32(wire >> 3)
582
+		wireType := int(wire & 0x7)
583
+		if wireType == 4 {
584
+			return fmt.Errorf("proto: CheckAgentRequest: wiretype end group for non-group")
585
+		}
586
+		if fieldNum <= 0 {
587
+			return fmt.Errorf("proto: CheckAgentRequest: illegal tag %d (wire type %d)", fieldNum, wire)
588
+		}
589
+		switch fieldNum {
590
+		case 1:
591
+			if wireType != 2 {
592
+				return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
593
+			}
594
+			var stringLen uint64
595
+			for shift := uint(0); ; shift += 7 {
596
+				if shift >= 64 {
597
+					return ErrIntOverflowSsh
598
+				}
599
+				if iNdEx >= l {
600
+					return io.ErrUnexpectedEOF
601
+				}
602
+				b := dAtA[iNdEx]
603
+				iNdEx++
604
+				stringLen |= (uint64(b) & 0x7F) << shift
605
+				if b < 0x80 {
606
+					break
607
+				}
608
+			}
609
+			intStringLen := int(stringLen)
610
+			if intStringLen < 0 {
611
+				return ErrInvalidLengthSsh
612
+			}
613
+			postIndex := iNdEx + intStringLen
614
+			if postIndex > l {
615
+				return io.ErrUnexpectedEOF
616
+			}
617
+			m.ID = string(dAtA[iNdEx:postIndex])
618
+			iNdEx = postIndex
619
+		default:
620
+			iNdEx = preIndex
621
+			skippy, err := skipSsh(dAtA[iNdEx:])
622
+			if err != nil {
623
+				return err
624
+			}
625
+			if skippy < 0 {
626
+				return ErrInvalidLengthSsh
627
+			}
628
+			if (iNdEx + skippy) > l {
629
+				return io.ErrUnexpectedEOF
630
+			}
631
+			iNdEx += skippy
632
+		}
633
+	}
634
+
635
+	if iNdEx > l {
636
+		return io.ErrUnexpectedEOF
637
+	}
638
+	return nil
639
+}
640
+func (m *CheckAgentResponse) Unmarshal(dAtA []byte) error {
641
+	l := len(dAtA)
642
+	iNdEx := 0
643
+	for iNdEx < l {
644
+		preIndex := iNdEx
645
+		var wire uint64
646
+		for shift := uint(0); ; shift += 7 {
647
+			if shift >= 64 {
648
+				return ErrIntOverflowSsh
649
+			}
650
+			if iNdEx >= l {
651
+				return io.ErrUnexpectedEOF
652
+			}
653
+			b := dAtA[iNdEx]
654
+			iNdEx++
655
+			wire |= (uint64(b) & 0x7F) << shift
656
+			if b < 0x80 {
657
+				break
658
+			}
659
+		}
660
+		fieldNum := int32(wire >> 3)
661
+		wireType := int(wire & 0x7)
662
+		if wireType == 4 {
663
+			return fmt.Errorf("proto: CheckAgentResponse: wiretype end group for non-group")
664
+		}
665
+		if fieldNum <= 0 {
666
+			return fmt.Errorf("proto: CheckAgentResponse: illegal tag %d (wire type %d)", fieldNum, wire)
667
+		}
668
+		switch fieldNum {
669
+		default:
670
+			iNdEx = preIndex
671
+			skippy, err := skipSsh(dAtA[iNdEx:])
672
+			if err != nil {
673
+				return err
674
+			}
675
+			if skippy < 0 {
676
+				return ErrInvalidLengthSsh
677
+			}
678
+			if (iNdEx + skippy) > l {
679
+				return io.ErrUnexpectedEOF
680
+			}
681
+			iNdEx += skippy
682
+		}
683
+	}
684
+
685
+	if iNdEx > l {
686
+		return io.ErrUnexpectedEOF
687
+	}
688
+	return nil
689
+}
690
+func skipSsh(dAtA []byte) (n int, err error) {
691
+	l := len(dAtA)
692
+	iNdEx := 0
693
+	for iNdEx < l {
694
+		var wire uint64
695
+		for shift := uint(0); ; shift += 7 {
696
+			if shift >= 64 {
697
+				return 0, ErrIntOverflowSsh
698
+			}
699
+			if iNdEx >= l {
700
+				return 0, io.ErrUnexpectedEOF
701
+			}
702
+			b := dAtA[iNdEx]
703
+			iNdEx++
704
+			wire |= (uint64(b) & 0x7F) << shift
705
+			if b < 0x80 {
706
+				break
707
+			}
708
+		}
709
+		wireType := int(wire & 0x7)
710
+		switch wireType {
711
+		case 0:
712
+			for shift := uint(0); ; shift += 7 {
713
+				if shift >= 64 {
714
+					return 0, ErrIntOverflowSsh
715
+				}
716
+				if iNdEx >= l {
717
+					return 0, io.ErrUnexpectedEOF
718
+				}
719
+				iNdEx++
720
+				if dAtA[iNdEx-1] < 0x80 {
721
+					break
722
+				}
723
+			}
724
+			return iNdEx, nil
725
+		case 1:
726
+			iNdEx += 8
727
+			return iNdEx, nil
728
+		case 2:
729
+			var length int
730
+			for shift := uint(0); ; shift += 7 {
731
+				if shift >= 64 {
732
+					return 0, ErrIntOverflowSsh
733
+				}
734
+				if iNdEx >= l {
735
+					return 0, io.ErrUnexpectedEOF
736
+				}
737
+				b := dAtA[iNdEx]
738
+				iNdEx++
739
+				length |= (int(b) & 0x7F) << shift
740
+				if b < 0x80 {
741
+					break
742
+				}
743
+			}
744
+			iNdEx += length
745
+			if length < 0 {
746
+				return 0, ErrInvalidLengthSsh
747
+			}
748
+			return iNdEx, nil
749
+		case 3:
750
+			for {
751
+				var innerWire uint64
752
+				var start int = iNdEx
753
+				for shift := uint(0); ; shift += 7 {
754
+					if shift >= 64 {
755
+						return 0, ErrIntOverflowSsh
756
+					}
757
+					if iNdEx >= l {
758
+						return 0, io.ErrUnexpectedEOF
759
+					}
760
+					b := dAtA[iNdEx]
761
+					iNdEx++
762
+					innerWire |= (uint64(b) & 0x7F) << shift
763
+					if b < 0x80 {
764
+						break
765
+					}
766
+				}
767
+				innerWireType := int(innerWire & 0x7)
768
+				if innerWireType == 4 {
769
+					break
770
+				}
771
+				next, err := skipSsh(dAtA[start:])
772
+				if err != nil {
773
+					return 0, err
774
+				}
775
+				iNdEx = start + next
776
+			}
777
+			return iNdEx, nil
778
+		case 4:
779
+			return iNdEx, nil
780
+		case 5:
781
+			iNdEx += 4
782
+			return iNdEx, nil
783
+		default:
784
+			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
785
+		}
786
+	}
787
+	panic("unreachable")
788
+}
789
+
790
+var (
791
+	ErrInvalidLengthSsh = fmt.Errorf("proto: negative length found during unmarshaling")
792
+	ErrIntOverflowSsh   = fmt.Errorf("proto: integer overflow")
793
+)
794
+
795
+func init() { proto.RegisterFile("ssh.proto", fileDescriptorSsh) }
796
+
797
+var fileDescriptorSsh = []byte{
798
+	// 243 bytes of a gzipped FileDescriptorProto
799
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2c, 0x2e, 0xce, 0xd0,
800
+	0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xca, 0xcd, 0x4f, 0xaa, 0xd4, 0x2b, 0x2e, 0xce, 0x48,
801
+	0xcb, 0x2f, 0x2a, 0x4f, 0x2c, 0x4a, 0xd1, 0x2b, 0x33, 0x54, 0x52, 0xe2, 0xe2, 0x71, 0xaa, 0x2c,
802
+	0x49, 0x2d, 0xf6, 0x4d, 0x2d, 0x2e, 0x4e, 0x4c, 0x4f, 0x15, 0x12, 0xe2, 0x62, 0x49, 0x49, 0x2c,
803
+	0x49, 0x94, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x09, 0x02, 0xb3, 0x95, 0x94, 0xb9, 0x04, 0x9d, 0x33,
804
+	0x52, 0x93, 0xb3, 0x1d, 0xd3, 0x53, 0xf3, 0x4a, 0x82, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84,
805
+	0xf8, 0xb8, 0x98, 0x3c, 0x5d, 0xc0, 0xca, 0x38, 0x83, 0x98, 0x3c, 0x5d, 0x94, 0x44, 0xb8, 0x84,
806
+	0x90, 0x15, 0x15, 0x17, 0xe4, 0xe7, 0x15, 0xa7, 0x1a, 0xed, 0x62, 0xe4, 0x62, 0x0e, 0x0e, 0xf6,
807
+	0x10, 0x8a, 0xe6, 0xe2, 0x42, 0xc8, 0x0a, 0xa9, 0xea, 0x61, 0xba, 0x44, 0x0f, 0xc3, 0x0a, 0x29,
808
+	0x35, 0x42, 0xca, 0x20, 0x96, 0x08, 0x85, 0x71, 0xf1, 0xb8, 0x41, 0x14, 0x40, 0x8c, 0x57, 0xc0,
809
+	0xa6, 0x0f, 0xd9, 0x97, 0x52, 0x04, 0x55, 0x68, 0x30, 0x1a, 0x30, 0x3a, 0x59, 0x5c, 0x78, 0x28,
810
+	0xc7, 0x70, 0xe3, 0xa1, 0x1c, 0xc3, 0x87, 0x87, 0x72, 0x8c, 0x0d, 0x8f, 0xe4, 0x18, 0x57, 0x3c,
811
+	0x92, 0x63, 0x3c, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x5f,
812
+	0x3c, 0x92, 0x63, 0xf8, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x28, 0x2e, 0x84, 0x69,
813
+	0x49, 0x6c, 0xe0, 0x00, 0x37, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x31, 0x3e, 0x40, 0xab, 0x7d,
814
+	0x01, 0x00, 0x00,
815
+}
0 816
new file mode 100644
... ...
@@ -0,0 +1,22 @@
0
+syntax = "proto3";
1
+
2
+package moby.sshforward.v1;
3
+
4
+option go_package = "sshforward";
5
+
6
+service SSH {
7
+	rpc CheckAgent(CheckAgentRequest) returns (CheckAgentResponse);
8
+	rpc ForwardAgent(stream BytesMessage) returns (stream BytesMessage);
9
+}
10
+
11
+// BytesMessage contains a chunk of byte data
12
+message BytesMessage{
13
+	bytes data = 1;
14
+}
15
+
16
+message CheckAgentRequest {
17
+	string ID = 1;
18
+}
19
+
20
+message CheckAgentResponse {
21
+}
0 22
\ No newline at end of file
... ...
@@ -3,13 +3,13 @@ package blobmapping
3 3
 import (
4 4
 	"context"
5 5
 
6
-	"github.com/boltdb/bolt"
7 6
 	"github.com/containerd/containerd/content"
8 7
 	"github.com/containerd/containerd/snapshots"
9 8
 	"github.com/moby/buildkit/cache/metadata"
10 9
 	"github.com/moby/buildkit/snapshot"
11 10
 	digest "github.com/opencontainers/go-digest"
12 11
 	"github.com/sirupsen/logrus"
12
+	bolt "go.etcd.io/bbolt"
13 13
 )
14 14
 
15 15
 const blobKey = "blobmapping.blob"
16 16
new file mode 100644
... ...
@@ -0,0 +1,459 @@
0
+package bboltcachestorage
1
+
2
+import (
3
+	"bytes"
4
+	"encoding/json"
5
+	"fmt"
6
+
7
+	"github.com/moby/buildkit/solver"
8
+	digest "github.com/opencontainers/go-digest"
9
+	"github.com/pkg/errors"
10
+	bolt "go.etcd.io/bbolt"
11
+)
12
+
13
+const (
14
+	resultBucket    = "_result"
15
+	linksBucket     = "_links"
16
+	byResultBucket  = "_byresult"
17
+	backlinksBucket = "_backlinks"
18
+)
19
+
20
+type Store struct {
21
+	db *bolt.DB
22
+}
23
+
24
+func NewStore(dbPath string) (*Store, error) {
25
+	db, err := bolt.Open(dbPath, 0600, nil)
26
+	if err != nil {
27
+		return nil, errors.Wrapf(err, "failed to open database file %s", dbPath)
28
+	}
29
+	if err := db.Update(func(tx *bolt.Tx) error {
30
+		for _, b := range []string{resultBucket, linksBucket, byResultBucket, backlinksBucket} {
31
+			if _, err := tx.CreateBucketIfNotExists([]byte(b)); err != nil {
32
+				return err
33
+			}
34
+		}
35
+		return nil
36
+	}); err != nil {
37
+		return nil, err
38
+	}
39
+	db.NoSync = true
40
+	return &Store{db: db}, nil
41
+}
42
+
43
+func (s *Store) Exists(id string) bool {
44
+	exists := false
45
+	err := s.db.View(func(tx *bolt.Tx) error {
46
+		b := tx.Bucket([]byte(linksBucket)).Bucket([]byte(id))
47
+		exists = b != nil
48
+		return nil
49
+	})
50
+	if err != nil {
51
+		return false
52
+	}
53
+	return exists
54
+}
55
+
56
+func (s *Store) Walk(fn func(id string) error) error {
57
+	ids := make([]string, 0)
58
+	if err := s.db.View(func(tx *bolt.Tx) error {
59
+		b := tx.Bucket([]byte(linksBucket))
60
+		c := b.Cursor()
61
+		for k, v := c.First(); k != nil; k, v = c.Next() {
62
+			if v == nil {
63
+				ids = append(ids, string(k))
64
+			}
65
+		}
66
+		return nil
67
+	}); err != nil {
68
+		return err
69
+	}
70
+	for _, id := range ids {
71
+		if err := fn(id); err != nil {
72
+			return err
73
+		}
74
+	}
75
+	return nil
76
+}
77
+
78
+func (s *Store) WalkResults(id string, fn func(solver.CacheResult) error) error {
79
+	var list []solver.CacheResult
80
+	if err := s.db.View(func(tx *bolt.Tx) error {
81
+		b := tx.Bucket([]byte(resultBucket))
82
+		if b == nil {
83
+			return nil
84
+		}
85
+		b = b.Bucket([]byte(id))
86
+		if b == nil {
87
+			return nil
88
+		}
89
+
90
+		return b.ForEach(func(k, v []byte) error {
91
+			var res solver.CacheResult
92
+			if err := json.Unmarshal(v, &res); err != nil {
93
+				return err
94
+			}
95
+			list = append(list, res)
96
+			return nil
97
+		})
98
+	}); err != nil {
99
+		return err
100
+	}
101
+	for _, res := range list {
102
+		if err := fn(res); err != nil {
103
+			return err
104
+		}
105
+	}
106
+	return nil
107
+}
108
+
109
+func (s *Store) Load(id string, resultID string) (solver.CacheResult, error) {
110
+	var res solver.CacheResult
111
+	if err := s.db.View(func(tx *bolt.Tx) error {
112
+		b := tx.Bucket([]byte(resultBucket))
113
+		if b == nil {
114
+			return errors.WithStack(solver.ErrNotFound)
115
+		}
116
+		b = b.Bucket([]byte(id))
117
+		if b == nil {
118
+			return errors.WithStack(solver.ErrNotFound)
119
+		}
120
+
121
+		v := b.Get([]byte(resultID))
122
+		if v == nil {
123
+			return errors.WithStack(solver.ErrNotFound)
124
+		}
125
+
126
+		return json.Unmarshal(v, &res)
127
+	}); err != nil {
128
+		return solver.CacheResult{}, err
129
+	}
130
+	return res, nil
131
+}
132
+
133
+func (s *Store) AddResult(id string, res solver.CacheResult) error {
134
+	return s.db.Update(func(tx *bolt.Tx) error {
135
+		_, err := tx.Bucket([]byte(linksBucket)).CreateBucketIfNotExists([]byte(id))
136
+		if err != nil {
137
+			return err
138
+		}
139
+
140
+		b, err := tx.Bucket([]byte(resultBucket)).CreateBucketIfNotExists([]byte(id))
141
+		if err != nil {
142
+			return err
143
+		}
144
+		dt, err := json.Marshal(res)
145
+		if err != nil {
146
+			return err
147
+		}
148
+		if err := b.Put([]byte(res.ID), dt); err != nil {
149
+			return err
150
+		}
151
+		b, err = tx.Bucket([]byte(byResultBucket)).CreateBucketIfNotExists([]byte(res.ID))
152
+		if err != nil {
153
+			return err
154
+		}
155
+		if err := b.Put([]byte(id), []byte{}); err != nil {
156
+			return err
157
+		}
158
+
159
+		return nil
160
+	})
161
+}
162
+
163
+func (s *Store) WalkIDsByResult(resultID string, fn func(string) error) error {
164
+	ids := map[string]struct{}{}
165
+	if err := s.db.View(func(tx *bolt.Tx) error {
166
+		b := tx.Bucket([]byte(byResultBucket))
167
+		if b == nil {
168
+			return nil
169
+		}
170
+		b = b.Bucket([]byte(resultID))
171
+		if b == nil {
172
+			return nil
173
+		}
174
+		return b.ForEach(func(k, v []byte) error {
175
+			ids[string(k)] = struct{}{}
176
+			return nil
177
+		})
178
+	}); err != nil {
179
+		return err
180
+	}
181
+	for id := range ids {
182
+		if err := fn(id); err != nil {
183
+			return err
184
+		}
185
+	}
186
+	return nil
187
+}
188
+
189
+func (s *Store) Release(resultID string) error {
190
+	return s.db.Update(func(tx *bolt.Tx) error {
191
+		b := tx.Bucket([]byte(byResultBucket))
192
+		if b == nil {
193
+			return errors.WithStack(solver.ErrNotFound)
194
+		}
195
+		b = b.Bucket([]byte(resultID))
196
+		if b == nil {
197
+			return errors.WithStack(solver.ErrNotFound)
198
+		}
199
+		if err := b.ForEach(func(k, v []byte) error {
200
+			return s.releaseHelper(tx, string(k), resultID)
201
+		}); err != nil {
202
+			return err
203
+		}
204
+		return nil
205
+	})
206
+}
207
+
208
+func (s *Store) releaseHelper(tx *bolt.Tx, id, resultID string) error {
209
+	results := tx.Bucket([]byte(resultBucket)).Bucket([]byte(id))
210
+	if results == nil {
211
+		return nil
212
+	}
213
+
214
+	if err := results.Delete([]byte(resultID)); err != nil {
215
+		return err
216
+	}
217
+
218
+	ids := tx.Bucket([]byte(byResultBucket))
219
+
220
+	ids = ids.Bucket([]byte(resultID))
221
+	if ids == nil {
222
+		return nil
223
+	}
224
+
225
+	if err := ids.Delete([]byte(id)); err != nil {
226
+		return err
227
+	}
228
+
229
+	if isEmptyBucket(ids) {
230
+		if err := tx.Bucket([]byte(byResultBucket)).DeleteBucket([]byte(resultID)); err != nil {
231
+			return err
232
+		}
233
+	}
234
+
235
+	links := tx.Bucket([]byte(resultBucket))
236
+	if results == nil {
237
+		return nil
238
+	}
239
+	links = links.Bucket([]byte(id))
240
+
241
+	return s.emptyBranchWithParents(tx, []byte(id))
242
+}
243
+
244
+func (s *Store) emptyBranchWithParents(tx *bolt.Tx, id []byte) error {
245
+	results := tx.Bucket([]byte(resultBucket)).Bucket(id)
246
+	if results == nil {
247
+		return nil
248
+	}
249
+
250
+	isEmptyLinks := true
251
+	links := tx.Bucket([]byte(linksBucket)).Bucket(id)
252
+	if links != nil {
253
+		isEmptyLinks = isEmptyBucket(links)
254
+	}
255
+
256
+	if !isEmptyBucket(results) || !isEmptyLinks {
257
+		return nil
258
+	}
259
+
260
+	if backlinks := tx.Bucket([]byte(backlinksBucket)).Bucket(id); backlinks != nil {
261
+		if err := backlinks.ForEach(func(k, v []byte) error {
262
+			if subLinks := tx.Bucket([]byte(linksBucket)).Bucket(k); subLinks != nil {
263
+				if err := subLinks.ForEach(func(k, v []byte) error {
264
+					parts := bytes.Split(k, []byte("@"))
265
+					if len(parts) != 2 {
266
+						return errors.Errorf("invalid key %s", k)
267
+					}
268
+					if bytes.Equal(id, parts[1]) {
269
+						return subLinks.Delete(k)
270
+					}
271
+					return nil
272
+				}); err != nil {
273
+					return err
274
+				}
275
+
276
+				if isEmptyBucket(subLinks) {
277
+					if err := tx.Bucket([]byte(linksBucket)).DeleteBucket(k); err != nil {
278
+						return err
279
+					}
280
+				}
281
+			}
282
+			return s.emptyBranchWithParents(tx, k)
283
+		}); err != nil {
284
+			return err
285
+		}
286
+		if err := tx.Bucket([]byte(backlinksBucket)).DeleteBucket(id); err != nil {
287
+			return err
288
+		}
289
+	}
290
+
291
+	// intentionally ignoring errors
292
+	tx.Bucket([]byte(linksBucket)).DeleteBucket([]byte(id))
293
+	tx.Bucket([]byte(resultBucket)).DeleteBucket([]byte(id))
294
+
295
+	return nil
296
+}
297
+
298
+func (s *Store) AddLink(id string, link solver.CacheInfoLink, target string) error {
299
+	return s.db.Update(func(tx *bolt.Tx) error {
300
+		b, err := tx.Bucket([]byte(linksBucket)).CreateBucketIfNotExists([]byte(id))
301
+		if err != nil {
302
+			return err
303
+		}
304
+
305
+		dt, err := json.Marshal(link)
306
+		if err != nil {
307
+			return err
308
+		}
309
+
310
+		if err := b.Put(bytes.Join([][]byte{dt, []byte(target)}, []byte("@")), []byte{}); err != nil {
311
+			return err
312
+		}
313
+
314
+		b, err = tx.Bucket([]byte(backlinksBucket)).CreateBucketIfNotExists([]byte(target))
315
+		if err != nil {
316
+			return err
317
+		}
318
+
319
+		if err := b.Put([]byte(id), []byte{}); err != nil {
320
+			return err
321
+		}
322
+
323
+		return nil
324
+	})
325
+}
326
+
327
+func (s *Store) WalkLinks(id string, link solver.CacheInfoLink, fn func(id string) error) error {
328
+	var links []string
329
+	if err := s.db.View(func(tx *bolt.Tx) error {
330
+		b := tx.Bucket([]byte(linksBucket))
331
+		if b == nil {
332
+			return nil
333
+		}
334
+		b = b.Bucket([]byte(id))
335
+		if b == nil {
336
+			return nil
337
+		}
338
+
339
+		dt, err := json.Marshal(link)
340
+		if err != nil {
341
+			return err
342
+		}
343
+		index := bytes.Join([][]byte{dt, {}}, []byte("@"))
344
+		c := b.Cursor()
345
+		k, _ := c.Seek([]byte(index))
346
+		for {
347
+			if k != nil && bytes.HasPrefix(k, index) {
348
+				target := bytes.TrimPrefix(k, index)
349
+				links = append(links, string(target))
350
+				k, _ = c.Next()
351
+			} else {
352
+				break
353
+			}
354
+		}
355
+
356
+		return nil
357
+	}); err != nil {
358
+		return err
359
+	}
360
+	for _, l := range links {
361
+		if err := fn(l); err != nil {
362
+			return err
363
+		}
364
+	}
365
+	return nil
366
+}
367
+
368
+func (s *Store) HasLink(id string, link solver.CacheInfoLink, target string) bool {
369
+	var v bool
370
+	if err := s.db.View(func(tx *bolt.Tx) error {
371
+		b := tx.Bucket([]byte(linksBucket))
372
+		if b == nil {
373
+			return nil
374
+		}
375
+		b = b.Bucket([]byte(id))
376
+		if b == nil {
377
+			return nil
378
+		}
379
+
380
+		dt, err := json.Marshal(link)
381
+		if err != nil {
382
+			return err
383
+		}
384
+		v = b.Get(bytes.Join([][]byte{dt, []byte(target)}, []byte("@"))) != nil
385
+		return nil
386
+	}); err != nil {
387
+		return false
388
+	}
389
+	return v
390
+}
391
+
392
+func (s *Store) WalkBacklinks(id string, fn func(id string, link solver.CacheInfoLink) error) error {
393
+	var outIDs []string
394
+	var outLinks []solver.CacheInfoLink
395
+
396
+	if err := s.db.View(func(tx *bolt.Tx) error {
397
+		links := tx.Bucket([]byte(linksBucket))
398
+		if links == nil {
399
+			return nil
400
+		}
401
+		backLinks := tx.Bucket([]byte(backlinksBucket))
402
+		if backLinks == nil {
403
+			return nil
404
+		}
405
+		b := backLinks.Bucket([]byte(id))
406
+		if b == nil {
407
+			return nil
408
+		}
409
+
410
+		if err := b.ForEach(func(bid, v []byte) error {
411
+			b = links.Bucket(bid)
412
+			if b == nil {
413
+				return nil
414
+			}
415
+			if err := b.ForEach(func(k, v []byte) error {
416
+				parts := bytes.Split(k, []byte("@"))
417
+				if len(parts) == 2 {
418
+					if string(parts[1]) != id {
419
+						return nil
420
+					}
421
+					var l solver.CacheInfoLink
422
+					if err := json.Unmarshal(parts[0], &l); err != nil {
423
+						return err
424
+					}
425
+					l.Digest = digest.FromBytes([]byte(fmt.Sprintf("%s@%d", l.Digest, l.Output)))
426
+					l.Output = 0
427
+					outIDs = append(outIDs, string(bid))
428
+					outLinks = append(outLinks, l)
429
+				}
430
+				return nil
431
+			}); err != nil {
432
+				return err
433
+			}
434
+			return nil
435
+		}); err != nil {
436
+			return err
437
+		}
438
+
439
+		return nil
440
+	}); err != nil {
441
+		return err
442
+	}
443
+
444
+	for i := range outIDs {
445
+		if err := fn(outIDs[i], outLinks[i]); err != nil {
446
+			return err
447
+		}
448
+	}
449
+	return nil
450
+}
451
+
452
+func isEmptyBucket(b *bolt.Bucket) bool {
453
+	if b == nil {
454
+		return true
455
+	}
456
+	k, _ := b.Cursor().First()
457
+	return k == nil
458
+}
0 459
deleted file mode 100644
... ...
@@ -1,459 +0,0 @@
1
-package boltdbcachestorage
2
-
3
-import (
4
-	"bytes"
5
-	"encoding/json"
6
-	"fmt"
7
-
8
-	"github.com/boltdb/bolt"
9
-	"github.com/moby/buildkit/solver"
10
-	digest "github.com/opencontainers/go-digest"
11
-	"github.com/pkg/errors"
12
-)
13
-
14
-const (
15
-	resultBucket    = "_result"
16
-	linksBucket     = "_links"
17
-	byResultBucket  = "_byresult"
18
-	backlinksBucket = "_backlinks"
19
-)
20
-
21
-type Store struct {
22
-	db *bolt.DB
23
-}
24
-
25
-func NewStore(dbPath string) (*Store, error) {
26
-	db, err := bolt.Open(dbPath, 0600, nil)
27
-	if err != nil {
28
-		return nil, errors.Wrapf(err, "failed to open database file %s", dbPath)
29
-	}
30
-	if err := db.Update(func(tx *bolt.Tx) error {
31
-		for _, b := range []string{resultBucket, linksBucket, byResultBucket, backlinksBucket} {
32
-			if _, err := tx.CreateBucketIfNotExists([]byte(b)); err != nil {
33
-				return err
34
-			}
35
-		}
36
-		return nil
37
-	}); err != nil {
38
-		return nil, err
39
-	}
40
-	db.NoSync = true
41
-	return &Store{db: db}, nil
42
-}
43
-
44
-func (s *Store) Exists(id string) bool {
45
-	exists := false
46
-	err := s.db.View(func(tx *bolt.Tx) error {
47
-		b := tx.Bucket([]byte(linksBucket)).Bucket([]byte(id))
48
-		exists = b != nil
49
-		return nil
50
-	})
51
-	if err != nil {
52
-		return false
53
-	}
54
-	return exists
55
-}
56
-
57
-func (s *Store) Walk(fn func(id string) error) error {
58
-	ids := make([]string, 0)
59
-	if err := s.db.View(func(tx *bolt.Tx) error {
60
-		b := tx.Bucket([]byte(linksBucket))
61
-		c := b.Cursor()
62
-		for k, v := c.First(); k != nil; k, v = c.Next() {
63
-			if v == nil {
64
-				ids = append(ids, string(k))
65
-			}
66
-		}
67
-		return nil
68
-	}); err != nil {
69
-		return err
70
-	}
71
-	for _, id := range ids {
72
-		if err := fn(id); err != nil {
73
-			return err
74
-		}
75
-	}
76
-	return nil
77
-}
78
-
79
-func (s *Store) WalkResults(id string, fn func(solver.CacheResult) error) error {
80
-	var list []solver.CacheResult
81
-	if err := s.db.View(func(tx *bolt.Tx) error {
82
-		b := tx.Bucket([]byte(resultBucket))
83
-		if b == nil {
84
-			return nil
85
-		}
86
-		b = b.Bucket([]byte(id))
87
-		if b == nil {
88
-			return nil
89
-		}
90
-
91
-		return b.ForEach(func(k, v []byte) error {
92
-			var res solver.CacheResult
93
-			if err := json.Unmarshal(v, &res); err != nil {
94
-				return err
95
-			}
96
-			list = append(list, res)
97
-			return nil
98
-		})
99
-	}); err != nil {
100
-		return err
101
-	}
102
-	for _, res := range list {
103
-		if err := fn(res); err != nil {
104
-			return err
105
-		}
106
-	}
107
-	return nil
108
-}
109
-
110
-func (s *Store) Load(id string, resultID string) (solver.CacheResult, error) {
111
-	var res solver.CacheResult
112
-	if err := s.db.View(func(tx *bolt.Tx) error {
113
-		b := tx.Bucket([]byte(resultBucket))
114
-		if b == nil {
115
-			return errors.WithStack(solver.ErrNotFound)
116
-		}
117
-		b = b.Bucket([]byte(id))
118
-		if b == nil {
119
-			return errors.WithStack(solver.ErrNotFound)
120
-		}
121
-
122
-		v := b.Get([]byte(resultID))
123
-		if v == nil {
124
-			return errors.WithStack(solver.ErrNotFound)
125
-		}
126
-
127
-		return json.Unmarshal(v, &res)
128
-	}); err != nil {
129
-		return solver.CacheResult{}, err
130
-	}
131
-	return res, nil
132
-}
133
-
134
-func (s *Store) AddResult(id string, res solver.CacheResult) error {
135
-	return s.db.Update(func(tx *bolt.Tx) error {
136
-		_, err := tx.Bucket([]byte(linksBucket)).CreateBucketIfNotExists([]byte(id))
137
-		if err != nil {
138
-			return err
139
-		}
140
-
141
-		b, err := tx.Bucket([]byte(resultBucket)).CreateBucketIfNotExists([]byte(id))
142
-		if err != nil {
143
-			return err
144
-		}
145
-		dt, err := json.Marshal(res)
146
-		if err != nil {
147
-			return err
148
-		}
149
-		if err := b.Put([]byte(res.ID), dt); err != nil {
150
-			return err
151
-		}
152
-		b, err = tx.Bucket([]byte(byResultBucket)).CreateBucketIfNotExists([]byte(res.ID))
153
-		if err != nil {
154
-			return err
155
-		}
156
-		if err := b.Put([]byte(id), []byte{}); err != nil {
157
-			return err
158
-		}
159
-
160
-		return nil
161
-	})
162
-}
163
-
164
-func (s *Store) WalkIDsByResult(resultID string, fn func(string) error) error {
165
-	ids := map[string]struct{}{}
166
-	if err := s.db.View(func(tx *bolt.Tx) error {
167
-		b := tx.Bucket([]byte(byResultBucket))
168
-		if b == nil {
169
-			return nil
170
-		}
171
-		b = b.Bucket([]byte(resultID))
172
-		if b == nil {
173
-			return nil
174
-		}
175
-		return b.ForEach(func(k, v []byte) error {
176
-			ids[string(k)] = struct{}{}
177
-			return nil
178
-		})
179
-	}); err != nil {
180
-		return err
181
-	}
182
-	for id := range ids {
183
-		if err := fn(id); err != nil {
184
-			return err
185
-		}
186
-	}
187
-	return nil
188
-}
189
-
190
-func (s *Store) Release(resultID string) error {
191
-	return s.db.Update(func(tx *bolt.Tx) error {
192
-		b := tx.Bucket([]byte(byResultBucket))
193
-		if b == nil {
194
-			return errors.WithStack(solver.ErrNotFound)
195
-		}
196
-		b = b.Bucket([]byte(resultID))
197
-		if b == nil {
198
-			return errors.WithStack(solver.ErrNotFound)
199
-		}
200
-		if err := b.ForEach(func(k, v []byte) error {
201
-			return s.releaseHelper(tx, string(k), resultID)
202
-		}); err != nil {
203
-			return err
204
-		}
205
-		return nil
206
-	})
207
-}
208
-
209
-func (s *Store) releaseHelper(tx *bolt.Tx, id, resultID string) error {
210
-	results := tx.Bucket([]byte(resultBucket)).Bucket([]byte(id))
211
-	if results == nil {
212
-		return nil
213
-	}
214
-
215
-	if err := results.Delete([]byte(resultID)); err != nil {
216
-		return err
217
-	}
218
-
219
-	ids := tx.Bucket([]byte(byResultBucket))
220
-
221
-	ids = ids.Bucket([]byte(resultID))
222
-	if ids == nil {
223
-		return nil
224
-	}
225
-
226
-	if err := ids.Delete([]byte(id)); err != nil {
227
-		return err
228
-	}
229
-
230
-	if isEmptyBucket(ids) {
231
-		if err := tx.Bucket([]byte(byResultBucket)).DeleteBucket([]byte(resultID)); err != nil {
232
-			return err
233
-		}
234
-	}
235
-
236
-	links := tx.Bucket([]byte(resultBucket))
237
-	if results == nil {
238
-		return nil
239
-	}
240
-	links = links.Bucket([]byte(id))
241
-
242
-	return s.emptyBranchWithParents(tx, []byte(id))
243
-}
244
-
245
-func (s *Store) emptyBranchWithParents(tx *bolt.Tx, id []byte) error {
246
-	results := tx.Bucket([]byte(resultBucket)).Bucket(id)
247
-	if results == nil {
248
-		return nil
249
-	}
250
-
251
-	isEmptyLinks := true
252
-	links := tx.Bucket([]byte(linksBucket)).Bucket(id)
253
-	if links != nil {
254
-		isEmptyLinks = isEmptyBucket(links)
255
-	}
256
-
257
-	if !isEmptyBucket(results) || !isEmptyLinks {
258
-		return nil
259
-	}
260
-
261
-	if backlinks := tx.Bucket([]byte(backlinksBucket)).Bucket(id); backlinks != nil {
262
-		if err := backlinks.ForEach(func(k, v []byte) error {
263
-			if subLinks := tx.Bucket([]byte(linksBucket)).Bucket(k); subLinks != nil {
264
-				if err := subLinks.ForEach(func(k, v []byte) error {
265
-					parts := bytes.Split(k, []byte("@"))
266
-					if len(parts) != 2 {
267
-						return errors.Errorf("invalid key %s", k)
268
-					}
269
-					if bytes.Equal(id, parts[1]) {
270
-						return subLinks.Delete(k)
271
-					}
272
-					return nil
273
-				}); err != nil {
274
-					return err
275
-				}
276
-
277
-				if isEmptyBucket(subLinks) {
278
-					if err := tx.Bucket([]byte(linksBucket)).DeleteBucket(k); err != nil {
279
-						return err
280
-					}
281
-				}
282
-			}
283
-			return s.emptyBranchWithParents(tx, k)
284
-		}); err != nil {
285
-			return err
286
-		}
287
-		if err := tx.Bucket([]byte(backlinksBucket)).DeleteBucket(id); err != nil {
288
-			return err
289
-		}
290
-	}
291
-
292
-	// intentionally ignoring errors
293
-	tx.Bucket([]byte(linksBucket)).DeleteBucket([]byte(id))
294
-	tx.Bucket([]byte(resultBucket)).DeleteBucket([]byte(id))
295
-
296
-	return nil
297
-}
298
-
299
-func (s *Store) AddLink(id string, link solver.CacheInfoLink, target string) error {
300
-	return s.db.Update(func(tx *bolt.Tx) error {
301
-		b, err := tx.Bucket([]byte(linksBucket)).CreateBucketIfNotExists([]byte(id))
302
-		if err != nil {
303
-			return err
304
-		}
305
-
306
-		dt, err := json.Marshal(link)
307
-		if err != nil {
308
-			return err
309
-		}
310
-
311
-		if err := b.Put(bytes.Join([][]byte{dt, []byte(target)}, []byte("@")), []byte{}); err != nil {
312
-			return err
313
-		}
314
-
315
-		b, err = tx.Bucket([]byte(backlinksBucket)).CreateBucketIfNotExists([]byte(target))
316
-		if err != nil {
317
-			return err
318
-		}
319
-
320
-		if err := b.Put([]byte(id), []byte{}); err != nil {
321
-			return err
322
-		}
323
-
324
-		return nil
325
-	})
326
-}
327
-
328
-func (s *Store) WalkLinks(id string, link solver.CacheInfoLink, fn func(id string) error) error {
329
-	var links []string
330
-	if err := s.db.View(func(tx *bolt.Tx) error {
331
-		b := tx.Bucket([]byte(linksBucket))
332
-		if b == nil {
333
-			return nil
334
-		}
335
-		b = b.Bucket([]byte(id))
336
-		if b == nil {
337
-			return nil
338
-		}
339
-
340
-		dt, err := json.Marshal(link)
341
-		if err != nil {
342
-			return err
343
-		}
344
-		index := bytes.Join([][]byte{dt, {}}, []byte("@"))
345
-		c := b.Cursor()
346
-		k, _ := c.Seek([]byte(index))
347
-		for {
348
-			if k != nil && bytes.HasPrefix(k, index) {
349
-				target := bytes.TrimPrefix(k, index)
350
-				links = append(links, string(target))
351
-				k, _ = c.Next()
352
-			} else {
353
-				break
354
-			}
355
-		}
356
-
357
-		return nil
358
-	}); err != nil {
359
-		return err
360
-	}
361
-	for _, l := range links {
362
-		if err := fn(l); err != nil {
363
-			return err
364
-		}
365
-	}
366
-	return nil
367
-}
368
-
369
-func (s *Store) HasLink(id string, link solver.CacheInfoLink, target string) bool {
370
-	var v bool
371
-	if err := s.db.View(func(tx *bolt.Tx) error {
372
-		b := tx.Bucket([]byte(linksBucket))
373
-		if b == nil {
374
-			return nil
375
-		}
376
-		b = b.Bucket([]byte(id))
377
-		if b == nil {
378
-			return nil
379
-		}
380
-
381
-		dt, err := json.Marshal(link)
382
-		if err != nil {
383
-			return err
384
-		}
385
-		v = b.Get(bytes.Join([][]byte{dt, []byte(target)}, []byte("@"))) != nil
386
-		return nil
387
-	}); err != nil {
388
-		return false
389
-	}
390
-	return v
391
-}
392
-
393
-func (s *Store) WalkBacklinks(id string, fn func(id string, link solver.CacheInfoLink) error) error {
394
-	var outIDs []string
395
-	var outLinks []solver.CacheInfoLink
396
-
397
-	if err := s.db.View(func(tx *bolt.Tx) error {
398
-		links := tx.Bucket([]byte(linksBucket))
399
-		if links == nil {
400
-			return nil
401
-		}
402
-		backLinks := tx.Bucket([]byte(backlinksBucket))
403
-		if backLinks == nil {
404
-			return nil
405
-		}
406
-		b := backLinks.Bucket([]byte(id))
407
-		if b == nil {
408
-			return nil
409
-		}
410
-
411
-		if err := b.ForEach(func(bid, v []byte) error {
412
-			b = links.Bucket(bid)
413
-			if b == nil {
414
-				return nil
415
-			}
416
-			if err := b.ForEach(func(k, v []byte) error {
417
-				parts := bytes.Split(k, []byte("@"))
418
-				if len(parts) == 2 {
419
-					if string(parts[1]) != id {
420
-						return nil
421
-					}
422
-					var l solver.CacheInfoLink
423
-					if err := json.Unmarshal(parts[0], &l); err != nil {
424
-						return err
425
-					}
426
-					l.Digest = digest.FromBytes([]byte(fmt.Sprintf("%s@%d", l.Digest, l.Output)))
427
-					l.Output = 0
428
-					outIDs = append(outIDs, string(bid))
429
-					outLinks = append(outLinks, l)
430
-				}
431
-				return nil
432
-			}); err != nil {
433
-				return err
434
-			}
435
-			return nil
436
-		}); err != nil {
437
-			return err
438
-		}
439
-
440
-		return nil
441
-	}); err != nil {
442
-		return err
443
-	}
444
-
445
-	for i := range outIDs {
446
-		if err := fn(outIDs[i], outLinks[i]); err != nil {
447
-			return err
448
-		}
449
-	}
450
-	return nil
451
-}
452
-
453
-func isEmptyBucket(b *bolt.Bucket) bool {
454
-	if b == nil {
455
-		return true
456
-	}
457
-	k, _ := b.Cursor().First()
458
-	return k == nil
459
-}
... ...
@@ -10,12 +10,12 @@ import (
10 10
 	"github.com/sirupsen/logrus"
11 11
 )
12 12
 
13
-type CacheID string
14
-
13
+// NewInMemoryCacheManager creates a new in-memory cache manager
15 14
 func NewInMemoryCacheManager() CacheManager {
16 15
 	return NewCacheManager(identity.NewID(), NewInMemoryCacheStorage(), NewInMemoryResultStorage())
17 16
 }
18 17
 
18
+// NewCacheManager creates a new cache manager with specific storage backend
19 19
 func NewCacheManager(id string, storage CacheKeyStorage, results CacheResultStorage) CacheManager {
20 20
 	cm := &cacheManager{
21 21
 		id:      id,
... ...
@@ -26,7 +26,7 @@ type Builder interface {
26 26
 
27 27
 // Solver provides a shared graph of all the vertexes currently being
28 28
 // processed. Every vertex that is being solved needs to be loaded into job
29
-// first. Vertex operations are invoked and progress tracking happends through
29
+// first. Vertex operations are invoked and progress tracking happens through
30 30
 // jobs.
31 31
 type Solver struct {
32 32
 	mu      sync.RWMutex
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"strings"
8 8
 	"sync"
9 9
 
10
+	"github.com/containerd/containerd/platforms"
10 11
 	"github.com/docker/distribution/reference"
11 12
 	"github.com/moby/buildkit/cache"
12 13
 	"github.com/moby/buildkit/cache/remotecache"
... ...
@@ -49,7 +50,7 @@ func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res *
49 49
 			func(ref string) {
50 50
 				cm = newLazyCacheManager(ref, func() (solver.CacheManager, error) {
51 51
 					var cmNew solver.CacheManager
52
-					if err := inVertexContext(b.builder.Context(ctx), "importing cache manifest from "+ref, func(ctx context.Context) error {
52
+					if err := inVertexContext(b.builder.Context(ctx), "importing cache manifest from "+ref, "", func(ctx context.Context) error {
53 53
 						if b.resolveCacheImporter == nil {
54 54
 							return errors.New("no cache importer is available")
55 55
 						}
... ...
@@ -143,7 +144,13 @@ func (s *llbBridge) ResolveImageConfig(ctx context.Context, ref string, opt gw.R
143 143
 	if opt.LogName == "" {
144 144
 		opt.LogName = fmt.Sprintf("resolve image config for %s", ref)
145 145
 	}
146
-	err = inVertexContext(s.builder.Context(ctx), opt.LogName, func(ctx context.Context) error {
146
+	id := ref // make a deterministic ID for avoiding duplicates
147
+	if platform := opt.Platform; platform == nil {
148
+		id += platforms.Format(platforms.DefaultSpec())
149
+	} else {
150
+		id += platforms.Format(*platform)
151
+	}
152
+	err = inVertexContext(s.builder.Context(ctx), opt.LogName, id, func(ctx context.Context) error {
147 153
 		dgst, config, err = w.ResolveImageConfig(ctx, ref, opt)
148 154
 		return err
149 155
 	})
... ...
@@ -16,7 +16,6 @@ import (
16 16
 	"sync"
17 17
 	"time"
18 18
 
19
-	"github.com/boltdb/bolt"
20 19
 	"github.com/containerd/containerd/mount"
21 20
 	"github.com/docker/docker/pkg/locker"
22 21
 	"github.com/moby/buildkit/cache"
... ...
@@ -26,6 +25,7 @@ import (
26 26
 	"github.com/moby/buildkit/identity"
27 27
 	"github.com/moby/buildkit/session"
28 28
 	"github.com/moby/buildkit/session/secrets"
29
+	"github.com/moby/buildkit/session/sshforward"
29 30
 	"github.com/moby/buildkit/snapshot"
30 31
 	"github.com/moby/buildkit/solver"
31 32
 	"github.com/moby/buildkit/solver/llbsolver"
... ...
@@ -36,6 +36,9 @@ import (
36 36
 	"github.com/opencontainers/runc/libcontainer/system"
37 37
 	"github.com/pkg/errors"
38 38
 	"github.com/sirupsen/logrus"
39
+	bolt "go.etcd.io/bbolt"
40
+	"google.golang.org/grpc/codes"
41
+	"google.golang.org/grpc/status"
39 42
 )
40 43
 
41 44
 const execCacheType = "buildkit.exec.v0"
... ...
@@ -279,6 +282,85 @@ func (e *execOp) getRefCacheDirNoCache(ctx context.Context, key string, ref cach
279 279
 	return mRef, nil
280 280
 }
281 281
 
282
+func (e *execOp) getSSHMountable(ctx context.Context, m *pb.Mount) (cache.Mountable, error) {
283
+	sessionID := session.FromContext(ctx)
284
+	if sessionID == "" {
285
+		return nil, errors.New("could not access local files without session")
286
+	}
287
+
288
+	timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
289
+	defer cancel()
290
+
291
+	caller, err := e.sm.Get(timeoutCtx, sessionID)
292
+	if err != nil {
293
+		return nil, err
294
+	}
295
+
296
+	if err := sshforward.CheckSSHID(ctx, caller, m.SSHOpt.ID); err != nil {
297
+		if m.SSHOpt.Optional {
298
+			return nil, nil
299
+		}
300
+		if st, ok := status.FromError(err); ok && st.Code() == codes.Unimplemented {
301
+			return nil, errors.Errorf("no ssh forwarded from the client")
302
+		}
303
+		return nil, err
304
+	}
305
+
306
+	return &sshMount{mount: m, caller: caller}, nil
307
+}
308
+
309
+type sshMount struct {
310
+	mount  *pb.Mount
311
+	caller session.Caller
312
+}
313
+
314
+func (sm *sshMount) Mount(ctx context.Context, readonly bool) (snapshot.Mountable, error) {
315
+	return &sshMountInstance{sm: sm}, nil
316
+}
317
+
318
+type sshMountInstance struct {
319
+	sm      *sshMount
320
+	cleanup func() error
321
+}
322
+
323
+func (sm *sshMountInstance) Mount() ([]mount.Mount, error) {
324
+	ctx, cancel := context.WithCancel(context.TODO())
325
+
326
+	sock, cleanup, err := sshforward.MountSSHSocket(ctx, sm.sm.caller, sshforward.SocketOpt{
327
+		ID:   sm.sm.mount.SSHOpt.ID,
328
+		UID:  int(sm.sm.mount.SSHOpt.Uid),
329
+		GID:  int(sm.sm.mount.SSHOpt.Gid),
330
+		Mode: int(sm.sm.mount.SSHOpt.Mode),
331
+	})
332
+	if err != nil {
333
+		cancel()
334
+		return nil, err
335
+	}
336
+	sm.cleanup = func() error {
337
+		var err error
338
+		if cleanup != nil {
339
+			err = cleanup()
340
+		}
341
+		cancel()
342
+		return err
343
+	}
344
+
345
+	return []mount.Mount{{
346
+		Type:    "bind",
347
+		Source:  sock,
348
+		Options: []string{"rbind"},
349
+	}}, nil
350
+}
351
+
352
+func (sm *sshMountInstance) Release() error {
353
+	if sm.cleanup != nil {
354
+		if err := sm.cleanup(); err != nil {
355
+			return err
356
+		}
357
+	}
358
+	return nil
359
+}
360
+
282 361
 func (e *execOp) getSecretMountable(ctx context.Context, m *pb.Mount) (cache.Mountable, error) {
283 362
 	if m.SecretOpt == nil {
284 363
 		return nil, errors.Errorf("invalid sercet mount options")
... ...
@@ -482,6 +564,17 @@ func (e *execOp) Exec(ctx context.Context, inputs []solver.Result) ([]solver.Res
482 482
 				continue
483 483
 			}
484 484
 			mountable = secretMount
485
+
486
+		case pb.MountType_SSH:
487
+			sshMount, err := e.getSSHMountable(ctx, m)
488
+			if err != nil {
489
+				return nil, err
490
+			}
491
+			if sshMount == nil {
492
+				continue
493
+			}
494
+			mountable = sshMount
495
+
485 496
 		default:
486 497
 			return nil, errors.Errorf("mount type %s not implemented", m.MountType)
487 498
 		}
... ...
@@ -168,7 +168,7 @@ func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest
168 168
 			inp.Refs = m
169 169
 		}
170 170
 
171
-		if err := inVertexContext(j.Context(ctx), exp.Name(), func(ctx context.Context) error {
171
+		if err := inVertexContext(j.Context(ctx), exp.Name(), "", func(ctx context.Context) error {
172 172
 			exporterResponse, err = exp.Export(ctx, inp)
173 173
 			return err
174 174
 		}); err != nil {
... ...
@@ -177,7 +177,7 @@ func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest
177 177
 	}
178 178
 
179 179
 	if e := exp.CacheExporter; e != nil {
180
-		if err := inVertexContext(j.Context(ctx), "exporting cache", func(ctx context.Context) error {
180
+		if err := inVertexContext(j.Context(ctx), "exporting cache", "", func(ctx context.Context) error {
181 181
 			prepareDone := oneOffProgress(ctx, "preparing build cache for export")
182 182
 			if err := res.EachRef(func(res solver.CachedResult) error {
183 183
 				// all keys have same export chain so exporting others is not needed
... ...
@@ -243,9 +243,12 @@ func oneOffProgress(ctx context.Context, id string) func(err error) error {
243 243
 	}
244 244
 }
245 245
 
246
-func inVertexContext(ctx context.Context, name string, f func(ctx context.Context) error) error {
246
+func inVertexContext(ctx context.Context, name, id string, f func(ctx context.Context) error) error {
247
+	if id == "" {
248
+		id = identity.NewID()
249
+	}
247 250
 	v := client.Vertex{
248
-		Digest: digest.FromBytes([]byte(identity.NewID())),
251
+		Digest: digest.FromBytes([]byte(id)),
249 252
 		Name:   name,
250 253
 	}
251 254
 	pw, _, ctx := progress.FromContext(ctx, progress.WithMetadata("vertex", v.Digest))
... ...
@@ -1,12 +1,25 @@
1 1
 package pb
2 2
 
3
+// InputIndex is incrementing index to the input vertex
3 4
 type InputIndex int64
5
+
6
+// OutputIndex is incrementing index that another vertex can depend on
4 7
 type OutputIndex int64
5 8
 
9
+// RootMount is a base mountpoint
6 10
 const RootMount = "/"
11
+
12
+// SkipOutput marks a disabled output index
7 13
 const SkipOutput OutputIndex = -1
14
+
15
+// Empty marks an input with no content
8 16
 const Empty InputIndex = -1
17
+
18
+// LLBBuilder is a special builder for BuildOp that directly builds LLB
9 19
 const LLBBuilder InputIndex = -1
10 20
 
21
+// LLBDefinitionInput marks an input that contains LLB definition for BuildOp
11 22
 const LLBDefinitionInput = "buildkit.llb.definition"
23
+
24
+// LLBDefaultDefinitionFile is a filename containing the definition in LLBBuilder
12 25
 const LLBDefaultDefinitionFile = LLBDefinitionInput
... ...
@@ -19,6 +19,7 @@
19 19
 		Mount
20 20
 		CacheOpt
21 21
 		SecretOpt
22
+		SSHOpt
22 23
 		CopyOp
23 24
 		CopySource
24 25
 		SourceOp
... ...
@@ -41,6 +42,8 @@ import _ "github.com/gogo/protobuf/gogoproto"
41 41
 import github_com_opencontainers_go_digest "github.com/opencontainers/go-digest"
42 42
 import github_com_moby_buildkit_util_apicaps "github.com/moby/buildkit/util/apicaps"
43 43
 
44
+import sortkeys "github.com/gogo/protobuf/sortkeys"
45
+
44 46
 import io "io"
45 47
 
46 48
 // Reference imports to suppress errors if they are not otherwise used.
... ...
@@ -512,6 +515,7 @@ type Mount struct {
512 512
 	MountType MountType   `protobuf:"varint,6,opt,name=mountType,proto3,enum=pb.MountType" json:"mountType,omitempty"`
513 513
 	CacheOpt  *CacheOpt   `protobuf:"bytes,20,opt,name=cacheOpt" json:"cacheOpt,omitempty"`
514 514
 	SecretOpt *SecretOpt  `protobuf:"bytes,21,opt,name=secretOpt" json:"secretOpt,omitempty"`
515
+	SSHOpt    *SSHOpt     `protobuf:"bytes,22,opt,name=SSHOpt" json:"SSHOpt,omitempty"`
515 516
 }
516 517
 
517 518
 func (m *Mount) Reset()                    { *m = Mount{} }
... ...
@@ -561,6 +565,13 @@ func (m *Mount) GetSecretOpt() *SecretOpt {
561 561
 	return nil
562 562
 }
563 563
 
564
+func (m *Mount) GetSSHOpt() *SSHOpt {
565
+	if m != nil {
566
+		return m.SSHOpt
567
+	}
568
+	return nil
569
+}
570
+
564 571
 // CacheOpt defines options specific to cache mounts
565 572
 type CacheOpt struct {
566 573
 	// ID is an optional namespace for the mount
... ...
@@ -643,6 +654,61 @@ func (m *SecretOpt) GetOptional() bool {
643 643
 	return false
644 644
 }
645 645
 
646
+// SSHOpt defines options describing secret mounts
647
+type SSHOpt struct {
648
+	// ID of exposed ssh rule. Used for quering the value.
649
+	ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
650
+	// UID of agent socket
651
+	Uid uint32 `protobuf:"varint,2,opt,name=uid,proto3" json:"uid,omitempty"`
652
+	// GID of agent socket
653
+	Gid uint32 `protobuf:"varint,3,opt,name=gid,proto3" json:"gid,omitempty"`
654
+	// Mode is the filesystem mode of agent socket
655
+	Mode uint32 `protobuf:"varint,4,opt,name=mode,proto3" json:"mode,omitempty"`
656
+	// Optional defines if ssh socket is required. Error is produced
657
+	// if client does not expose ssh.
658
+	Optional bool `protobuf:"varint,5,opt,name=optional,proto3" json:"optional,omitempty"`
659
+}
660
+
661
+func (m *SSHOpt) Reset()                    { *m = SSHOpt{} }
662
+func (m *SSHOpt) String() string            { return proto.CompactTextString(m) }
663
+func (*SSHOpt) ProtoMessage()               {}
664
+func (*SSHOpt) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{8} }
665
+
666
+func (m *SSHOpt) GetID() string {
667
+	if m != nil {
668
+		return m.ID
669
+	}
670
+	return ""
671
+}
672
+
673
+func (m *SSHOpt) GetUid() uint32 {
674
+	if m != nil {
675
+		return m.Uid
676
+	}
677
+	return 0
678
+}
679
+
680
+func (m *SSHOpt) GetGid() uint32 {
681
+	if m != nil {
682
+		return m.Gid
683
+	}
684
+	return 0
685
+}
686
+
687
+func (m *SSHOpt) GetMode() uint32 {
688
+	if m != nil {
689
+		return m.Mode
690
+	}
691
+	return 0
692
+}
693
+
694
+func (m *SSHOpt) GetOptional() bool {
695
+	if m != nil {
696
+		return m.Optional
697
+	}
698
+	return false
699
+}
700
+
646 701
 // CopyOp copies files across Ops.
647 702
 type CopyOp struct {
648 703
 	Src  []*CopySource `protobuf:"bytes,1,rep,name=src" json:"src,omitempty"`
... ...
@@ -652,7 +718,7 @@ type CopyOp struct {
652 652
 func (m *CopyOp) Reset()                    { *m = CopyOp{} }
653 653
 func (m *CopyOp) String() string            { return proto.CompactTextString(m) }
654 654
 func (*CopyOp) ProtoMessage()               {}
655
-func (*CopyOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{8} }
655
+func (*CopyOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{9} }
656 656
 
657 657
 func (m *CopyOp) GetSrc() []*CopySource {
658 658
 	if m != nil {
... ...
@@ -677,7 +743,7 @@ type CopySource struct {
677 677
 func (m *CopySource) Reset()                    { *m = CopySource{} }
678 678
 func (m *CopySource) String() string            { return proto.CompactTextString(m) }
679 679
 func (*CopySource) ProtoMessage()               {}
680
-func (*CopySource) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{9} }
680
+func (*CopySource) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{10} }
681 681
 
682 682
 func (m *CopySource) GetSelector() string {
683 683
 	if m != nil {
... ...
@@ -698,7 +764,7 @@ type SourceOp struct {
698 698
 func (m *SourceOp) Reset()                    { *m = SourceOp{} }
699 699
 func (m *SourceOp) String() string            { return proto.CompactTextString(m) }
700 700
 func (*SourceOp) ProtoMessage()               {}
701
-func (*SourceOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{10} }
701
+func (*SourceOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{11} }
702 702
 
703 703
 func (m *SourceOp) GetIdentifier() string {
704 704
 	if m != nil {
... ...
@@ -726,7 +792,7 @@ type BuildOp struct {
726 726
 func (m *BuildOp) Reset()                    { *m = BuildOp{} }
727 727
 func (m *BuildOp) String() string            { return proto.CompactTextString(m) }
728 728
 func (*BuildOp) ProtoMessage()               {}
729
-func (*BuildOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{11} }
729
+func (*BuildOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{12} }
730 730
 
731 731
 func (m *BuildOp) GetInputs() map[string]*BuildInput {
732 732
 	if m != nil {
... ...
@@ -757,7 +823,7 @@ type BuildInput struct {
757 757
 func (m *BuildInput) Reset()                    { *m = BuildInput{} }
758 758
 func (m *BuildInput) String() string            { return proto.CompactTextString(m) }
759 759
 func (*BuildInput) ProtoMessage()               {}
760
-func (*BuildInput) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{12} }
760
+func (*BuildInput) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{13} }
761 761
 
762 762
 // OpMetadata is a per-vertex metadata entry, which can be defined for arbitrary Op vertex and overridable on the run time.
763 763
 type OpMetadata struct {
... ...
@@ -774,7 +840,7 @@ type OpMetadata struct {
774 774
 func (m *OpMetadata) Reset()                    { *m = OpMetadata{} }
775 775
 func (m *OpMetadata) String() string            { return proto.CompactTextString(m) }
776 776
 func (*OpMetadata) ProtoMessage()               {}
777
-func (*OpMetadata) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{13} }
777
+func (*OpMetadata) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{14} }
778 778
 
779 779
 func (m *OpMetadata) GetIgnoreCache() bool {
780 780
 	if m != nil {
... ...
@@ -811,7 +877,7 @@ type ExportCache struct {
811 811
 func (m *ExportCache) Reset()                    { *m = ExportCache{} }
812 812
 func (m *ExportCache) String() string            { return proto.CompactTextString(m) }
813 813
 func (*ExportCache) ProtoMessage()               {}
814
-func (*ExportCache) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{14} }
814
+func (*ExportCache) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{15} }
815 815
 
816 816
 func (m *ExportCache) GetValue() bool {
817 817
 	if m != nil {
... ...
@@ -830,7 +896,7 @@ type ProxyEnv struct {
830 830
 func (m *ProxyEnv) Reset()                    { *m = ProxyEnv{} }
831 831
 func (m *ProxyEnv) String() string            { return proto.CompactTextString(m) }
832 832
 func (*ProxyEnv) ProtoMessage()               {}
833
-func (*ProxyEnv) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{15} }
833
+func (*ProxyEnv) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{16} }
834 834
 
835 835
 func (m *ProxyEnv) GetHttpProxy() string {
836 836
 	if m != nil {
... ...
@@ -868,7 +934,7 @@ type WorkerConstraints struct {
868 868
 func (m *WorkerConstraints) Reset()                    { *m = WorkerConstraints{} }
869 869
 func (m *WorkerConstraints) String() string            { return proto.CompactTextString(m) }
870 870
 func (*WorkerConstraints) ProtoMessage()               {}
871
-func (*WorkerConstraints) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{16} }
871
+func (*WorkerConstraints) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{17} }
872 872
 
873 873
 func (m *WorkerConstraints) GetFilter() []string {
874 874
 	if m != nil {
... ...
@@ -889,7 +955,7 @@ type Definition struct {
889 889
 func (m *Definition) Reset()                    { *m = Definition{} }
890 890
 func (m *Definition) String() string            { return proto.CompactTextString(m) }
891 891
 func (*Definition) ProtoMessage()               {}
892
-func (*Definition) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{17} }
892
+func (*Definition) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{18} }
893 893
 
894 894
 func (m *Definition) GetDef() [][]byte {
895 895
 	if m != nil {
... ...
@@ -913,7 +979,7 @@ type HostIP struct {
913 913
 func (m *HostIP) Reset()                    { *m = HostIP{} }
914 914
 func (m *HostIP) String() string            { return proto.CompactTextString(m) }
915 915
 func (*HostIP) ProtoMessage()               {}
916
-func (*HostIP) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{18} }
916
+func (*HostIP) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{19} }
917 917
 
918 918
 func (m *HostIP) GetHost() string {
919 919
 	if m != nil {
... ...
@@ -938,6 +1004,7 @@ func init() {
938 938
 	proto.RegisterType((*Mount)(nil), "pb.Mount")
939 939
 	proto.RegisterType((*CacheOpt)(nil), "pb.CacheOpt")
940 940
 	proto.RegisterType((*SecretOpt)(nil), "pb.SecretOpt")
941
+	proto.RegisterType((*SSHOpt)(nil), "pb.SSHOpt")
941 942
 	proto.RegisterType((*CopyOp)(nil), "pb.CopyOp")
942 943
 	proto.RegisterType((*CopySource)(nil), "pb.CopySource")
943 944
 	proto.RegisterType((*SourceOp)(nil), "pb.SourceOp")
... ...
@@ -1355,6 +1422,18 @@ func (m *Mount) MarshalTo(dAtA []byte) (int, error) {
1355 1355
 		}
1356 1356
 		i += n11
1357 1357
 	}
1358
+	if m.SSHOpt != nil {
1359
+		dAtA[i] = 0xb2
1360
+		i++
1361
+		dAtA[i] = 0x1
1362
+		i++
1363
+		i = encodeVarintOps(dAtA, i, uint64(m.SSHOpt.Size()))
1364
+		n12, err := m.SSHOpt.MarshalTo(dAtA[i:])
1365
+		if err != nil {
1366
+			return 0, err
1367
+		}
1368
+		i += n12
1369
+	}
1358 1370
 	return i, nil
1359 1371
 }
1360 1372
 
... ...
@@ -1436,6 +1515,55 @@ func (m *SecretOpt) MarshalTo(dAtA []byte) (int, error) {
1436 1436
 	return i, nil
1437 1437
 }
1438 1438
 
1439
+func (m *SSHOpt) Marshal() (dAtA []byte, err error) {
1440
+	size := m.Size()
1441
+	dAtA = make([]byte, size)
1442
+	n, err := m.MarshalTo(dAtA)
1443
+	if err != nil {
1444
+		return nil, err
1445
+	}
1446
+	return dAtA[:n], nil
1447
+}
1448
+
1449
+func (m *SSHOpt) MarshalTo(dAtA []byte) (int, error) {
1450
+	var i int
1451
+	_ = i
1452
+	var l int
1453
+	_ = l
1454
+	if len(m.ID) > 0 {
1455
+		dAtA[i] = 0xa
1456
+		i++
1457
+		i = encodeVarintOps(dAtA, i, uint64(len(m.ID)))
1458
+		i += copy(dAtA[i:], m.ID)
1459
+	}
1460
+	if m.Uid != 0 {
1461
+		dAtA[i] = 0x10
1462
+		i++
1463
+		i = encodeVarintOps(dAtA, i, uint64(m.Uid))
1464
+	}
1465
+	if m.Gid != 0 {
1466
+		dAtA[i] = 0x18
1467
+		i++
1468
+		i = encodeVarintOps(dAtA, i, uint64(m.Gid))
1469
+	}
1470
+	if m.Mode != 0 {
1471
+		dAtA[i] = 0x20
1472
+		i++
1473
+		i = encodeVarintOps(dAtA, i, uint64(m.Mode))
1474
+	}
1475
+	if m.Optional {
1476
+		dAtA[i] = 0x28
1477
+		i++
1478
+		if m.Optional {
1479
+			dAtA[i] = 1
1480
+		} else {
1481
+			dAtA[i] = 0
1482
+		}
1483
+		i++
1484
+	}
1485
+	return i, nil
1486
+}
1487
+
1439 1488
 func (m *CopyOp) Marshal() (dAtA []byte, err error) {
1440 1489
 	size := m.Size()
1441 1490
 	dAtA = make([]byte, size)
... ...
@@ -1523,10 +1651,15 @@ func (m *SourceOp) MarshalTo(dAtA []byte) (int, error) {
1523 1523
 		i += copy(dAtA[i:], m.Identifier)
1524 1524
 	}
1525 1525
 	if len(m.Attrs) > 0 {
1526
+		keysForAttrs := make([]string, 0, len(m.Attrs))
1526 1527
 		for k, _ := range m.Attrs {
1528
+			keysForAttrs = append(keysForAttrs, string(k))
1529
+		}
1530
+		sortkeys.Strings(keysForAttrs)
1531
+		for _, k := range keysForAttrs {
1527 1532
 			dAtA[i] = 0x12
1528 1533
 			i++
1529
-			v := m.Attrs[k]
1534
+			v := m.Attrs[string(k)]
1530 1535
 			mapSize := 1 + len(k) + sovOps(uint64(len(k))) + 1 + len(v) + sovOps(uint64(len(v)))
1531 1536
 			i = encodeVarintOps(dAtA, i, uint64(mapSize))
1532 1537
 			dAtA[i] = 0xa
... ...
@@ -1563,10 +1696,15 @@ func (m *BuildOp) MarshalTo(dAtA []byte) (int, error) {
1563 1563
 		i = encodeVarintOps(dAtA, i, uint64(m.Builder))
1564 1564
 	}
1565 1565
 	if len(m.Inputs) > 0 {
1566
+		keysForInputs := make([]string, 0, len(m.Inputs))
1566 1567
 		for k, _ := range m.Inputs {
1568
+			keysForInputs = append(keysForInputs, string(k))
1569
+		}
1570
+		sortkeys.Strings(keysForInputs)
1571
+		for _, k := range keysForInputs {
1567 1572
 			dAtA[i] = 0x12
1568 1573
 			i++
1569
-			v := m.Inputs[k]
1574
+			v := m.Inputs[string(k)]
1570 1575
 			msgSize := 0
1571 1576
 			if v != nil {
1572 1577
 				msgSize = v.Size()
... ...
@@ -1582,11 +1720,11 @@ func (m *BuildOp) MarshalTo(dAtA []byte) (int, error) {
1582 1582
 				dAtA[i] = 0x12
1583 1583
 				i++
1584 1584
 				i = encodeVarintOps(dAtA, i, uint64(v.Size()))
1585
-				n12, err := v.MarshalTo(dAtA[i:])
1585
+				n13, err := v.MarshalTo(dAtA[i:])
1586 1586
 				if err != nil {
1587 1587
 					return 0, err
1588 1588
 				}
1589
-				i += n12
1589
+				i += n13
1590 1590
 			}
1591 1591
 		}
1592 1592
 	}
... ...
@@ -1594,17 +1732,22 @@ func (m *BuildOp) MarshalTo(dAtA []byte) (int, error) {
1594 1594
 		dAtA[i] = 0x1a
1595 1595
 		i++
1596 1596
 		i = encodeVarintOps(dAtA, i, uint64(m.Def.Size()))
1597
-		n13, err := m.Def.MarshalTo(dAtA[i:])
1597
+		n14, err := m.Def.MarshalTo(dAtA[i:])
1598 1598
 		if err != nil {
1599 1599
 			return 0, err
1600 1600
 		}
1601
-		i += n13
1601
+		i += n14
1602 1602
 	}
1603 1603
 	if len(m.Attrs) > 0 {
1604
+		keysForAttrs := make([]string, 0, len(m.Attrs))
1604 1605
 		for k, _ := range m.Attrs {
1606
+			keysForAttrs = append(keysForAttrs, string(k))
1607
+		}
1608
+		sortkeys.Strings(keysForAttrs)
1609
+		for _, k := range keysForAttrs {
1605 1610
 			dAtA[i] = 0x22
1606 1611
 			i++
1607
-			v := m.Attrs[k]
1612
+			v := m.Attrs[string(k)]
1608 1613
 			mapSize := 1 + len(k) + sovOps(uint64(len(k))) + 1 + len(v) + sovOps(uint64(len(v)))
1609 1614
 			i = encodeVarintOps(dAtA, i, uint64(mapSize))
1610 1615
 			dAtA[i] = 0xa
... ...
@@ -1669,10 +1812,15 @@ func (m *OpMetadata) MarshalTo(dAtA []byte) (int, error) {
1669 1669
 		i++
1670 1670
 	}
1671 1671
 	if len(m.Description) > 0 {
1672
+		keysForDescription := make([]string, 0, len(m.Description))
1672 1673
 		for k, _ := range m.Description {
1674
+			keysForDescription = append(keysForDescription, string(k))
1675
+		}
1676
+		sortkeys.Strings(keysForDescription)
1677
+		for _, k := range keysForDescription {
1673 1678
 			dAtA[i] = 0x12
1674 1679
 			i++
1675
-			v := m.Description[k]
1680
+			v := m.Description[string(k)]
1676 1681
 			mapSize := 1 + len(k) + sovOps(uint64(len(k))) + 1 + len(v) + sovOps(uint64(len(v)))
1677 1682
 			i = encodeVarintOps(dAtA, i, uint64(mapSize))
1678 1683
 			dAtA[i] = 0xa
... ...
@@ -1689,17 +1837,22 @@ func (m *OpMetadata) MarshalTo(dAtA []byte) (int, error) {
1689 1689
 		dAtA[i] = 0x22
1690 1690
 		i++
1691 1691
 		i = encodeVarintOps(dAtA, i, uint64(m.ExportCache.Size()))
1692
-		n14, err := m.ExportCache.MarshalTo(dAtA[i:])
1692
+		n15, err := m.ExportCache.MarshalTo(dAtA[i:])
1693 1693
 		if err != nil {
1694 1694
 			return 0, err
1695 1695
 		}
1696
-		i += n14
1696
+		i += n15
1697 1697
 	}
1698 1698
 	if len(m.Caps) > 0 {
1699
+		keysForCaps := make([]string, 0, len(m.Caps))
1699 1700
 		for k, _ := range m.Caps {
1701
+			keysForCaps = append(keysForCaps, string(k))
1702
+		}
1703
+		sortkeys.Strings(keysForCaps)
1704
+		for _, k := range keysForCaps {
1700 1705
 			dAtA[i] = 0x2a
1701 1706
 			i++
1702
-			v := m.Caps[k]
1707
+			v := m.Caps[github_com_moby_buildkit_util_apicaps.CapID(k)]
1703 1708
 			mapSize := 1 + len(k) + sovOps(uint64(len(k))) + 1 + 1
1704 1709
 			i = encodeVarintOps(dAtA, i, uint64(mapSize))
1705 1710
 			dAtA[i] = 0xa
... ...
@@ -1846,10 +1999,15 @@ func (m *Definition) MarshalTo(dAtA []byte) (int, error) {
1846 1846
 		}
1847 1847
 	}
1848 1848
 	if len(m.Metadata) > 0 {
1849
+		keysForMetadata := make([]string, 0, len(m.Metadata))
1849 1850
 		for k, _ := range m.Metadata {
1851
+			keysForMetadata = append(keysForMetadata, string(k))
1852
+		}
1853
+		sortkeys.Strings(keysForMetadata)
1854
+		for _, k := range keysForMetadata {
1850 1855
 			dAtA[i] = 0x12
1851 1856
 			i++
1852
-			v := m.Metadata[k]
1857
+			v := m.Metadata[github_com_opencontainers_go_digest.Digest(k)]
1853 1858
 			msgSize := 0
1854 1859
 			if (&v) != nil {
1855 1860
 				msgSize = (&v).Size()
... ...
@@ -1864,11 +2022,11 @@ func (m *Definition) MarshalTo(dAtA []byte) (int, error) {
1864 1864
 			dAtA[i] = 0x12
1865 1865
 			i++
1866 1866
 			i = encodeVarintOps(dAtA, i, uint64((&v).Size()))
1867
-			n15, err := (&v).MarshalTo(dAtA[i:])
1867
+			n16, err := (&v).MarshalTo(dAtA[i:])
1868 1868
 			if err != nil {
1869 1869
 				return 0, err
1870 1870
 			}
1871
-			i += n15
1871
+			i += n16
1872 1872
 		}
1873 1873
 	}
1874 1874
 	return i, nil
... ...
@@ -2099,6 +2257,10 @@ func (m *Mount) Size() (n int) {
2099 2099
 		l = m.SecretOpt.Size()
2100 2100
 		n += 2 + l + sovOps(uint64(l))
2101 2101
 	}
2102
+	if m.SSHOpt != nil {
2103
+		l = m.SSHOpt.Size()
2104
+		n += 2 + l + sovOps(uint64(l))
2105
+	}
2102 2106
 	return n
2103 2107
 }
2104 2108
 
... ...
@@ -2137,6 +2299,28 @@ func (m *SecretOpt) Size() (n int) {
2137 2137
 	return n
2138 2138
 }
2139 2139
 
2140
+func (m *SSHOpt) Size() (n int) {
2141
+	var l int
2142
+	_ = l
2143
+	l = len(m.ID)
2144
+	if l > 0 {
2145
+		n += 1 + l + sovOps(uint64(l))
2146
+	}
2147
+	if m.Uid != 0 {
2148
+		n += 1 + sovOps(uint64(m.Uid))
2149
+	}
2150
+	if m.Gid != 0 {
2151
+		n += 1 + sovOps(uint64(m.Gid))
2152
+	}
2153
+	if m.Mode != 0 {
2154
+		n += 1 + sovOps(uint64(m.Mode))
2155
+	}
2156
+	if m.Optional {
2157
+		n += 2
2158
+	}
2159
+	return n
2160
+}
2161
+
2140 2162
 func (m *CopyOp) Size() (n int) {
2141 2163
 	var l int
2142 2164
 	_ = l
... ...
@@ -3508,6 +3692,39 @@ func (m *Mount) Unmarshal(dAtA []byte) error {
3508 3508
 				return err
3509 3509
 			}
3510 3510
 			iNdEx = postIndex
3511
+		case 22:
3512
+			if wireType != 2 {
3513
+				return fmt.Errorf("proto: wrong wireType = %d for field SSHOpt", wireType)
3514
+			}
3515
+			var msglen int
3516
+			for shift := uint(0); ; shift += 7 {
3517
+				if shift >= 64 {
3518
+					return ErrIntOverflowOps
3519
+				}
3520
+				if iNdEx >= l {
3521
+					return io.ErrUnexpectedEOF
3522
+				}
3523
+				b := dAtA[iNdEx]
3524
+				iNdEx++
3525
+				msglen |= (int(b) & 0x7F) << shift
3526
+				if b < 0x80 {
3527
+					break
3528
+				}
3529
+			}
3530
+			if msglen < 0 {
3531
+				return ErrInvalidLengthOps
3532
+			}
3533
+			postIndex := iNdEx + msglen
3534
+			if postIndex > l {
3535
+				return io.ErrUnexpectedEOF
3536
+			}
3537
+			if m.SSHOpt == nil {
3538
+				m.SSHOpt = &SSHOpt{}
3539
+			}
3540
+			if err := m.SSHOpt.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
3541
+				return err
3542
+			}
3543
+			iNdEx = postIndex
3511 3544
 		default:
3512 3545
 			iNdEx = preIndex
3513 3546
 			skippy, err := skipOps(dAtA[iNdEx:])
... ...
@@ -3783,6 +4000,162 @@ func (m *SecretOpt) Unmarshal(dAtA []byte) error {
3783 3783
 	}
3784 3784
 	return nil
3785 3785
 }
3786
+func (m *SSHOpt) Unmarshal(dAtA []byte) error {
3787
+	l := len(dAtA)
3788
+	iNdEx := 0
3789
+	for iNdEx < l {
3790
+		preIndex := iNdEx
3791
+		var wire uint64
3792
+		for shift := uint(0); ; shift += 7 {
3793
+			if shift >= 64 {
3794
+				return ErrIntOverflowOps
3795
+			}
3796
+			if iNdEx >= l {
3797
+				return io.ErrUnexpectedEOF
3798
+			}
3799
+			b := dAtA[iNdEx]
3800
+			iNdEx++
3801
+			wire |= (uint64(b) & 0x7F) << shift
3802
+			if b < 0x80 {
3803
+				break
3804
+			}
3805
+		}
3806
+		fieldNum := int32(wire >> 3)
3807
+		wireType := int(wire & 0x7)
3808
+		if wireType == 4 {
3809
+			return fmt.Errorf("proto: SSHOpt: wiretype end group for non-group")
3810
+		}
3811
+		if fieldNum <= 0 {
3812
+			return fmt.Errorf("proto: SSHOpt: illegal tag %d (wire type %d)", fieldNum, wire)
3813
+		}
3814
+		switch fieldNum {
3815
+		case 1:
3816
+			if wireType != 2 {
3817
+				return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
3818
+			}
3819
+			var stringLen uint64
3820
+			for shift := uint(0); ; shift += 7 {
3821
+				if shift >= 64 {
3822
+					return ErrIntOverflowOps
3823
+				}
3824
+				if iNdEx >= l {
3825
+					return io.ErrUnexpectedEOF
3826
+				}
3827
+				b := dAtA[iNdEx]
3828
+				iNdEx++
3829
+				stringLen |= (uint64(b) & 0x7F) << shift
3830
+				if b < 0x80 {
3831
+					break
3832
+				}
3833
+			}
3834
+			intStringLen := int(stringLen)
3835
+			if intStringLen < 0 {
3836
+				return ErrInvalidLengthOps
3837
+			}
3838
+			postIndex := iNdEx + intStringLen
3839
+			if postIndex > l {
3840
+				return io.ErrUnexpectedEOF
3841
+			}
3842
+			m.ID = string(dAtA[iNdEx:postIndex])
3843
+			iNdEx = postIndex
3844
+		case 2:
3845
+			if wireType != 0 {
3846
+				return fmt.Errorf("proto: wrong wireType = %d for field Uid", wireType)
3847
+			}
3848
+			m.Uid = 0
3849
+			for shift := uint(0); ; shift += 7 {
3850
+				if shift >= 64 {
3851
+					return ErrIntOverflowOps
3852
+				}
3853
+				if iNdEx >= l {
3854
+					return io.ErrUnexpectedEOF
3855
+				}
3856
+				b := dAtA[iNdEx]
3857
+				iNdEx++
3858
+				m.Uid |= (uint32(b) & 0x7F) << shift
3859
+				if b < 0x80 {
3860
+					break
3861
+				}
3862
+			}
3863
+		case 3:
3864
+			if wireType != 0 {
3865
+				return fmt.Errorf("proto: wrong wireType = %d for field Gid", wireType)
3866
+			}
3867
+			m.Gid = 0
3868
+			for shift := uint(0); ; shift += 7 {
3869
+				if shift >= 64 {
3870
+					return ErrIntOverflowOps
3871
+				}
3872
+				if iNdEx >= l {
3873
+					return io.ErrUnexpectedEOF
3874
+				}
3875
+				b := dAtA[iNdEx]
3876
+				iNdEx++
3877
+				m.Gid |= (uint32(b) & 0x7F) << shift
3878
+				if b < 0x80 {
3879
+					break
3880
+				}
3881
+			}
3882
+		case 4:
3883
+			if wireType != 0 {
3884
+				return fmt.Errorf("proto: wrong wireType = %d for field Mode", wireType)
3885
+			}
3886
+			m.Mode = 0
3887
+			for shift := uint(0); ; shift += 7 {
3888
+				if shift >= 64 {
3889
+					return ErrIntOverflowOps
3890
+				}
3891
+				if iNdEx >= l {
3892
+					return io.ErrUnexpectedEOF
3893
+				}
3894
+				b := dAtA[iNdEx]
3895
+				iNdEx++
3896
+				m.Mode |= (uint32(b) & 0x7F) << shift
3897
+				if b < 0x80 {
3898
+					break
3899
+				}
3900
+			}
3901
+		case 5:
3902
+			if wireType != 0 {
3903
+				return fmt.Errorf("proto: wrong wireType = %d for field Optional", wireType)
3904
+			}
3905
+			var v int
3906
+			for shift := uint(0); ; shift += 7 {
3907
+				if shift >= 64 {
3908
+					return ErrIntOverflowOps
3909
+				}
3910
+				if iNdEx >= l {
3911
+					return io.ErrUnexpectedEOF
3912
+				}
3913
+				b := dAtA[iNdEx]
3914
+				iNdEx++
3915
+				v |= (int(b) & 0x7F) << shift
3916
+				if b < 0x80 {
3917
+					break
3918
+				}
3919
+			}
3920
+			m.Optional = bool(v != 0)
3921
+		default:
3922
+			iNdEx = preIndex
3923
+			skippy, err := skipOps(dAtA[iNdEx:])
3924
+			if err != nil {
3925
+				return err
3926
+			}
3927
+			if skippy < 0 {
3928
+				return ErrInvalidLengthOps
3929
+			}
3930
+			if (iNdEx + skippy) > l {
3931
+				return io.ErrUnexpectedEOF
3932
+			}
3933
+			iNdEx += skippy
3934
+		}
3935
+	}
3936
+
3937
+	if iNdEx > l {
3938
+		return io.ErrUnexpectedEOF
3939
+	}
3940
+	return nil
3941
+}
3786 3942
 func (m *CopyOp) Unmarshal(dAtA []byte) error {
3787 3943
 	l := len(dAtA)
3788 3944
 	iNdEx := 0
... ...
@@ -5663,94 +6036,96 @@ var (
5663 5663
 func init() { proto.RegisterFile("ops.proto", fileDescriptorOps) }
5664 5664
 
5665 5665
 var fileDescriptorOps = []byte{
5666
-	// 1415 bytes of a gzipped FileDescriptorProto
5667
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xcd, 0x6f, 0x1b, 0x45,
5668
-	0x14, 0x8f, 0xd7, 0x9f, 0xfb, 0x9c, 0xa4, 0x66, 0xfa, 0x81, 0x09, 0x25, 0x09, 0x5b, 0x40, 0x69,
5669
-	0xd2, 0x38, 0x92, 0x2b, 0xb5, 0x15, 0x87, 0x8a, 0xf8, 0xa3, 0x8a, 0x29, 0x89, 0xa3, 0x71, 0x08,
5670
-	0xc7, 0x6a, 0xb3, 0x1e, 0x3b, 0xab, 0x38, 0x3b, 0xab, 0xdd, 0x71, 0x1b, 0x5f, 0x38, 0xf4, 0x2f,
5671
-	0x40, 0x42, 0xe2, 0xce, 0x91, 0x0b, 0xff, 0x01, 0xf7, 0x1e, 0xb9, 0xc2, 0xa1, 0xa0, 0xf2, 0x8f,
5672
-	0xa0, 0xf7, 0x66, 0xd6, 0xbb, 0xfd, 0x40, 0xb4, 0x82, 0x93, 0xdf, 0xbc, 0xf7, 0x9b, 0xdf, 0xcc,
5673
-	0xfc, 0xde, 0x9b, 0x79, 0x6b, 0xb0, 0x65, 0x18, 0x37, 0xc2, 0x48, 0x2a, 0xc9, 0xac, 0xf0, 0x64,
5674
-	0x65, 0x7b, 0xec, 0xab, 0xd3, 0xe9, 0x49, 0xc3, 0x93, 0xe7, 0x3b, 0x63, 0x39, 0x96, 0x3b, 0x14,
5675
-	0x3a, 0x99, 0x8e, 0x68, 0x44, 0x03, 0xb2, 0xf4, 0x14, 0xe7, 0x47, 0x0b, 0xac, 0x7e, 0xc8, 0x3e,
5676
-	0x86, 0x92, 0x1f, 0x84, 0x53, 0x15, 0xd7, 0x73, 0xeb, 0xf9, 0x8d, 0x6a, 0xd3, 0x6e, 0x84, 0x27,
5677
-	0x8d, 0x1e, 0x7a, 0xb8, 0x09, 0xb0, 0x75, 0x28, 0x88, 0x0b, 0xe1, 0xd5, 0xad, 0xf5, 0xdc, 0x46,
5678
-	0xb5, 0x09, 0x08, 0xe8, 0x5e, 0x08, 0xaf, 0x1f, 0xee, 0x2d, 0x70, 0x8a, 0xb0, 0xcf, 0xa0, 0x14,
5679
-	0xcb, 0x69, 0xe4, 0x89, 0x7a, 0x9e, 0x30, 0x8b, 0x88, 0x19, 0x90, 0x87, 0x50, 0x26, 0x8a, 0x4c,
5680
-	0x9e, 0x0c, 0x67, 0xf5, 0x42, 0xca, 0xd4, 0x96, 0xe1, 0x4c, 0x33, 0x61, 0x84, 0xdd, 0x80, 0xe2,
5681
-	0xc9, 0xd4, 0x9f, 0x0c, 0xeb, 0x45, 0x82, 0x54, 0x11, 0xd2, 0x42, 0x07, 0x61, 0x74, 0x8c, 0x6d,
5682
-	0x40, 0x25, 0x9c, 0xb8, 0x6a, 0x24, 0xa3, 0xf3, 0x3a, 0xa4, 0x0b, 0x1e, 0x1a, 0x1f, 0x9f, 0x47,
5683
-	0xd9, 0x5d, 0xa8, 0x7a, 0x32, 0x88, 0x55, 0xe4, 0xfa, 0x81, 0x8a, 0xeb, 0x55, 0x02, 0x5f, 0x45,
5684
-	0xf0, 0x37, 0x32, 0x3a, 0x13, 0x51, 0x3b, 0x0d, 0xf2, 0x2c, 0xb2, 0x55, 0x00, 0x4b, 0x86, 0xce,
5685
-	0x0f, 0x39, 0xa8, 0x24, 0xac, 0xcc, 0x81, 0xc5, 0xdd, 0xc8, 0x3b, 0xf5, 0x95, 0xf0, 0xd4, 0x34,
5686
-	0x12, 0xf5, 0xdc, 0x7a, 0x6e, 0xc3, 0xe6, 0x2f, 0xf9, 0xd8, 0x32, 0x58, 0xfd, 0x01, 0x09, 0x65,
5687
-	0x73, 0xab, 0x3f, 0x60, 0x75, 0x28, 0x1f, 0xbb, 0x91, 0xef, 0x06, 0x8a, 0x94, 0xb1, 0x79, 0x32,
5688
-	0x64, 0xd7, 0xc1, 0xee, 0x0f, 0x8e, 0x45, 0x14, 0xfb, 0x32, 0x20, 0x3d, 0x6c, 0x9e, 0x3a, 0xd8,
5689
-	0x2a, 0x40, 0x7f, 0xf0, 0x40, 0xb8, 0x48, 0x1a, 0xd7, 0x8b, 0xeb, 0xf9, 0x0d, 0x9b, 0x67, 0x3c,
5690
-	0xce, 0xb7, 0x50, 0xa4, 0x1c, 0xb1, 0x2f, 0xa1, 0x34, 0xf4, 0xc7, 0x22, 0x56, 0x7a, 0x3b, 0xad,
5691
-	0xe6, 0xb3, 0xe7, 0x6b, 0x0b, 0xbf, 0x3f, 0x5f, 0xdb, 0xcc, 0x14, 0x83, 0x0c, 0x45, 0xe0, 0xc9,
5692
-	0x40, 0xb9, 0x7e, 0x20, 0xa2, 0x78, 0x67, 0x2c, 0xb7, 0xf5, 0x94, 0x46, 0x87, 0x7e, 0xb8, 0x61,
5693
-	0x60, 0x37, 0xa1, 0xe8, 0x07, 0x43, 0x71, 0x41, 0xfb, 0xcf, 0xb7, 0x2e, 0x1b, 0xaa, 0x6a, 0x7f,
5694
-	0xaa, 0xc2, 0xa9, 0xea, 0x61, 0x88, 0x6b, 0x84, 0x13, 0x42, 0x49, 0x97, 0x00, 0xbb, 0x0e, 0x85,
5695
-	0x73, 0xa1, 0x5c, 0x5a, 0xbe, 0xda, 0xac, 0xa0, 0xb4, 0xfb, 0x42, 0xb9, 0x9c, 0xbc, 0x58, 0x5d,
5696
-	0xe7, 0x72, 0x8a, 0xd2, 0x5b, 0x69, 0x75, 0xed, 0xa3, 0x87, 0x9b, 0x00, 0xfb, 0x14, 0xca, 0x81,
5697
-	0x50, 0x4f, 0x64, 0x74, 0x46, 0x12, 0x2d, 0xeb, 0x9c, 0x1f, 0x08, 0xb5, 0x2f, 0x87, 0x82, 0x27,
5698
-	0x31, 0xe7, 0xa7, 0x1c, 0x14, 0x90, 0x98, 0x31, 0x28, 0xb8, 0xd1, 0x58, 0x97, 0xab, 0xcd, 0xc9,
5699
-	0x66, 0x35, 0xc8, 0x8b, 0xe0, 0x31, 0xad, 0x61, 0x73, 0x34, 0xd1, 0xe3, 0x3d, 0x19, 0x1a, 0xd1,
5700
-	0xd1, 0xc4, 0x79, 0xd3, 0x58, 0x44, 0x46, 0x6b, 0xb2, 0xd9, 0x4d, 0xb0, 0xc3, 0x48, 0x5e, 0xcc,
5701
-	0x1e, 0xe1, 0xec, 0x62, 0xa6, 0x92, 0xd0, 0xd9, 0x0d, 0x1e, 0xf3, 0x4a, 0x68, 0x2c, 0xb6, 0x09,
5702
-	0x20, 0x2e, 0x54, 0xe4, 0xee, 0xc9, 0x58, 0xc5, 0xf5, 0x12, 0x9d, 0x86, 0x0a, 0x18, 0x1d, 0xbd,
5703
-	0x43, 0x9e, 0x89, 0x3a, 0x3f, 0x5b, 0x50, 0xa4, 0x43, 0xb2, 0x0d, 0x94, 0x34, 0x9c, 0xea, 0xec,
5704
-	0xe4, 0x5b, 0xcc, 0x48, 0x0a, 0x94, 0xbc, 0xb9, 0xa2, 0x98, 0xc8, 0x15, 0xa8, 0xc4, 0x62, 0x22,
5705
-	0x3c, 0x25, 0x23, 0x53, 0x3f, 0xf3, 0x31, 0x6e, 0x7d, 0x88, 0x29, 0xd6, 0xa7, 0x21, 0x9b, 0x6d,
5706
-	0x41, 0x49, 0x52, 0x5e, 0xe8, 0x40, 0xff, 0x90, 0x2d, 0x03, 0x41, 0xf2, 0x48, 0xb8, 0x43, 0x19,
5707
-	0x4c, 0x66, 0x74, 0xcc, 0x0a, 0x9f, 0x8f, 0xd9, 0x16, 0xd8, 0x94, 0x89, 0xa3, 0x59, 0x28, 0xea,
5708
-	0x25, 0xca, 0xc0, 0xd2, 0x3c, 0x4b, 0xe8, 0xe4, 0x69, 0x1c, 0x6f, 0x9e, 0xe7, 0x7a, 0xa7, 0xa2,
5709
-	0x1f, 0xaa, 0xfa, 0x95, 0x54, 0xaf, 0xb6, 0xf1, 0xf1, 0x79, 0x14, 0x69, 0x63, 0xe1, 0x45, 0x42,
5710
-	0x21, 0xf4, 0x2a, 0x41, 0x89, 0x76, 0x90, 0x38, 0x79, 0x1a, 0x77, 0x7a, 0x50, 0x49, 0x28, 0xf0,
5711
-	0x0a, 0xf5, 0x3a, 0xe6, 0x72, 0x59, 0xbd, 0x0e, 0xdb, 0x86, 0x72, 0x7c, 0xea, 0x46, 0x7e, 0x30,
5712
-	0x26, 0x5d, 0x96, 0x9b, 0x97, 0xe7, 0x2b, 0x0e, 0xb4, 0x1f, 0xc9, 0x12, 0x8c, 0x23, 0xc1, 0x9e,
5713
-	0x2f, 0xf1, 0x1a, 0x57, 0x0d, 0xf2, 0x53, 0x7f, 0x48, 0x3c, 0x4b, 0x1c, 0x4d, 0xf4, 0x8c, 0x7d,
5714
-	0x5d, 0x27, 0x4b, 0x1c, 0x4d, 0x14, 0xfb, 0x5c, 0x0e, 0x05, 0xc9, 0xba, 0xc4, 0xc9, 0x46, 0xfd,
5715
-	0x64, 0xa8, 0x7c, 0x19, 0xb8, 0x93, 0x44, 0xbf, 0x64, 0xec, 0xdc, 0x87, 0x92, 0x7e, 0xc3, 0xd8,
5716
-	0x3a, 0xe4, 0xe3, 0xc8, 0x33, 0xef, 0xe8, 0x72, 0xf2, 0xb8, 0xe9, 0x67, 0x90, 0x63, 0x68, 0x9e,
5717
-	0x48, 0x2b, 0x4d, 0xa4, 0xc3, 0x01, 0x52, 0xd8, 0xff, 0x53, 0x30, 0xce, 0xf7, 0x39, 0xa8, 0x24,
5718
-	0xcf, 0x2f, 0xbe, 0x25, 0xfe, 0x50, 0x04, 0xca, 0x1f, 0xf9, 0x22, 0x32, 0x62, 0x64, 0x3c, 0x6c,
5719
-	0x1b, 0x8a, 0xae, 0x52, 0x51, 0x72, 0x45, 0xdf, 0xcf, 0xbe, 0xdd, 0x8d, 0x5d, 0x8c, 0x74, 0x03,
5720
-	0x15, 0xcd, 0xb8, 0x46, 0xad, 0xdc, 0x03, 0x48, 0x9d, 0xa8, 0xdf, 0x99, 0x98, 0x19, 0x56, 0x34,
5721
-	0xd9, 0x15, 0x28, 0x3e, 0x76, 0x27, 0x53, 0x61, 0x36, 0xa5, 0x07, 0x9f, 0x5b, 0xf7, 0x72, 0xce,
5722
-	0x2f, 0x16, 0x94, 0xcd, 0x5b, 0xce, 0x6e, 0x41, 0x99, 0xde, 0x72, 0xb3, 0xa3, 0x37, 0x9f, 0x34,
5723
-	0x81, 0xb0, 0x9d, 0x79, 0x93, 0xca, 0xec, 0xd1, 0x50, 0xe9, 0x66, 0x65, 0xf6, 0x98, 0xb6, 0xac,
5724
-	0xfc, 0x50, 0x8c, 0x4c, 0x37, 0xa2, 0x54, 0x74, 0xc4, 0xc8, 0x0f, 0x7c, 0xcc, 0x19, 0xc7, 0x10,
5725
-	0xbb, 0x95, 0x9c, 0xba, 0x40, 0x8c, 0xd7, 0xb2, 0x8c, 0xaf, 0x1f, 0xba, 0x07, 0xd5, 0xcc, 0x32,
5726
-	0x6f, 0x38, 0xf5, 0x27, 0xd9, 0x53, 0x9b, 0x25, 0x89, 0x4e, 0xb7, 0xd2, 0x54, 0x85, 0xff, 0xa0,
5727
-	0xdf, 0x1d, 0x80, 0x94, 0xf2, 0xed, 0x2b, 0xc5, 0x79, 0x9a, 0x07, 0xe8, 0x87, 0xf8, 0x78, 0x0e,
5728
-	0x5d, 0x7a, 0x93, 0x17, 0xfd, 0x71, 0x20, 0x23, 0xf1, 0x88, 0x2e, 0x2b, 0xcd, 0xaf, 0xf0, 0xaa,
5729
-	0xf6, 0xd1, 0xbd, 0x62, 0xbb, 0x50, 0x1d, 0x8a, 0xd8, 0x8b, 0x7c, 0x2a, 0x72, 0x23, 0xfa, 0x1a,
5730
-	0x9e, 0x29, 0xe5, 0x69, 0x74, 0x52, 0x84, 0xd6, 0x2a, 0x3b, 0x87, 0x35, 0x61, 0x51, 0x5c, 0x84,
5731
-	0x32, 0x52, 0x66, 0x15, 0xdd, 0xf2, 0x2f, 0xe9, 0x8f, 0x07, 0xf4, 0xd3, 0x4a, 0xbc, 0x2a, 0xd2,
5732
-	0x01, 0x73, 0xa1, 0xe0, 0xb9, 0xa1, 0xee, 0x77, 0xd5, 0x66, 0xfd, 0x95, 0xf5, 0xda, 0x6e, 0xa8,
5733
-	0x45, 0x6b, 0xdd, 0xc6, 0xb3, 0x3e, 0xfd, 0x63, 0x6d, 0x2b, 0xd3, 0xe4, 0xce, 0xe5, 0xc9, 0x6c,
5734
-	0x87, 0xea, 0xe5, 0xcc, 0x57, 0x3b, 0x53, 0xe5, 0x4f, 0x76, 0xdc, 0xd0, 0x47, 0x3a, 0x9c, 0xd8,
5735
-	0xeb, 0x70, 0xa2, 0x5e, 0xb9, 0x0f, 0xb5, 0x57, 0xf7, 0xfd, 0x2e, 0x39, 0x58, 0xb9, 0x0b, 0xf6,
5736
-	0x7c, 0x1f, 0xff, 0x36, 0xb1, 0x92, 0x4d, 0xde, 0x0d, 0xa8, 0x66, 0xce, 0x8d, 0xc0, 0x63, 0x02,
5737
-	0x6a, 0xf5, 0xf5, 0xc0, 0x79, 0x8a, 0xdf, 0x1b, 0x49, 0xc7, 0xf9, 0x08, 0xe0, 0x54, 0xa9, 0xf0,
5738
-	0x11, 0xb5, 0x20, 0xb3, 0x88, 0x8d, 0x1e, 0x42, 0xb0, 0x35, 0xa8, 0xe2, 0x20, 0x36, 0x71, 0xbd,
5739
-	0x53, 0x9a, 0x11, 0x6b, 0xc0, 0x87, 0x60, 0x8f, 0xe6, 0xd3, 0x75, 0xeb, 0xa8, 0x8c, 0x92, 0xd9,
5740
-	0x1f, 0x40, 0x25, 0x90, 0x26, 0xa6, 0x3b, 0x62, 0x39, 0x90, 0x14, 0x72, 0xb6, 0xe0, 0xbd, 0xd7,
5741
-	0x3e, 0x8e, 0xd8, 0x35, 0x28, 0x8d, 0xfc, 0x89, 0xa2, 0xeb, 0x8a, 0x4d, 0xd6, 0x8c, 0x9c, 0xdf,
5742
-	0x72, 0x00, 0xe9, 0xd5, 0x42, 0x45, 0xf0, 0xde, 0x21, 0x66, 0x51, 0xdf, 0xb3, 0x09, 0x54, 0xce,
5743
-	0x4d, 0x06, 0x4d, 0x1d, 0x5d, 0x7f, 0xf9, 0x3a, 0x36, 0x92, 0x04, 0xeb, 0xdc, 0x36, 0x4d, 0x6e,
5744
-	0xdf, 0xe5, 0x03, 0x66, 0xbe, 0xc2, 0xca, 0x43, 0x58, 0x7a, 0x89, 0xee, 0x2d, 0x6f, 0x6a, 0x5a,
5745
-	0x65, 0xd9, 0x94, 0xdd, 0x82, 0x92, 0x6e, 0xee, 0xf8, 0x6e, 0xa3, 0x65, 0x68, 0xc8, 0xa6, 0xde,
5746
-	0x72, 0x98, 0x7c, 0xea, 0xf5, 0x0e, 0x37, 0x37, 0xa0, 0x6c, 0x3e, 0x5a, 0x98, 0x0d, 0xc5, 0xaf,
5747
-	0x0f, 0x06, 0xdd, 0xa3, 0xda, 0x02, 0xab, 0x40, 0x61, 0xaf, 0x3f, 0x38, 0xaa, 0xe5, 0xd0, 0x3a,
5748
-	0xe8, 0x1f, 0x74, 0x6b, 0xd6, 0xe6, 0x17, 0x60, 0xcf, 0x9b, 0x2b, 0xba, 0x5b, 0xbd, 0x83, 0x4e,
5749
-	0x6d, 0x81, 0x01, 0x94, 0x06, 0xdd, 0x36, 0xef, 0x22, 0xb8, 0x0c, 0xf9, 0xc1, 0x60, 0xaf, 0x66,
5750
-	0x21, 0x55, 0x7b, 0xb7, 0xbd, 0xd7, 0xad, 0xe5, 0xd1, 0x3c, 0xda, 0x3f, 0x7c, 0x30, 0xa8, 0x15,
5751
-	0x36, 0xef, 0xc0, 0xa5, 0x57, 0x1a, 0x20, 0xcd, 0xde, 0xdb, 0xe5, 0x5d, 0x64, 0xaa, 0x42, 0xf9,
5752
-	0x90, 0xf7, 0x8e, 0x77, 0x8f, 0xba, 0xb5, 0x1c, 0x06, 0xbe, 0xea, 0xb7, 0x1f, 0x76, 0x3b, 0x35,
5753
-	0xab, 0x55, 0x7b, 0xf6, 0x62, 0x35, 0xf7, 0xeb, 0x8b, 0xd5, 0xdc, 0x9f, 0x2f, 0x56, 0x73, 0xdf,
5754
-	0xfd, 0xb5, 0xba, 0x70, 0x52, 0xa2, 0x3f, 0x03, 0xb7, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x8c,
5755
-	0x1e, 0x1e, 0x98, 0x4c, 0x0c, 0x00, 0x00,
5666
+	// 1444 bytes of a gzipped FileDescriptorProto
5667
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x4b, 0x6f, 0x1b, 0x47,
5668
+	0x12, 0x16, 0x87, 0xcf, 0x29, 0x4a, 0x32, 0xb7, 0xfd, 0x58, 0xae, 0xd6, 0x2b, 0x69, 0xc7, 0xbb,
5669
+	0x81, 0x2c, 0x59, 0x14, 0x40, 0x03, 0xb6, 0x91, 0x83, 0x11, 0xf1, 0x61, 0x88, 0x71, 0x24, 0x0a,
5670
+	0x4d, 0x45, 0x39, 0x1a, 0xa3, 0x61, 0x93, 0x1a, 0x88, 0x9a, 0x1e, 0xcc, 0x34, 0x6d, 0xf1, 0x92,
5671
+	0x83, 0x7f, 0x41, 0x80, 0x00, 0xb9, 0xe7, 0x98, 0x1f, 0x91, 0xbb, 0x8f, 0x41, 0x4e, 0x49, 0x0e,
5672
+	0x4e, 0xa0, 0xfc, 0x91, 0xa0, 0xaa, 0x7b, 0x38, 0xe3, 0x47, 0x10, 0x1b, 0x09, 0x72, 0x62, 0x75,
5673
+	0xd5, 0xd7, 0x5f, 0xd7, 0xab, 0xbb, 0x86, 0x60, 0xcb, 0x30, 0x6e, 0x84, 0x91, 0x54, 0x92, 0x59,
5674
+	0xe1, 0xc9, 0xca, 0xf6, 0xd8, 0x57, 0xa7, 0xd3, 0x93, 0x86, 0x27, 0xcf, 0x77, 0xc6, 0x72, 0x2c,
5675
+	0x77, 0xc8, 0x74, 0x32, 0x1d, 0xd1, 0x8a, 0x16, 0x24, 0xe9, 0x2d, 0xce, 0xd7, 0x16, 0x58, 0xfd,
5676
+	0x90, 0xfd, 0x17, 0x4a, 0x7e, 0x10, 0x4e, 0x55, 0x5c, 0xcf, 0xad, 0xe7, 0x37, 0xaa, 0x4d, 0xbb,
5677
+	0x11, 0x9e, 0x34, 0x7a, 0xa8, 0xe1, 0xc6, 0xc0, 0xd6, 0xa1, 0x20, 0x2e, 0x84, 0x57, 0xb7, 0xd6,
5678
+	0x73, 0x1b, 0xd5, 0x26, 0x20, 0xa0, 0x7b, 0x21, 0xbc, 0x7e, 0xb8, 0xb7, 0xc0, 0xc9, 0xc2, 0x3e,
5679
+	0x80, 0x52, 0x2c, 0xa7, 0x91, 0x27, 0xea, 0x79, 0xc2, 0x2c, 0x22, 0x66, 0x40, 0x1a, 0x42, 0x19,
5680
+	0x2b, 0x32, 0x79, 0x32, 0x9c, 0xd5, 0x0b, 0x29, 0x53, 0x5b, 0x86, 0x33, 0xcd, 0x84, 0x16, 0x76,
5681
+	0x0b, 0x8a, 0x27, 0x53, 0x7f, 0x32, 0xac, 0x17, 0x09, 0x52, 0x45, 0x48, 0x0b, 0x15, 0x84, 0xd1,
5682
+	0x36, 0xb6, 0x01, 0x95, 0x70, 0xe2, 0xaa, 0x91, 0x8c, 0xce, 0xeb, 0x90, 0x1e, 0x78, 0x68, 0x74,
5683
+	0x7c, 0x6e, 0x65, 0xf7, 0xa1, 0xea, 0xc9, 0x20, 0x56, 0x91, 0xeb, 0x07, 0x2a, 0xae, 0x57, 0x09,
5684
+	0x7c, 0x1d, 0xc1, 0x9f, 0xc9, 0xe8, 0x4c, 0x44, 0xed, 0xd4, 0xc8, 0xb3, 0xc8, 0x56, 0x01, 0x2c,
5685
+	0x19, 0x3a, 0x5f, 0xe5, 0xa0, 0x92, 0xb0, 0x32, 0x07, 0x16, 0x77, 0x23, 0xef, 0xd4, 0x57, 0xc2,
5686
+	0x53, 0xd3, 0x48, 0xd4, 0x73, 0xeb, 0xb9, 0x0d, 0x9b, 0xbf, 0xa2, 0x63, 0xcb, 0x60, 0xf5, 0x07,
5687
+	0x94, 0x28, 0x9b, 0x5b, 0xfd, 0x01, 0xab, 0x43, 0xf9, 0xd8, 0x8d, 0x7c, 0x37, 0x50, 0x94, 0x19,
5688
+	0x9b, 0x27, 0x4b, 0x76, 0x13, 0xec, 0xfe, 0xe0, 0x58, 0x44, 0xb1, 0x2f, 0x03, 0xca, 0x87, 0xcd,
5689
+	0x53, 0x05, 0x5b, 0x05, 0xe8, 0x0f, 0x1e, 0x09, 0x17, 0x49, 0xe3, 0x7a, 0x71, 0x3d, 0xbf, 0x61,
5690
+	0xf3, 0x8c, 0xc6, 0xf9, 0x1c, 0x8a, 0x54, 0x23, 0xf6, 0x31, 0x94, 0x86, 0xfe, 0x58, 0xc4, 0x4a,
5691
+	0xbb, 0xd3, 0x6a, 0xbe, 0x78, 0xb9, 0xb6, 0xf0, 0xd3, 0xcb, 0xb5, 0xcd, 0x4c, 0x33, 0xc8, 0x50,
5692
+	0x04, 0x9e, 0x0c, 0x94, 0xeb, 0x07, 0x22, 0x8a, 0x77, 0xc6, 0x72, 0x5b, 0x6f, 0x69, 0x74, 0xe8,
5693
+	0x87, 0x1b, 0x06, 0x76, 0x1b, 0x8a, 0x7e, 0x30, 0x14, 0x17, 0xe4, 0x7f, 0xbe, 0x75, 0xd5, 0x50,
5694
+	0x55, 0xfb, 0x53, 0x15, 0x4e, 0x55, 0x0f, 0x4d, 0x5c, 0x23, 0x9c, 0x10, 0x4a, 0xba, 0x05, 0xd8,
5695
+	0x4d, 0x28, 0x9c, 0x0b, 0xe5, 0xd2, 0xf1, 0xd5, 0x66, 0x05, 0x53, 0xbb, 0x2f, 0x94, 0xcb, 0x49,
5696
+	0x8b, 0xdd, 0x75, 0x2e, 0xa7, 0x98, 0x7a, 0x2b, 0xed, 0xae, 0x7d, 0xd4, 0x70, 0x63, 0x60, 0xff,
5697
+	0x87, 0x72, 0x20, 0xd4, 0x33, 0x19, 0x9d, 0x51, 0x8a, 0x96, 0x75, 0xcd, 0x0f, 0x84, 0xda, 0x97,
5698
+	0x43, 0xc1, 0x13, 0x9b, 0xf3, 0x4d, 0x0e, 0x0a, 0x48, 0xcc, 0x18, 0x14, 0xdc, 0x68, 0xac, 0xdb,
5699
+	0xd5, 0xe6, 0x24, 0xb3, 0x1a, 0xe4, 0x45, 0xf0, 0x94, 0xce, 0xb0, 0x39, 0x8a, 0xa8, 0xf1, 0x9e,
5700
+	0x0d, 0x4d, 0xd2, 0x51, 0xc4, 0x7d, 0xd3, 0x58, 0x44, 0x26, 0xd7, 0x24, 0xb3, 0xdb, 0x60, 0x87,
5701
+	0x91, 0xbc, 0x98, 0x3d, 0xc1, 0xdd, 0xc5, 0x4c, 0x27, 0xa1, 0xb2, 0x1b, 0x3c, 0xe5, 0x95, 0xd0,
5702
+	0x48, 0x6c, 0x13, 0x40, 0x5c, 0xa8, 0xc8, 0xdd, 0x93, 0xb1, 0x8a, 0xeb, 0x25, 0x8a, 0x86, 0x1a,
5703
+	0x18, 0x15, 0xbd, 0x43, 0x9e, 0xb1, 0x3a, 0xdf, 0x5b, 0x50, 0xa4, 0x20, 0xd9, 0x06, 0xa6, 0x34,
5704
+	0x9c, 0xea, 0xea, 0xe4, 0x5b, 0xcc, 0xa4, 0x14, 0xa8, 0x78, 0xf3, 0x8c, 0x62, 0x21, 0x57, 0xa0,
5705
+	0x12, 0x8b, 0x89, 0xf0, 0x94, 0x8c, 0x4c, 0xff, 0xcc, 0xd7, 0xe8, 0xfa, 0x10, 0x4b, 0xac, 0xa3,
5706
+	0x21, 0x99, 0x6d, 0x41, 0x49, 0x52, 0x5d, 0x28, 0xa0, 0xdf, 0xa9, 0x96, 0x81, 0x20, 0x79, 0x24,
5707
+	0xdc, 0xa1, 0x0c, 0x26, 0x33, 0x0a, 0xb3, 0xc2, 0xe7, 0x6b, 0xb6, 0x05, 0x36, 0x55, 0xe2, 0x68,
5708
+	0x16, 0x8a, 0x7a, 0x89, 0x2a, 0xb0, 0x34, 0xaf, 0x12, 0x2a, 0x79, 0x6a, 0xc7, 0x9b, 0xe7, 0xb9,
5709
+	0xde, 0xa9, 0xe8, 0x87, 0xaa, 0x7e, 0x2d, 0xcd, 0x57, 0xdb, 0xe8, 0xf8, 0xdc, 0x8a, 0xb4, 0xb1,
5710
+	0xf0, 0x22, 0xa1, 0x10, 0x7a, 0x9d, 0xa0, 0x44, 0x3b, 0x48, 0x94, 0x3c, 0xb5, 0x33, 0x07, 0x4a,
5711
+	0x83, 0xc1, 0x1e, 0x22, 0x6f, 0xa4, 0x2f, 0x83, 0xd6, 0x70, 0x63, 0x71, 0x7a, 0x50, 0x49, 0x8e,
5712
+	0xc1, 0x6b, 0xd6, 0xeb, 0x98, 0x0b, 0x68, 0xf5, 0x3a, 0x6c, 0x1b, 0xca, 0xf1, 0xa9, 0x1b, 0xf9,
5713
+	0xc1, 0x98, 0x72, 0xb7, 0xdc, 0xbc, 0x3a, 0xf7, 0x6a, 0xa0, 0xf5, 0xc8, 0x94, 0x60, 0x1c, 0x09,
5714
+	0xf6, 0xdc, 0x8d, 0x37, 0xb8, 0x6a, 0x90, 0x9f, 0xfa, 0x43, 0xe2, 0x59, 0xe2, 0x28, 0xa2, 0x66,
5715
+	0xec, 0xeb, 0x5e, 0x5a, 0xe2, 0x28, 0x62, 0x41, 0xce, 0xe5, 0x50, 0x50, 0xea, 0x97, 0x38, 0xc9,
5716
+	0x98, 0x63, 0x19, 0x2a, 0x5f, 0x06, 0xee, 0x24, 0xc9, 0x71, 0xb2, 0x76, 0x26, 0x49, 0x7c, 0x7f,
5717
+	0xcb, 0x69, 0x0f, 0xa1, 0xa4, 0x5f, 0x55, 0xb6, 0x0e, 0xf9, 0x38, 0xf2, 0xcc, 0xcb, 0xbe, 0x9c,
5718
+	0x3c, 0xb7, 0xfa, 0x61, 0xe6, 0x68, 0x9a, 0xb7, 0x96, 0x95, 0xb6, 0x96, 0xc3, 0x01, 0x52, 0xd8,
5719
+	0x5f, 0xd3, 0xc2, 0xce, 0x97, 0x39, 0xa8, 0x24, 0x03, 0x01, 0x5f, 0x37, 0x7f, 0x28, 0x02, 0xe5,
5720
+	0x8f, 0x7c, 0x11, 0x99, 0x64, 0x64, 0x34, 0x6c, 0x1b, 0x8a, 0xae, 0x52, 0x51, 0xf2, 0x68, 0xfc,
5721
+	0x33, 0x3b, 0x4d, 0x1a, 0xbb, 0x68, 0xe9, 0x06, 0x2a, 0x9a, 0x71, 0x8d, 0x5a, 0x79, 0x00, 0x90,
5722
+	0x2a, 0x31, 0x7f, 0x67, 0x62, 0x66, 0x58, 0x51, 0x64, 0xd7, 0xa0, 0xf8, 0xd4, 0x9d, 0x4c, 0x85,
5723
+	0x71, 0x4a, 0x2f, 0x3e, 0xb4, 0x1e, 0xe4, 0x9c, 0x6f, 0x2d, 0x28, 0x9b, 0xe9, 0xc2, 0xee, 0x40,
5724
+	0x99, 0xa6, 0x8b, 0xf1, 0xe8, 0xed, 0x91, 0x26, 0x10, 0xb6, 0x33, 0x1f, 0x9b, 0x19, 0x1f, 0x0d,
5725
+	0x95, 0x1e, 0x9f, 0xc6, 0xc7, 0x74, 0x88, 0xe6, 0x87, 0x62, 0x64, 0xe6, 0x23, 0x95, 0xa2, 0x23,
5726
+	0x46, 0x7e, 0xe0, 0x63, 0xcd, 0x38, 0x9a, 0xd8, 0x9d, 0x24, 0xea, 0x02, 0x31, 0xde, 0xc8, 0x32,
5727
+	0xbe, 0x19, 0x74, 0x0f, 0xaa, 0x99, 0x63, 0xde, 0x12, 0xf5, 0xff, 0xb2, 0x51, 0x9b, 0x23, 0x89,
5728
+	0x4e, 0x0f, 0xf7, 0x34, 0x0b, 0x7f, 0x22, 0x7f, 0xf7, 0x00, 0x52, 0xca, 0x77, 0xef, 0x14, 0xe7,
5729
+	0x79, 0x1e, 0xa0, 0x1f, 0xe2, 0x73, 0x3e, 0x74, 0x69, 0x4a, 0x2c, 0xfa, 0xe3, 0x40, 0x46, 0xe2,
5730
+	0x09, 0x3d, 0x1f, 0xb4, 0xbf, 0xc2, 0xab, 0x5a, 0x47, 0xb7, 0x98, 0xed, 0x42, 0x75, 0x28, 0x62,
5731
+	0x2f, 0xf2, 0xa9, 0xc9, 0x4d, 0xd2, 0xd7, 0x30, 0xa6, 0x94, 0xa7, 0xd1, 0x49, 0x11, 0x3a, 0x57,
5732
+	0xd9, 0x3d, 0xac, 0x09, 0x8b, 0xe2, 0x22, 0x94, 0x91, 0x32, 0xa7, 0xe8, 0x8f, 0x90, 0x2b, 0xfa,
5733
+	0x73, 0x06, 0xf5, 0x74, 0x12, 0xaf, 0x8a, 0x74, 0xc1, 0x5c, 0x28, 0x78, 0x6e, 0xa8, 0x27, 0x70,
5734
+	0xb5, 0x59, 0x7f, 0xed, 0xbc, 0xb6, 0x1b, 0xea, 0xa4, 0xb5, 0xee, 0x62, 0xac, 0xcf, 0x7f, 0x5e,
5735
+	0xdb, 0xca, 0x8c, 0xdd, 0x73, 0x79, 0x32, 0xdb, 0xa1, 0x7e, 0x39, 0xf3, 0xd5, 0xce, 0x54, 0xf9,
5736
+	0x93, 0x1d, 0x37, 0xf4, 0x91, 0x0e, 0x37, 0xf6, 0x3a, 0x9c, 0xa8, 0x57, 0x1e, 0x42, 0xed, 0x75,
5737
+	0xbf, 0xdf, 0xa7, 0x06, 0x2b, 0xf7, 0xc1, 0x9e, 0xfb, 0xf1, 0x47, 0x1b, 0x2b, 0xd9, 0xe2, 0xdd,
5738
+	0x82, 0x6a, 0x26, 0x6e, 0x04, 0x1e, 0x13, 0x50, 0x67, 0x5f, 0x2f, 0x9c, 0xe7, 0xf8, 0x05, 0x94,
5739
+	0xcc, 0xc0, 0xff, 0x00, 0x9c, 0x2a, 0x15, 0x3e, 0xa1, 0xa1, 0x68, 0x0e, 0xb1, 0x51, 0x43, 0x08,
5740
+	0xb6, 0x06, 0x55, 0x5c, 0xc4, 0xc6, 0xae, 0x3d, 0xa5, 0x1d, 0xb1, 0x06, 0xfc, 0x1b, 0xec, 0xd1,
5741
+	0x7c, 0xbb, 0x1e, 0x66, 0x95, 0x51, 0xb2, 0xfb, 0x5f, 0x50, 0x09, 0xa4, 0xb1, 0xe9, 0x19, 0x5d,
5742
+	0x0e, 0x24, 0x99, 0x9c, 0x2d, 0xf8, 0xc7, 0x1b, 0x9f, 0x6b, 0xec, 0x06, 0x94, 0x46, 0xfe, 0x44,
5743
+	0xd1, 0x75, 0xc5, 0xb1, 0x6f, 0x56, 0xce, 0x8f, 0x39, 0x80, 0xf4, 0x6a, 0x61, 0x46, 0xf0, 0xde,
5744
+	0x21, 0x66, 0x51, 0xdf, 0xb3, 0x09, 0x54, 0xce, 0x4d, 0x05, 0x4d, 0x1f, 0xdd, 0x7c, 0xf5, 0x3a,
5745
+	0x36, 0x92, 0x02, 0xeb, 0xda, 0x36, 0x4d, 0x6d, 0xdf, 0xe7, 0x93, 0x6a, 0x7e, 0xc2, 0xca, 0x63,
5746
+	0x58, 0x7a, 0x85, 0xee, 0x1d, 0x6f, 0x6a, 0xda, 0x65, 0xd9, 0x92, 0xdd, 0x81, 0x92, 0xfe, 0xdc,
5747
+	0xc0, 0x77, 0x1b, 0x25, 0x43, 0x43, 0x32, 0xcd, 0x96, 0xc3, 0xe4, 0xe3, 0xb3, 0x77, 0xb8, 0xb9,
5748
+	0x01, 0x65, 0xf3, 0x19, 0xc5, 0x6c, 0x28, 0x7e, 0x7a, 0x30, 0xe8, 0x1e, 0xd5, 0x16, 0x58, 0x05,
5749
+	0x0a, 0x7b, 0xfd, 0xc1, 0x51, 0x2d, 0x87, 0xd2, 0x41, 0xff, 0xa0, 0x5b, 0xb3, 0x36, 0x3f, 0x02,
5750
+	0x7b, 0x3e, 0xee, 0x51, 0xdd, 0xea, 0x1d, 0x74, 0x6a, 0x0b, 0x0c, 0xa0, 0x34, 0xe8, 0xb6, 0x79,
5751
+	0x17, 0xc1, 0x65, 0xc8, 0x0f, 0x06, 0x7b, 0x35, 0x0b, 0xa9, 0xda, 0xbb, 0xed, 0xbd, 0x6e, 0x2d,
5752
+	0x8f, 0xe2, 0xd1, 0xfe, 0xe1, 0xa3, 0x41, 0xad, 0xb0, 0x79, 0x0f, 0xae, 0xbc, 0x36, 0x6e, 0x69,
5753
+	0xf7, 0xde, 0x2e, 0xef, 0x22, 0x53, 0x15, 0xca, 0x87, 0xbc, 0x77, 0xbc, 0x7b, 0xd4, 0xad, 0xe5,
5754
+	0xd0, 0xf0, 0x49, 0xbf, 0xfd, 0xb8, 0xdb, 0xa9, 0x59, 0xad, 0x6b, 0x2f, 0x2e, 0x57, 0x73, 0xdf,
5755
+	0x5d, 0xae, 0xe6, 0x7e, 0xb8, 0x5c, 0xcd, 0xfd, 0x72, 0xb9, 0x9a, 0xfb, 0xe2, 0xd7, 0xd5, 0x85,
5756
+	0x93, 0x12, 0xfd, 0x45, 0xb9, 0xfb, 0x5b, 0x00, 0x00, 0x00, 0xff, 0xff, 0x84, 0xfe, 0x08, 0x0c,
5757
+	0xe2, 0x0c, 0x00, 0x00,
5756 5758
 }
... ...
@@ -6,6 +6,8 @@ package pb;
6 6
 
7 7
 import "github.com/gogo/protobuf/gogoproto/gogo.proto";
8 8
 
9
+option (gogoproto.stable_marshaler_all) = true;
10
+
9 11
 // Op represents a vertex of the LLB DAG.
10 12
 message Op {
11 13
 	// inputs is a set of input edges.
... ...
@@ -72,6 +74,7 @@ message Mount {
72 72
 	MountType mountType = 6;
73 73
 	CacheOpt cacheOpt = 20;
74 74
 	SecretOpt secretOpt = 21;
75
+	SSHOpt SSHOpt = 22;
75 76
 }
76 77
 
77 78
 // MountType defines a type of a mount from a supported set
... ...
@@ -116,6 +119,21 @@ message SecretOpt {
116 116
 	bool optional = 5;
117 117
 }
118 118
 
119
+// SSHOpt defines options describing secret mounts
120
+message SSHOpt {
121
+	// ID of exposed ssh rule. Used for quering the value.
122
+	string ID = 1;
123
+	// UID of agent socket
124
+	uint32 uid = 2;
125
+	// GID of agent socket
126
+	uint32 gid = 3;
127
+	// Mode is the filesystem mode of agent socket
128
+	uint32 mode = 4;
129
+	// Optional defines if ssh socket is required. Error is produced
130
+	// if client does not expose ssh.
131
+	bool optional = 5;
132
+}
133
+
119 134
 // CopyOp copies files across Ops.
120 135
 message CopyOp {
121 136
 	repeated CopySource src = 1;
... ...
@@ -371,7 +371,7 @@ func debugSchedulerPreUnpark(e *edge, inc []pipe.Sender, updates, allPipes []pip
371 371
 		if dep.req != nil {
372 372
 			des = dep.req.Request().(*edgeRequest).desiredState
373 373
 		}
374
-		logrus.Debugf(":: dep%d %s state=%s des=%s keys=%s hasslowcache=%v", i, e.edge.Vertex.Inputs()[i].Vertex.Name(), dep.state, des, len(dep.keys), e.slowCacheFunc(dep) != nil)
374
+		logrus.Debugf(":: dep%d %s state=%s des=%s keys=%d hasslowcache=%v", i, e.edge.Vertex.Inputs()[i].Vertex.Name(), dep.state, des, len(dep.keys), e.slowCacheFunc(dep) != nil)
375 375
 	}
376 376
 
377 377
 	for i, in := range inc {
... ...
@@ -11,7 +11,6 @@ import (
11 11
 	"regexp"
12 12
 	"strings"
13 13
 
14
-	"github.com/boltdb/bolt"
15 14
 	"github.com/docker/docker/pkg/locker"
16 15
 	"github.com/moby/buildkit/cache"
17 16
 	"github.com/moby/buildkit/cache/metadata"
... ...
@@ -22,6 +21,7 @@ import (
22 22
 	"github.com/moby/buildkit/util/progress/logs"
23 23
 	"github.com/pkg/errors"
24 24
 	"github.com/sirupsen/logrus"
25
+	bolt "go.etcd.io/bbolt"
25 26
 )
26 27
 
27 28
 var validHex = regexp.MustCompile(`^[a-f0-9]{40}$`)
... ...
@@ -15,7 +15,6 @@ import (
15 15
 	"strings"
16 16
 	"time"
17 17
 
18
-	"github.com/boltdb/bolt"
19 18
 	"github.com/docker/docker/pkg/locker"
20 19
 	"github.com/moby/buildkit/cache"
21 20
 	"github.com/moby/buildkit/cache/metadata"
... ...
@@ -24,6 +23,7 @@ import (
24 24
 	"github.com/moby/buildkit/util/tracing"
25 25
 	digest "github.com/opencontainers/go-digest"
26 26
 	"github.com/pkg/errors"
27
+	bolt "go.etcd.io/bbolt"
27 28
 )
28 29
 
29 30
 type Opt struct {
... ...
@@ -6,7 +6,6 @@ import (
6 6
 	"fmt"
7 7
 	"time"
8 8
 
9
-	"github.com/boltdb/bolt"
10 9
 	"github.com/moby/buildkit/cache"
11 10
 	"github.com/moby/buildkit/cache/contenthash"
12 11
 	"github.com/moby/buildkit/cache/metadata"
... ...
@@ -20,6 +19,7 @@ import (
20 20
 	"github.com/pkg/errors"
21 21
 	"github.com/sirupsen/logrus"
22 22
 	"github.com/tonistiigi/fsutil"
23
+	bolt "go.etcd.io/bbolt"
23 24
 	"golang.org/x/time/rate"
24 25
 	"google.golang.org/grpc/codes"
25 26
 	"google.golang.org/grpc/status"
... ...
@@ -3,10 +3,13 @@ package contentutil
3 3
 import (
4 4
 	"context"
5 5
 	"io"
6
+	"sync"
6 7
 
7 8
 	"github.com/containerd/containerd/content"
9
+	"github.com/containerd/containerd/images"
8 10
 	"github.com/containerd/containerd/remotes"
9 11
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
12
+	"github.com/pkg/errors"
10 13
 )
11 14
 
12 15
 func Copy(ctx context.Context, ingester content.Ingester, provider content.Provider, desc ocispec.Descriptor) error {
... ...
@@ -41,3 +44,38 @@ func (r *rc) Read(b []byte) (int, error) {
41 41
 	}
42 42
 	return n, err
43 43
 }
44
+
45
+func CopyChain(ctx context.Context, ingester content.Ingester, provider content.Provider, desc ocispec.Descriptor) error {
46
+	var m sync.Mutex
47
+	manifestStack := []ocispec.Descriptor{}
48
+
49
+	filterHandler := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
50
+		switch desc.MediaType {
51
+		case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest,
52
+			images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
53
+			m.Lock()
54
+			manifestStack = append(manifestStack, desc)
55
+			m.Unlock()
56
+			return nil, images.ErrStopHandler
57
+		default:
58
+			return nil, nil
59
+		}
60
+	})
61
+	handlers := []images.Handler{
62
+		images.ChildrenHandler(provider),
63
+		filterHandler,
64
+		remotes.FetchHandler(ingester, &localFetcher{provider}),
65
+	}
66
+
67
+	if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil {
68
+		return errors.WithStack(err)
69
+	}
70
+
71
+	for i := len(manifestStack) - 1; i >= 0; i-- {
72
+		if err := Copy(ctx, ingester, provider, manifestStack[i]); err != nil {
73
+			return errors.WithStack(err)
74
+		}
75
+	}
76
+
77
+	return nil
78
+}
... ...
@@ -55,6 +55,9 @@ func (r *readerAt) ReadAt(b []byte, off int64) (int, error) {
55 55
 	var totalN int
56 56
 	for len(b) > 0 {
57 57
 		n, err := r.Reader.Read(b)
58
+		if err == io.EOF && n == len(b) {
59
+			err = nil
60
+		}
58 61
 		r.offset += int64(n)
59 62
 		totalN += n
60 63
 		b = b[n:]
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	"github.com/pkg/errors"
12 12
 )
13 13
 
14
+// NewMultiProvider creates a new mutable provider with a base provider
14 15
 func NewMultiProvider(base content.Provider) *MultiProvider {
15 16
 	return &MultiProvider{
16 17
 		base: base,
... ...
@@ -18,12 +19,14 @@ func NewMultiProvider(base content.Provider) *MultiProvider {
18 18
 	}
19 19
 }
20 20
 
21
+// MultiProvider is a provider backed by a mutable map of providers
21 22
 type MultiProvider struct {
22 23
 	mu   sync.RWMutex
23 24
 	base content.Provider
24 25
 	sub  map[digest.Digest]content.Provider
25 26
 }
26 27
 
28
+// ReaderAt returns a content.ReaderAt
27 29
 func (mp *MultiProvider) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
28 30
 	mp.mu.RLock()
29 31
 	if p, ok := mp.sub[desc.Digest]; ok {
... ...
@@ -37,6 +40,7 @@ func (mp *MultiProvider) ReaderAt(ctx context.Context, desc ocispec.Descriptor)
37 37
 	return mp.base.ReaderAt(ctx, desc)
38 38
 }
39 39
 
40
+// Add adds a new child provider for a specific digest
40 41
 func (mp *MultiProvider) Add(dgst digest.Digest, p content.Provider) {
41 42
 	mp.mu.Lock()
42 43
 	defer mp.mu.Unlock()
43 44
new file mode 100644
... ...
@@ -0,0 +1,57 @@
0
+package contentutil
1
+
2
+import (
3
+	"context"
4
+	"net/http"
5
+
6
+	"github.com/containerd/containerd/content"
7
+	"github.com/containerd/containerd/remotes"
8
+	"github.com/containerd/containerd/remotes/docker"
9
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
10
+)
11
+
12
+func ProviderFromRef(ref string) (ocispec.Descriptor, content.Provider, error) {
13
+	remote := docker.NewResolver(docker.ResolverOptions{
14
+		Client: http.DefaultClient,
15
+	})
16
+
17
+	name, desc, err := remote.Resolve(context.TODO(), ref)
18
+	if err != nil {
19
+		return ocispec.Descriptor{}, nil, err
20
+	}
21
+
22
+	fetcher, err := remote.Fetcher(context.TODO(), name)
23
+	if err != nil {
24
+		return ocispec.Descriptor{}, nil, err
25
+	}
26
+	return desc, FromFetcher(fetcher), nil
27
+}
28
+
29
+func IngesterFromRef(ref string) (content.Ingester, error) {
30
+	remote := docker.NewResolver(docker.ResolverOptions{
31
+		Client: http.DefaultClient,
32
+	})
33
+
34
+	pusher, err := remote.Pusher(context.TODO(), ref)
35
+	if err != nil {
36
+		return nil, err
37
+	}
38
+
39
+	return &ingester{
40
+		pusher: pusher,
41
+	}, nil
42
+}
43
+
44
+type ingester struct {
45
+	pusher remotes.Pusher
46
+}
47
+
48
+func (w *ingester) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
49
+	var wo content.WriterOpts
50
+	for _, o := range opts {
51
+		if err := o(&wo); err != nil {
52
+			return nil, err
53
+		}
54
+	}
55
+	return w.pusher.Push(ctx, wo.Desc)
56
+}
... ...
@@ -21,11 +21,13 @@ type contextKeyT string
21 21
 
22 22
 var contextKey = contextKeyT("buildkit/util/flightcontrol.progress")
23 23
 
24
+// Group is a flightcontrol syncronization group
24 25
 type Group struct {
25 26
 	mu sync.Mutex       // protects m
26 27
 	m  map[string]*call // lazily initialized
27 28
 }
28 29
 
30
+// Do executes a context function syncronized by the key
29 31
 func (g *Group) Do(ctx context.Context, key string, fn func(ctx context.Context) (interface{}, error)) (v interface{}, err error) {
30 32
 	defer func() {
31 33
 		if errors.Cause(err) == errRetry {
... ...
@@ -312,13 +314,3 @@ func (ps *progressState) close(pw progress.Writer) {
312 312
 	}
313 313
 	ps.mu.Unlock()
314 314
 }
315
-
316
-func WriteProgress(ctx context.Context, pw progress.Writer) error {
317
-	v := ctx.Value(contextKey)
318
-	p, ok := v.(*progressState)
319
-	if !ok {
320
-		return errors.Errorf("invalid context not from flightcontrol")
321
-	}
322
-	p.add(pw)
323
-	return nil
324
-}
... ...
@@ -14,12 +14,12 @@ import (
14 14
 	"github.com/pkg/errors"
15 15
 )
16 16
 
17
-type IngesterProvider interface {
17
+type ContentCache interface {
18 18
 	content.Ingester
19 19
 	content.Provider
20 20
 }
21 21
 
22
-func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester IngesterProvider, p *specs.Platform) (digest.Digest, []byte, error) {
22
+func Config(ctx context.Context, str string, resolver remotes.Resolver, cache ContentCache, p *specs.Platform) (digest.Digest, []byte, error) {
23 23
 	// TODO: fix buildkit to take interface instead of struct
24 24
 	var platform platforms.MatchComparer
25 25
 	if p != nil {
... ...
@@ -36,7 +36,7 @@ func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester
36 36
 		Digest: ref.Digest(),
37 37
 	}
38 38
 	if desc.Digest != "" {
39
-		ra, err := ingester.ReaderAt(ctx, desc)
39
+		ra, err := cache.ReaderAt(ctx, desc)
40 40
 		if err == nil {
41 41
 			desc.Size = ra.Size()
42 42
 			mt, err := DetectManifestMediaType(ra)
... ...
@@ -58,19 +58,23 @@ func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester
58 58
 		return "", nil, err
59 59
 	}
60 60
 
61
+	if desc.MediaType == images.MediaTypeDockerSchema1Manifest {
62
+		return readSchema1Config(ctx, ref.String(), desc, fetcher, cache)
63
+	}
64
+
61 65
 	handlers := []images.Handler{
62
-		remotes.FetchHandler(ingester, fetcher),
63
-		childrenConfigHandler(ingester, platform),
66
+		remotes.FetchHandler(cache, fetcher),
67
+		childrenConfigHandler(cache, platform),
64 68
 	}
65 69
 	if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil {
66 70
 		return "", nil, err
67 71
 	}
68
-	config, err := images.Config(ctx, ingester, desc, platform)
72
+	config, err := images.Config(ctx, cache, desc, platform)
69 73
 	if err != nil {
70 74
 		return "", nil, err
71 75
 	}
72 76
 
73
-	dt, err := content.ReadBlob(ctx, ingester, config)
77
+	dt, err := content.ReadBlob(ctx, cache, config)
74 78
 	if err != nil {
75 79
 		return "", nil, err
76 80
 	}
77 81
new file mode 100644
... ...
@@ -0,0 +1,87 @@
0
+package imageutil
1
+
2
+import (
3
+	"context"
4
+	"encoding/json"
5
+	"io/ioutil"
6
+	"strings"
7
+	"time"
8
+
9
+	"github.com/containerd/containerd/remotes"
10
+	digest "github.com/opencontainers/go-digest"
11
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
12
+	"github.com/pkg/errors"
13
+)
14
+
15
+func readSchema1Config(ctx context.Context, ref string, desc specs.Descriptor, fetcher remotes.Fetcher, cache ContentCache) (digest.Digest, []byte, error) {
16
+	rc, err := fetcher.Fetch(ctx, desc)
17
+	if err != nil {
18
+		return "", nil, err
19
+	}
20
+	defer rc.Close()
21
+	dt, err := ioutil.ReadAll(rc)
22
+	if err != nil {
23
+		return "", nil, errors.Wrap(err, "failed to fetch schema1 manifest")
24
+	}
25
+	dt, err = convertSchema1ConfigMeta(dt)
26
+	if err != nil {
27
+		return "", nil, err
28
+	}
29
+	return desc.Digest, dt, nil
30
+}
31
+
32
+func convertSchema1ConfigMeta(in []byte) ([]byte, error) {
33
+	type history struct {
34
+		V1Compatibility string `json:"v1Compatibility"`
35
+	}
36
+	var m struct {
37
+		History []history `json:"history"`
38
+	}
39
+	if err := json.Unmarshal(in, &m); err != nil {
40
+		return nil, errors.Wrap(err, "failed to unmarshal schema1 manifest")
41
+	}
42
+	if len(m.History) == 0 {
43
+		return nil, errors.Errorf("invalid schema1 manifest")
44
+	}
45
+
46
+	var img specs.Image
47
+	if err := json.Unmarshal([]byte(m.History[0].V1Compatibility), &img); err != nil {
48
+		return nil, errors.Wrap(err, "failed to unmarshal image from schema 1 history")
49
+	}
50
+
51
+	img.RootFS = specs.RootFS{
52
+		Type: "layers", // filled in by exporter
53
+	}
54
+	img.History = make([]specs.History, len(m.History))
55
+
56
+	for i := range m.History {
57
+		var h v1History
58
+		if err := json.Unmarshal([]byte(m.History[i].V1Compatibility), &h); err != nil {
59
+			return nil, errors.Wrap(err, "failed to unmarshal history")
60
+		}
61
+		img.History[len(m.History)-i-1] = specs.History{
62
+			Author:     h.Author,
63
+			Comment:    h.Comment,
64
+			Created:    &h.Created,
65
+			CreatedBy:  strings.Join(h.ContainerConfig.Cmd, " "),
66
+			EmptyLayer: (h.ThrowAway != nil && *h.ThrowAway) || (h.Size != nil && *h.Size == 0),
67
+		}
68
+	}
69
+
70
+	dt, err := json.MarshalIndent(img, "", "   ")
71
+	if err != nil {
72
+		return nil, errors.Wrap(err, "failed to marshal schema1 config")
73
+	}
74
+	return dt, nil
75
+}
76
+
77
+type v1History struct {
78
+	Author          string    `json:"author,omitempty"`
79
+	Created         time.Time `json:"created"`
80
+	Comment         string    `json:"comment,omitempty"`
81
+	ThrowAway       *bool     `json:"throwaway,omitempty"`
82
+	Size            *int      `json:"Size,omitempty"` // used before ThrowAway field
83
+	ContainerConfig struct {
84
+		Cmd []string `json:"Cmd,omitempty"`
85
+	} `json:"container_config,omitempty"`
86
+}
... ...
@@ -1,12 +1,12 @@
1
-github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd
2 1
 github.com/pkg/errors v0.8.0
2
+go.etcd.io/bbolt v1.3.1-etcd.8
3 3
 
4 4
 github.com/stretchr/testify v1.1.4
5 5
 github.com/davecgh/go-spew v1.1.0
6 6
 github.com/pmezard/go-difflib v1.0.0
7 7
 golang.org/x/sys 1b2967e3c290b7c545b3db0deeda16e9be4f98a2
8 8
 
9
-github.com/containerd/containerd v1.2.0-beta.2
9
+github.com/containerd/containerd d97a907f7f781c0ab8340877d8e6b53cc7f1c2f6
10 10
 github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
11 11
 golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
12 12
 github.com/sirupsen/logrus v1.0.0
... ...
@@ -16,19 +16,20 @@ golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd
16 16
 github.com/gogo/protobuf v1.0.0
17 17
 github.com/gogo/googleapis b23578765ee54ff6bceff57f397d833bf4ca6869
18 18
 github.com/golang/protobuf v1.1.0
19
-github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b
19
+github.com/containerd/continuity f44b615e492bdfb371aae2f76ec694d9da1db537
20 20
 github.com/opencontainers/image-spec v1.0.1
21 21
 github.com/opencontainers/runc 20aff4f0488c6d4b8df4d85b4f63f1f704c11abd
22
-github.com/Microsoft/go-winio v0.4.10
22
+github.com/Microsoft/go-winio v0.4.11
23 23
 github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
24
-github.com/opencontainers/runtime-spec d810dbc60d8c5aeeb3d054bd1132fab2121968ce # v1.0.1-43-gd810dbc
25
-github.com/containerd/go-runc acb7c88cac264acca9b5eae187a117f4d77a1292
24
+github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353 # v1.0.1-45-geba862d
25
+github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
26 26
 github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
27 27
 google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
28 28
 golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
29 29
 github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
30 30
 github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16
31
-github.com/Microsoft/hcsshim 44c060121b68e8bdc40b411beba551f3b4ee9e55
31
+github.com/Microsoft/hcsshim v0.7.3
32
+golang.org/x/crypto 0709b304e793a5edb4a2c0145f281ecdc20838a4
32 33
 
33 34
 github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
34 35
 github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b
... ...
@@ -49,8 +50,9 @@ github.com/docker/distribution 30578ca32960a4d368bf6db67b0a33c2a1f3dc6f
49 49
 github.com/tonistiigi/units 6950e57a87eaf136bbe44ef2ec8e75b9e3569de2
50 50
 github.com/docker/cli 99576756eb3303b7af8102c502f21a912e3c1af6 https://github.com/tonistiigi/docker-cli.git
51 51
 github.com/docker/docker-credential-helpers d68f9aeca33f5fd3f08eeae5e9d175edf4e731d1
52
-github.com/docker/libnetwork 822e5b59d346b7ad0735df2c8e445e9787320e67
52
+github.com/docker/libnetwork 36d3bed0e9f4b3c8c66df9bd45278bb90b33e911
53 53
 github.com/BurntSushi/toml 3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005
54
+github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb
54 55
 
55 56
 github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
56 57
 github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
... ...
@@ -36,7 +36,7 @@ func (s *cacheResultStorage) Save(res solver.Result) (solver.CacheResult, error)
36 36
 	return solver.CacheResult{ID: ref.ID(), CreatedAt: time.Now()}, nil
37 37
 }
38 38
 func (s *cacheResultStorage) Load(ctx context.Context, res solver.CacheResult) (solver.Result, error) {
39
-	return s.load(res.ID)
39
+	return s.load(res.ID, false)
40 40
 }
41 41
 
42 42
 func (s *cacheResultStorage) getWorkerRef(id string) (Worker, string, error) {
... ...
@@ -51,7 +51,7 @@ func (s *cacheResultStorage) getWorkerRef(id string) (Worker, string, error) {
51 51
 	return w, refID, nil
52 52
 }
53 53
 
54
-func (s *cacheResultStorage) load(id string) (solver.Result, error) {
54
+func (s *cacheResultStorage) load(id string, hidden bool) (solver.Result, error) {
55 55
 	w, refID, err := s.getWorkerRef(id)
56 56
 	if err != nil {
57 57
 		return nil, err
... ...
@@ -59,7 +59,7 @@ func (s *cacheResultStorage) load(id string) (solver.Result, error) {
59 59
 	if refID == "" {
60 60
 		return NewWorkerRefResult(nil, w), nil
61 61
 	}
62
-	ref, err := w.LoadRef(refID)
62
+	ref, err := w.LoadRef(refID, hidden)
63 63
 	if err != nil {
64 64
 		return nil, err
65 65
 	}
... ...
@@ -71,7 +71,7 @@ func (s *cacheResultStorage) LoadRemote(ctx context.Context, res solver.CacheRes
71 71
 	if err != nil {
72 72
 		return nil, err
73 73
 	}
74
-	ref, err := w.LoadRef(refID)
74
+	ref, err := w.LoadRef(refID, true)
75 75
 	if err != nil {
76 76
 		return nil, err
77 77
 	}
... ...
@@ -83,7 +83,7 @@ func (s *cacheResultStorage) LoadRemote(ctx context.Context, res solver.CacheRes
83 83
 	return remote, nil
84 84
 }
85 85
 func (s *cacheResultStorage) Exists(id string) bool {
86
-	ref, err := s.load(id)
86
+	ref, err := s.load(id, true)
87 87
 	if err != nil {
88 88
 		return false
89 89
 	}
... ...
@@ -21,7 +21,7 @@ type Worker interface {
21 21
 	Labels() map[string]string
22 22
 	Platforms() []specs.Platform
23 23
 	GCPolicy() []client.PruneInfo
24
-	LoadRef(id string) (cache.ImmutableRef, error)
24
+	LoadRef(id string, hidden bool) (cache.ImmutableRef, error)
25 25
 	// ResolveOp resolves Vertex.Sys() to Op implementation.
26 26
 	ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge) (solver.Op, error)
27 27
 	ResolveImageConfig(ctx context.Context, ref string, opt gw.ResolveImageConfigOpt) (digest.Digest, []byte, error)