Skip to content

Commit c531749

Browse files
committed
workaround race condition in ContainerList
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent 67c9ecb commit c531749

File tree

3 files changed

+44
-19
lines changed

3 files changed

+44
-19
lines changed

cmd/compose/remove.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,6 @@ func runRemove(ctx context.Context, backend api.Service, opts removeOptions, ser
6464
return err
6565
}
6666

67-
if opts.stop {
68-
err := backend.Stop(ctx, name, api.StopOptions{
69-
Services: services,
70-
Project: project,
71-
})
72-
if err != nil {
73-
return err
74-
}
75-
}
76-
7767
return backend.Remove(ctx, name, api.RemoveOptions{
7868
Services: services,
7969
Force: opts.force,

pkg/compose/remove.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ import (
3131

3232
func (s *composeService) Remove(ctx context.Context, projectName string, options api.RemoveOptions) error {
3333
projectName = strings.ToLower(projectName)
34+
35+
if options.Stop {
36+
err := s.Stop(ctx, projectName, api.StopOptions{
37+
Services: options.Services,
38+
Project: options.Project,
39+
})
40+
if err != nil {
41+
return err
42+
}
43+
}
44+
3445
containers, err := s.getContainers(ctx, projectName, oneOffExclude, true, options.Services...)
3546
if err != nil {
3647
if api.IsNotFoundError(err) {
@@ -44,14 +55,27 @@ func (s *composeService) Remove(ctx context.Context, projectName string, options
4455
containers = containers.filter(isService(options.Project.ServiceNames()...))
4556
}
4657

47-
stoppedContainers := containers.filter(func(c moby.Container) bool {
48-
return c.State != ContainerRunning || (options.Stop && s.dryRun)
49-
})
58+
var stoppedContainers Containers
59+
for _, container := range containers {
60+
// We have to inspect containers, as State reported by getContainers suffers a race condition
61+
inspected, err := s.apiClient().ContainerInspect(ctx, container.ID)
62+
if api.IsNotFoundError(err) {
63+
// Already removed. Maybe configured with auto-remove
64+
continue
65+
}
66+
if err != nil {
67+
return err
68+
}
69+
if !inspected.State.Running || (options.Stop && s.dryRun) {
70+
stoppedContainers = append(stoppedContainers, container)
71+
}
72+
}
5073

5174
var names []string
5275
stoppedContainers.forEach(func(c moby.Container) {
5376
names = append(names, getCanonicalContainerName(c))
5477
})
78+
fmt.Fprintln(s.stderr(), names)
5579

5680
if len(names) == 0 {
5781
fmt.Fprintln(s.stderr(), "No stopped containers")

pkg/e2e/compose_test.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,23 +169,34 @@ func TestRm(t *testing.T) {
169169
c.RunDockerComposeCmd(t, "-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "up", "-d")
170170
})
171171

172-
t.Run("rm -sf", func(t *testing.T) {
172+
t.Run("rm --stop --force simple", func(t *testing.T) {
173173
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "rm",
174-
"-sf", "simple")
174+
"--stop", "--force", "simple")
175175
res.Assert(t, icmd.Expected{Err: "Removed", ExitCode: 0})
176176
})
177177

178-
t.Run("check containers after rm -sf", func(t *testing.T) {
178+
t.Run("check containers after rm", func(t *testing.T) {
179179
res := c.RunDockerCmd(t, "ps", "--all")
180-
assert.Assert(t, !strings.Contains(res.Combined(), projectName+"_simple"), res.Combined())
180+
assert.Assert(t, !strings.Contains(res.Combined(), projectName+"-simple"), res.Combined())
181+
assert.Assert(t, strings.Contains(res.Combined(), projectName+"-another"), res.Combined())
181182
})
182183

183-
t.Run("rm -sf <none>", func(t *testing.T) {
184+
t.Run("up (again)", func(t *testing.T) {
185+
c.RunDockerComposeCmd(t, "-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "up", "-d")
186+
})
187+
188+
t.Run("rm ---stop --force <none>", func(t *testing.T) {
184189
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "rm",
185-
"-sf", "simple")
190+
"--stop", "--force")
186191
res.Assert(t, icmd.Expected{ExitCode: 0})
187192
})
188193

194+
t.Run("check containers after rm", func(t *testing.T) {
195+
res := c.RunDockerCmd(t, "ps", "--all")
196+
assert.Assert(t, !strings.Contains(res.Combined(), projectName+"-simple"), res.Combined())
197+
assert.Assert(t, !strings.Contains(res.Combined(), projectName+"-another"), res.Combined())
198+
})
199+
189200
t.Run("down", func(t *testing.T) {
190201
c.RunDockerComposeCmd(t, "-p", projectName, "down")
191202
})

0 commit comments

Comments
 (0)