mirror of https://github.com/docker/compose.git
				
				
				
			Add kill command
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
		
							parent
							
								
									4d3d7c11ca
								
							
						
					
					
						commit
						0aa3f4a189
					
				|  | @ -203,6 +203,10 @@ func (cs *aciComposeService) Convert(ctx context.Context, project *types.Project | |||
| 	return nil, errdefs.ErrNotImplemented | ||||
| } | ||||
| 
 | ||||
| func (cs *aciComposeService) Kill(ctx context.Context, project *types.Project, options compose.KillOptions) error { | ||||
| 	return errdefs.ErrNotImplemented | ||||
| } | ||||
| 
 | ||||
| func (cs *aciComposeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) error { | ||||
| 	return errdefs.ErrNotImplemented | ||||
| } | ||||
|  |  | |||
|  | @ -76,6 +76,10 @@ func (c *composeService) Convert(context.Context, *types.Project, compose.Conver | |||
| 	return nil, errdefs.ErrNotImplemented | ||||
| } | ||||
| 
 | ||||
| func (c *composeService) Kill(ctx context.Context, project *types.Project, options compose.KillOptions) error { | ||||
| 	return errdefs.ErrNotImplemented | ||||
| } | ||||
| 
 | ||||
| func (c *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) error { | ||||
| 	return errdefs.ErrNotImplemented | ||||
| } | ||||
|  |  | |||
|  | @ -49,6 +49,8 @@ type Service interface { | |||
| 	List(ctx context.Context) ([]Stack, error) | ||||
| 	// Convert translate compose model into backend's native format
 | ||||
| 	Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) | ||||
| 	// Kill executes the equivalent to a `compose kill`
 | ||||
| 	Kill(ctx context.Context, project *types.Project, options KillOptions) error | ||||
| 	// RunOneOffContainer creates a service oneoff container and starts its dependencies
 | ||||
| 	RunOneOffContainer(ctx context.Context, project *types.Project, opts RunOptions) error | ||||
| } | ||||
|  | @ -81,6 +83,12 @@ type ConvertOptions struct { | |||
| 	Format string | ||||
| } | ||||
| 
 | ||||
| // KillOptions group options of the Kill API
 | ||||
| type KillOptions struct { | ||||
| 	// Signal to send to containers
 | ||||
| 	Signal string | ||||
| } | ||||
| 
 | ||||
| // RunOptions options to execute compose run
 | ||||
| type RunOptions struct { | ||||
| 	Service    string | ||||
|  |  | |||
|  | @ -78,16 +78,26 @@ func CreatedEvent(ID string) Event { | |||
| 	return NewEvent(ID, Done, "Created") | ||||
| } | ||||
| 
 | ||||
| // StoppingEvent stops a new Stopping in progress Event
 | ||||
| // StoppingEvent creates a new Stopping in progress Event
 | ||||
| func StoppingEvent(ID string) Event { | ||||
| 	return NewEvent(ID, Working, "Stopping") | ||||
| } | ||||
| 
 | ||||
| // StoppedEvent stops a new Stopping in progress Event
 | ||||
| // StoppedEvent creates a new Stopping in progress Event
 | ||||
| func StoppedEvent(ID string) Event { | ||||
| 	return NewEvent(ID, Done, "Stopped") | ||||
| } | ||||
| 
 | ||||
| // KillingEvent creates a new Killing in progress Event
 | ||||
| func KillingEvent(ID string) Event { | ||||
| 	return NewEvent(ID, Working, "Killing") | ||||
| } | ||||
| 
 | ||||
| // KilledEvent creates a new Killed in progress Event
 | ||||
| func KilledEvent(ID string) Event { | ||||
| 	return NewEvent(ID, Done, "Killed") | ||||
| } | ||||
| 
 | ||||
| // RemovingEvent creates a new Removing in progress Event
 | ||||
| func RemovingEvent(ID string) Event { | ||||
| 	return NewEvent(ID, Working, "Removing") | ||||
|  |  | |||
|  | @ -113,6 +113,7 @@ func Command(contextType string) *cobra.Command { | |||
| 		listCommand(), | ||||
| 		logsCommand(&opts, contextType), | ||||
| 		convertCommand(&opts), | ||||
| 		killCommand(&opts), | ||||
| 		runCommand(&opts), | ||||
| 	) | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,63 @@ | |||
| /* | ||||
|    Copyright 2020 Docker Compose CLI authors | ||||
| 
 | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
| 
 | ||||
|        http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| package compose | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 
 | ||||
| 	"github.com/spf13/cobra" | ||||
| 
 | ||||
| 	"github.com/docker/compose-cli/api/client" | ||||
| 	"github.com/docker/compose-cli/api/compose" | ||||
| ) | ||||
| 
 | ||||
| type killOptions struct { | ||||
| 	*projectOptions | ||||
| 	Signal string | ||||
| } | ||||
| 
 | ||||
| func killCommand(p *projectOptions) *cobra.Command { | ||||
| 	opts := killOptions{ | ||||
| 		projectOptions: p, | ||||
| 	} | ||||
| 	cmd := &cobra.Command{ | ||||
| 		Use:   "kill [options] [SERVICE...]", | ||||
| 		Short: "Force stop service containers.", | ||||
| 		RunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			return runKill(cmd.Context(), opts, args) | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	flags := cmd.Flags() | ||||
| 	flags.StringVarP(&opts.Signal, "signal", "s", "SIGKILL", "SIGNAL to send to the container.") | ||||
| 
 | ||||
| 	return cmd | ||||
| } | ||||
| 
 | ||||
| func runKill(ctx context.Context, opts killOptions, services []string) error { | ||||
| 	c, err := client.NewWithDefaultLocalBackend(ctx) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	project, err := opts.toProject(services) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return c.ComposeService().Kill(ctx, project, compose.KillOptions{ | ||||
| 		Signal: opts.Signal, | ||||
| 	}) | ||||
| } | ||||
|  | @ -25,6 +25,7 @@ import ( | |||
| 
 | ||||
| 	"github.com/docker/compose-cli/api/compose" | ||||
| 	"github.com/docker/compose-cli/api/config" | ||||
| 	"github.com/docker/compose-cli/api/errdefs" | ||||
| 
 | ||||
| 	ecsapi "github.com/aws/aws-sdk-go/service/ecs" | ||||
| 	"github.com/aws/aws-sdk-go/service/elbv2" | ||||
|  | @ -46,6 +47,10 @@ import ( | |||
| 	"sigs.k8s.io/kustomize/kyaml/yaml/merge2" | ||||
| ) | ||||
| 
 | ||||
| func (b *ecsAPIService) Kill(ctx context.Context, project *types.Project, options compose.KillOptions) error { | ||||
| 	return errdefs.ErrNotImplemented | ||||
| } | ||||
| 
 | ||||
| func (b *ecsAPIService) Convert(ctx context.Context, project *types.Project, options compose.ConvertOptions) ([]byte, error) { | ||||
| 	err := b.resolveServiceImagesDigests(ctx, project) | ||||
| 	if err != nil { | ||||
|  |  | |||
|  | @ -65,6 +65,10 @@ func (e ecsLocalSimulation) Up(ctx context.Context, project *types.Project, opti | |||
| 	return errdefs.ErrNotImplemented | ||||
| } | ||||
| 
 | ||||
| func (e ecsLocalSimulation) Kill(ctx context.Context, project *types.Project, options compose.KillOptions) error { | ||||
| 	return e.compose.Kill(ctx, project, options) | ||||
| } | ||||
| 
 | ||||
| func (e ecsLocalSimulation) Convert(ctx context.Context, project *types.Project, options compose.ConvertOptions) ([]byte, error) { | ||||
| 	enhanced, err := e.enhanceForLocalSimulation(project) | ||||
| 	if err != nil { | ||||
|  |  | |||
|  | @ -103,6 +103,10 @@ func (s *composeService) Convert(ctx context.Context, project *types.Project, op | |||
| 	return nil, errdefs.ErrNotImplemented | ||||
| } | ||||
| 
 | ||||
| func (s *composeService) Kill(ctx context.Context, project *types.Project, options compose.KillOptions) error { | ||||
| 	return errdefs.ErrNotImplemented | ||||
| } | ||||
| 
 | ||||
| // RunOneOffContainer creates a service oneoff container and starts its dependencies
 | ||||
| func (s *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) error { | ||||
| 	return errdefs.ErrNotImplemented | ||||
|  |  | |||
|  | @ -70,3 +70,9 @@ func (containers Containers) names() []string { | |||
| 	} | ||||
| 	return names | ||||
| } | ||||
| 
 | ||||
| func (containers Containers) forEach(fn func(moby.Container)) { | ||||
| 	for _, c := range containers { | ||||
| 		fn(c) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,60 @@ | |||
| /* | ||||
|    Copyright 2020 Docker Compose CLI authors | ||||
| 
 | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
| 
 | ||||
|        http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| package compose | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 
 | ||||
| 	"github.com/compose-spec/compose-go/types" | ||||
| 	moby "github.com/docker/docker/api/types" | ||||
| 	"github.com/docker/docker/api/types/filters" | ||||
| 	"golang.org/x/sync/errgroup" | ||||
| 
 | ||||
| 	"github.com/docker/compose-cli/api/compose" | ||||
| 	"github.com/docker/compose-cli/api/progress" | ||||
| ) | ||||
| 
 | ||||
| func (s *composeService) Kill(ctx context.Context, project *types.Project, options compose.KillOptions) error { | ||||
| 	w := progress.ContextWriter(ctx) | ||||
| 
 | ||||
| 	var containers Containers | ||||
| 	containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ | ||||
| 		Filters: filters.NewArgs(projectFilter(project.Name)), | ||||
| 		All:     true, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	eg, ctx := errgroup.WithContext(ctx) | ||||
| 	containers. | ||||
| 		filter(isService(project.ServiceNames()...)). | ||||
| 		forEach(func(container moby.Container) { | ||||
| 			eg.Go(func() error { | ||||
| 				eventName := getContainerProgressName(container) | ||||
| 				w.Event(progress.KillingEvent(eventName)) | ||||
| 				err := s.apiClient.ContainerKill(ctx, container.ID, options.Signal) | ||||
| 				if err != nil { | ||||
| 					w.Event(progress.ErrorMessageEvent(eventName, "Error while Killing")) | ||||
| 					return err | ||||
| 				} | ||||
| 				w.Event(progress.KilledEvent(eventName)) | ||||
| 				return nil | ||||
| 			}) | ||||
| 		}) | ||||
| 	return eg.Wait() | ||||
| } | ||||
|  | @ -38,6 +38,8 @@ func (s *composeService) Stop(ctx context.Context, project *types.Project) error | |||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	containers = containers.filter(isService(project.ServiceNames()...)) | ||||
| 
 | ||||
| 	return InReverseDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error { | ||||
| 		return s.stopContainers(ctx, w, containers.filter(isService(service.Name))) | ||||
| 	}) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue