mirror of https://github.com/docker/compose.git
Merge pull request #9764 from laurazard/apply-model-kill
Apply compose model on `compose kill`, add `--remove-orphans`
This commit is contained in:
commit
832eee0e8f
|
@ -18,15 +18,18 @@ package compose
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/docker/compose/v2/pkg/api"
|
"github.com/docker/compose/v2/pkg/api"
|
||||||
|
"github.com/docker/compose/v2/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type killOptions struct {
|
type killOptions struct {
|
||||||
*projectOptions
|
*projectOptions
|
||||||
signal string
|
removeOrphans bool
|
||||||
|
signal string
|
||||||
}
|
}
|
||||||
|
|
||||||
func killCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
func killCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||||
|
@ -43,20 +46,24 @@ func killCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
|
removeOrphans := utils.StringToBool(os.Getenv("COMPOSE_REMOVE_ORPHANS"))
|
||||||
|
flags.BoolVar(&opts.removeOrphans, "remove-orphans", removeOrphans, "Remove containers for services not defined in the Compose file.")
|
||||||
flags.StringVarP(&opts.signal, "signal", "s", "SIGKILL", "SIGNAL to send to the container.")
|
flags.StringVarP(&opts.signal, "signal", "s", "SIGKILL", "SIGNAL to send to the container.")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runKill(ctx context.Context, backend api.Service, opts killOptions, services []string) error {
|
func runKill(ctx context.Context, backend api.Service, opts killOptions, services []string) error {
|
||||||
name, err := opts.toProjectName()
|
project, name, err := opts.projectOrName()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return backend.Kill(ctx, name, api.KillOptions{
|
return backend.Kill(ctx, name, api.KillOptions{
|
||||||
Services: services,
|
RemoveOrphans: opts.removeOrphans,
|
||||||
Signal: opts.signal,
|
Project: project,
|
||||||
|
Services: services,
|
||||||
|
Signal: opts.signal,
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ Force stop service containers.
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
|
| `--remove-orphans` | | | Remove containers for services not defined in the Compose file. |
|
||||||
| `-s`, `--signal` | `string` | `SIGKILL` | SIGNAL to send to the container. |
|
| `-s`, `--signal` | `string` | `SIGKILL` | SIGNAL to send to the container. |
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,16 @@ usage: docker compose kill [OPTIONS] [SERVICE...]
|
||||||
pname: docker compose
|
pname: docker compose
|
||||||
plink: docker_compose.yaml
|
plink: docker_compose.yaml
|
||||||
options:
|
options:
|
||||||
|
- option: remove-orphans
|
||||||
|
value_type: bool
|
||||||
|
default_value: "false"
|
||||||
|
description: Remove containers for services not defined in the Compose file.
|
||||||
|
deprecated: false
|
||||||
|
hidden: false
|
||||||
|
experimental: false
|
||||||
|
experimentalcli: false
|
||||||
|
kubernetes: false
|
||||||
|
swarm: false
|
||||||
- option: signal
|
- option: signal
|
||||||
shorthand: s
|
shorthand: s
|
||||||
value_type: string
|
value_type: string
|
||||||
|
|
|
@ -197,6 +197,10 @@ type ImagesOptions struct {
|
||||||
|
|
||||||
// KillOptions group options of the Kill API
|
// KillOptions group options of the Kill API
|
||||||
type KillOptions struct {
|
type KillOptions struct {
|
||||||
|
// RemoveOrphans will cleanup containers that are not declared on the compose model but own the same labels
|
||||||
|
RemoveOrphans bool
|
||||||
|
// Project is the compose project used to define this app. Might be nil if user ran command just with project name
|
||||||
|
Project *types.Project
|
||||||
// Services passed in the command line to be killed
|
// Services passed in the command line to be killed
|
||||||
Services []string
|
Services []string
|
||||||
// Signal to send to containers
|
// Signal to send to containers
|
||||||
|
|
|
@ -45,6 +45,17 @@ func (s *composeService) kill(ctx context.Context, projectName string, options a
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
project := options.Project
|
||||||
|
if project == nil {
|
||||||
|
project, err = s.getProjectWithResources(ctx, containers, projectName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !options.RemoveOrphans {
|
||||||
|
containers = containers.filter(isService(project.ServiceNames()...))
|
||||||
|
}
|
||||||
if len(containers) == 0 {
|
if len(containers) == 0 {
|
||||||
fmt.Fprintf(s.stderr(), "no container to kill")
|
fmt.Fprintf(s.stderr(), "no container to kill")
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
|
|
||||||
moby "github.com/docker/docker/api/types"
|
moby "github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
"github.com/docker/docker/api/types/volume"
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
|
|
||||||
|
@ -52,6 +53,12 @@ func TestKillAll(t *testing.T) {
|
||||||
Filters: filters.NewArgs(projectFilter(name)),
|
Filters: filters.NewArgs(projectFilter(name)),
|
||||||
}).Return(
|
}).Return(
|
||||||
[]moby.Container{testContainer("service1", "123", false), testContainer("service1", "456", false), testContainer("service2", "789", false)}, nil)
|
[]moby.Container{testContainer("service1", "123", false), testContainer("service1", "456", false), testContainer("service2", "789", false)}, nil)
|
||||||
|
api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))).
|
||||||
|
Return(volume.VolumeListOKBody{}, nil)
|
||||||
|
api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).
|
||||||
|
Return([]moby.NetworkResource{
|
||||||
|
{ID: "abc123", Name: "testProject_default"},
|
||||||
|
}, nil)
|
||||||
api.EXPECT().ContainerKill(anyCancellableContext(), "123", "").Return(nil)
|
api.EXPECT().ContainerKill(anyCancellableContext(), "123", "").Return(nil)
|
||||||
api.EXPECT().ContainerKill(anyCancellableContext(), "456", "").Return(nil)
|
api.EXPECT().ContainerKill(anyCancellableContext(), "456", "").Return(nil)
|
||||||
api.EXPECT().ContainerKill(anyCancellableContext(), "789", "").Return(nil)
|
api.EXPECT().ContainerKill(anyCancellableContext(), "789", "").Return(nil)
|
||||||
|
@ -77,6 +84,12 @@ func TestKillSignal(t *testing.T) {
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
api.EXPECT().ContainerList(ctx, listOptions).Return([]moby.Container{testContainer(serviceName, "123", false)}, nil)
|
api.EXPECT().ContainerList(ctx, listOptions).Return([]moby.Container{testContainer(serviceName, "123", false)}, nil)
|
||||||
|
api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))).
|
||||||
|
Return(volume.VolumeListOKBody{}, nil)
|
||||||
|
api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).
|
||||||
|
Return([]moby.NetworkResource{
|
||||||
|
{ID: "abc123", Name: "testProject_default"},
|
||||||
|
}, nil)
|
||||||
api.EXPECT().ContainerKill(anyCancellableContext(), "123", "SIGTERM").Return(nil)
|
api.EXPECT().ContainerKill(anyCancellableContext(), "123", "SIGTERM").Return(nil)
|
||||||
|
|
||||||
err := tested.kill(ctx, name, compose.KillOptions{Services: []string{serviceName}, Signal: "SIGTERM"})
|
err := tested.kill(ctx, name, compose.KillOptions{Services: []string{serviceName}, Signal: "SIGTERM"})
|
||||||
|
|
Loading…
Reference in New Issue