debug: evaluate all refs to allow multi-platform debugging

Signed-off-by: Justin Chadwell <me@jedevc.com>
pull/1786/head
Justin Chadwell 2 years ago
parent 4a0a67d7a2
commit 45fccef3f3

@ -15,9 +15,11 @@ import (
gateway "github.com/moby/buildkit/frontend/gateway/client" gateway "github.com/moby/buildkit/frontend/gateway/client"
"github.com/moby/buildkit/solver/errdefs" "github.com/moby/buildkit/solver/errdefs"
"github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/solver/result"
specs "github.com/opencontainers/image-spec/specs-go/v1" specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
) )
func NewResultContext(ctx context.Context, c *client.Client, solveOpt client.SolveOpt, res *gateway.Result) (*ResultContext, error) { func NewResultContext(ctx context.Context, c *client.Client, solveOpt client.SolveOpt, res *gateway.Result) (*ResultContext, error) {
@ -28,11 +30,8 @@ func NewResultContext(ctx context.Context, c *client.Client, solveOpt client.Sol
return getResultAt(ctx, c, solveOpt, def, nil) return getResultAt(ctx, c, solveOpt, def, nil)
} }
func getDefinition(ctx context.Context, res *gateway.Result) (*pb.Definition, error) { func getDefinition(ctx context.Context, res *gateway.Result) (*result.Result[*pb.Definition], error) {
ref, err := res.SingleRef() return result.ConvertResult(res, func(ref gateway.Reference) (*pb.Definition, error) {
if err != nil {
return nil, err
}
st, err := ref.ToState() st, err := ref.ToState()
if err != nil { if err != nil {
return nil, err return nil, err
@ -42,9 +41,10 @@ func getDefinition(ctx context.Context, res *gateway.Result) (*pb.Definition, er
return nil, err return nil, err
} }
return def.ToPB(), nil return def.ToPB(), nil
})
} }
func getResultAt(ctx context.Context, c *client.Client, solveOpt client.SolveOpt, target *pb.Definition, statusChan chan *client.SolveStatus) (*ResultContext, error) { func getResultAt(ctx context.Context, c *client.Client, solveOpt client.SolveOpt, targets *result.Result[*pb.Definition], statusChan chan *client.SolveStatus) (*ResultContext, error) {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
@ -80,12 +80,29 @@ func getResultAt(ctx context.Context, c *client.Client, solveOpt client.SolveOpt
doneErr := errors.Errorf("done") doneErr := errors.Errorf("done")
ctx, cancel := context.WithCancelCause(ctx) ctx, cancel := context.WithCancelCause(ctx)
defer cancel(doneErr) defer cancel(doneErr)
resultCtx := ResultContext{}
res2, err := c.Solve(ctx, gateway.SolveRequest{ // force evaluation of all targets in parallel
results := make(map[*pb.Definition]*gateway.Result)
resultsMu := sync.Mutex{}
eg, egCtx := errgroup.WithContext(ctx)
targets.EachRef(func(def *pb.Definition) error {
eg.Go(func() error {
res2, err := c.Solve(egCtx, gateway.SolveRequest{
Evaluate: true, Evaluate: true,
Definition: target, Definition: def,
}) })
if err != nil { if err != nil {
return err
}
resultsMu.Lock()
results[def] = res2
resultsMu.Unlock()
return nil
})
return nil
})
resultCtx := ResultContext{}
if err := eg.Wait(); err != nil {
var se *errdefs.SolveError var se *errdefs.SolveError
if errors.As(err, &se) { if errors.As(err, &se) {
resultCtx.solveErr = se resultCtx.solveErr = se
@ -93,6 +110,13 @@ func getResultAt(ctx context.Context, c *client.Client, solveOpt client.SolveOpt
return nil, err return nil, err
} }
} }
res2, _ := result.ConvertResult(targets, func(def *pb.Definition) (gateway.Reference, error) {
if res, ok := results[def]; ok {
return res.Ref, nil
}
return nil, nil
})
// Record the client and ctx as well so that containers can be created from the SolveError. // Record the client and ctx as well so that containers can be created from the SolveError.
resultCtx.res = res2 resultCtx.res = res2
resultCtx.gwClient = c resultCtx.gwClient = c
@ -208,32 +232,25 @@ func (r *ResultContext) getProcessConfig(cfg *controllerapi.InvokeConfig, stdin
} }
func containerConfigFromResult(ctx context.Context, res *gateway.Result, c gateway.Client, cfg controllerapi.InvokeConfig) (*gateway.NewContainerRequest, error) { func containerConfigFromResult(ctx context.Context, res *gateway.Result, c gateway.Client, cfg controllerapi.InvokeConfig) (*gateway.NewContainerRequest, error) {
if res.Ref == nil {
return nil, errors.Errorf("no reference is registered")
}
if cfg.Initial { if cfg.Initial {
return nil, errors.Errorf("starting from the container from the initial state of the step is supported only on the failed steps") return nil, errors.Errorf("starting from the container from the initial state of the step is supported only on the failed steps")
} }
st, err := res.Ref.ToState()
if err != nil { ps, err := exptypes.ParsePlatforms(res.Metadata)
return nil, err
}
def, err := st.Marshal(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
imgRef, err := c.Solve(ctx, gateway.SolveRequest{ ref, ok := res.FindRef(ps.Platforms[0].ID)
Definition: def.ToPB(), if !ok {
}) return nil, errors.Errorf("no reference found")
if err != nil {
return nil, err
} }
return &gateway.NewContainerRequest{ return &gateway.NewContainerRequest{
Mounts: []gateway.Mount{ Mounts: []gateway.Mount{
{ {
Dest: "/", Dest: "/",
MountType: pb.MountType_BIND, MountType: pb.MountType_BIND,
Ref: imgRef.Ref, Ref: ref,
}, },
}, },
}, nil }, nil

Loading…
Cancel
Save