From 855a879a6a079c3cbaecf287a73dd2a7177045eb Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 16 Dec 2020 10:14:31 +0100 Subject: [PATCH] Introduce `removeOrphans` to cleanup injected AWS simulation container Signed-off-by: Nicolas De Loof --- aci/compose.go | 8 +++--- api/client/compose.go | 2 +- api/compose/api.go | 2 +- cli/cmd/compose/down.go | 2 +- cli/cmd/compose/up.go | 2 +- ecs/down.go | 10 ++++---- ecs/local/compose.go | 4 +-- ecs/up.go | 2 +- example/backend.go | 4 +-- go.mod | 1 - local/compose/down.go | 56 ++++++++++++++++++++++++++++++++--------- server/proxy/compose.go | 2 +- 12 files changed, 63 insertions(+), 32 deletions(-) diff --git a/aci/compose.go b/aci/compose.go index 2b9f47b4b..94fed7b21 100644 --- a/aci/compose.go +++ b/aci/compose.go @@ -102,14 +102,14 @@ func (cs aciComposeService) warnKeepVolumeOnDown(ctx context.Context, projectNam return nil } -func (cs *aciComposeService) Down(ctx context.Context, project string) error { - logrus.Debugf("Down on project with name %q", project) +func (cs *aciComposeService) Down(ctx context.Context, projectName string, removeOrphans bool) error { + logrus.Debugf("Down on projectName with name %q", projectName) - if err := cs.warnKeepVolumeOnDown(ctx, project); err != nil { + if err := cs.warnKeepVolumeOnDown(ctx, projectName); err != nil { return err } - cg, err := deleteACIContainerGroup(ctx, cs.ctx, project) + cg, err := deleteACIContainerGroup(ctx, cs.ctx, projectName) if err != nil { return err } diff --git a/api/client/compose.go b/api/client/compose.go index b069a6ab4..78578e3cc 100644 --- a/api/client/compose.go +++ b/api/client/compose.go @@ -52,7 +52,7 @@ func (c *composeService) Up(context.Context, *types.Project, bool) error { return errdefs.ErrNotImplemented } -func (c *composeService) Down(context.Context, string) error { +func (c *composeService) Down(context.Context, string, bool) error { return errdefs.ErrNotImplemented } diff --git a/api/compose/api.go b/api/compose/api.go index 1a2b6f234..a1ba9f21c 100644 --- a/api/compose/api.go +++ b/api/compose/api.go @@ -37,7 +37,7 @@ type Service interface { // Up executes the equivalent to a `compose up` Up(ctx context.Context, project *types.Project, detach bool) error // Down executes the equivalent to a `compose down` - Down(ctx context.Context, projectName string) error + Down(ctx context.Context, projectName string, removeOrphans bool) error // Logs executes the equivalent to a `compose logs` Logs(ctx context.Context, projectName string, consumer LogConsumer, options LogOptions) error // Ps executes the equivalent to a `compose ps` diff --git a/cli/cmd/compose/down.go b/cli/cmd/compose/down.go index 3b05c038b..a4b12f870 100644 --- a/cli/cmd/compose/down.go +++ b/cli/cmd/compose/down.go @@ -52,7 +52,7 @@ func runDown(ctx context.Context, opts composeOptions) error { if err != nil { return "", err } - return projectName, c.ComposeService().Down(ctx, projectName) + return projectName, c.ComposeService().Down(ctx, projectName, false) }) return err } diff --git a/cli/cmd/compose/up.go b/cli/cmd/compose/up.go index 3b1f104f1..4b971581c 100644 --- a/cli/cmd/compose/up.go +++ b/cli/cmd/compose/up.go @@ -96,7 +96,7 @@ func runCreateStart(ctx context.Context, opts composeOptions, services []string) fmt.Println("Gracefully stopping...") ctx = context.Background() _, err = progress.Run(ctx, func(ctx context.Context) (string, error) { - return "", c.ComposeService().Down(ctx, project.Name) + return "", c.ComposeService().Down(ctx, project.Name, false) }) } return err diff --git a/ecs/down.go b/ecs/down.go index bd1c434f5..6ad4dee42 100644 --- a/ecs/down.go +++ b/ecs/down.go @@ -22,8 +22,8 @@ import ( "github.com/docker/compose-cli/progress" ) -func (b *ecsAPIService) Down(ctx context.Context, project string) error { - resources, err := b.aws.ListStackResources(ctx, project) +func (b *ecsAPIService) Down(ctx context.Context, projectName string, removeOrphans bool) error { + resources, err := b.aws.ListStackResources(ctx, projectName) if err != nil { return err } @@ -38,16 +38,16 @@ func (b *ecsAPIService) Down(ctx context.Context, project string) error { return err } - previousEvents, err := b.previousStackEvents(ctx, project) + previousEvents, err := b.previousStackEvents(ctx, projectName) if err != nil { return err } - err = b.aws.DeleteStack(ctx, project) + err = b.aws.DeleteStack(ctx, projectName) if err != nil { return err } - return b.WaitStackCompletion(ctx, project, stackDelete, previousEvents...) + return b.WaitStackCompletion(ctx, projectName, stackDelete, previousEvents...) } func (b *ecsAPIService) previousStackEvents(ctx context.Context, project string) ([]string, error) { diff --git a/ecs/local/compose.go b/ecs/local/compose.go index fff413cc1..54a6dcd2e 100644 --- a/ecs/local/compose.go +++ b/ecs/local/compose.go @@ -147,8 +147,8 @@ func (e ecsLocalSimulation) enhanceForLocalSimulation(project *types.Project) (* return project, nil } -func (e ecsLocalSimulation) Down(ctx context.Context, projectName string) error { - return e.compose.Down(ctx, projectName) +func (e ecsLocalSimulation) Down(ctx context.Context, projectName string, removeOrphans bool) error { + return e.compose.Down(ctx, projectName, true) } func (e ecsLocalSimulation) Logs(ctx context.Context, projectName string, consumer compose.LogConsumer, options componse.LogOptions) error { diff --git a/ecs/up.go b/ecs/up.go index 0af2fe70c..8f3240471 100644 --- a/ecs/up.go +++ b/ecs/up.go @@ -90,7 +90,7 @@ func (b *ecsAPIService) Up(ctx context.Context, project *types.Project, detach b go func() { <-signalChan fmt.Println("user interrupted deployment. Deleting stack...") - b.Down(ctx, project.Name) // nolint:errcheck + b.Down(ctx, project.Name, false) // nolint:errcheck }() err = b.WaitStackCompletion(ctx, project.Name, operation) diff --git a/example/backend.go b/example/backend.go index 646a1d5bc..39422a5a8 100644 --- a/example/backend.go +++ b/example/backend.go @@ -164,8 +164,8 @@ func (cs *composeService) Up(ctx context.Context, project *types.Project, detach return nil } -func (cs *composeService) Down(ctx context.Context, project string) error { - fmt.Printf("Down command on project %q", project) +func (cs *composeService) Down(ctx context.Context, projectName string, removeOrphans bool) error { + fmt.Printf("Down command on project %q", projectName) return nil } diff --git a/go.mod b/go.mod index 59dc7d083..dab8c3d3e 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,6 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.6.1 github.com/valyala/fasttemplate v1.2.1 // indirect - golang.org/x/mod v0.3.0 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 diff --git a/local/compose/down.go b/local/compose/down.go index a9ada09e0..7fd285b6e 100644 --- a/local/compose/down.go +++ b/local/compose/down.go @@ -30,7 +30,7 @@ import ( "golang.org/x/sync/errgroup" ) -func (s *composeService) Down(ctx context.Context, projectName string) error { +func (s *composeService) Down(ctx context.Context, projectName string, removeOrphans bool) error { eg, _ := errgroup.WithContext(ctx) w := progress.ContextWriter(ctx) @@ -39,10 +39,27 @@ func (s *composeService) Down(ctx context.Context, projectName string) error { return err } - err = InReverseDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error { - filter := filters.NewArgs(projectFilter(project.Name), serviceFilter(service.Name)) - return s.removeContainers(ctx, w, eg, filter) + containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ + Filters: filters.NewArgs(projectFilter(project.Name)), + All: true, }) + if err != nil { + return err + } + + err = InReverseDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error { + serviceContainers, others := split(containers, isService(service.Name)) + err := s.removeContainers(ctx, w, eg, serviceContainers) + containers = others + return err + }) + + if removeOrphans { + err := s.removeContainers(ctx, w, eg, containers) + if err != nil { + return err + } + } if err != nil { return err @@ -70,14 +87,7 @@ func (s *composeService) Down(ctx context.Context, projectName string) error { return eg.Wait() } -func (s *composeService) removeContainers(ctx context.Context, w progress.Writer, eg *errgroup.Group, filter filters.Args) error { - containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ - Filters: filter, - All: true, - }) - if err != nil { - return err - } +func (s *composeService) removeContainers(ctx context.Context, w progress.Writer, eg *errgroup.Group, containers []moby.Container) error { for _, container := range containers { eg.Go(func() error { eventName := "Container " + getContainerName(container) @@ -147,3 +157,25 @@ func loadProjectOptionsFromLabels(c moby.Container) (*cli.ProjectOptions, error) cli.WithWorkingDirectory(c.Labels[workingDirLabel]), cli.WithName(c.Labels[projectLabel])) } + +type containerPredicate func(c moby.Container) bool + +func isService(service string) containerPredicate { + return func(c moby.Container) bool { + return c.Labels[serviceLabel] == service + } +} + +// split return a container slice with elements to match predicate +func split(containers []moby.Container, predicate containerPredicate) ([]moby.Container, []moby.Container) { + var right []moby.Container + var left []moby.Container + for _, c := range containers { + if predicate(c) { + right = append(right, c) + } else { + left = append(left, c) + } + } + return right, left +} diff --git a/server/proxy/compose.go b/server/proxy/compose.go index 3c584d201..348d4a0d0 100644 --- a/server/proxy/compose.go +++ b/server/proxy/compose.go @@ -42,7 +42,7 @@ func (p *proxy) Down(ctx context.Context, request *composev1.ComposeDownRequest) } projectName = project.Name } - return &composev1.ComposeDownResponse{ProjectName: projectName}, Client(ctx).ComposeService().Down(ctx, projectName) + return &composev1.ComposeDownResponse{ProjectName: projectName}, Client(ctx).ComposeService().Down(ctx, projectName, false) } func (p *proxy) Services(ctx context.Context, request *composev1.ComposeServicesRequest) (*composev1.ComposeServicesResponse, error) {