|
|
@ -2,6 +2,7 @@ package builder
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/docker/buildx/driver"
|
|
|
|
"github.com/docker/buildx/driver"
|
|
|
|
ctxkube "github.com/docker/buildx/driver/kubernetes/context"
|
|
|
|
ctxkube "github.com/docker/buildx/driver/kubernetes/context"
|
|
|
@ -29,16 +30,27 @@ type Node struct {
|
|
|
|
Err error
|
|
|
|
Err error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Nodes returns nodes for this builder.
|
|
|
|
type nodesFactory struct {
|
|
|
|
func (b *Builder) Nodes() []Node {
|
|
|
|
nodes []Node
|
|
|
|
return b.nodes
|
|
|
|
once sync.Once
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// LoadNodes loads and returns nodes for this builder.
|
|
|
|
// Nodes loads and returns nodes for this builder.
|
|
|
|
// TODO: this should be a method on a Node object and lazy load data for each driver.
|
|
|
|
func (b *Builder) Nodes(ctx context.Context) (_ []Node, err error) {
|
|
|
|
func (b *Builder) LoadNodes(ctx context.Context, withData bool) (_ []Node, err error) {
|
|
|
|
b.nodesFactory.once.Do(func() {
|
|
|
|
eg, _ := errgroup.WithContext(ctx)
|
|
|
|
err = b.loadNodes(ctx)
|
|
|
|
b.nodes = make([]Node, len(b.NodeGroup.Nodes))
|
|
|
|
})
|
|
|
|
|
|
|
|
return b.nodesFactory.nodes, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NodesWithData loads nodes with data for this builder.
|
|
|
|
|
|
|
|
func (b *Builder) NodesWithData(ctx context.Context) (_ []Node, err error) {
|
|
|
|
|
|
|
|
err = b.loadNodesWithData(ctx)
|
|
|
|
|
|
|
|
return b.nodesFactory.nodes, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (b *Builder) loadNodes(ctx context.Context) (err error) {
|
|
|
|
|
|
|
|
b.nodesFactory.nodes = make([]Node, len(b.NodeGroup.Nodes))
|
|
|
|
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
defer func() {
|
|
|
|
if b.err == nil && err != nil {
|
|
|
|
if b.err == nil && err != nil {
|
|
|
@ -48,14 +60,15 @@ func (b *Builder) LoadNodes(ctx context.Context, withData bool) (_ []Node, err e
|
|
|
|
|
|
|
|
|
|
|
|
factory, err := b.Factory(ctx)
|
|
|
|
factory, err := b.Factory(ctx)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
imageopt, err := b.ImageOpt()
|
|
|
|
imageopt, err := b.ImageOpt()
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eg, _ := errgroup.WithContext(ctx)
|
|
|
|
for i, n := range b.NodeGroup.Nodes {
|
|
|
|
for i, n := range b.NodeGroup.Nodes {
|
|
|
|
func(i int, n store.Node) {
|
|
|
|
func(i int, n store.Node) {
|
|
|
|
eg.Go(func() error {
|
|
|
|
eg.Go(func() error {
|
|
|
@ -64,7 +77,7 @@ func (b *Builder) LoadNodes(ctx context.Context, withData bool) (_ []Node, err e
|
|
|
|
ProxyConfig: storeutil.GetProxyConfig(b.opts.dockerCli),
|
|
|
|
ProxyConfig: storeutil.GetProxyConfig(b.opts.dockerCli),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
defer func() {
|
|
|
|
b.nodes[i] = node
|
|
|
|
b.nodesFactory.nodes[i] = node
|
|
|
|
}()
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
dockerapi, err := dockerutil.NewClientAPI(b.opts.dockerCli, n.Endpoint)
|
|
|
|
dockerapi, err := dockerutil.NewClientAPI(b.opts.dockerCli, n.Endpoint)
|
|
|
@ -108,59 +121,71 @@ func (b *Builder) LoadNodes(ctx context.Context, withData bool) (_ []Node, err e
|
|
|
|
node.Err = err
|
|
|
|
node.Err = err
|
|
|
|
return nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
node.Driver = d
|
|
|
|
node.Driver = d
|
|
|
|
node.ImageOpt = imageopt
|
|
|
|
node.ImageOpt = imageopt
|
|
|
|
|
|
|
|
|
|
|
|
if withData {
|
|
|
|
|
|
|
|
if err := node.loadData(ctx); err != nil {
|
|
|
|
|
|
|
|
node.Err = err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}(i, n)
|
|
|
|
}(i, n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := eg.Wait(); err != nil {
|
|
|
|
return eg.Wait()
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (b *Builder) loadNodesWithData(ctx context.Context) (err error) {
|
|
|
|
|
|
|
|
// ensure nodes are loaded
|
|
|
|
|
|
|
|
if _, err = b.Nodes(ctx); err != nil {
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: This should be done in the routine loading driver data
|
|
|
|
eg, _ := errgroup.WithContext(ctx)
|
|
|
|
if withData {
|
|
|
|
for idx := range b.nodesFactory.nodes {
|
|
|
|
kubernetesDriverCount := 0
|
|
|
|
func(idx int) {
|
|
|
|
for _, d := range b.nodes {
|
|
|
|
eg.Go(func() error {
|
|
|
|
if d.DriverInfo != nil && len(d.DriverInfo.DynamicNodes) > 0 {
|
|
|
|
if err = b.nodesFactory.nodes[idx].loadData(ctx); err != nil {
|
|
|
|
kubernetesDriverCount++
|
|
|
|
b.nodesFactory.nodes[idx].Err = err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}(idx)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = eg.Wait(); err != nil {
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
kubernetesDriverCount := 0
|
|
|
|
|
|
|
|
for _, d := range b.nodesFactory.nodes {
|
|
|
|
|
|
|
|
if d.DriverInfo != nil && len(d.DriverInfo.DynamicNodes) > 0 {
|
|
|
|
|
|
|
|
kubernetesDriverCount++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
isAllKubernetesDrivers := len(b.nodes) == kubernetesDriverCount
|
|
|
|
isAllKubernetesDrivers := len(b.nodesFactory.nodes) == kubernetesDriverCount
|
|
|
|
if isAllKubernetesDrivers {
|
|
|
|
if isAllKubernetesDrivers {
|
|
|
|
var nodes []Node
|
|
|
|
var nodes []Node
|
|
|
|
var dynamicNodes []store.Node
|
|
|
|
var dynamicNodes []store.Node
|
|
|
|
for _, di := range b.nodes {
|
|
|
|
for _, di := range b.nodesFactory.nodes {
|
|
|
|
// dynamic nodes are used in Kubernetes driver.
|
|
|
|
// dynamic nodes are used in Kubernetes driver.
|
|
|
|
// Kubernetes' pods are dynamically mapped to BuildKit Nodes.
|
|
|
|
// Kubernetes' pods are dynamically mapped to BuildKit Nodes.
|
|
|
|
if di.DriverInfo != nil && len(di.DriverInfo.DynamicNodes) > 0 {
|
|
|
|
if di.DriverInfo != nil && len(di.DriverInfo.DynamicNodes) > 0 {
|
|
|
|
for i := 0; i < len(di.DriverInfo.DynamicNodes); i++ {
|
|
|
|
for i := 0; i < len(di.DriverInfo.DynamicNodes); i++ {
|
|
|
|
diClone := di
|
|
|
|
diClone := di
|
|
|
|
if pl := di.DriverInfo.DynamicNodes[i].Platforms; len(pl) > 0 {
|
|
|
|
if pl := di.DriverInfo.DynamicNodes[i].Platforms; len(pl) > 0 {
|
|
|
|
diClone.Platforms = pl
|
|
|
|
diClone.Platforms = pl
|
|
|
|
}
|
|
|
|
|
|
|
|
nodes = append(nodes, di)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dynamicNodes = append(dynamicNodes, di.DriverInfo.DynamicNodes...)
|
|
|
|
nodes = append(nodes, di)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dynamicNodes = append(dynamicNodes, di.DriverInfo.DynamicNodes...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// not append (remove the static nodes in the store)
|
|
|
|
|
|
|
|
b.NodeGroup.Nodes = dynamicNodes
|
|
|
|
|
|
|
|
b.nodes = nodes
|
|
|
|
|
|
|
|
b.NodeGroup.Dynamic = true
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// not append (remove the static nodes in the store)
|
|
|
|
|
|
|
|
b.NodeGroup.Nodes = dynamicNodes
|
|
|
|
|
|
|
|
b.nodesFactory.nodes = nodes
|
|
|
|
|
|
|
|
b.NodeGroup.Dynamic = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return b.nodes, nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (n *Node) loadData(ctx context.Context) error {
|
|
|
|
func (n *Node) loadData(ctx context.Context) error {
|
|
|
|