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

Commit f3d093c

Browse files
committed
introduce cascade stop "--abort-on-container-exit" option
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
1 parent 7a7114f commit f3d093c

File tree

8 files changed

+56
-13
lines changed

8 files changed

+56
-13
lines changed

api/compose/api.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ type CreateOptions struct {
6767
type StartOptions struct {
6868
// Attach will attach to container and pipe stdout/stderr to LogConsumer
6969
Attach LogConsumer
70-
// CascadeStop will run `Stop` on any container exit
71-
CascadeStop bool
70+
// Listener will get notified on container events
71+
Listener Listener
7272
}
7373

7474
// UpOptions group options of the Up API
@@ -185,5 +185,14 @@ type Stack struct {
185185
// LogConsumer is a callback to process log messages from services
186186
type LogConsumer interface {
187187
Log(service, container, message string)
188-
Exit(service, container string, exitCode int)
188+
Status(service, container, message string)
189+
}
190+
191+
// Listener get notified on container Events
192+
type Listener chan Event
193+
194+
// Event let us know a Container exited
195+
type Event struct {
196+
Service string
197+
Status int
189198
}

cli/cmd/compose/start.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ package compose
1818

1919
import (
2020
"context"
21-
"github.com/docker/compose-cli/api/compose"
2221
"os"
2322

2423
"github.com/spf13/cobra"
2524

2625
"github.com/docker/compose-cli/api/client"
26+
"github.com/docker/compose-cli/api/compose"
2727
"github.com/docker/compose-cli/api/progress"
2828
"github.com/docker/compose-cli/cli/formatter"
2929
)

cli/cmd/compose/up.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ type upOptions struct {
4949
forceRecreate bool
5050
noRecreate bool
5151
noStart bool
52+
cascadeStop bool
5253
}
5354

5455
func (o upOptions) recreateStrategy() string {
@@ -73,6 +74,9 @@ func upCommand(p *projectOptions, contextType string) *cobra.Command {
7374
RunE: func(cmd *cobra.Command, args []string) error {
7475
switch contextType {
7576
case store.LocalContextType, store.DefaultContextType, store.EcsLocalSimulationContextType:
77+
if opts.cascadeStop && opts.Detach {
78+
return fmt.Errorf("--abort-on-container-exit and --detach are incompatible")
79+
}
7680
if opts.forceRecreate && opts.noRecreate {
7781
return fmt.Errorf("--force-recreate and --no-recreate are incompatible")
7882
}
@@ -95,6 +99,7 @@ func upCommand(p *projectOptions, contextType string) *cobra.Command {
9599
flags.BoolVar(&opts.forceRecreate, "force-recreate", false, "Recreate containers even if their configuration and image haven't changed.")
96100
flags.BoolVar(&opts.noRecreate, "no-recreate", false, "If containers already exist, don't recreate them. Incompatible with --force-recreate.")
97101
flags.BoolVar(&opts.noStart, "no-start", false, "Don't start the services after creating them.")
102+
flags.BoolVar(&opts.cascadeStop, "abort-on-container-exit", false, "Stops all containers if any container was stopped. Incompatible with -d")
98103
}
99104

100105
return upCmd
@@ -145,9 +150,25 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
145150
return nil
146151
}
147152

153+
ctx, cancel := context.WithCancel(ctx)
154+
listener := make(chan compose.Event)
155+
go func() {
156+
var aborting bool
157+
for {
158+
<-listener
159+
if opts.cascadeStop && !aborting {
160+
aborting = true
161+
fmt.Println("Aborting on container exit...")
162+
cancel()
163+
}
164+
}
165+
}()
166+
148167
err = c.ComposeService().Start(ctx, project, compose.StartOptions{
149-
Attach: formatter.NewLogConsumer(ctx, os.Stdout),
168+
Attach: formatter.NewLogConsumer(ctx, os.Stdout),
169+
Listener: listener,
150170
})
171+
151172
if errors.Is(ctx.Err(), context.Canceled) {
152173
fmt.Println("Gracefully stopping...")
153174
ctx = context.Background()

cli/formatter/logs.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,10 @@ func (l *logConsumer) Log(service, container, message string) {
5151
}
5252
}
5353

54-
func (l *logConsumer) Exit(service, container string, exitCode int) {
55-
msg := fmt.Sprintf("%s exited with code %d\n", container, exitCode)
56-
l.writer.Write([]byte(l.getColorFunc(service)(msg)))
54+
func (l *logConsumer) Status(service, container, msg string) {
55+
cf := l.getColorFunc(service)
56+
buf := bytes.NewBufferString(fmt.Sprintf("%s %s \n", cf(container), cf(msg)))
57+
l.writer.Write(buf.Bytes()) // nolint:errcheck
5758
}
5859

5960
func (l *logConsumer) getColorFunc(service string) colorFunc {

ecs/logs.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ func (a *allowListLogConsumer) Log(service, container, message string) {
5555
}
5656
}
5757

58-
func (a *allowListLogConsumer) Exit(service, container string, exitCode int) {
58+
func (a *allowListLogConsumer) Status(service, container, message string) {
5959
if a.allowList[service] {
60-
a.delegate.Exit(service, container, exitCode)
60+
a.delegate.Status(service, container, message)
6161
}
6262
}

local/compose/attach.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ func (s *composeService) attach(ctx context.Context, project *types.Project, con
4444
fmt.Printf("Attaching to %s\n", strings.Join(names, ", "))
4545

4646
for _, container := range containers {
47-
s.attachContainer(ctx, container, consumer, project)
47+
err := s.attachContainer(ctx, container, consumer, project)
48+
if err != nil {
49+
return nil, err
50+
}
4851
}
4952
return containers, nil
5053
}

local/compose/containers.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package compose
1818

1919
import (
2020
"context"
21+
2122
"github.com/compose-spec/compose-go/types"
2223
moby "github.com/docker/docker/api/types"
2324
"github.com/docker/docker/api/types/filters"

local/compose/start.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ package compose
1818

1919
import (
2020
"context"
21-
"github.com/docker/docker/api/types/container"
21+
"fmt"
2222

2323
"github.com/docker/compose-cli/api/compose"
2424

2525
"github.com/compose-spec/compose-go/types"
26+
"github.com/docker/docker/api/types/container"
2627
"golang.org/x/sync/errgroup"
2728
)
2829

@@ -60,7 +61,14 @@ func (s *composeService) Start(ctx context.Context, project *types.Project, opti
6061
statusC, errC := s.apiClient.ContainerWait(ctx, c.ID, container.WaitConditionNotRunning)
6162
select {
6263
case status := <-statusC:
63-
options.Attach.Exit(c.Labels[serviceLabel], getContainerNameWithoutProject(c), int(status.StatusCode))
64+
service := c.Labels[serviceLabel]
65+
options.Attach.Status(service, getContainerNameWithoutProject(c), fmt.Sprintf("exited with code %d", status.StatusCode))
66+
if options.Listener != nil {
67+
options.Listener <- compose.Event{
68+
Service: service,
69+
Status: int(status.StatusCode),
70+
}
71+
}
6472
return nil
6573
case err := <-errC:
6674
return err

0 commit comments

Comments
 (0)