Stop project on Ctrl+C

Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
This commit is contained in:
Ulysses Souza 2021-01-20 09:35:06 -03:00
parent ed67111b3d
commit 0529415fa7
10 changed files with 102 additions and 12 deletions

View File

@ -64,6 +64,10 @@ func (cs *aciComposeService) Start(ctx context.Context, project *types.Project,
return errdefs.ErrNotImplemented
}
func (cs *aciComposeService) Stop(ctx context.Context, project *types.Project, consumer compose.LogConsumer) error {
return errdefs.ErrNotImplemented
}
func (cs *aciComposeService) Up(ctx context.Context, project *types.Project, options compose.UpOptions) error {
logrus.Debugf("Up on project with name %q", project.Name)

View File

@ -48,6 +48,10 @@ func (c *composeService) Start(ctx context.Context, project *types.Project, cons
return errdefs.ErrNotImplemented
}
func (c *composeService) Stop(ctx context.Context, project *types.Project, consumer compose.LogConsumer) error {
return errdefs.ErrNotImplemented
}
func (c *composeService) Up(context.Context, *types.Project, compose.UpOptions) error {
return errdefs.ErrNotImplemented
}

View File

@ -35,6 +35,8 @@ type Service interface {
Create(ctx context.Context, project *types.Project, opts CreateOptions) error
// Start executes the equivalent to a `compose start`
Start(ctx context.Context, project *types.Project, consumer LogConsumer) error
// Stop executes the equivalent to a `compose stop`
Stop(ctx context.Context, project *types.Project, consumer LogConsumer) error
// Up executes the equivalent to a `compose up`
Up(ctx context.Context, project *types.Project, options UpOptions) error
// Down executes the equivalent to a `compose down`

View File

@ -78,11 +78,16 @@ func CreatedEvent(ID string) Event {
return NewEvent(ID, Done, "Created")
}
// StoppingEvent stops a new Removing in progress Event
// StoppingEvent stops a new Stopping in progress Event
func StoppingEvent(ID string) Event {
return NewEvent(ID, Working, "Stopping")
}
// StoppedEvent stops a new Stopping in progress Event
func StoppedEvent(ID string) Event {
return NewEvent(ID, Done, "Stopped")
}
// RemovingEvent creates a new Removing in progress Event
func RemovingEvent(ID string) Event {
return NewEvent(ID, Working, "Removing")

View File

@ -106,7 +106,7 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
fmt.Println("Gracefully stopping...")
ctx = context.Background()
_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
return "", c.ComposeService().Down(ctx, project.Name, compose.DownOptions{})
return "", c.ComposeService().Stop(ctx, project, consumer)
})
}
return err

View File

@ -57,6 +57,10 @@ func (e ecsLocalSimulation) Start(ctx context.Context, project *types.Project, c
return e.compose.Start(ctx, project, consumer)
}
func (e ecsLocalSimulation) Stop(ctx context.Context, project *types.Project, consumer compose.LogConsumer) error {
return e.compose.Stop(ctx, project, consumer)
}
func (e ecsLocalSimulation) Up(ctx context.Context, project *types.Project, options compose.UpOptions) error {
return errdefs.ErrNotImplemented
}

View File

@ -51,6 +51,10 @@ func (b *ecsAPIService) Start(ctx context.Context, project *types.Project, consu
return errdefs.ErrNotImplemented
}
func (b *ecsAPIService) Stop(ctx context.Context, project *types.Project, consumer compose.LogConsumer) error {
return errdefs.ErrNotImplemented
}
func (b *ecsAPIService) Up(ctx context.Context, project *types.Project, options compose.UpOptions) error {
logrus.Debugf("deploying on AWS with region=%q", b.Region)
err := b.aws.CheckRequirements(ctx, b.Region)

View File

@ -79,7 +79,10 @@ func (s *composeService) Create(ctx context.Context, project *types.Project, opt
if opts.RemoveOrphans {
eg, _ := errgroup.WithContext(ctx)
w := progress.ContextWriter(ctx)
s.removeContainers(ctx, w, eg, orphans)
err := s.removeContainers(ctx, w, eg, orphans)
if err != nil {
return err
}
if eg.Wait() != nil {
return err
}

View File

@ -55,13 +55,13 @@ func (s *composeService) Down(ctx context.Context, projectName string, options c
err = InReverseDependencyOrder(ctx, options.Project, func(c context.Context, service types.ServiceConfig) error {
serviceContainers, others := containers.split(isService(service.Name))
s.removeContainers(ctx, w, eg, serviceContainers)
err := s.removeContainers(ctx, w, eg, serviceContainers)
containers = others
return err
})
if options.RemoveOrphans {
s.removeContainers(ctx, w, eg, containers)
err := s.removeContainers(ctx, w, eg, containers)
if err != nil {
return err
}
@ -93,17 +93,27 @@ func (s *composeService) Down(ctx context.Context, projectName string, options c
return eg.Wait()
}
func (s *composeService) removeContainers(ctx context.Context, w progress.Writer, eg *errgroup.Group, containers []moby.Container) {
func (s *composeService) stopContainers(ctx context.Context, w progress.Writer, containers []moby.Container) error {
for _, container := range containers {
toStop := container
eventName := "Container " + getCanonicalContainerName(toStop)
w.Event(progress.StoppingEvent(eventName))
err := s.apiClient.ContainerStop(ctx, toStop.ID, nil)
if err != nil {
w.Event(progress.ErrorMessageEvent(eventName, "Error while Stopping"))
return err
}
w.Event(progress.StoppedEvent(eventName))
}
return nil
}
func (s *composeService) removeContainers(ctx context.Context, w progress.Writer, eg *errgroup.Group, containers []moby.Container) error {
for _, container := range containers {
toDelete := container
eg.Go(func() error {
eventName := "Container " + getCanonicalContainerName(toDelete)
w.Event(progress.StoppingEvent(eventName))
err := s.apiClient.ContainerStop(ctx, toDelete.ID, nil)
if err != nil {
w.Event(progress.ErrorMessageEvent(eventName, "Error while Stopping"))
return err
}
err := s.stopContainers(ctx, w, []moby.Container{container})
w.Event(progress.RemovingEvent(eventName))
err = s.apiClient.ContainerRemove(ctx, toDelete.ID, moby.ContainerRemoveOptions{Force: true})
if err != nil {
@ -114,6 +124,7 @@ func (s *composeService) removeContainers(ctx context.Context, w progress.Writer
return nil
})
}
return eg.Wait()
}
func (s *composeService) projectFromContainerLabels(ctx context.Context, projectName string) (*types.Project, error) {

53
local/compose/stop.go Normal file
View File

@ -0,0 +1,53 @@
/*
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"
moby "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/compose-cli/api/compose"
"github.com/docker/compose-cli/api/progress"
"github.com/compose-spec/compose-go/types"
"golang.org/x/sync/errgroup"
)
func (s *composeService) Stop(ctx context.Context, project *types.Project, consumer compose.LogConsumer) error {
eg, _ := errgroup.WithContext(ctx)
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
}
err = InReverseDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error {
serviceContainers, others := containers.split(isService(service.Name))
err := s.stopContainers(ctx, w, serviceContainers)
containers = others
return err
})
return eg.Wait()
}