kill only need project name

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2022-03-14 08:16:26 +01:00
parent 6ce57ea2f4
commit cd8074d501
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
6 changed files with 42 additions and 31 deletions

View File

@ -19,25 +19,44 @@ package compose
import ( import (
"context" "context"
"github.com/compose-spec/compose-go/types"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/api"
) )
type killOptions struct {
*projectOptions
signal string
}
func killCommand(p *projectOptions, backend api.Service) *cobra.Command { func killCommand(p *projectOptions, backend api.Service) *cobra.Command {
var opts api.KillOptions opts := killOptions{
projectOptions: p,
}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "kill [options] [SERVICE...]", Use: "kill [options] [SERVICE...]",
Short: "Force stop service containers.", Short: "Force stop service containers.",
RunE: p.WithProject(func(ctx context.Context, project *types.Project) error { RunE: Adapt(func(ctx context.Context, args []string) error {
return backend.Kill(ctx, project, opts) return runKill(ctx, backend, opts, args)
}), }),
ValidArgsFunction: serviceCompletion(p), ValidArgsFunction: serviceCompletion(p),
} }
flags := cmd.Flags() flags := cmd.Flags()
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 {
projectName, err := opts.toProjectName()
if err != nil {
return err
}
return backend.Kill(ctx, projectName, api.KillOptions{
Services: services,
Signal: opts.signal,
})
}

View File

@ -54,7 +54,7 @@ type Service interface {
// Convert translate compose model into backend's native format // Convert translate compose model into backend's native format
Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error)
// Kill executes the equivalent to a `compose kill` // Kill executes the equivalent to a `compose kill`
Kill(ctx context.Context, project *types.Project, options KillOptions) error Kill(ctx context.Context, project string, options KillOptions) error
// RunOneOffContainer creates a service oneoff container and starts its dependencies // RunOneOffContainer creates a service oneoff container and starts its dependencies
RunOneOffContainer(ctx context.Context, project *types.Project, opts RunOptions) (int, error) RunOneOffContainer(ctx context.Context, project *types.Project, opts RunOptions) (int, error)
// Remove executes the equivalent to a `compose rm` // Remove executes the equivalent to a `compose rm`

View File

@ -37,7 +37,7 @@ type ServiceProxy struct {
PsFn func(ctx context.Context, projectName string, options PsOptions) ([]ContainerSummary, error) PsFn func(ctx context.Context, projectName string, options PsOptions) ([]ContainerSummary, error)
ListFn func(ctx context.Context, options ListOptions) ([]Stack, error) ListFn func(ctx context.Context, options ListOptions) ([]Stack, error)
ConvertFn func(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) ConvertFn func(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error)
KillFn func(ctx context.Context, project *types.Project, options KillOptions) error KillFn func(ctx context.Context, project string, options KillOptions) error
RunOneOffContainerFn func(ctx context.Context, project *types.Project, opts RunOptions) (int, error) RunOneOffContainerFn func(ctx context.Context, project *types.Project, opts RunOptions) (int, error)
RemoveFn func(ctx context.Context, project string, options RemoveOptions) error RemoveFn func(ctx context.Context, project string, options RemoveOptions) error
ExecFn func(ctx context.Context, project string, opts RunOptions) (int, error) ExecFn func(ctx context.Context, project string, opts RunOptions) (int, error)
@ -219,13 +219,10 @@ func (s *ServiceProxy) Convert(ctx context.Context, project *types.Project, opti
} }
// Kill implements Service interface // Kill implements Service interface
func (s *ServiceProxy) Kill(ctx context.Context, project *types.Project, options KillOptions) error { func (s *ServiceProxy) Kill(ctx context.Context, project string, options KillOptions) error {
if s.KillFn == nil { if s.KillFn == nil {
return ErrNotImplemented return ErrNotImplemented
} }
for _, i := range s.interceptors {
i(ctx, project)
}
return s.KillFn(ctx, project, options) return s.KillFn(ctx, project, options)
} }

View File

@ -18,8 +18,8 @@ package compose
import ( import (
"context" "context"
"fmt"
"github.com/compose-spec/compose-go/types"
moby "github.com/docker/docker/api/types" moby "github.com/docker/docker/api/types"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
@ -27,29 +27,29 @@ import (
"github.com/docker/compose/v2/pkg/progress" "github.com/docker/compose/v2/pkg/progress"
) )
func (s *composeService) Kill(ctx context.Context, project *types.Project, options api.KillOptions) error { func (s *composeService) Kill(ctx context.Context, project string, options api.KillOptions) error {
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
return s.kill(ctx, project, options) return s.kill(ctx, project, options)
}) })
} }
func (s *composeService) kill(ctx context.Context, project *types.Project, options api.KillOptions) error { func (s *composeService) kill(ctx context.Context, project string, options api.KillOptions) error {
w := progress.ContextWriter(ctx) w := progress.ContextWriter(ctx)
services := options.Services services := options.Services
if len(services) == 0 {
services = project.ServiceNames()
}
var containers Containers var containers Containers
containers, err := s.getContainers(ctx, project.Name, oneOffInclude, false, services...) containers, err := s.getContainers(ctx, project, oneOffInclude, false, services...)
if err != nil { if err != nil {
return err return err
} }
if len(containers) == 0 {
fmt.Fprintf(s.stderr(), "no container to kill")
}
eg, ctx := errgroup.WithContext(ctx) eg, ctx := errgroup.WithContext(ctx)
containers. containers.
filter(isService(project.ServiceNames()...)).
forEach(func(container moby.Container) { forEach(func(container moby.Container) {
eg.Go(func() error { eg.Go(func() error {
eventName := getContainerProgressName(container) eventName := getContainerProgressName(container)

View File

@ -22,7 +22,6 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/compose-spec/compose-go/types"
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/golang/mock/gomock" "github.com/golang/mock/gomock"
@ -45,18 +44,18 @@ func TestKillAll(t *testing.T) {
tested.dockerCli = cli tested.dockerCli = cli
cli.EXPECT().Client().Return(api).AnyTimes() cli.EXPECT().Client().Return(api).AnyTimes()
project := types.Project{Name: strings.ToLower(testProject), Services: []types.ServiceConfig{testService("service1"), testService("service2")}} name := strings.ToLower(testProject)
ctx := context.Background() ctx := context.Background()
api.EXPECT().ContainerList(ctx, moby.ContainerListOptions{ api.EXPECT().ContainerList(ctx, moby.ContainerListOptions{
Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject))), 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().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)
err := tested.kill(ctx, &project, compose.KillOptions{}) err := tested.kill(ctx, name, compose.KillOptions{})
assert.NilError(t, err) assert.NilError(t, err)
} }
@ -70,23 +69,19 @@ func TestKillSignal(t *testing.T) {
tested.dockerCli = cli tested.dockerCli = cli
cli.EXPECT().Client().Return(api).AnyTimes() cli.EXPECT().Client().Return(api).AnyTimes()
project := types.Project{Name: strings.ToLower(testProject), Services: []types.ServiceConfig{testService(serviceName)}} name := strings.ToLower(testProject)
listOptions := moby.ContainerListOptions{ listOptions := moby.ContainerListOptions{
Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)), serviceFilter(serviceName)), Filters: filters.NewArgs(projectFilter(name), serviceFilter(serviceName)),
} }
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().ContainerKill(anyCancellableContext(), "123", "SIGTERM").Return(nil) api.EXPECT().ContainerKill(anyCancellableContext(), "123", "SIGTERM").Return(nil)
err := tested.kill(ctx, &project, compose.KillOptions{Services: []string{serviceName}, Signal: "SIGTERM"}) err := tested.kill(ctx, name, compose.KillOptions{Services: []string{serviceName}, Signal: "SIGTERM"})
assert.NilError(t, err) assert.NilError(t, err)
} }
func testService(name string) types.ServiceConfig {
return types.ServiceConfig{Name: name}
}
func testContainer(service string, id string, oneOff bool) moby.Container { func testContainer(service string, id string, oneOff bool) moby.Container {
return moby.Container{ return moby.Container{
ID: id, ID: id,

View File

@ -60,7 +60,7 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
return progress.Run(ctx, func(ctx context.Context) error { return progress.Run(ctx, func(ctx context.Context) error {
go func() { go func() {
<-signalChan <-signalChan
s.Kill(ctx, project, api.KillOptions{ // nolint:errcheck s.Kill(ctx, project.Name, api.KillOptions{ // nolint:errcheck
Services: options.Create.Services, Services: options.Create.Services,
}) })
}() }()