From 0364e00aacaff3fd2baeebf6bf06ba3557585c59 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Mon, 1 Nov 2021 17:09:48 -0700 Subject: [PATCH] gateway: allow access to current frontend definition Signed-off-by: Tonis Tiigi --- frontend/gateway/gateway.go | 70 ++++++++++++++++++++++++++- frontend/gateway/grpcclient/client.go | 21 ++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/frontend/gateway/gateway.go b/frontend/gateway/gateway.go index ac48a795e043..2a51225acaa1 100644 --- a/frontend/gateway/gateway.go +++ b/frontend/gateway/gateway.go @@ -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() diff --git a/frontend/gateway/grpcclient/client.go b/frontend/gateway/grpcclient/client.go index ff72aa906492..82e285979110 100644 --- a/frontend/gateway/grpcclient/client.go +++ b/frontend/gateway/grpcclient/client.go @@ -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 {