mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 18:13:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			224 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			224 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package store
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/containerd/platforms"
 | 
						|
	"github.com/docker/buildx/util/confutil"
 | 
						|
	"github.com/docker/buildx/util/platformutil"
 | 
						|
	specs "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						|
	"github.com/pkg/errors"
 | 
						|
	"github.com/sirupsen/logrus"
 | 
						|
)
 | 
						|
 | 
						|
type NodeGroup struct {
 | 
						|
	Name    string
 | 
						|
	Driver  string
 | 
						|
	Nodes   []Node
 | 
						|
	Dynamic bool
 | 
						|
 | 
						|
	// skip the following fields from being saved in the store
 | 
						|
	DockerContext bool      `json:"-"`
 | 
						|
	LastActivity  time.Time `json:"-"`
 | 
						|
}
 | 
						|
 | 
						|
type Node struct {
 | 
						|
	Name           string
 | 
						|
	Endpoint       string
 | 
						|
	Platforms      []specs.Platform
 | 
						|
	DriverOpts     map[string]string
 | 
						|
	BuildkitdFlags []string `json:"Flags"` // keep the field name for backward compatibility
 | 
						|
 | 
						|
	Files map[string][]byte
 | 
						|
}
 | 
						|
 | 
						|
func (ng *NodeGroup) Leave(name string) error {
 | 
						|
	if ng.Dynamic {
 | 
						|
		return errors.New("dynamic node group does not support Leave")
 | 
						|
	}
 | 
						|
	i := ng.findNode(name)
 | 
						|
	if i == -1 {
 | 
						|
		return errors.Errorf("node %q not found for %s", name, ng.Name)
 | 
						|
	}
 | 
						|
	if len(ng.Nodes) == 1 {
 | 
						|
		return errors.Errorf("can not leave last node, do you want to rm instance instead?")
 | 
						|
	}
 | 
						|
	ng.Nodes = append(ng.Nodes[:i], ng.Nodes[i+1:]...)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (ng *NodeGroup) Update(name, endpoint string, platforms []string, endpointsSet bool, actionAppend bool, buildkitdFlags []string, buildkitdConfigFile string, do map[string]string) error {
 | 
						|
	if ng.Dynamic {
 | 
						|
		return errors.New("dynamic node group does not support Update")
 | 
						|
	}
 | 
						|
	i := ng.findNode(name)
 | 
						|
	if i == -1 && !actionAppend {
 | 
						|
		if len(ng.Nodes) > 0 {
 | 
						|
			return errors.Errorf("node %s not found, did you mean to append?", name)
 | 
						|
		}
 | 
						|
		ng.Nodes = nil
 | 
						|
	}
 | 
						|
 | 
						|
	pp, err := platformutil.Parse(platforms)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	var files map[string][]byte
 | 
						|
	if buildkitdConfigFile != "" {
 | 
						|
		files, err = confutil.LoadConfigFiles(buildkitdConfigFile)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if i != -1 {
 | 
						|
		n := ng.Nodes[i]
 | 
						|
		needsRestart := false
 | 
						|
		if endpointsSet {
 | 
						|
			n.Endpoint = endpoint
 | 
						|
			needsRestart = true
 | 
						|
		}
 | 
						|
		if len(platforms) > 0 {
 | 
						|
			n.Platforms = pp
 | 
						|
		}
 | 
						|
		if buildkitdFlags != nil {
 | 
						|
			n.BuildkitdFlags = buildkitdFlags
 | 
						|
			needsRestart = true
 | 
						|
		}
 | 
						|
		if do != nil {
 | 
						|
			n.DriverOpts = do
 | 
						|
			needsRestart = true
 | 
						|
		}
 | 
						|
		if buildkitdConfigFile != "" {
 | 
						|
			for k, v := range files {
 | 
						|
				n.Files[k] = v
 | 
						|
			}
 | 
						|
			needsRestart = true
 | 
						|
		}
 | 
						|
		if needsRestart {
 | 
						|
			logrus.Warn("new settings may not be used until builder is restarted")
 | 
						|
		}
 | 
						|
 | 
						|
		ng.Nodes[i] = n
 | 
						|
		return ng.validateDuplicates(endpoint, i)
 | 
						|
	}
 | 
						|
 | 
						|
	if name == "" {
 | 
						|
		name = ng.nextNodeName()
 | 
						|
	}
 | 
						|
 | 
						|
	name, err = ValidateName(name)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	n := Node{
 | 
						|
		Name:           name,
 | 
						|
		Endpoint:       endpoint,
 | 
						|
		Platforms:      pp,
 | 
						|
		DriverOpts:     do,
 | 
						|
		BuildkitdFlags: buildkitdFlags,
 | 
						|
		Files:          files,
 | 
						|
	}
 | 
						|
 | 
						|
	ng.Nodes = append(ng.Nodes, n)
 | 
						|
	return ng.validateDuplicates(endpoint, len(ng.Nodes)-1)
 | 
						|
}
 | 
						|
 | 
						|
func (ng *NodeGroup) Copy() *NodeGroup {
 | 
						|
	nodes := make([]Node, len(ng.Nodes))
 | 
						|
	for i, node := range ng.Nodes {
 | 
						|
		nodes[i] = *node.Copy()
 | 
						|
	}
 | 
						|
	return &NodeGroup{
 | 
						|
		Name:    ng.Name,
 | 
						|
		Driver:  ng.Driver,
 | 
						|
		Nodes:   nodes,
 | 
						|
		Dynamic: ng.Dynamic,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (n *Node) Copy() *Node {
 | 
						|
	platforms := []specs.Platform{}
 | 
						|
	copy(platforms, n.Platforms)
 | 
						|
	buildkitdFlags := []string{}
 | 
						|
	copy(buildkitdFlags, n.BuildkitdFlags)
 | 
						|
	driverOpts := map[string]string{}
 | 
						|
	for k, v := range n.DriverOpts {
 | 
						|
		driverOpts[k] = v
 | 
						|
	}
 | 
						|
	files := map[string][]byte{}
 | 
						|
	for k, v := range n.Files {
 | 
						|
		vv := []byte{}
 | 
						|
		copy(vv, v)
 | 
						|
		files[k] = vv
 | 
						|
	}
 | 
						|
	return &Node{
 | 
						|
		Name:           n.Name,
 | 
						|
		Endpoint:       n.Endpoint,
 | 
						|
		Platforms:      platforms,
 | 
						|
		BuildkitdFlags: buildkitdFlags,
 | 
						|
		DriverOpts:     driverOpts,
 | 
						|
		Files:          files,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (ng *NodeGroup) validateDuplicates(ep string, idx int) error {
 | 
						|
	i := 0
 | 
						|
	for _, n := range ng.Nodes {
 | 
						|
		if n.Endpoint == ep {
 | 
						|
			i++
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if i > 1 {
 | 
						|
		return errors.Errorf("invalid duplicate endpoint %s", ep)
 | 
						|
	}
 | 
						|
 | 
						|
	m := map[string]struct{}{}
 | 
						|
	for _, p := range ng.Nodes[idx].Platforms {
 | 
						|
		m[platforms.Format(p)] = struct{}{}
 | 
						|
	}
 | 
						|
 | 
						|
	for i := range ng.Nodes {
 | 
						|
		if i == idx {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		ng.Nodes[i].Platforms = filterPlatforms(ng.Nodes[i].Platforms, m)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (ng *NodeGroup) findNode(name string) int {
 | 
						|
	for i, n := range ng.Nodes {
 | 
						|
		if n.Name == name {
 | 
						|
			return i
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return -1
 | 
						|
}
 | 
						|
 | 
						|
func (ng *NodeGroup) nextNodeName() string {
 | 
						|
	i := 0
 | 
						|
	for {
 | 
						|
		name := fmt.Sprintf("%s%d", ng.Name, i)
 | 
						|
		if ii := ng.findNode(name); ii != -1 {
 | 
						|
			i++
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		return name
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func filterPlatforms(in []specs.Platform, m map[string]struct{}) []specs.Platform {
 | 
						|
	out := make([]specs.Platform, 0, len(in))
 | 
						|
	for _, p := range in {
 | 
						|
		if _, ok := m[platforms.Format(p)]; !ok {
 | 
						|
			out = append(out, p)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return out
 | 
						|
}
 |