Skip to content
This repository was archived by the owner on Nov 27, 2023. It is now read-only.

Commit 3f47414

Browse files
authored
Merge pull request #1163 from docker/stop-on-ctrlc
Stop project on Ctrl+C
2 parents d53d437 + 0529415 commit 3f47414

File tree

10 files changed

+102
-12
lines changed

10 files changed

+102
-12
lines changed

aci/compose.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ func (cs *aciComposeService) Start(ctx context.Context, project *types.Project,
6464
return errdefs.ErrNotImplemented
6565
}
6666

67+
func (cs *aciComposeService) Stop(ctx context.Context, project *types.Project, consumer compose.LogConsumer) error {
68+
return errdefs.ErrNotImplemented
69+
}
70+
6771
func (cs *aciComposeService) Up(ctx context.Context, project *types.Project, options compose.UpOptions) error {
6872
logrus.Debugf("Up on project with name %q", project.Name)
6973

api/client/compose.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ func (c *composeService) Start(ctx context.Context, project *types.Project, cons
4848
return errdefs.ErrNotImplemented
4949
}
5050

51+
func (c *composeService) Stop(ctx context.Context, project *types.Project, consumer compose.LogConsumer) error {
52+
return errdefs.ErrNotImplemented
53+
}
54+
5155
func (c *composeService) Up(context.Context, *types.Project, compose.UpOptions) error {
5256
return errdefs.ErrNotImplemented
5357
}

api/compose/api.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ type Service interface {
3535
Create(ctx context.Context, project *types.Project, opts CreateOptions) error
3636
// Start executes the equivalent to a `compose start`
3737
Start(ctx context.Context, project *types.Project, consumer LogConsumer) error
38+
// Stop executes the equivalent to a `compose stop`
39+
Stop(ctx context.Context, project *types.Project, consumer LogConsumer) error
3840
// Up executes the equivalent to a `compose up`
3941
Up(ctx context.Context, project *types.Project, options UpOptions) error
4042
// Down executes the equivalent to a `compose down`

api/progress/event.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,16 @@ func CreatedEvent(ID string) Event {
7878
return NewEvent(ID, Done, "Created")
7979
}
8080

81-
// StoppingEvent stops a new Removing in progress Event
81+
// StoppingEvent stops a new Stopping in progress Event
8282
func StoppingEvent(ID string) Event {
8383
return NewEvent(ID, Working, "Stopping")
8484
}
8585

86+
// StoppedEvent stops a new Stopping in progress Event
87+
func StoppedEvent(ID string) Event {
88+
return NewEvent(ID, Done, "Stopped")
89+
}
90+
8691
// RemovingEvent creates a new Removing in progress Event
8792
func RemovingEvent(ID string) Event {
8893
return NewEvent(ID, Working, "Removing")

cli/cmd/compose/up.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
117117
fmt.Println("Gracefully stopping...")
118118
ctx = context.Background()
119119
_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
120-
return "", c.ComposeService().Down(ctx, project.Name, compose.DownOptions{})
120+
return "", c.ComposeService().Stop(ctx, project, consumer)
121121
})
122122
}
123123
return err

ecs/local/compose.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ func (e ecsLocalSimulation) Start(ctx context.Context, project *types.Project, c
5757
return e.compose.Start(ctx, project, consumer)
5858
}
5959

60+
func (e ecsLocalSimulation) Stop(ctx context.Context, project *types.Project, consumer compose.LogConsumer) error {
61+
return e.compose.Stop(ctx, project, consumer)
62+
}
63+
6064
func (e ecsLocalSimulation) Up(ctx context.Context, project *types.Project, options compose.UpOptions) error {
6165
return errdefs.ErrNotImplemented
6266
}

ecs/up.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ func (b *ecsAPIService) Start(ctx context.Context, project *types.Project, consu
5151
return errdefs.ErrNotImplemented
5252
}
5353

54+
func (b *ecsAPIService) Stop(ctx context.Context, project *types.Project, consumer compose.LogConsumer) error {
55+
return errdefs.ErrNotImplemented
56+
}
57+
5458
func (b *ecsAPIService) Up(ctx context.Context, project *types.Project, options compose.UpOptions) error {
5559
logrus.Debugf("deploying on AWS with region=%q", b.Region)
5660
err := b.aws.CheckRequirements(ctx, b.Region)

local/compose/create.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ func (s *composeService) Create(ctx context.Context, project *types.Project, opt
7979
if opts.RemoveOrphans {
8080
eg, _ := errgroup.WithContext(ctx)
8181
w := progress.ContextWriter(ctx)
82-
s.removeContainers(ctx, w, eg, orphans)
82+
err := s.removeContainers(ctx, w, eg, orphans)
83+
if err != nil {
84+
return err
85+
}
8386
if eg.Wait() != nil {
8487
return err
8588
}

local/compose/down.go

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,13 @@ func (s *composeService) Down(ctx context.Context, projectName string, options c
5555

5656
err = InReverseDependencyOrder(ctx, options.Project, func(c context.Context, service types.ServiceConfig) error {
5757
serviceContainers, others := containers.split(isService(service.Name))
58-
s.removeContainers(ctx, w, eg, serviceContainers)
58+
err := s.removeContainers(ctx, w, eg, serviceContainers)
5959
containers = others
6060
return err
6161
})
6262

6363
if options.RemoveOrphans {
64-
s.removeContainers(ctx, w, eg, containers)
64+
err := s.removeContainers(ctx, w, eg, containers)
6565
if err != nil {
6666
return err
6767
}
@@ -93,17 +93,27 @@ func (s *composeService) Down(ctx context.Context, projectName string, options c
9393
return eg.Wait()
9494
}
9595

96-
func (s *composeService) removeContainers(ctx context.Context, w progress.Writer, eg *errgroup.Group, containers []moby.Container) {
96+
func (s *composeService) stopContainers(ctx context.Context, w progress.Writer, containers []moby.Container) error {
97+
for _, container := range containers {
98+
toStop := container
99+
eventName := "Container " + getCanonicalContainerName(toStop)
100+
w.Event(progress.StoppingEvent(eventName))
101+
err := s.apiClient.ContainerStop(ctx, toStop.ID, nil)
102+
if err != nil {
103+
w.Event(progress.ErrorMessageEvent(eventName, "Error while Stopping"))
104+
return err
105+
}
106+
w.Event(progress.StoppedEvent(eventName))
107+
}
108+
return nil
109+
}
110+
111+
func (s *composeService) removeContainers(ctx context.Context, w progress.Writer, eg *errgroup.Group, containers []moby.Container) error {
97112
for _, container := range containers {
98113
toDelete := container
99114
eg.Go(func() error {
100115
eventName := "Container " + getCanonicalContainerName(toDelete)
101-
w.Event(progress.StoppingEvent(eventName))
102-
err := s.apiClient.ContainerStop(ctx, toDelete.ID, nil)
103-
if err != nil {
104-
w.Event(progress.ErrorMessageEvent(eventName, "Error while Stopping"))
105-
return err
106-
}
116+
err := s.stopContainers(ctx, w, []moby.Container{container})
107117
w.Event(progress.RemovingEvent(eventName))
108118
err = s.apiClient.ContainerRemove(ctx, toDelete.ID, moby.ContainerRemoveOptions{Force: true})
109119
if err != nil {
@@ -114,6 +124,7 @@ func (s *composeService) removeContainers(ctx context.Context, w progress.Writer
114124
return nil
115125
})
116126
}
127+
return eg.Wait()
117128
}
118129

119130
func (s *composeService) projectFromContainerLabels(ctx context.Context, projectName string) (*types.Project, error) {

local/compose/stop.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
Copyright 2020 Docker Compose CLI authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package compose
18+
19+
import (
20+
"context"
21+
22+
moby "github.com/docker/docker/api/types"
23+
"github.com/docker/docker/api/types/filters"
24+
25+
"github.com/docker/compose-cli/api/compose"
26+
"github.com/docker/compose-cli/api/progress"
27+
28+
"github.com/compose-spec/compose-go/types"
29+
"golang.org/x/sync/errgroup"
30+
)
31+
32+
func (s *composeService) Stop(ctx context.Context, project *types.Project, consumer compose.LogConsumer) error {
33+
eg, _ := errgroup.WithContext(ctx)
34+
w := progress.ContextWriter(ctx)
35+
36+
var containers Containers
37+
containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{
38+
Filters: filters.NewArgs(projectFilter(project.Name)),
39+
All: true,
40+
})
41+
if err != nil {
42+
return err
43+
}
44+
45+
err = InReverseDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error {
46+
serviceContainers, others := containers.split(isService(service.Name))
47+
err := s.stopContainers(ctx, w, serviceContainers)
48+
containers = others
49+
return err
50+
})
51+
52+
return eg.Wait()
53+
}

0 commit comments

Comments
 (0)