Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Evaluate(Ref) Gateway API #3137

Merged
merged 5 commits into from
Oct 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions client/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,19 @@ func (g *gatewayClientForBuild) StatFile(ctx context.Context, in *gatewayapi.Sta
return g.gateway.StatFile(ctx, in, opts...)
}

func (g *gatewayClientForBuild) Evaluate(ctx context.Context, in *gatewayapi.EvaluateRequest, opts ...grpc.CallOption) (*gatewayapi.EvaluateResponse, error) {
if err := g.caps.Supports(gatewayapi.CapGatewayEvaluate); err != nil {
if err2 := g.caps.Supports(gatewayapi.CapStatFile); err2 != nil {
return nil, err
}
ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
_, err := g.gateway.StatFile(ctx, &gatewayapi.StatFileRequest{Ref: in.Ref, Path: "."}, opts...)
return &gatewayapi.EvaluateResponse{}, err
}
ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
return g.gateway.Evaluate(ctx, in, opts...)
}

func (g *gatewayClientForBuild) Ping(ctx context.Context, in *gatewayapi.PingRequest, opts ...grpc.CallOption) (*gatewayapi.PongResponse, error) {
ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
return g.gateway.Ping(ctx, in, opts...)
Expand Down
8 changes: 8 additions & 0 deletions control/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ func (gwf *GatewayForwarder) ReadFile(ctx context.Context, req *gwapi.ReadFileRe
return fwd.ReadFile(ctx, req)
}

func (gwf *GatewayForwarder) Evaluate(ctx context.Context, req *gwapi.EvaluateRequest) (*gwapi.EvaluateResponse, error) {
fwd, err := gwf.lookupForwarder(ctx)
if err != nil {
return nil, errors.Wrap(err, "forwarding Evaluate")
}
return fwd.Evaluate(ctx, req)
}

func (gwf *GatewayForwarder) Ping(ctx context.Context, req *gwapi.PingRequest) (*gwapi.PongResponse, error) {
fwd, err := gwf.lookupForwarder(ctx)
if err != nil {
Expand Down
50 changes: 50 additions & 0 deletions frontend/frontend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func TestFrontendIntegration(t *testing.T) {
testRefReadFile,
testRefReadDir,
testRefStatFile,
testRefEvaluate,
testReturnNil,
))
}
Expand Down Expand Up @@ -291,6 +292,55 @@ func testRefStatFile(t *testing.T, sb integration.Sandbox) {
require.NoError(t, err)
}

func testRefEvaluate(t *testing.T, sb integration.Sandbox) {
ctx := sb.Context()

c, err := client.New(ctx, sb.Address())
require.NoError(t, err)
defer c.Close()

frontend := func(ctx context.Context, c gateway.Client) (*gateway.Result, error) {
st := llb.Scratch().File(llb.Mkfile("/test", 0666, []byte{}))
def, err := st.Marshal(ctx)
if err != nil {
return nil, err
}
res, err := c.Solve(ctx, gateway.SolveRequest{
Definition: def.ToPB(),
})
if err != nil {
return nil, err
}
ref, err := res.SingleRef()
if err != nil {
return nil, err
}

st = llb.Scratch().File(llb.Mkfile("/test/dir-does-not-exist", 0666, []byte{}))
def, err = st.Marshal(ctx)
if err != nil {
return nil, err
}
res, err = c.Solve(ctx, gateway.SolveRequest{
Definition: def.ToPB(),
})
if err != nil {
return nil, err
}
ref2, err := res.SingleRef()
if err != nil {
return nil, err
}

require.NoError(t, ref.Evaluate(ctx))
require.Error(t, ref2.Evaluate(ctx))
return gateway.NewResult(), nil
}

_, err = c.Build(ctx, client.SolveOpt{}, "", frontend, nil)
require.NoError(t, err)
}

func tmpdir(t *testing.T, appliers ...fstest.Applier) (string, error) {
tmpdir := t.TempDir()
if err := fstest.Apply(appliers...).Apply(tmpdir); err != nil {
Expand Down
1 change: 1 addition & 0 deletions frontend/gateway/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ type ContainerProcess interface {

type Reference interface {
ToState() (llb.State, error)
Evaluate(ctx context.Context) error
ReadFile(ctx context.Context, req ReadRequest) ([]byte, error)
StatFile(ctx context.Context, req StatRequest) (*fstypes.Stat, error)
ReadDir(ctx context.Context, req ReadDirRequest) ([]*fstypes.Stat, error)
Expand Down
8 changes: 8 additions & 0 deletions frontend/gateway/forwarder/forward.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,14 @@ func (r *ref) ToState() (st llb.State, err error) {
return llb.NewState(defop), nil
}

func (r *ref) Evaluate(ctx context.Context) error {
_, err := r.resultProxy.Result(ctx)
if err != nil {
return r.c.wrapSolveError(err)
}
return nil
}

func (r *ref) ReadFile(ctx context.Context, req client.ReadRequest) ([]byte, error) {
m, err := r.getMountable(ctx)
if err != nil {
Expand Down
22 changes: 16 additions & 6 deletions frontend/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -754,15 +754,15 @@ func (lbf *llbBridgeForwarder) Solve(ctx context.Context, req *pb.SolveRequest)
return resp, nil
}

func (lbf *llbBridgeForwarder) getImmutableRef(ctx context.Context, id, path string) (cache.ImmutableRef, error) {
func (lbf *llbBridgeForwarder) getImmutableRef(ctx context.Context, id string) (cache.ImmutableRef, error) {
lbf.mu.Lock()
ref, ok := lbf.refs[id]
lbf.mu.Unlock()
if !ok {
return nil, errors.Errorf("no such ref: %v", id)
return nil, errors.Errorf("no such ref: %s", id)
}
if ref == nil {
return nil, errors.Wrap(os.ErrNotExist, path)
return nil, errors.Errorf("empty ref: %s", id)
}

r, err := ref.Result(ctx)
Expand All @@ -781,7 +781,7 @@ func (lbf *llbBridgeForwarder) getImmutableRef(ctx context.Context, id, path str
func (lbf *llbBridgeForwarder) ReadFile(ctx context.Context, req *pb.ReadFileRequest) (*pb.ReadFileResponse, error) {
ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)

ref, err := lbf.getImmutableRef(ctx, req.Ref, req.FilePath)
ref, err := lbf.getImmutableRef(ctx, req.Ref)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -812,7 +812,7 @@ func (lbf *llbBridgeForwarder) ReadFile(ctx context.Context, req *pb.ReadFileReq
func (lbf *llbBridgeForwarder) ReadDir(ctx context.Context, req *pb.ReadDirRequest) (*pb.ReadDirResponse, error) {
ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)

ref, err := lbf.getImmutableRef(ctx, req.Ref, req.DirPath)
ref, err := lbf.getImmutableRef(ctx, req.Ref)
if err != nil {
return nil, err
}
Expand All @@ -836,7 +836,7 @@ func (lbf *llbBridgeForwarder) ReadDir(ctx context.Context, req *pb.ReadDirReque
func (lbf *llbBridgeForwarder) StatFile(ctx context.Context, req *pb.StatFileRequest) (*pb.StatFileResponse, error) {
ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)

ref, err := lbf.getImmutableRef(ctx, req.Ref, req.Path)
ref, err := lbf.getImmutableRef(ctx, req.Ref)
if err != nil {
return nil, err
}
Expand All @@ -852,6 +852,16 @@ func (lbf *llbBridgeForwarder) StatFile(ctx context.Context, req *pb.StatFileReq
return &pb.StatFileResponse{Stat: st}, nil
}

func (lbf *llbBridgeForwarder) Evaluate(ctx context.Context, req *pb.EvaluateRequest) (*pb.EvaluateResponse, error) {
ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)

_, err := lbf.getImmutableRef(ctx, req.Ref)
if err != nil {
return nil, err
}
return &pb.EvaluateResponse{}, nil
}

func (lbf *llbBridgeForwarder) Ping(context.Context, *pb.PingRequest) (*pb.PongResponse, error) {
workers := lbf.workers.WorkerInfos()
pbWorkers := make([]*apitypes.WorkerRecord, 0, len(workers))
Expand Down
34 changes: 14 additions & 20 deletions frontend/gateway/grpcclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,30 +387,15 @@ func (c *grpcClient) Solve(ctx context.Context, creq client.SolveRequest) (res *
if c.caps.Supports(pb.CapGatewayEvaluateSolve) == nil {
req.Evaluate = creq.Evaluate
} else {
// If evaluate is not supported, fallback to running Stat(".") in order to
// trigger an evaluation of the result.
// If evaluate is not supported, fallback to running Stat(".") in
// order to trigger an evaluation of the result.
defer func() {
if res == nil {
return
}

var (
id string
ref client.Reference
)
ref, err = res.SingleRef()
if err != nil {
for refID := range res.Refs {
id = refID
break
}
} else {
id = ref.(*reference).id
}

_, err = c.client.StatFile(ctx, &pb.StatFileRequest{
Ref: id,
Path: ".",
err = res.EachRef(func(ref client.Reference) error {
_, err := ref.StatFile(ctx, client.StatRequest{Path: "."})
return err
})
}()
}
Expand Down Expand Up @@ -1054,6 +1039,15 @@ func (r *reference) ToState() (st llb.State, err error) {
return llb.NewState(defop), nil
}

func (r *reference) Evaluate(ctx context.Context) error {
req := &pb.EvaluateRequest{Ref: r.id}
_, err := r.c.client.Evaluate(ctx, req)
if err != nil {
return err
}
return nil
}

func (r *reference) ReadFile(ctx context.Context, req client.ReadRequest) ([]byte, error) {
rfr := &pb.ReadFileRequest{FilePath: req.Filename, Ref: r.id}
if r := req.Range; r != nil {
Expand Down
9 changes: 9 additions & 0 deletions frontend/gateway/pb/caps.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ const (
// errors.
CapGatewayEvaluateSolve apicaps.CapID = "gateway.solve.evaluate"

CapGatewayEvaluate apicaps.CapID = "gateway.evaluate"

// CapGatewayWarnings is the capability to log warnings from frontend
CapGatewayWarnings apicaps.CapID = "gateway.warnings"

Expand Down Expand Up @@ -198,6 +200,13 @@ func init() {
Status: apicaps.CapStatusExperimental,
})

Caps.Init(apicaps.Cap{
ID: CapGatewayEvaluate,
Name: "gateway evaluate",
Enabled: true,
Status: apicaps.CapStatusExperimental,
})

Caps.Init(apicaps.Cap{
ID: CapGatewayWarnings,
Name: "logging warnings",
Expand Down
Loading