gateway: allow access to current frontend definition

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
master
Tonis Tiigi 2021-11-01 17:09:48 -07:00
parent 0ad26d49f2
commit 0364e00aac
2 changed files with 90 additions and 1 deletions

View File

@ -7,12 +7,15 @@ import (
"io"
"net"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"github.com/containerd/containerd/mount"
"github.com/docker/distribution/reference"
"github.com/docker/docker/pkg/idtools"
"github.com/gogo/googleapis/google/rpc"
gogotypes "github.com/gogo/protobuf/types"
"github.com/golang/protobuf/ptypes/any"
@ -28,6 +31,7 @@ import (
pb "github.com/moby/buildkit/frontend/gateway/pb"
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/snapshot"
"github.com/moby/buildkit/solver"
"github.com/moby/buildkit/solver/errdefs"
llberrdefs "github.com/moby/buildkit/solver/llbsolver/errdefs"
@ -88,6 +92,8 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
var rootFS cache.MutableRef
var readonly bool // TODO: try to switch to read-only by default.
var frontendDef *opspb.Definition
if isDevel {
devRes, err := llbBridge.Solve(ctx,
frontend.SolveRequest{
@ -106,10 +112,12 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
if devRes.Ref == nil {
return nil, errors.Errorf("development gateway didn't return default result")
}
frontendDef = devRes.Ref.Definition()
res, err := devRes.Ref.Result(ctx)
if err != nil {
return nil, err
}
workerRef, ok := res.Sys().(*worker.WorkerRef)
if !ok {
return nil, errors.Errorf("invalid ref: %T", res.Sys())
@ -171,6 +179,7 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
return nil, errors.Errorf("gateway source didn't return default result")
}
frontendDef = res.Ref.Definition()
r, err := res.Ref.Result(ctx)
if err != nil {
return nil, err
@ -252,7 +261,19 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
return nil, err
}
err = w.Executor().Run(ctx, "", mountWithSession(rootFS, session.NewGroup(sid)), nil, executor.ProcessInfo{Meta: meta, Stdin: lbf.Stdin, Stdout: lbf.Stdout, Stderr: os.Stderr}, nil)
mdmnt, release, err := metadataMount(frontendDef)
if err != nil {
return nil, err
}
if release != nil {
defer release()
}
var mnts []executor.Mount
if mdmnt != nil {
mnts = append(mnts, *mdmnt)
}
err = w.Executor().Run(ctx, "", mountWithSession(rootFS, session.NewGroup(sid)), mnts, executor.ProcessInfo{Meta: meta, Stdin: lbf.Stdin, Stdout: lbf.Stdout, Stderr: os.Stderr}, nil)
if err != nil {
if errdefs.IsCanceled(err) && lbf.isErrServerClosed {
@ -272,6 +293,53 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
return lbf.Result()
}
func metadataMount(def *opspb.Definition) (*executor.Mount, func(), error) {
dt, err := def.Marshal()
if err != nil {
return nil, nil, err
}
dir, err := os.MkdirTemp("", "buildkit-metadata")
if err != nil {
return nil, nil, err
}
if err := os.WriteFile(filepath.Join(dir, "frontend.bin"), dt, 0400); err != nil {
return nil, nil, err
}
return &executor.Mount{
Src: &bind{dir},
Dest: "/run/config/buildkit/metadata",
Readonly: true,
}, func() {
os.RemoveAll(dir)
}, nil
}
type bind struct {
dir string
}
func (b *bind) Mount(ctx context.Context, readonly bool) (snapshot.Mountable, error) {
return &bindMount{b.dir, readonly}, nil
}
type bindMount struct {
dir string
readonly bool
}
func (b *bindMount) Mount() ([]mount.Mount, func() error, error) {
return []mount.Mount{{
Type: "bind",
Source: b.dir,
Options: []string{"bind", "ro"},
}}, func() error { return nil }, nil
}
func (b *bindMount) IdentityMapping() *idtools.IdentityMapping {
return nil
}
func (lbf *llbBridgeForwarder) Discard() {
lbf.mu.Lock()
defer lbf.mu.Unlock()

View File

@ -457,6 +457,27 @@ func (c *grpcClient) BuildOpts() client.BuildOpts {
}
}
func (c *grpcClient) CurrentFrontend() (*llb.State, error) {
fp := "/run/config/buildkit/metadata/frontend.bin"
if _, err := os.Stat(fp); err != nil {
return nil, nil
}
dt, err := os.ReadFile(fp)
if err != nil {
return nil, err
}
var def opspb.Definition
if err := def.Unmarshal(dt); err != nil {
return nil, err
}
op, err := llb.NewDefinitionOp(&def)
if err != nil {
return nil, err
}
st := llb.NewState(op)
return &st, nil
}
func (c *grpcClient) Inputs(ctx context.Context) (map[string]llb.State, error) {
err := c.caps.Supports(pb.CapFrontendInputs)
if err != nil {