From 8ceaf49296be74f46faa04afe1882bca51450c6d Mon Sep 17 00:00:00 2001 From: koooge Date: Sat, 6 Apr 2024 01:28:30 +0200 Subject: [PATCH] Ignore missing containers when compose down -p Signed-off-by: koooge --- pkg/compose/dependencies.go | 10 +++--- pkg/compose/dependencies_test.go | 54 ++++++++++++++++++++++++++++++-- pkg/compose/down.go | 2 +- pkg/compose/stop.go | 2 +- 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/pkg/compose/dependencies.go b/pkg/compose/dependencies.go index 4a3fa4bd..f8f136fd 100644 --- a/pkg/compose/dependencies.go +++ b/pkg/compose/dependencies.go @@ -77,7 +77,7 @@ func downDirectionTraversal(visitorFn func(context.Context, string) error) *grap // InDependencyOrder applies the function to the services of the project taking in account the dependency order func InDependencyOrder(ctx context.Context, project *types.Project, fn func(context.Context, string) error, options ...func(*graphTraversal)) error { - graph, err := NewGraph(project, ServiceStopped) + graph, err := NewGraph(project, ServiceStopped, false) if err != nil { return err } @@ -89,8 +89,8 @@ func InDependencyOrder(ctx context.Context, project *types.Project, fn func(cont } // InReverseDependencyOrder applies the function to the services of the project in reverse order of dependencies -func InReverseDependencyOrder(ctx context.Context, project *types.Project, fn func(context.Context, string) error, options ...func(*graphTraversal)) error { - graph, err := NewGraph(project, ServiceStarted) +func InReverseDependencyOrder(ctx context.Context, project *types.Project, ignoreMissing bool, fn func(context.Context, string) error, options ...func(*graphTraversal)) error { + graph, err := NewGraph(project, ServiceStarted, ignoreMissing) if err != nil { return err } @@ -257,7 +257,7 @@ func (v *Vertex) GetChildren() []*Vertex { } // NewGraph returns the dependency graph of the services -func NewGraph(project *types.Project, initialStatus ServiceStatus) (*Graph, error) { +func NewGraph(project *types.Project, initialStatus ServiceStatus, ignoreMissing bool) (*Graph, error) { graph := &Graph{ lock: sync.RWMutex{}, Vertices: map[string]*Vertex{}, @@ -271,7 +271,7 @@ func NewGraph(project *types.Project, initialStatus ServiceStatus) (*Graph, erro for _, name := range s.GetDependencies() { err := graph.AddEdge(s.Name, name) if err != nil { - if !s.DependsOn[name].Required { + if ignoreMissing || !s.DependsOn[name].Required { delete(s.DependsOn, name) project.Services[index] = s continue diff --git a/pkg/compose/dependencies_test.go b/pkg/compose/dependencies_test.go index b54702fb..5b5d609d 100644 --- a/pkg/compose/dependencies_test.go +++ b/pkg/compose/dependencies_test.go @@ -115,7 +115,7 @@ func TestInDependencyReverseDownCommandOrder(t *testing.T) { t.Cleanup(cancel) var order []string - err := InReverseDependencyOrder(ctx, createTestProject(), func(ctx context.Context, service string) error { + err := InReverseDependencyOrder(ctx, createTestProject(), false, func(ctx context.Context, service string) error { order = append(order, service) return nil }) @@ -270,7 +270,57 @@ func TestBuildGraph(t *testing.T) { Services: tC.services, } - graph, err := NewGraph(&project, ServiceStopped) + graph, err := NewGraph(&project, ServiceStopped, false) + assert.NilError(t, err, fmt.Sprintf("failed to build graph for: %s", tC.desc)) + + for k, vertex := range graph.Vertices { + expected, ok := tC.expectedVertices[k] + assert.Equal(t, true, ok) + assert.Equal(t, true, isVertexEqual(*expected, *vertex)) + } + }) + } +} + +func TestBuildGraphIgnoreMissing(t *testing.T) { + testCases := []struct { + desc string + services types.Services + expectedVertices map[string]*Vertex + }{ + { + desc: "service depends on init container which is already removed", + services: types.Services{ + "test": { + Name: "test", + DependsOn: types.DependsOnConfig{ + "test-removed-init-container": types.ServiceDependency{ + Condition: "service_completed_successfully", + Restart: false, + Extensions: types.Extensions(nil), + Required: true, + }, + }, + }, + }, + expectedVertices: map[string]*Vertex{ + "test": { + Key: "test", + Service: "test", + Status: ServiceStopped, + Children: map[string]*Vertex{}, + Parents: map[string]*Vertex{}, + }, + }, + }, + } + for _, tC := range testCases { + t.Run(tC.desc, func(t *testing.T) { + project := types.Project{ + Services: tC.services, + } + + graph, err := NewGraph(&project, ServiceStopped, true) assert.NilError(t, err, fmt.Sprintf("failed to build graph for: %s", tC.desc)) for k, vertex := range graph.Vertices { diff --git a/pkg/compose/down.go b/pkg/compose/down.go index b7887c5a..3a9aa551 100644 --- a/pkg/compose/down.go +++ b/pkg/compose/down.go @@ -74,7 +74,7 @@ func (s *composeService) down(ctx context.Context, projectName string, options a resourceToRemove = true } - err = InReverseDependencyOrder(ctx, project, func(c context.Context, service string) error { + err = InReverseDependencyOrder(ctx, project, true, func(c context.Context, service string) error { serviceContainers := containers.filter(isService(service)) err := s.removeContainers(ctx, serviceContainers, options.Timeout, options.Volumes) return err diff --git a/pkg/compose/stop.go b/pkg/compose/stop.go index a7f6d68d..08c42b1b 100644 --- a/pkg/compose/stop.go +++ b/pkg/compose/stop.go @@ -50,7 +50,7 @@ func (s *composeService) stop(ctx context.Context, projectName string, options a } w := progress.ContextWriter(ctx) - return InReverseDependencyOrder(ctx, project, func(c context.Context, service string) error { + return InReverseDependencyOrder(ctx, project, false, func(c context.Context, service string) error { if !utils.StringContains(options.Services, service) { return nil }