github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/hack/integration-cli-on-swarm/agent/worker/executor.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "io" 8 "os" 9 "strings" 10 11 "github.com/docker/docker/api/types" 12 "github.com/docker/docker/api/types/container" 13 "github.com/docker/docker/api/types/mount" 14 "github.com/docker/docker/client" 15 "github.com/docker/docker/pkg/stdcopy" 16 ) 17 18 // testChunkExecutor executes integration-cli binary. 19 // image needs to be the worker image itself. testFlags are OR-set of regexp for filtering tests. 20 type testChunkExecutor func(image string, tests []string) (int64, string, error) 21 22 func dryTestChunkExecutor() testChunkExecutor { 23 return func(image string, tests []string) (int64, string, error) { 24 return 0, fmt.Sprintf("DRY RUN (image=%q, tests=%v)", image, tests), nil 25 } 26 } 27 28 // privilegedTestChunkExecutor invokes a privileged container from the worker 29 // service via bind-mounted API socket so as to execute the test chunk 30 func privilegedTestChunkExecutor(autoRemove bool) testChunkExecutor { 31 return func(image string, tests []string) (int64, string, error) { 32 cli, err := client.NewEnvClient() 33 if err != nil { 34 return 0, "", err 35 } 36 // propagate variables from the host (needs to be defined in the compose file) 37 experimental := os.Getenv("DOCKER_EXPERIMENTAL") 38 graphdriver := os.Getenv("DOCKER_GRAPHDRIVER") 39 if graphdriver == "" { 40 info, err := cli.Info(context.Background()) 41 if err != nil { 42 return 0, "", err 43 } 44 graphdriver = info.Driver 45 } 46 // `daemon_dest` is similar to `$DEST` (e.g. `bundles/VERSION/test-integration`) 47 // but it exists outside of `bundles` so as to make `$DOCKER_GRAPHDRIVER` work. 48 // 49 // Without this hack, `$DOCKER_GRAPHDRIVER` fails because of (e.g.) `overlay2 is not supported over overlayfs` 50 // 51 // see integration-cli/daemon/daemon.go 52 daemonDest := "/daemon_dest" 53 config := container.Config{ 54 Image: image, 55 Env: []string{ 56 "TESTFLAGS=-check.f " + strings.Join(tests, "|"), 57 "KEEPBUNDLE=1", 58 "DOCKER_INTEGRATION_TESTS_VERIFIED=1", // for avoiding rebuilding integration-cli 59 "DOCKER_EXPERIMENTAL=" + experimental, 60 "DOCKER_GRAPHDRIVER=" + graphdriver, 61 "DOCKER_INTEGRATION_DAEMON_DEST=" + daemonDest, 62 }, 63 Labels: map[string]string{ 64 "org.dockerproject.integration-cli-on-swarm": "", 65 "org.dockerproject.integration-cli-on-swarm.comment": "this non-service container is created for running privileged programs on Swarm. you can remove this container manually if the corresponding service is already stopped.", 66 }, 67 Entrypoint: []string{"hack/dind"}, 68 Cmd: []string{"hack/make.sh", "test-integration"}, 69 } 70 hostConfig := container.HostConfig{ 71 AutoRemove: autoRemove, 72 Privileged: true, 73 Mounts: []mount.Mount{ 74 { 75 Type: mount.TypeVolume, 76 Target: daemonDest, 77 }, 78 }, 79 } 80 id, stream, err := runContainer(context.Background(), cli, config, hostConfig) 81 if err != nil { 82 return 0, "", err 83 } 84 var b bytes.Buffer 85 teeContainerStream(&b, os.Stdout, os.Stderr, stream) 86 resultC, errC := cli.ContainerWait(context.Background(), id, "") 87 select { 88 case err := <-errC: 89 return 0, "", err 90 case result := <-resultC: 91 return result.StatusCode, b.String(), nil 92 } 93 } 94 } 95 96 func runContainer(ctx context.Context, cli *client.Client, config container.Config, hostConfig container.HostConfig) (string, io.ReadCloser, error) { 97 created, err := cli.ContainerCreate(context.Background(), 98 &config, &hostConfig, nil, "") 99 if err != nil { 100 return "", nil, err 101 } 102 if err = cli.ContainerStart(ctx, created.ID, types.ContainerStartOptions{}); err != nil { 103 return "", nil, err 104 } 105 stream, err := cli.ContainerLogs(ctx, 106 created.ID, 107 types.ContainerLogsOptions{ 108 ShowStdout: true, 109 ShowStderr: true, 110 Follow: true, 111 }) 112 return created.ID, stream, err 113 } 114 115 func teeContainerStream(w, stdout, stderr io.Writer, stream io.ReadCloser) { 116 stdcopy.StdCopy(io.MultiWriter(w, stdout), io.MultiWriter(w, stderr), stream) 117 stream.Close() 118 }