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.
buildx/util/builderutil/driver.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
}