diff --git a/commands/create.go b/commands/create.go index 2a9c1296a089..87b53a806beb 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,6 +229,30 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error { return err } + ngi := &nginfo{ng: ng} + + timeoutCtx, cancel := context.WithTimeout(ctx, 20*time.Second) + defer cancel() + + if err = loadNodeGroupData(timeoutCtx, dockerCli, ngi); err != nil { + return err + } + for _, info := range ngi.drivers { + if err := info.di.Err; err != nil { + 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 { @@ -234,15 +263,6 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error { } } - ngi := &nginfo{ng: ng} - - timeoutCtx, cancel := context.WithTimeout(ctx, 20*time.Second) - defer cancel() - - if err = loadNodeGroupData(timeoutCtx, dockerCli, ngi); err != nil { - return err - } - if in.bootstrap { if _, err = boot(ctx, ngi); err != nil { return err diff --git a/store/nodegroup.go b/store/nodegroup.go index c9f97a672286..b6288e0981a9 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 {