refactor: mutualize builder logic
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>pull/865/head
parent
a3a4e48f25
commit
9d37e466a0
@ -1,353 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/buildx/build"
|
||||
"github.com/docker/buildx/driver"
|
||||
"github.com/docker/buildx/store"
|
||||
"github.com/docker/buildx/store/storeutil"
|
||||
"github.com/docker/buildx/util/platformutil"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/context/kubernetes"
|
||||
ctxstore "github.com/docker/cli/cli/context/store"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
// driversForNodeGroup returns drivers for a nodegroup instance
|
||||
func driversForNodeGroup(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, contextPathHash string) ([]build.DriverInfo, error) {
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
|
||||
dis := make([]build.DriverInfo, len(ng.Nodes))
|
||||
|
||||
var f driver.Factory
|
||||
if ng.Driver != "" {
|
||||
f = driver.GetFactory(ng.Driver, true)
|
||||
if f == nil {
|
||||
return nil, errors.Errorf("failed to find driver %q", f)
|
||||
}
|
||||
} else {
|
||||
dockerapi, err := storeutil.ClientForEndpoint(dockerCli, ng.Nodes[0].Endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err = driver.GetDefaultFactory(ctx, dockerapi, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ng.Driver = f.Name()
|
||||
}
|
||||
imageopt, err := storeutil.GetImageConfig(dockerCli, ng)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i, n := range ng.Nodes {
|
||||
func(i int, n store.Node) {
|
||||
eg.Go(func() error {
|
||||
di := build.DriverInfo{
|
||||
Name: n.Name,
|
||||
Platform: n.Platforms,
|
||||
}
|
||||
defer func() {
|
||||
dis[i] = di
|
||||
}()
|
||||
|
||||
dockerapi, err := storeutil.ClientForEndpoint(dockerCli, n.Endpoint)
|
||||
if err != nil {
|
||||
di.Err = err
|
||||
return nil
|
||||
}
|
||||
|
||||
contextStore := dockerCli.ContextStore()
|
||||
|
||||
var kcc driver.KubeClientConfig
|
||||
kcc, err = configFromContext(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: n should retain real context name.
|
||||
kcc, err = configFromContext("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
|
||||
return nil
|
||||
})
|
||||
}(i, n)
|
||||
}
|
||||
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dis, nil
|
||||
}
|
||||
|
||||
func configFromContext(endpointName string, s ctxstore.Reader) (clientcmd.ClientConfig, error) {
|
||||
if strings.HasPrefix(endpointName, "kubernetes://") {
|
||||
u, _ := url.Parse(endpointName)
|
||||
if kubeconfig := u.Query().Get("kubeconfig"); kubeconfig != "" {
|
||||
_ = os.Setenv(clientcmd.RecommendedConfigPathEnvVar, kubeconfig)
|
||||
}
|
||||
rules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
apiConfig, err := rules.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return clientcmd.NewDefaultClientConfig(*apiConfig, &clientcmd.ConfigOverrides{}), nil
|
||||
}
|
||||
return kubernetes.ConfigFromContext(endpointName, s)
|
||||
}
|
||||
|
||||
func getInstanceOrDefault(ctx context.Context, dockerCli command.Cli, instance, contextPathHash string) ([]build.DriverInfo, error) {
|
||||
var defaultOnly bool
|
||||
|
||||
if instance == "default" && instance != dockerCli.CurrentContext() {
|
||||
return nil, errors.Errorf("use `docker --context=default buildx` to switch to default context")
|
||||
}
|
||||
if instance == "default" || instance == dockerCli.CurrentContext() {
|
||||
instance = ""
|
||||
defaultOnly = true
|
||||
}
|
||||
list, err := dockerCli.ContextStore().List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, l := range list {
|
||||
if l.Name == instance {
|
||||
return nil, errors.Errorf("use `docker --context=%s buildx` to switch to context %s", instance, instance)
|
||||
}
|
||||
}
|
||||
|
||||
if instance != "" {
|
||||
return getInstanceByName(ctx, dockerCli, instance, contextPathHash)
|
||||
}
|
||||
return getDefaultDrivers(ctx, dockerCli, defaultOnly, contextPathHash)
|
||||
}
|
||||
|
||||
func getInstanceByName(ctx context.Context, dockerCli command.Cli, instance, contextPathHash string) ([]build.DriverInfo, error) {
|
||||
txn, release, err := storeutil.GetStore(dockerCli)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer release()
|
||||
|
||||
ng, err := txn.NodeGroupByName(instance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return driversForNodeGroup(ctx, dockerCli, ng, contextPathHash)
|
||||
}
|
||||
|
||||
// getDefaultDrivers returns drivers based on current cli config
|
||||
func getDefaultDrivers(ctx context.Context, dockerCli command.Cli, defaultOnly bool, contextPathHash string) ([]build.DriverInfo, error) {
|
||||
txn, release, err := storeutil.GetStore(dockerCli)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer release()
|
||||
|
||||
if !defaultOnly {
|
||||
ng, err := storeutil.GetCurrentInstance(txn, dockerCli)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ng != nil {
|
||||
return driversForNodeGroup(ctx, dockerCli, ng, contextPathHash)
|
||||
}
|
||||
}
|
||||
|
||||
imageopt, err := storeutil.GetImageConfig(dockerCli, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d, err := driver.GetDriver(ctx, "buildx_buildkit_default", nil, dockerCli.Client(), imageopt.Auth, nil, nil, nil, nil, nil, contextPathHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []build.DriverInfo{
|
||||
{
|
||||
Name: "default",
|
||||
Driver: d,
|
||||
ImageOpt: imageopt,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func loadInfoData(ctx context.Context, d *dinfo) error {
|
||||
if d.di.Driver == nil {
|
||||
return nil
|
||||
}
|
||||
info, err := d.di.Driver.Info(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.info = info
|
||||
if info.Status == driver.Running {
|
||||
c, err := d.di.Driver.Client(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
workers, err := c.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
|
||||
}
|
||||
|
||||
func loadNodeGroupData(ctx context.Context, dockerCli command.Cli, ngi *nginfo) error {
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
|
||||
dis, err := driversForNodeGroup(ctx, dockerCli, ngi.ng, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ngi.drivers = make([]dinfo, len(dis))
|
||||
for i, di := range dis {
|
||||
d := di
|
||||
ngi.drivers[i].di = &d
|
||||
func(d *dinfo) {
|
||||
eg.Go(func() error {
|
||||
if err := loadInfoData(ctx, d); err != nil {
|
||||
d.err = err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}(&ngi.drivers[i])
|
||||
}
|
||||
|
||||
if eg.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kubernetesDriverCount := 0
|
||||
|
||||
for _, di := range ngi.drivers {
|
||||
if di.info != nil && len(di.info.DynamicNodes) > 0 {
|
||||
kubernetesDriverCount++
|
||||
}
|
||||
}
|
||||
|
||||
isAllKubernetesDrivers := len(ngi.drivers) == kubernetesDriverCount
|
||||
|
||||
if isAllKubernetesDrivers {
|
||||
var drivers []dinfo
|
||||
var dynamicNodes []store.Node
|
||||
|
||||
for _, di := range ngi.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)
|
||||
ngi.ng.Nodes = dynamicNodes
|
||||
ngi.drivers = drivers
|
||||
ngi.ng.Dynamic = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type dinfo struct {
|
||||
di *build.DriverInfo
|
||||
info *driver.Info
|
||||
platforms []specs.Platform
|
||||
err error
|
||||
}
|
||||
|
||||
type nginfo struct {
|
||||
ng *store.NodeGroup
|
||||
drivers []dinfo
|
||||
err error
|
||||
}
|
||||
|
||||
func boot(ctx context.Context, ngi *nginfo) (bool, error) {
|
||||
toBoot := make([]int, 0, len(ngi.drivers))
|
||||
for i, d := range ngi.drivers {
|
||||
if d.err != nil || d.di.Err != nil || d.di.Driver == nil || d.info == nil {
|
||||
continue
|
||||
}
|
||||
if d.info.Status != driver.Running {
|
||||
toBoot = append(toBoot, i)
|
||||
}
|
||||
}
|
||||
if len(toBoot) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
printer := progress.NewPrinter(context.TODO(), os.Stderr, "auto")
|
||||
|
||||
baseCtx := ctx
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
for _, idx := range toBoot {
|
||||
func(idx int) {
|
||||
eg.Go(func() error {
|
||||
pw := progress.WithPrefix(printer, ngi.ng.Nodes[idx].Name, len(toBoot) > 1)
|
||||
_, err := driver.Boot(ctx, baseCtx, ngi.drivers[idx].di.Driver, pw)
|
||||
if err != nil {
|
||||
ngi.drivers[idx].err = err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}(idx)
|
||||
}
|
||||
|
||||
err := eg.Wait()
|
||||
err1 := printer.Wait()
|
||||
if err == nil {
|
||||
err = err1
|
||||
}
|
||||
|
||||
return true, err
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
cxtkubernetes "github.com/docker/cli/cli/context/kubernetes"
|
||||
ctxstore "github.com/docker/cli/cli/context/store"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
// FromContext loads k8s config from context
|
||||
func FromContext(endpointName string, s ctxstore.Reader) (clientcmd.ClientConfig, error) {
|
||||
if strings.HasPrefix(endpointName, "kubernetes://") {
|
||||
u, _ := url.Parse(endpointName)
|
||||
if kubeconfig := u.Query().Get("kubeconfig"); kubeconfig != "" {
|
||||
_ = os.Setenv(clientcmd.RecommendedConfigPathEnvVar, kubeconfig)
|
||||
}
|
||||
rules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
apiConfig, err := rules.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return clientcmd.NewDefaultClientConfig(*apiConfig, &clientcmd.ConfigOverrides{}), nil
|
||||
}
|
||||
return cxtkubernetes.ConfigFromContext(endpointName, s)
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
package builderutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/docker/buildx/driver"
|
||||
"github.com/docker/buildx/store"
|
||||
"github.com/docker/buildx/store/storeutil"
|
||||
"github.com/docker/buildx/util/imagetools"
|
||||
"github.com/docker/buildx/util/progress"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// Builder represents an active builder object
|
||||
type Builder struct {
|
||||
dockerCli command.Cli
|
||||
txn *store.Txn
|
||||
|
||||
NodeGroup *store.NodeGroup
|
||||
Drivers []Driver
|
||||
Err error
|
||||
}
|
||||
|
||||
// New initializes a new builder client
|
||||
func New(dockerCli command.Cli, txn *store.Txn, name string) (_ *Builder, err error) {
|
||||
b := &Builder{
|
||||
dockerCli: dockerCli,
|
||||
txn: txn,
|
||||
}
|
||||
|
||||
if name != "" {
|
||||
b.NodeGroup, err = storeutil.GetNodeGroup(txn, dockerCli, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
b.NodeGroup, err = storeutil.GetCurrentInstance(txn, dockerCli)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Validate validates builder context
|
||||
func (b *Builder) Validate() error {
|
||||
if b.NodeGroup.Name == "default" && b.NodeGroup.Name != b.dockerCli.CurrentContext() {
|
||||
return errors.Errorf("use `docker --context=default buildx` to switch to default context")
|
||||
}
|
||||
list, err := b.dockerCli.ContextStore().List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, l := range list {
|
||||
if l.Name == b.NodeGroup.Name && b.NodeGroup.Name != "default" {
|
||||
return errors.Errorf("use `docker --context=%s buildx` to switch to context %q", b.NodeGroup.Name, b.NodeGroup.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetImageOpt returns registry auth configuration
|
||||
func (b *Builder) GetImageOpt() (imagetools.Opt, error) {
|
||||
return storeutil.GetImageConfig(b.dockerCli, b.NodeGroup)
|
||||
}
|
||||
|
||||
// Boot bootstrap a builder
|
||||
func (b *Builder) Boot(ctx context.Context) (bool, error) {
|
||||
toBoot := make([]int, 0, len(b.Drivers))
|
||||
for idx, d := range b.Drivers {
|
||||
if d.Err != nil || d.Driver == nil || d.Info == nil {
|
||||
continue
|
||||
}
|
||||
if d.Info.Status != driver.Running {
|
||||
toBoot = append(toBoot, idx)
|
||||
}
|
||||
}
|
||||
if len(toBoot) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
printer := progress.NewPrinter(context.Background(), os.Stderr, progress.PrinterModeAuto)
|
||||
|
||||
baseCtx := ctx
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
for _, idx := range toBoot {
|
||||
func(idx int) {
|
||||
eg.Go(func() error {
|
||||
pw := progress.WithPrefix(printer, b.NodeGroup.Nodes[idx].Name, len(toBoot) > 1)
|
||||
_, err := driver.Boot(ctx, baseCtx, b.Drivers[idx].Driver, pw)
|
||||
if err != nil {
|
||||
b.Drivers[idx].Err = err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}(idx)
|
||||
}
|
||||
|
||||
err := eg.Wait()
|
||||
err1 := printer.Wait()
|
||||
if err == nil {
|
||||
err = err1
|
||||
}
|
||||
|
||||
return true, err
|
||||
}
|
||||
|
||||
// GetBuilders returns all builders
|
||||
func GetBuilders(dockerCli command.Cli, txn *store.Txn) ([]*Builder, error) {
|
||||
storeng, err := txn.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
currentName := "default"
|
||||
current, err := storeutil.GetCurrentInstance(txn, dockerCli)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if current != nil {
|
||||
currentName = current.Name
|
||||
if current.Name == "default" {
|
||||
currentName = current.Nodes[0].Endpoint
|
||||
}
|
||||
}
|
||||
|
||||
currentSet := false
|
||||
storeBuilders := make([]*Builder, len(storeng))
|
||||
for i, ng := range storeng {
|
||||
if !currentSet && ng.Name == currentName {
|
||||
ng.Current = true
|
||||
currentSet = true
|
||||
}
|
||||
storeBuilders[i] = &Builder{
|
||||
dockerCli: dockerCli,
|
||||
txn: txn,
|
||||
NodeGroup: ng,
|
||||
}
|
||||
}
|
||||
|
||||
list, err := dockerCli.ContextStore().List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctxBuilders := make([]*Builder, len(list))
|
||||
for i, l := range list {
|
||||
defaultNg := false
|
||||
if !currentSet && l.Name == currentName {
|
||||
defaultNg = true
|
||||
currentSet = true
|
||||
}
|
||||
ctxBuilders[i] = &Builder{
|
||||
dockerCli: dockerCli,
|
||||
txn: txn,
|
||||
NodeGroup: &store.NodeGroup{
|
||||
Name: l.Name,
|
||||
Current: defaultNg,
|
||||
Nodes: []store.Node{
|
||||
{
|
||||
Name: l.Name,
|
||||
Endpoint: l.Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return append(storeBuilders, ctxBuilders...), nil
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
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
|
||||
}
|
Loading…
Reference in New Issue