Forráskód Böngészése

Merge pull request #1502 from docker/init_container

add support for service_completed_successfully
Nicolas De loof 4 éve
szülő
commit
0e8a56bfcb

+ 33 - 2
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 {

+ 10 - 0
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())
+}

+ 11 - 0
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"