Skip to content

Commit 832eee0

Browse files
authored
Merge pull request docker#9764 from laurazard/apply-model-kill
Apply compose model on `compose kill`, add `--remove-orphans`
2 parents 6fe34c4 + a226fe9 commit 832eee0

File tree

6 files changed

+50
-4
lines changed

6 files changed

+50
-4
lines changed

cmd/compose/kill.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,18 @@ package compose
1818

1919
import (
2020
"context"
21+
"os"
2122

2223
"github.com/spf13/cobra"
2324

2425
"github.com/docker/compose/v2/pkg/api"
26+
"github.com/docker/compose/v2/pkg/utils"
2527
)
2628

2729
type killOptions struct {
2830
*projectOptions
29-
signal string
31+
removeOrphans bool
32+
signal string
3033
}
3134

3235
func killCommand(p *projectOptions, backend api.Service) *cobra.Command {
@@ -43,20 +46,24 @@ func killCommand(p *projectOptions, backend api.Service) *cobra.Command {
4346
}
4447

4548
flags := cmd.Flags()
49+
removeOrphans := utils.StringToBool(os.Getenv("COMPOSE_REMOVE_ORPHANS"))
50+
flags.BoolVar(&opts.removeOrphans, "remove-orphans", removeOrphans, "Remove containers for services not defined in the Compose file.")
4651
flags.StringVarP(&opts.signal, "signal", "s", "SIGKILL", "SIGNAL to send to the container.")
4752

4853
return cmd
4954
}
5055

5156
func runKill(ctx context.Context, backend api.Service, opts killOptions, services []string) error {
52-
name, err := opts.toProjectName()
57+
project, name, err := opts.projectOrName()
5358
if err != nil {
5459
return err
5560
}
5661

5762
return backend.Kill(ctx, name, api.KillOptions{
58-
Services: services,
59-
Signal: opts.signal,
63+
RemoveOrphans: opts.removeOrphans,
64+
Project: project,
65+
Services: services,
66+
Signal: opts.signal,
6067
})
6168

6269
}

docs/reference/compose_kill.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Force stop service containers.
77

88
| Name | Type | Default | Description |
99
| --- | --- | --- | --- |
10+
| `--remove-orphans` | | | Remove containers for services not defined in the Compose file. |
1011
| `-s`, `--signal` | `string` | `SIGKILL` | SIGNAL to send to the container. |
1112

1213

docs/reference/docker_compose_kill.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ usage: docker compose kill [OPTIONS] [SERVICE...]
1010
pname: docker compose
1111
plink: docker_compose.yaml
1212
options:
13+
- option: remove-orphans
14+
value_type: bool
15+
default_value: "false"
16+
description: Remove containers for services not defined in the Compose file.
17+
deprecated: false
18+
hidden: false
19+
experimental: false
20+
experimentalcli: false
21+
kubernetes: false
22+
swarm: false
1323
- option: signal
1424
shorthand: s
1525
value_type: string

pkg/api/api.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ type ImagesOptions struct {
197197

198198
// KillOptions group options of the Kill API
199199
type KillOptions struct {
200+
// RemoveOrphans will cleanup containers that are not declared on the compose model but own the same labels
201+
RemoveOrphans bool
202+
// Project is the compose project used to define this app. Might be nil if user ran command just with project name
203+
Project *types.Project
200204
// Services passed in the command line to be killed
201205
Services []string
202206
// Signal to send to containers

pkg/compose/kill.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ func (s *composeService) kill(ctx context.Context, projectName string, options a
4545
return err
4646
}
4747

48+
project := options.Project
49+
if project == nil {
50+
project, err = s.getProjectWithResources(ctx, containers, projectName)
51+
if err != nil {
52+
return err
53+
}
54+
}
55+
56+
if !options.RemoveOrphans {
57+
containers = containers.filter(isService(project.ServiceNames()...))
58+
}
4859
if len(containers) == 0 {
4960
fmt.Fprintf(s.stderr(), "no container to kill")
5061
}

pkg/compose/kill_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525

2626
moby "github.com/docker/docker/api/types"
2727
"github.com/docker/docker/api/types/filters"
28+
"github.com/docker/docker/api/types/volume"
2829
"github.com/golang/mock/gomock"
2930
"gotest.tools/v3/assert"
3031

@@ -52,6 +53,12 @@ func TestKillAll(t *testing.T) {
5253
Filters: filters.NewArgs(projectFilter(name)),
5354
}).Return(
5455
[]moby.Container{testContainer("service1", "123", false), testContainer("service1", "456", false), testContainer("service2", "789", false)}, nil)
56+
api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))).
57+
Return(volume.VolumeListOKBody{}, nil)
58+
api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).
59+
Return([]moby.NetworkResource{
60+
{ID: "abc123", Name: "testProject_default"},
61+
}, nil)
5562
api.EXPECT().ContainerKill(anyCancellableContext(), "123", "").Return(nil)
5663
api.EXPECT().ContainerKill(anyCancellableContext(), "456", "").Return(nil)
5764
api.EXPECT().ContainerKill(anyCancellableContext(), "789", "").Return(nil)
@@ -77,6 +84,12 @@ func TestKillSignal(t *testing.T) {
7784

7885
ctx := context.Background()
7986
api.EXPECT().ContainerList(ctx, listOptions).Return([]moby.Container{testContainer(serviceName, "123", false)}, nil)
87+
api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))).
88+
Return(volume.VolumeListOKBody{}, nil)
89+
api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).
90+
Return([]moby.NetworkResource{
91+
{ID: "abc123", Name: "testProject_default"},
92+
}, nil)
8093
api.EXPECT().ContainerKill(anyCancellableContext(), "123", "SIGTERM").Return(nil)
8194

8295
err := tested.kill(ctx, name, compose.KillOptions{Services: []string{serviceName}, Signal: "SIGTERM"})

0 commit comments

Comments
 (0)