Skip to content

Commit bc9f7e6

Browse files
committed
rm: clean up all nodes before returning errors
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
1 parent f80d155 commit bc9f7e6

2 files changed

Lines changed: 69 additions & 17 deletions

File tree

commands/rm.go

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package commands
22

33
import (
44
"context"
5+
stderrors "errors"
56
"fmt"
67
"time"
78

@@ -90,7 +91,7 @@ func runRm(ctx context.Context, dockerCli command.Cli, in rmOptions) error {
9091
return err
9192
}
9293

93-
err1 := rm(ctx, nodes, in)
94+
err1 := rm(timeoutCtx, nodes, in)
9495
if err := txn.Remove(b.Name); err != nil {
9596
return err
9697
}
@@ -140,24 +141,36 @@ func rmCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
140141
}
141142

142143
func rm(ctx context.Context, nodes []builder.Node, in rmOptions) (err error) {
144+
errCh := make(chan error, len(nodes)*3)
145+
var eg errgroup.Group
143146
for _, node := range nodes {
144-
if node.Driver == nil {
145-
continue
146-
}
147-
// Do not stop the buildkitd daemon when --keep-daemon is provided
148-
if !in.keepDaemon {
149-
if err := node.Driver.Stop(ctx, true); err != nil {
150-
return err
147+
eg.Go(func() error {
148+
if node.Err != nil {
149+
errCh <- errors.Wrapf(node.Err, "failed to load node %s", node.Name)
151150
}
152-
}
153-
if err := node.Driver.Rm(ctx, true, !in.keepState, !in.keepDaemon); err != nil {
154-
return err
155-
}
156-
if node.Err != nil {
157-
err = node.Err
158-
}
151+
if node.Driver == nil {
152+
return nil
153+
}
154+
// Do not stop the buildkitd daemon when --keep-daemon is provided
155+
if !in.keepDaemon {
156+
if err := node.Driver.Stop(ctx, true); err != nil {
157+
errCh <- errors.Wrapf(err, "failed to stop node %s", node.Name)
158+
}
159+
}
160+
if err := node.Driver.Rm(ctx, true, !in.keepState, !in.keepDaemon); err != nil {
161+
errCh <- errors.Wrapf(err, "failed to remove node %s", node.Name)
162+
}
163+
return nil
164+
})
165+
}
166+
_ = eg.Wait()
167+
close(errCh)
168+
169+
var errs []error
170+
for err := range errCh {
171+
errs = append(errs, err)
159172
}
160-
return err
173+
return stderrors.Join(errs...)
161174
}
162175

163176
func rmAllInactive(ctx context.Context, txn *store.Txn, dockerCli command.Cli, in rmOptions) error {
@@ -184,7 +197,7 @@ func rmAllInactive(ctx context.Context, txn *store.Txn, dockerCli command.Cli, i
184197
return nil
185198
}
186199
if b.Inactive() {
187-
rmerr := rm(ctx, nodes, in)
200+
rmerr := rm(timeoutCtx, nodes, in)
188201
if err := txn.Remove(b.Name); err != nil {
189202
return err
190203
}

tests/rm.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ var rmTests = []func(t *testing.T, sb integration.Sandbox){
2525
testRmMulti,
2626
testRmInvalidBuildkitdConfig,
2727
testRmAllInactiveInvalidBuildkitdConfig,
28+
testRmUnreachableEndpoint,
2829
}
2930

3031
func testRm(t *testing.T, sb integration.Sandbox) {
@@ -34,6 +35,7 @@ func testRm(t *testing.T, sb integration.Sandbox) {
3435

3536
out, err := rmCmd(sb, withArgs("default"))
3637
require.Error(t, err, out) // can't remove a docker builder
38+
require.Contains(t, out, "context builder cannot be removed")
3739

3840
out, err = createCmd(sb, withArgs("--driver", "docker-container"))
3941
require.NoError(t, err, out)
@@ -155,6 +157,43 @@ func testRmAllInactiveInvalidBuildkitdConfig(t *testing.T, sb integration.Sandbo
155157
builderName = ""
156158
}
157159

160+
func testRmUnreachableEndpoint(t *testing.T, sb integration.Sandbox) {
161+
if !isDockerContainerWorker(sb) {
162+
t.Skip("only testing with docker-container worker")
163+
}
164+
165+
out, err := createCmd(sb, withArgs("--driver", "docker-container"))
166+
require.NoError(t, err, out)
167+
builderName := strings.TrimSpace(out)
168+
169+
out, err = inspectCmd(sb, withArgs(builderName, "--bootstrap"))
170+
require.NoError(t, err, out)
171+
172+
t.Cleanup(func() {
173+
if builderName == "" {
174+
return
175+
}
176+
_, _ = rmCmd(sb, withArgs("--keep-daemon", builderName))
177+
})
178+
179+
var goodContainer string
180+
updateStoredBuilder(t, sb, builderName, func(ng *store.NodeGroup) {
181+
require.NotEmpty(t, ng.Nodes)
182+
goodContainer = driver.BuilderName(ng.Nodes[0].Name)
183+
badNode := ng.Nodes[0]
184+
badNode.Name += "-unreachable"
185+
badNode.Endpoint = "tcp://127.0.0.1:1"
186+
ng.Nodes = append([]store.Node{badNode}, ng.Nodes...)
187+
})
188+
189+
out, err = rmCmd(sb, withArgs("--timeout=2s", builderName))
190+
require.Error(t, err, out)
191+
require.Contains(t, out, "failed to remove "+builderName)
192+
requireNoStoredBuilder(t, sb, builderName)
193+
requireNoContainer(t, sb, goodContainer)
194+
builderName = ""
195+
}
196+
158197
func updateStoredBuilder(t *testing.T, sb integration.Sandbox, name string, fn func(*store.NodeGroup)) {
159198
t.Helper()
160199

0 commit comments

Comments
 (0)