瀏覽代碼

Merge pull request #9764 from laurazard/apply-model-kill

Apply compose model on `compose kill`, add `--remove-orphans`
Laura Brehm 3 年之前
父節點
當前提交
832eee0e8f
共有 6 個文件被更改,包括 50 次插入4 次删除
  1. 11 4
      cmd/compose/kill.go
  2. 1 0
      docs/reference/compose_kill.md
  3. 10 0
      docs/reference/docker_compose_kill.yaml
  4. 4 0
      pkg/api/api.go
  5. 11 0
      pkg/compose/kill.go
  6. 13 0
      pkg/compose/kill_test.go

+ 11 - 4
cmd/compose/kill.go

@@ -18,15 +18,18 @@ package compose
 
 import (
 	"context"
+	"os"
 
 	"github.com/spf13/cobra"
 
 	"github.com/docker/compose/v2/pkg/api"
+	"github.com/docker/compose/v2/pkg/utils"
 )
 
 type killOptions struct {
 	*projectOptions
-	signal string
+	removeOrphans bool
+	signal        string
 }
 
 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()
+	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.")
 
 	return cmd
 }
 
 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 {
 		return err
 	}
 
 	return backend.Kill(ctx, name, api.KillOptions{
-		Services: services,
-		Signal:   opts.signal,
+		RemoveOrphans: opts.removeOrphans,
+		Project:       project,
+		Services:      services,
+		Signal:        opts.signal,
 	})
 
 }

+ 1 - 0
docs/reference/compose_kill.md

@@ -7,6 +7,7 @@ Force stop service containers.
 
 | 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. |
 
 

+ 10 - 0
docs/reference/docker_compose_kill.yaml

@@ -10,6 +10,16 @@ usage: docker compose kill [OPTIONS] [SERVICE...]
 pname: docker compose
 plink: docker_compose.yaml
 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
       shorthand: s
       value_type: string

+ 4 - 0
pkg/api/api.go

@@ -197,6 +197,10 @@ type ImagesOptions struct {
 
 // KillOptions group options of the Kill API
 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 []string
 	// Signal to send to containers

+ 11 - 0
pkg/compose/kill.go

@@ -45,6 +45,17 @@ func (s *composeService) kill(ctx context.Context, projectName string, options a
 		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 {
 		fmt.Fprintf(s.stderr(), "no container to kill")
 	}

+ 13 - 0
pkg/compose/kill_test.go

@@ -25,6 +25,7 @@ import (
 
 	moby "github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/filters"
+	"github.com/docker/docker/api/types/volume"
 	"github.com/golang/mock/gomock"
 	"gotest.tools/v3/assert"
 
@@ -52,6 +53,12 @@ func TestKillAll(t *testing.T) {
 		Filters: filters.NewArgs(projectFilter(name)),
 	}).Return(
 		[]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(), "456", "").Return(nil)
 	api.EXPECT().ContainerKill(anyCancellableContext(), "789", "").Return(nil)
@@ -77,6 +84,12 @@ func TestKillSignal(t *testing.T) {
 
 	ctx := context.Background()
 	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)
 
 	err := tested.kill(ctx, name, compose.KillOptions{Services: []string{serviceName}, Signal: "SIGTERM"})