From 15a21a449f45216d97f201e7fe0c83d551bb6533 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 7 Apr 2021 11:52:10 +0200 Subject: [PATCH] add support for service_completed_successfully Signed-off-by: Nicolas De Loof --- local/compose/convergence.go | 35 +++++++++++++++++-- local/e2e/compose/compose_test.go | 10 ++++++ .../fixtures/init-container/compose.yaml | 11 ++++++ 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 local/e2e/compose/fixtures/init-container/compose.yaml diff --git a/local/compose/convergence.go b/local/compose/convergence.go index 585996d27..ecef62099 100644 --- a/local/compose/convergence.go +++ b/local/compose/convergence.go @@ -25,6 +25,7 @@ import ( "github.com/compose-spec/compose-go/types" "github.com/containerd/containerd/platforms" moby "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/network" specs "github.com/opencontainers/image-spec/specs-go/v1" @@ -162,6 +163,14 @@ func (s *composeService) waitDependencies(ctx context.Context, project *types.Pr } } }) + case "service_completed_successfully": + exit, err := s.waitCompleted(ctx, project, dep) + if err != nil { + return err + } + if exit != 0 { + return fmt.Errorf("service %q didn't completed successfully: exit %d", dep, exit) + } } } return eg.Wait() @@ -330,8 +339,8 @@ func (s *composeService) connectContainerToNetwork(ctx context.Context, id strin func (s *composeService) isServiceHealthy(ctx context.Context, project *types.Project, service string) (bool, error) { containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ Filters: filters.NewArgs( - filters.Arg("label", fmt.Sprintf("%s=%s", projectLabel, project.Name)), - filters.Arg("label", fmt.Sprintf("%s=%s", serviceLabel, service)), + projectFilter(project.Name), + serviceFilter(service), ), }) if err != nil { @@ -356,6 +365,28 @@ func (s *composeService) isServiceHealthy(ctx context.Context, project *types.Pr return true, nil } +func (s *composeService) waitCompleted(ctx context.Context, project *types.Project, dep string) (int64, error) { + containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ + Filters: filters.NewArgs( + projectFilter(project.Name), + serviceFilter(dep), + ), + }) + if err != nil { + return 0, err + } + for _, c := range containers { + wait, errors := s.apiClient.ContainerWait(ctx, c.ID, container.WaitConditionNextExit) + select { + case w := <-wait: + return w.StatusCode, nil + case err := <-errors: + return 0, err + } + } + return 0, nil +} + func (s *composeService) startService(ctx context.Context, project *types.Project, service types.ServiceConfig) error { err := s.waitDependencies(ctx, project, service) if err != nil { diff --git a/local/e2e/compose/compose_test.go b/local/e2e/compose/compose_test.go index 079acbed9..86f2111f0 100644 --- a/local/e2e/compose/compose_test.go +++ b/local/e2e/compose/compose_test.go @@ -147,3 +147,13 @@ func TestAttachRestart(t *testing.T) { execRegex := regexp.MustCompile(`another_1 \| world`) assert.Equal(t, len(execRegex.FindAllStringIndex(output, -1)), 3, res.Combined()) } + +func TestInitContainer(t *testing.T) { + c := NewParallelE2eCLI(t, binDir) + + res := c.RunDockerOrExitError("compose", "--ansi=never", "--project-directory", "./fixtures/init-container", "up") + defer c.RunDockerCmd("compose", "-p", "init-container", "down") + output := res.Stdout() + + assert.Assert(t, strings.Contains(output, "foo_1 | hello\nbar_1 | world"), res.Combined()) +} diff --git a/local/e2e/compose/fixtures/init-container/compose.yaml b/local/e2e/compose/fixtures/init-container/compose.yaml new file mode 100644 index 000000000..275727edd --- /dev/null +++ b/local/e2e/compose/fixtures/init-container/compose.yaml @@ -0,0 +1,11 @@ +services: + foo: + image: alpine + command: "echo hello" + + bar: + image: alpine + command: "echo world" + depends_on: + foo: + condition: "service_completed_successfully"