diff --git a/clab/clab.go b/clab/clab.go index a64c8d94b..81d019256 100644 --- a/clab/clab.go +++ b/clab/clab.go @@ -286,35 +286,56 @@ func (c *CLab) CreateLinks(ctx context.Context, workers uint, postdeploy bool) { wg.Wait() } -func (c *CLab) DeleteNodes(ctx context.Context, workers uint, deleteCandidates map[string]nodes.Node) { - wg := new(sync.WaitGroup) +func (c *CLab) DeleteNodes(ctx context.Context, workers uint, deleteCandidates map[string]nodes.Node, serialNodes map[string]struct{}) { - nodeChan := make(chan nodes.Node) + wg := new(sync.WaitGroup) wg.Add(int(workers)) - for i := uint(0); i < workers; i++ { - go func(i uint) { - defer wg.Done() - for { - select { - case n := <-nodeChan: - if n == nil { - log.Debugf("Worker %d terminating...", i) - return - } - err := n.Delete(ctx) - if err != nil { - log.Errorf("could not remove container %q: %v", n.Config().LongName, err) - } - case <-ctx.Done(): + if len(serialNodes) > 0 { + wg.Add(1) + } + + concurrentChan := make(chan nodes.Node) + serialChan := make(chan nodes.Node) + + workerFunc := func(i uint, input chan nodes.Node, wg *sync.WaitGroup) { + defer wg.Done() + for { + select { + case n := <-input: + if n == nil { + log.Debugf("Worker %d terminating...", i) return } + err := n.Delete(ctx) + if err != nil { + log.Errorf("could not remove container %q: %v", n.Config().LongName, err) + } + case <-ctx.Done(): + return } - }(i) + } + } + + // start concurrent workers + for i := uint(0); i < workers; i++ { + go workerFunc(i, concurrentChan, wg) } - for _, n := range deleteCandidates { - nodeChan <- n + + // start the serial worker + go workerFunc(workers, serialChan, wg) + + // send nodes to workers + for _, n := range c.Nodes { + if _, ok := serialNodes[n.Config().LongName]; ok { + serialChan <- n + continue + } + concurrentChan <- n } - close(nodeChan) + + // close channel to terminate the workers + close(concurrentChan) + close(serialChan) wg.Wait() diff --git a/cmd/destroy.go b/cmd/destroy.go index d7d183026..347530c2e 100644 --- a/cmd/destroy.go +++ b/cmd/destroy.go @@ -186,13 +186,23 @@ func destroyLab(ctx context.Context, c *clab.CLab) (err error) { maxWorkers = uint(len(c.Nodes)) } + // a set of workers that do not support concurrency + serialNodes := make(map[string]struct{}) + for _, n := range c.Nodes { + if n.GetRuntime().GetName() == runtime.IgniteRuntime { + serialNodes[n.Config().LongName] = struct{}{} + // decreasing the num of maxWorkers as they are used for concurrent nodes + maxWorkers = maxWorkers - 1 + } + } + // Serializing ignite workers due to busy device error if _, ok := c.Runtimes[runtime.IgniteRuntime]; ok { maxWorkers = 1 } log.Infof("Destroying lab: %s", c.Config.Name) - c.DeleteNodes(ctx, maxWorkers, c.Nodes) + c.DeleteNodes(ctx, maxWorkers, c.Nodes, serialNodes) // remove the lab directories if cleanup {