From 8e1b32365ea16dd90c1d6619361a8e9cc0dc6adf Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Mon, 20 Nov 2023 08:35:32 +0100 Subject: [PATCH] fix --remove-orphans not to consider disabled services as orphaned Signed-off-by: Nicolas De Loof --- pkg/compose/containers.go | 16 ++++++++++++++++ pkg/compose/down.go | 2 +- pkg/e2e/compose_test.go | 21 +++++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/pkg/compose/containers.go b/pkg/compose/containers.go index 47df374d5f..6adf91b956 100644 --- a/pkg/compose/containers.go +++ b/pkg/compose/containers.go @@ -22,6 +22,7 @@ import ( "sort" "strconv" + "github.com/compose-spec/compose-go/types" "github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/utils" moby "github.com/docker/docker/api/types" @@ -123,6 +124,21 @@ func isNotService(services ...string) containerPredicate { } } +// isOrphaned is a predicate to select containers without a matching service definition in compose project +func isOrphaned(project *types.Project) containerPredicate { + var services []string + for _, s := range project.Services { + services = append(services, s.Name) + } + for _, s := range project.DisabledServices { + services = append(services, s.Name) + } + return func(c moby.Container) bool { + service := c.Labels[api.ServiceLabel] + return !utils.StringContains(services, service) + } +} + func isNotOneOff(c moby.Container) bool { v, ok := c.Labels[api.OneoffLabel] return !ok || v == "False" diff --git a/pkg/compose/down.go b/pkg/compose/down.go index f0d3ddf1c6..c720867d34 100644 --- a/pkg/compose/down.go +++ b/pkg/compose/down.go @@ -83,7 +83,7 @@ func (s *composeService) down(ctx context.Context, projectName string, options a return err } - orphans := containers.filter(isNotService(project.ServiceNames()...)) + orphans := containers.filter(isOrphaned(project)) if options.RemoveOrphans && len(orphans) > 0 { err := s.removeContainers(ctx, w, orphans, options.Timeout, false) if err != nil { diff --git a/pkg/e2e/compose_test.go b/pkg/e2e/compose_test.go index 38300605cf..6384c29c86 100644 --- a/pkg/e2e/compose_test.go +++ b/pkg/e2e/compose_test.go @@ -292,3 +292,24 @@ func TestStopWithDependenciesAttached(t *testing.T) { res := c.RunDockerComposeCmd(t, "-f", "./fixtures/dependencies/compose.yaml", "-p", projectName, "up", "--attach-dependencies", "foo") res.Assert(t, icmd.Expected{Out: "exited with code 0"}) } + +func TestRemoveOrphaned(t *testing.T) { + const projectName = "compose-e2e-remove-orphaned" + c := NewParallelCLI(t) + + cleanup := func() { + c.RunDockerComposeCmd(t, "-p", projectName, "down", "--remove-orphans", "--timeout=0") + } + cleanup() + t.Cleanup(cleanup) + + // run stack + c.RunDockerComposeCmd(t, "-f", "./fixtures/sentences/compose.yaml", "-p", projectName, "up", "-d") + + // down "web" service with orphaned removed + c.RunDockerComposeCmd(t, "-f", "./fixtures/sentences/compose.yaml", "-p", projectName, "down", "--remove-orphans", "web") + + // check "words" service has not been considered orphaned + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/sentences/compose.yaml", "-p", projectName, "ps", "--format", "{{.Name}}") + res.Assert(t, icmd.Expected{Out: fmt.Sprintf("%s-words-1", projectName)}) +}