2018-07-05 21:31:50 +00:00
|
|
|
package forwarder
|
2017-12-13 23:46:52 +00:00
|
|
|
|
|
|
|
import (
|
2018-01-16 22:30:10 +00:00
|
|
|
"context"
|
2018-07-11 02:31:33 +00:00
|
|
|
"sync"
|
2017-12-14 01:29:03 +00:00
|
|
|
|
2017-12-13 23:46:52 +00:00
|
|
|
"github.com/moby/buildkit/cache"
|
2018-10-02 11:17:57 +00:00
|
|
|
cacheutil "github.com/moby/buildkit/cache/util"
|
2018-07-04 02:47:40 +00:00
|
|
|
clienttypes "github.com/moby/buildkit/client"
|
2019-12-09 20:50:21 +00:00
|
|
|
"github.com/moby/buildkit/client/llb"
|
2017-12-13 23:46:52 +00:00
|
|
|
"github.com/moby/buildkit/frontend"
|
|
|
|
"github.com/moby/buildkit/frontend/gateway/client"
|
2018-09-21 22:19:10 +00:00
|
|
|
gwpb "github.com/moby/buildkit/frontend/gateway/pb"
|
2018-05-11 05:58:41 +00:00
|
|
|
"github.com/moby/buildkit/solver"
|
2018-09-21 22:19:10 +00:00
|
|
|
opspb "github.com/moby/buildkit/solver/pb"
|
2018-07-05 21:15:14 +00:00
|
|
|
"github.com/moby/buildkit/util/apicaps"
|
2018-04-13 21:13:48 +00:00
|
|
|
"github.com/moby/buildkit/worker"
|
2017-12-14 01:29:03 +00:00
|
|
|
"github.com/pkg/errors"
|
2018-09-21 12:48:30 +00:00
|
|
|
fstypes "github.com/tonistiigi/fsutil/types"
|
2017-12-13 23:46:52 +00:00
|
|
|
)
|
|
|
|
|
2020-06-30 01:06:02 +00:00
|
|
|
func llbBridgeToGatewayClient(ctx context.Context, llbBridge frontend.FrontendLLBBridge, opts map[string]string, inputs map[string]*opspb.Definition, workerInfos []clienttypes.WorkerInfo, sid string) (*bridgeClient, error) {
|
2018-07-05 23:32:01 +00:00
|
|
|
return &bridgeClient{
|
|
|
|
opts: opts,
|
2020-02-07 19:53:18 +00:00
|
|
|
inputs: inputs,
|
2018-07-05 23:32:01 +00:00
|
|
|
FrontendLLBBridge: llbBridge,
|
2020-06-30 01:06:02 +00:00
|
|
|
sid: sid,
|
2018-07-05 23:32:01 +00:00
|
|
|
workerInfos: workerInfos,
|
|
|
|
final: map[*ref]struct{}{},
|
|
|
|
}, nil
|
2017-12-13 23:46:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type bridgeClient struct {
|
|
|
|
frontend.FrontendLLBBridge
|
2020-07-18 06:03:56 +00:00
|
|
|
mu sync.Mutex
|
|
|
|
opts map[string]string
|
|
|
|
inputs map[string]*opspb.Definition
|
|
|
|
final map[*ref]struct{}
|
|
|
|
sid string
|
|
|
|
refs []*ref
|
|
|
|
workerInfos []clienttypes.WorkerInfo
|
2017-12-13 23:46:52 +00:00
|
|
|
}
|
|
|
|
|
2018-07-05 23:32:01 +00:00
|
|
|
func (c *bridgeClient) Solve(ctx context.Context, req client.SolveRequest) (*client.Result, error) {
|
2018-07-11 23:51:41 +00:00
|
|
|
res, err := c.FrontendLLBBridge.Solve(ctx, frontend.SolveRequest{
|
2020-02-07 19:53:18 +00:00
|
|
|
Definition: req.Definition,
|
|
|
|
Frontend: req.Frontend,
|
|
|
|
FrontendOpt: req.FrontendOpt,
|
|
|
|
FrontendInputs: req.FrontendInputs,
|
|
|
|
CacheImports: req.CacheImports,
|
2020-06-30 01:06:02 +00:00
|
|
|
}, c.sid)
|
2017-12-13 23:46:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-07-05 23:32:01 +00:00
|
|
|
|
2018-07-11 23:51:41 +00:00
|
|
|
cRes := &client.Result{}
|
2018-07-11 02:31:33 +00:00
|
|
|
c.mu.Lock()
|
2018-07-11 23:51:41 +00:00
|
|
|
for k, r := range res.Refs {
|
2019-12-09 20:50:21 +00:00
|
|
|
rr, err := newRef(r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-07-05 23:32:01 +00:00
|
|
|
c.refs = append(c.refs, rr)
|
2018-07-11 23:51:41 +00:00
|
|
|
cRes.AddRef(k, rr)
|
|
|
|
}
|
|
|
|
if r := res.Ref; r != nil {
|
2019-12-09 20:50:21 +00:00
|
|
|
rr, err := newRef(r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-07-11 23:51:41 +00:00
|
|
|
c.refs = append(c.refs, rr)
|
|
|
|
cRes.SetRef(rr)
|
2018-07-05 23:32:01 +00:00
|
|
|
}
|
2018-07-11 02:31:33 +00:00
|
|
|
c.mu.Unlock()
|
2018-07-11 23:51:41 +00:00
|
|
|
cRes.Metadata = res.Metadata
|
2018-07-05 23:32:01 +00:00
|
|
|
|
2018-07-11 23:51:41 +00:00
|
|
|
return cRes, nil
|
2017-12-13 23:46:52 +00:00
|
|
|
}
|
2018-07-05 21:15:14 +00:00
|
|
|
func (c *bridgeClient) BuildOpts() client.BuildOpts {
|
|
|
|
workers := make([]client.WorkerInfo, 0, len(c.workerInfos))
|
2018-07-04 02:47:40 +00:00
|
|
|
for _, w := range c.workerInfos {
|
2018-08-30 21:06:27 +00:00
|
|
|
workers = append(workers, client.WorkerInfo{
|
|
|
|
ID: w.ID,
|
|
|
|
Labels: w.Labels,
|
|
|
|
Platforms: w.Platforms,
|
|
|
|
})
|
2018-07-05 21:15:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return client.BuildOpts{
|
|
|
|
Opts: c.opts,
|
|
|
|
SessionID: c.sid,
|
|
|
|
Workers: workers,
|
|
|
|
Product: apicaps.ExportedProduct,
|
2018-09-21 22:19:10 +00:00
|
|
|
Caps: gwpb.Caps.CapSet(gwpb.Caps.All()),
|
|
|
|
LLBCaps: opspb.Caps.CapSet(opspb.Caps.All()),
|
2018-07-04 02:47:40 +00:00
|
|
|
}
|
|
|
|
}
|
2017-12-13 23:46:52 +00:00
|
|
|
|
2020-02-07 19:53:18 +00:00
|
|
|
func (c *bridgeClient) Inputs(ctx context.Context) (map[string]llb.State, error) {
|
2020-02-21 18:19:19 +00:00
|
|
|
inputs := make(map[string]llb.State)
|
|
|
|
for key, def := range c.inputs {
|
|
|
|
defop, err := llb.NewDefinitionOp(def)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
inputs[key] = llb.NewState(defop)
|
|
|
|
}
|
|
|
|
return inputs, nil
|
2020-02-07 19:53:18 +00:00
|
|
|
}
|
|
|
|
|
2018-07-11 23:51:41 +00:00
|
|
|
func (c *bridgeClient) toFrontendResult(r *client.Result) (*frontend.Result, error) {
|
|
|
|
if r == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
res := &frontend.Result{}
|
|
|
|
|
|
|
|
if r.Refs != nil {
|
2020-02-04 23:00:44 +00:00
|
|
|
res.Refs = make(map[string]solver.ResultProxy, len(r.Refs))
|
2018-07-11 23:51:41 +00:00
|
|
|
for k, r := range r.Refs {
|
|
|
|
rr, ok := r.(*ref)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.Errorf("invalid reference type for forward %T", r)
|
|
|
|
}
|
|
|
|
c.final[rr] = struct{}{}
|
2020-02-04 23:00:44 +00:00
|
|
|
res.Refs[k] = rr.ResultProxy
|
2018-07-11 23:51:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if r := r.Ref; r != nil {
|
2018-07-05 23:32:01 +00:00
|
|
|
rr, ok := r.(*ref)
|
|
|
|
if !ok {
|
2018-07-11 23:51:41 +00:00
|
|
|
return nil, errors.Errorf("invalid reference type for forward %T", r)
|
2018-07-05 23:32:01 +00:00
|
|
|
}
|
|
|
|
c.final[rr] = struct{}{}
|
2020-02-04 23:00:44 +00:00
|
|
|
res.Ref = rr.ResultProxy
|
2018-07-05 23:32:01 +00:00
|
|
|
}
|
2018-07-11 23:51:41 +00:00
|
|
|
res.Metadata = r.Metadata
|
|
|
|
|
|
|
|
return res, nil
|
2018-07-05 23:32:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *bridgeClient) discard(err error) {
|
|
|
|
for _, r := range c.refs {
|
|
|
|
if r != nil {
|
|
|
|
if _, ok := c.final[r]; !ok || err != nil {
|
|
|
|
r.Release(context.TODO())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-13 23:46:52 +00:00
|
|
|
type ref struct {
|
2020-02-04 23:00:44 +00:00
|
|
|
solver.ResultProxy
|
2019-12-09 20:50:21 +00:00
|
|
|
}
|
|
|
|
|
2020-02-04 23:00:44 +00:00
|
|
|
func newRef(r solver.ResultProxy) (*ref, error) {
|
|
|
|
return &ref{ResultProxy: r}, nil
|
2020-01-23 19:30:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *ref) ToState() (st llb.State, err error) {
|
2020-02-04 23:00:44 +00:00
|
|
|
defop, err := llb.NewDefinitionOp(r.Definition())
|
2019-12-09 20:50:21 +00:00
|
|
|
if err != nil {
|
2020-01-23 19:30:45 +00:00
|
|
|
return st, err
|
2019-12-09 20:50:21 +00:00
|
|
|
}
|
2020-01-23 19:30:45 +00:00
|
|
|
return llb.NewState(defop), nil
|
2017-12-13 23:46:52 +00:00
|
|
|
}
|
|
|
|
|
2018-05-29 21:15:13 +00:00
|
|
|
func (r *ref) ReadFile(ctx context.Context, req client.ReadRequest) ([]byte, error) {
|
2020-02-04 23:00:44 +00:00
|
|
|
ref, err := r.getImmutableRef(ctx)
|
2018-04-13 21:13:48 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-10-02 11:17:57 +00:00
|
|
|
newReq := cacheutil.ReadRequest{
|
2018-05-29 21:15:13 +00:00
|
|
|
Filename: req.Filename,
|
|
|
|
}
|
|
|
|
if r := req.Range; r != nil {
|
2018-10-02 11:17:57 +00:00
|
|
|
newReq.Range = &cacheutil.FileRange{
|
2018-05-29 21:15:13 +00:00
|
|
|
Offset: r.Offset,
|
|
|
|
Length: r.Length,
|
|
|
|
}
|
|
|
|
}
|
2018-10-02 11:17:57 +00:00
|
|
|
return cacheutil.ReadFile(ctx, ref, newReq)
|
2018-04-13 21:13:48 +00:00
|
|
|
}
|
|
|
|
|
2018-09-21 12:48:30 +00:00
|
|
|
func (r *ref) ReadDir(ctx context.Context, req client.ReadDirRequest) ([]*fstypes.Stat, error) {
|
2020-02-04 23:00:44 +00:00
|
|
|
ref, err := r.getImmutableRef(ctx)
|
2018-09-21 12:48:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-10-02 11:17:57 +00:00
|
|
|
newReq := cacheutil.ReadDirRequest{
|
2018-09-21 12:48:30 +00:00
|
|
|
Path: req.Path,
|
|
|
|
IncludePattern: req.IncludePattern,
|
|
|
|
}
|
2018-10-02 11:17:57 +00:00
|
|
|
return cacheutil.ReadDir(ctx, ref, newReq)
|
2018-09-21 12:48:30 +00:00
|
|
|
}
|
|
|
|
|
2018-10-02 13:45:39 +00:00
|
|
|
func (r *ref) StatFile(ctx context.Context, req client.StatRequest) (*fstypes.Stat, error) {
|
2020-02-04 23:00:44 +00:00
|
|
|
ref, err := r.getImmutableRef(ctx)
|
2018-10-02 13:45:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return cacheutil.StatFile(ctx, ref, req.Path)
|
|
|
|
}
|
|
|
|
|
2020-02-04 23:00:44 +00:00
|
|
|
func (r *ref) getImmutableRef(ctx context.Context) (cache.ImmutableRef, error) {
|
|
|
|
rr, err := r.ResultProxy.Result(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
ref, ok := rr.Sys().(*worker.WorkerRef)
|
2018-04-13 21:13:48 +00:00
|
|
|
if !ok {
|
2020-02-04 23:00:44 +00:00
|
|
|
return nil, errors.Errorf("invalid ref: %T", rr.Sys())
|
2017-12-14 01:29:03 +00:00
|
|
|
}
|
2018-04-13 21:13:48 +00:00
|
|
|
return ref.ImmutableRef, nil
|
2017-12-13 23:46:52 +00:00
|
|
|
}
|