buildx: rollback configuration if create fails

This builds on the added warnings from initialized builders, now
erroring the command, and additionally attempting to revert to the
previous configuration.

To preserve the previous configuration, we add a deep Copy() function to
the NodeGroup and Node so that we can easily restore it later if we
encounter a failure.

Signed-off-by: Justin Chadwell <me@jedevc.com>
pull/1206/head
Justin Chadwell 2 years ago
parent 309c49413c
commit 86825a95ce

@ -134,6 +134,11 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
}
}
ngOriginal := ng
if ngOriginal != nil {
ngOriginal = ngOriginal.Copy()
}
if ng == nil {
ng = &store.NodeGroup{
Name: name,
@ -224,16 +229,6 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
return err
}
if in.use && ep != "" {
current, err := storeutil.GetCurrentEndpoint(dockerCli)
if err != nil {
return err
}
if err := txn.SetCurrent(current, ng.Name, false, false); err != nil {
return err
}
}
ngi := &nginfo{ng: ng}
timeoutCtx, cancel := context.WithTimeout(ctx, 20*time.Second)
@ -244,7 +239,27 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
}
for _, info := range ngi.drivers {
if err := info.di.Err; err != nil {
logrus.Errorf("failed to initialize builder %s (%s): %s", ng.Name, info.di.Name, err)
err := errors.Errorf("failed to initialize builder %s (%s): %s", ng.Name, info.di.Name, err)
var err2 error
if ngOriginal == nil {
err2 = txn.Remove(ng.Name)
} else {
err2 = txn.Save(ngOriginal)
}
if err2 != nil {
logrus.Warnf("Could not rollback to previous state: %s", err2)
}
return err
}
}
if in.use && ep != "" {
current, err := storeutil.GetCurrentEndpoint(dockerCli)
if err != nil {
return err
}
if err := txn.SetCurrent(current, ng.Name, false, false); err != nil {
return err
}
}

@ -110,6 +110,44 @@ func (ng *NodeGroup) Update(name, endpoint string, platforms []string, endpoints
return nil
}
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)
flags := []string{}
copy(flags, n.Flags)
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,
Flags: flags,
DriverOpts: driverOpts,
Files: files,
}
}
func (ng *NodeGroup) validateDuplicates(ep string, idx int) error {
i := 0
for _, n := range ng.Nodes {

Loading…
Cancel
Save