2019-04-13 07:39:06 +08:00
|
|
|
package store
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
2019-04-18 08:55:27 +08:00
|
|
|
"github.com/containerd/containerd/platforms"
|
2021-11-03 13:48:20 +08:00
|
|
|
"github.com/docker/buildx/util/confutil"
|
2019-04-25 10:29:56 +08:00
|
|
|
"github.com/docker/buildx/util/platformutil"
|
2019-04-18 08:55:27 +08:00
|
|
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
2019-04-13 07:39:06 +08:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
type NodeGroup struct {
|
2019-11-12 18:10:39 +08:00
|
|
|
Name string
|
|
|
|
Driver string
|
|
|
|
Nodes []Node
|
|
|
|
Dynamic bool
|
2019-04-13 07:39:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type Node struct {
|
2019-08-01 01:54:20 +08:00
|
|
|
Name string
|
|
|
|
Endpoint string
|
|
|
|
Platforms []specs.Platform
|
|
|
|
Flags []string
|
2019-08-01 08:25:25 +08:00
|
|
|
DriverOpts map[string]string
|
2021-11-03 13:48:20 +08:00
|
|
|
|
|
|
|
Files map[string][]byte
|
2019-04-13 07:39:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ng *NodeGroup) Leave(name string) error {
|
2019-11-12 18:10:39 +08:00
|
|
|
if ng.Dynamic {
|
|
|
|
return errors.New("dynamic node group does not support Leave")
|
|
|
|
}
|
2019-04-13 07:39:06 +08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2019-08-01 08:25:25 +08:00
|
|
|
func (ng *NodeGroup) Update(name, endpoint string, platforms []string, endpointsSet bool, actionAppend bool, flags []string, configFile string, do map[string]string) error {
|
2019-11-12 18:10:39 +08:00
|
|
|
if ng.Dynamic {
|
|
|
|
return errors.New("dynamic node group does not support Update")
|
|
|
|
}
|
2019-04-13 07:39:06 +08:00
|
|
|
i := ng.findNode(name)
|
|
|
|
if i == -1 && !actionAppend {
|
2019-04-16 08:01:00 +08:00
|
|
|
if len(ng.Nodes) > 0 {
|
|
|
|
return errors.Errorf("node %s not found, did you mean to append?", name)
|
|
|
|
}
|
2019-04-13 07:39:06 +08:00
|
|
|
ng.Nodes = nil
|
|
|
|
}
|
2019-04-18 08:55:27 +08:00
|
|
|
|
|
|
|
pp, err := platformutil.Parse(platforms)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-04-13 07:39:06 +08:00
|
|
|
if i != -1 {
|
|
|
|
n := ng.Nodes[i]
|
|
|
|
if endpointsSet {
|
|
|
|
n.Endpoint = endpoint
|
|
|
|
}
|
|
|
|
if len(platforms) > 0 {
|
2019-04-18 08:55:27 +08:00
|
|
|
n.Platforms = pp
|
2019-04-13 07:39:06 +08:00
|
|
|
}
|
2019-07-09 06:06:07 +08:00
|
|
|
if flags != nil {
|
|
|
|
n.Flags = flags
|
|
|
|
}
|
2019-04-13 07:39:06 +08:00
|
|
|
ng.Nodes[i] = n
|
2019-04-18 08:55:27 +08:00
|
|
|
if err := ng.validateDuplicates(endpoint, i); err != nil {
|
2019-04-13 07:39:06 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if name == "" {
|
|
|
|
name = ng.nextNodeName()
|
|
|
|
}
|
|
|
|
|
2019-04-18 08:55:27 +08:00
|
|
|
name, err = ValidateName(name)
|
2019-04-13 07:39:06 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
n := Node{
|
2019-08-01 01:54:20 +08:00
|
|
|
Name: name,
|
|
|
|
Endpoint: endpoint,
|
|
|
|
Platforms: pp,
|
|
|
|
Flags: flags,
|
2019-08-01 08:25:25 +08:00
|
|
|
DriverOpts: do,
|
2019-04-13 07:39:06 +08:00
|
|
|
}
|
2021-11-03 13:48:20 +08:00
|
|
|
|
|
|
|
if configFile != "" {
|
|
|
|
files, err := confutil.LoadConfigFiles(configFile)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
n.Files = files
|
|
|
|
}
|
|
|
|
|
2019-04-13 07:39:06 +08:00
|
|
|
ng.Nodes = append(ng.Nodes, n)
|
|
|
|
|
2019-04-18 08:55:27 +08:00
|
|
|
if err := ng.validateDuplicates(endpoint, len(ng.Nodes)-1); err != nil {
|
2019-04-13 07:39:06 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-04-18 08:55:27 +08:00
|
|
|
func (ng *NodeGroup) validateDuplicates(ep string, idx int) error {
|
2019-04-13 07:39:06 +08:00
|
|
|
i := 0
|
|
|
|
for _, n := range ng.Nodes {
|
|
|
|
if n.Endpoint == ep {
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if i > 1 {
|
|
|
|
return errors.Errorf("invalid duplicate endpoint %s", ep)
|
|
|
|
}
|
2019-04-18 08:55:27 +08:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2019-04-13 07:39:06 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ng *NodeGroup) findNode(name string) int {
|
2019-04-16 08:01:00 +08:00
|
|
|
for i, n := range ng.Nodes {
|
2019-04-13 07:39:06 +08:00
|
|
|
if n.Name == name {
|
2019-04-16 08:01:00 +08:00
|
|
|
return i
|
2019-04-13 07:39:06 +08:00
|
|
|
}
|
|
|
|
}
|
2019-04-16 08:01:00 +08:00
|
|
|
return -1
|
2019-04-13 07:39:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ng *NodeGroup) nextNodeName() string {
|
|
|
|
i := 0
|
|
|
|
for {
|
|
|
|
name := fmt.Sprintf("%s%d", ng.Name, i)
|
2019-04-16 06:10:50 +08:00
|
|
|
if ii := ng.findNode(name); ii != -1 {
|
2019-04-13 07:39:06 +08:00
|
|
|
i++
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return name
|
|
|
|
}
|
|
|
|
}
|
2019-04-18 08:55:27 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|