Merge 08b6d36deb
into 287aaf1696
commit
6f1e0b73fd
@ -0,0 +1,230 @@
|
|||||||
|
package build
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
_ "crypto/sha256" // ensure digests can be computed
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/platforms"
|
||||||
|
"github.com/docker/buildx/builder"
|
||||||
|
"github.com/docker/buildx/options"
|
||||||
|
|
||||||
|
"github.com/docker/buildx/driver"
|
||||||
|
"github.com/docker/buildx/util/progress"
|
||||||
|
"github.com/moby/buildkit/client"
|
||||||
|
gateway "github.com/moby/buildkit/frontend/gateway/client"
|
||||||
|
"github.com/moby/buildkit/util/tracing"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
type driverPair struct {
|
||||||
|
driverIndex int
|
||||||
|
platforms []specs.Platform
|
||||||
|
so *client.SolveOpt
|
||||||
|
bopts gateway.BuildOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
func driverIndexes(m map[string][]driverPair) []int {
|
||||||
|
out := make([]int, 0, len(m))
|
||||||
|
visited := map[int]struct{}{}
|
||||||
|
for _, dp := range m {
|
||||||
|
for _, d := range dp {
|
||||||
|
if _, ok := visited[d.driverIndex]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
visited[d.driverIndex] = struct{}{}
|
||||||
|
out = append(out, d.driverIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func allIndexes(l int) []int {
|
||||||
|
out := make([]int, 0, l)
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
out = append(out, i)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureBooted(ctx context.Context, nodes []builder.Node, idxs []int, pw progress.Writer) ([]*client.Client, error) {
|
||||||
|
clients := make([]*client.Client, len(nodes))
|
||||||
|
|
||||||
|
baseCtx := ctx
|
||||||
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
|
|
||||||
|
for _, i := range idxs {
|
||||||
|
func(i int) {
|
||||||
|
eg.Go(func() error {
|
||||||
|
c, err := driver.Boot(ctx, baseCtx, nodes[i].Driver, pw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
clients[i] = c
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := eg.Wait(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return clients, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitToDriverPairs(availablePlatforms map[string]int, opt map[string]options.Options) map[string][]driverPair {
|
||||||
|
m := map[string][]driverPair{}
|
||||||
|
for k, opt := range opt {
|
||||||
|
mm := map[int][]specs.Platform{}
|
||||||
|
for _, p := range opt.Platforms {
|
||||||
|
k := platforms.Format(p)
|
||||||
|
idx := availablePlatforms[k] // default 0
|
||||||
|
pp := mm[idx]
|
||||||
|
pp = append(pp, p)
|
||||||
|
mm[idx] = pp
|
||||||
|
}
|
||||||
|
// if no platform is specified, use first driver
|
||||||
|
if len(mm) == 0 {
|
||||||
|
mm[0] = nil
|
||||||
|
}
|
||||||
|
dps := make([]driverPair, 0, 2)
|
||||||
|
for idx, pp := range mm {
|
||||||
|
dps = append(dps, driverPair{driverIndex: idx, platforms: pp})
|
||||||
|
}
|
||||||
|
m[k] = dps
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveDrivers(ctx context.Context, nodes []builder.Node, opt map[string]options.Options, pw progress.Writer) (map[string][]driverPair, []*client.Client, error) {
|
||||||
|
dps, clients, err := resolveDriversBase(ctx, nodes, opt, pw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bopts := make([]gateway.BuildOpts, len(clients))
|
||||||
|
|
||||||
|
span, ctx := tracing.StartSpan(ctx, "load buildkit capabilities", trace.WithSpanKind(trace.SpanKindInternal))
|
||||||
|
|
||||||
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
|
for i, c := range clients {
|
||||||
|
if c == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
func(i int, c *client.Client) {
|
||||||
|
eg.Go(func() error {
|
||||||
|
clients[i].Build(ctx, client.SolveOpt{}, "buildx", func(ctx context.Context, c gateway.Client) (*gateway.Result, error) {
|
||||||
|
bopts[i] = c.BuildOpts()
|
||||||
|
return nil, nil
|
||||||
|
}, nil)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}(i, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = eg.Wait()
|
||||||
|
tracing.FinishWithError(span, err)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
for key := range dps {
|
||||||
|
for i, dp := range dps[key] {
|
||||||
|
dps[key][i].bopts = bopts[dp.driverIndex]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dps, clients, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveDriversBase(ctx context.Context, nodes []builder.Node, opt map[string]options.Options, pw progress.Writer) (map[string][]driverPair, []*client.Client, error) {
|
||||||
|
availablePlatforms := map[string]int{}
|
||||||
|
for i, node := range nodes {
|
||||||
|
for _, p := range node.Platforms {
|
||||||
|
availablePlatforms[platforms.Format(p)] = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
undetectedPlatform := false
|
||||||
|
allPlatforms := map[string]int{}
|
||||||
|
for _, opt := range opt {
|
||||||
|
for _, p := range opt.Platforms {
|
||||||
|
k := platforms.Format(p)
|
||||||
|
allPlatforms[k] = -1
|
||||||
|
if _, ok := availablePlatforms[k]; !ok {
|
||||||
|
undetectedPlatform = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fast path
|
||||||
|
if len(nodes) == 1 || len(allPlatforms) == 0 {
|
||||||
|
m := map[string][]driverPair{}
|
||||||
|
for k, opt := range opt {
|
||||||
|
m[k] = []driverPair{{driverIndex: 0, platforms: opt.Platforms}}
|
||||||
|
}
|
||||||
|
clients, err := ensureBooted(ctx, nodes, driverIndexes(m), pw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return m, clients, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// map based on existing platforms
|
||||||
|
if !undetectedPlatform {
|
||||||
|
m := splitToDriverPairs(availablePlatforms, opt)
|
||||||
|
clients, err := ensureBooted(ctx, nodes, driverIndexes(m), pw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return m, clients, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// boot all drivers in k
|
||||||
|
clients, err := ensureBooted(ctx, nodes, allIndexes(len(nodes)), pw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
|
workers := make([][]*client.WorkerInfo, len(clients))
|
||||||
|
|
||||||
|
for i, c := range clients {
|
||||||
|
if c == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
func(i int) {
|
||||||
|
eg.Go(func() error {
|
||||||
|
ww, err := clients[i].ListWorkers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "listing workers")
|
||||||
|
}
|
||||||
|
workers[i] = ww
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := eg.Wait(); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, ww := range workers {
|
||||||
|
for _, w := range ww {
|
||||||
|
for _, p := range w.Platforms {
|
||||||
|
p = platforms.Normalize(p)
|
||||||
|
ps := platforms.Format(p)
|
||||||
|
|
||||||
|
if _, ok := availablePlatforms[ps]; !ok {
|
||||||
|
availablePlatforms[ps] = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return splitToDriverPairs(availablePlatforms, opt), clients, nil
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "crypto/sha256" // ensure digests can be computed
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/docker/cli/opts"
|
||||||
|
"github.com/moby/buildkit/client"
|
||||||
|
"github.com/moby/buildkit/client/llb"
|
||||||
|
"github.com/moby/buildkit/session"
|
||||||
|
"github.com/moby/buildkit/util/entitlements"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
Inputs Inputs
|
||||||
|
|
||||||
|
Allow []entitlements.Entitlement
|
||||||
|
Attests map[string]*string
|
||||||
|
BuildArgs map[string]string
|
||||||
|
CacheFrom []client.CacheOptionsEntry
|
||||||
|
CacheTo []client.CacheOptionsEntry
|
||||||
|
CgroupParent string
|
||||||
|
Exports []client.ExportEntry
|
||||||
|
ExtraHosts []string
|
||||||
|
ImageIDFile string
|
||||||
|
Labels map[string]string
|
||||||
|
NetworkMode string
|
||||||
|
NoCache bool
|
||||||
|
NoCacheFilter []string
|
||||||
|
Platforms []specs.Platform
|
||||||
|
Pull bool
|
||||||
|
Session []session.Attachable
|
||||||
|
ShmSize opts.MemBytes
|
||||||
|
Tags []string
|
||||||
|
Target string
|
||||||
|
Ulimits *opts.UlimitOpt
|
||||||
|
|
||||||
|
// Linked marks this target as exclusively linked (not requested by the user).
|
||||||
|
Linked bool
|
||||||
|
PrintFunc *PrintFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrintFunc struct {
|
||||||
|
Name string
|
||||||
|
Format string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Inputs struct {
|
||||||
|
ContextPath string
|
||||||
|
DockerfilePath string
|
||||||
|
InStream io.Reader
|
||||||
|
ContextState *llb.State
|
||||||
|
DockerfileInline string
|
||||||
|
NamedContexts map[string]NamedContext
|
||||||
|
}
|
||||||
|
|
||||||
|
type NamedContext struct {
|
||||||
|
Path string
|
||||||
|
State *llb.State
|
||||||
|
}
|
Loading…
Reference in New Issue