You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
186 lines
4.6 KiB
Go
186 lines
4.6 KiB
Go
package builderutil
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/docker/buildx/driver"
|
|
k8sconfig "github.com/docker/buildx/driver/kubernetes/config"
|
|
"github.com/docker/buildx/store"
|
|
"github.com/docker/buildx/store/storeutil"
|
|
"github.com/docker/buildx/util/imagetools"
|
|
"github.com/docker/buildx/util/platformutil"
|
|
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
"golang.org/x/sync/errgroup"
|
|
)
|
|
|
|
type Driver struct {
|
|
Name string
|
|
Driver driver.Driver
|
|
Info *driver.Info
|
|
Platforms []ocispecs.Platform
|
|
ImageOpt imagetools.Opt
|
|
Err error
|
|
}
|
|
|
|
// LoadDrivers loads drivers.
|
|
func (b *Builder) LoadDrivers(ctx context.Context, withData bool, contextPathHash string) error {
|
|
eg, _ := errgroup.WithContext(ctx)
|
|
b.Drivers = make([]Driver, len(b.NodeGroup.Nodes))
|
|
|
|
var f driver.Factory
|
|
if b.NodeGroup.Driver != "" {
|
|
f = driver.GetFactory(b.NodeGroup.Driver, true)
|
|
if f == nil {
|
|
return errors.Errorf("failed to find driver %q", f)
|
|
}
|
|
} else {
|
|
dockerapi, err := storeutil.ClientForEndpoint(b.dockerCli, b.NodeGroup.Nodes[0].Endpoint)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
f, err = driver.GetDefaultFactory(ctx, dockerapi, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
b.NodeGroup.Driver = f.Name()
|
|
}
|
|
|
|
imageopt, err := b.GetImageOpt()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for i, n := range b.NodeGroup.Nodes {
|
|
func(i int, n store.Node) {
|
|
eg.Go(func() error {
|
|
di := Driver{
|
|
Name: n.Name,
|
|
Platforms: n.Platforms,
|
|
}
|
|
defer func() {
|
|
b.Drivers[i] = di
|
|
}()
|
|
|
|
dockerapi, err := storeutil.ClientForEndpoint(b.dockerCli, n.Endpoint)
|
|
if err != nil {
|
|
di.Err = err
|
|
return nil
|
|
}
|
|
|
|
contextStore := b.dockerCli.ContextStore()
|
|
|
|
var kcc driver.KubeClientConfig
|
|
kcc, err = k8sconfig.FromContext(n.Endpoint, contextStore)
|
|
if err != nil {
|
|
// err is returned if n.Endpoint is non-context name like "unix:///var/run/docker.sock".
|
|
// try again with name="default".
|
|
// FIXME(@AkihiroSuda): n should retain real context name.
|
|
kcc, err = k8sconfig.FromContext("default", contextStore)
|
|
if err != nil {
|
|
logrus.Error(err)
|
|
}
|
|
}
|
|
|
|
tryToUseKubeConfigInCluster := false
|
|
if kcc == nil {
|
|
tryToUseKubeConfigInCluster = true
|
|
} else {
|
|
if _, err := kcc.ClientConfig(); err != nil {
|
|
tryToUseKubeConfigInCluster = true
|
|
}
|
|
}
|
|
if tryToUseKubeConfigInCluster {
|
|
kccInCluster := driver.KubeClientConfigInCluster{}
|
|
if _, err := kccInCluster.ClientConfig(); err == nil {
|
|
logrus.Debug("using kube config in cluster")
|
|
kcc = kccInCluster
|
|
}
|
|
}
|
|
|
|
d, err := driver.GetDriver(ctx, "buildx_buildkit_"+n.Name, f, dockerapi, imageopt.Auth, kcc, n.Flags, n.Files, n.DriverOpts, n.Platforms, contextPathHash)
|
|
if err != nil {
|
|
di.Err = err
|
|
return nil
|
|
}
|
|
di.Driver = d
|
|
di.ImageOpt = imageopt
|
|
|
|
if withData {
|
|
if err := di.loadData(ctx); err != nil {
|
|
di.Err = err
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}(i, n)
|
|
}
|
|
if err := eg.Wait(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if withData {
|
|
kubernetesDriverCount := 0
|
|
for _, d := range b.Drivers {
|
|
if d.Info != nil && len(d.Info.DynamicNodes) > 0 {
|
|
kubernetesDriverCount++
|
|
}
|
|
}
|
|
|
|
isAllKubernetesDrivers := len(b.Drivers) == kubernetesDriverCount
|
|
if isAllKubernetesDrivers {
|
|
var drivers []Driver
|
|
var dynamicNodes []store.Node
|
|
for _, di := range b.Drivers {
|
|
// dynamic nodes are used in Kubernetes driver.
|
|
// Kubernetes pods are dynamically mapped to BuildKit Nodes.
|
|
if di.Info != nil && len(di.Info.DynamicNodes) > 0 {
|
|
for i := 0; i < len(di.Info.DynamicNodes); i++ {
|
|
// all []dinfo share *build.DriverInfo and *driver.Info
|
|
diClone := di
|
|
if pl := di.Info.DynamicNodes[i].Platforms; len(pl) > 0 {
|
|
diClone.Platforms = pl
|
|
}
|
|
drivers = append(drivers, di)
|
|
}
|
|
dynamicNodes = append(dynamicNodes, di.Info.DynamicNodes...)
|
|
}
|
|
}
|
|
|
|
// not append (remove the static nodes in the store)
|
|
b.NodeGroup.Nodes = dynamicNodes
|
|
b.Drivers = drivers
|
|
b.NodeGroup.Dynamic = true
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (d *Driver) loadData(ctx context.Context) error {
|
|
if d.Driver == nil {
|
|
return nil
|
|
}
|
|
info, err := d.Driver.Info(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d.Info = info
|
|
if d.Info.Status == driver.Running {
|
|
cdriver, err := d.Driver.Client(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
workers, err := cdriver.ListWorkers(ctx)
|
|
if err != nil {
|
|
return errors.Wrap(err, "listing workers")
|
|
}
|
|
for _, w := range workers {
|
|
d.Platforms = append(d.Platforms, w.Platforms...)
|
|
}
|
|
d.Platforms = platformutil.Dedupe(d.Platforms)
|
|
}
|
|
return nil
|
|
}
|