diff --git a/commands/create.go b/commands/create.go index 9238551c..87b53a80 100644 --- a/commands/create.go +++ b/commands/create.go @@ -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 } } diff --git a/store/nodegroup.go b/store/nodegroup.go index c9f97a67..b6288e09 100644 --- a/store/nodegroup.go +++ b/store/nodegroup.go @@ -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 {