Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
Akihiro Suda authored on 2017/03/09 17:13:13... | ... |
@@ -64,3 +64,4 @@ Flags for debugging IT on Swarm itself: |
64 | 64 |
- `-rand-seed N`: the random seed. This flag is useful for deterministic replaying. By default(0), the timestamp is used. |
65 | 65 |
- `-filters-file FILE`: the file contains `-check.f` strings. By default, the file is automatically generated. |
66 | 66 |
- `-dry-run`: skip the actual workload |
67 |
+ - `keep-executor`: do not auto-remove executor containers, which is used for running privileged programs on Swarm |
... | ... |
@@ -19,69 +19,76 @@ import ( |
19 | 19 |
// image needs to be the worker image itself. testFlags are OR-set of regexp for filtering tests. |
20 | 20 |
type testChunkExecutor func(image string, tests []string) (int64, string, error) |
21 | 21 |
|
22 |
-func dryTestChunkExecutor(image string, tests []string) (int64, string, error) { |
|
23 |
- return 0, fmt.Sprintf("DRY RUN (image=%q, tests=%v)", image, tests), nil |
|
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 |
+ } |
|
24 | 26 |
} |
25 | 27 |
|
26 | 28 |
// privilegedTestChunkExecutor invokes a privileged container from the worker |
27 | 29 |
// service via bind-mounted API socket so as to execute the test chunk |
28 |
-func privilegedTestChunkExecutor(image string, tests []string) (int64, string, error) { |
|
29 |
- cli, err := client.NewEnvClient() |
|
30 |
- if err != nil { |
|
31 |
- return 0, "", err |
|
32 |
- } |
|
33 |
- // propagate variables from the host (needs to be defined in the compose file) |
|
34 |
- experimental := os.Getenv("DOCKER_EXPERIMENTAL") |
|
35 |
- graphdriver := os.Getenv("DOCKER_GRAPHDRIVER") |
|
36 |
- if graphdriver == "" { |
|
37 |
- info, err := cli.Info(context.Background()) |
|
30 |
+func privilegedTestChunkExecutor(autoRemove bool) testChunkExecutor { |
|
31 |
+ return func(image string, tests []string) (int64, string, error) { |
|
32 |
+ cli, err := client.NewEnvClient() |
|
38 | 33 |
if err != nil { |
39 | 34 |
return 0, "", err |
40 | 35 |
} |
41 |
- graphdriver = info.Driver |
|
42 |
- } |
|
43 |
- // `daemon_dest` is similar to `$DEST` (e.g. `bundles/VERSION/test-integration-cli`) |
|
44 |
- // but it exists outside of `bundles` so as to make `$DOCKER_GRAPHDRIVER` work. |
|
45 |
- // |
|
46 |
- // Without this hack, `$DOCKER_GRAPHDRIVER` fails because of (e.g.) `overlay2 is not supported over overlayfs` |
|
47 |
- // |
|
48 |
- // see integration-cli/daemon/daemon.go |
|
49 |
- daemonDest := "/daemon_dest" |
|
50 |
- config := container.Config{ |
|
51 |
- Image: image, |
|
52 |
- Env: []string{ |
|
53 |
- "TESTFLAGS=-check.f " + strings.Join(tests, "|"), |
|
54 |
- "KEEPBUNDLE=1", |
|
55 |
- "DOCKER_INTEGRATION_TESTS_VERIFIED=1", // for avoiding rebuilding integration-cli |
|
56 |
- "DOCKER_EXPERIMENTAL=" + experimental, |
|
57 |
- "DOCKER_GRAPHDRIVER=" + graphdriver, |
|
58 |
- "DOCKER_INTEGRATION_DAEMON_DEST=" + daemonDest, |
|
59 |
- }, |
|
60 |
- // TODO: set label? |
|
61 |
- Entrypoint: []string{"hack/dind"}, |
|
62 |
- Cmd: []string{"hack/make.sh", "test-integration-cli"}, |
|
63 |
- } |
|
64 |
- hostConfig := container.HostConfig{ |
|
65 |
- AutoRemove: true, |
|
66 |
- Privileged: true, |
|
67 |
- Mounts: []mount.Mount{ |
|
68 |
- { |
|
69 |
- Type: mount.TypeVolume, |
|
70 |
- Target: daemonDest, |
|
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-cli`) |
|
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, |
|
71 | 62 |
}, |
72 |
- }, |
|
73 |
- } |
|
74 |
- id, stream, err := runContainer(context.Background(), cli, config, hostConfig) |
|
75 |
- if err != nil { |
|
76 |
- return 0, "", err |
|
77 |
- } |
|
78 |
- var b bytes.Buffer |
|
79 |
- teeContainerStream(&b, os.Stdout, os.Stderr, stream) |
|
80 |
- rc, err := cli.ContainerWait(context.Background(), id) |
|
81 |
- if err != nil { |
|
82 |
- return 0, "", err |
|
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-cli"}, |
|
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 |
+ rc, err := cli.ContainerWait(context.Background(), id) |
|
87 |
+ if err != nil { |
|
88 |
+ return 0, "", err |
|
89 |
+ } |
|
90 |
+ return rc, b.String(), nil |
|
83 | 91 |
} |
84 |
- return rc, b.String(), nil |
|
85 | 92 |
} |
86 | 93 |
|
87 | 94 |
func runContainer(ctx context.Context, cli *client.Client, config container.Config, hostConfig container.HostConfig) (string, io.ReadCloser, error) { |
... | ... |
@@ -24,6 +24,7 @@ func validImageDigest(s string) bool { |
24 | 24 |
func xmain() error { |
25 | 25 |
workerImageDigest := flag.String("worker-image-digest", "", "Needs to be the digest of this worker image itself") |
26 | 26 |
dryRun := flag.Bool("dry-run", false, "Dry run") |
27 |
+ keepExecutor := flag.Bool("keep-executor", false, "Do not auto-remove executor containers, which is used for running privileged programs on Swarm") |
|
27 | 28 |
flag.Parse() |
28 | 29 |
if !validImageDigest(*workerImageDigest) { |
29 | 30 |
// Because of issue #29582. |
... | ... |
@@ -31,9 +32,9 @@ func xmain() error { |
31 | 31 |
// So, `docker run localregistry.example.com/blahblah:latest` fails: `Unable to find image 'localregistry.example.com/blahblah:latest' locally` |
32 | 32 |
return fmt.Errorf("worker-image-digest must be a digest, got %q", *workerImageDigest) |
33 | 33 |
} |
34 |
- executor := privilegedTestChunkExecutor |
|
34 |
+ executor := privilegedTestChunkExecutor(!*keepExecutor) |
|
35 | 35 |
if *dryRun { |
36 |
- executor = dryTestChunkExecutor |
|
36 |
+ executor = dryTestChunkExecutor() |
|
37 | 37 |
} |
38 | 38 |
return handle(*workerImageDigest, executor) |
39 | 39 |
} |
... | ... |
@@ -16,7 +16,7 @@ version: "3" |
16 | 16 |
services: |
17 | 17 |
worker: |
18 | 18 |
image: "{{.WorkerImage}}" |
19 |
- command: ["-worker-image-digest={{.WorkerImageDigest}}", "-dry-run={{.DryRun}}"] |
|
19 |
+ command: ["-worker-image-digest={{.WorkerImageDigest}}", "-dry-run={{.DryRun}}", "-keep-executor={{.KeepExecutor}}"] |
|
20 | 20 |
networks: |
21 | 21 |
- net |
22 | 22 |
volumes: |
... | ... |
@@ -57,14 +57,15 @@ volumes: |
57 | 57 |
` |
58 | 58 |
|
59 | 59 |
type composeOptions struct { |
60 |
- Replicas int |
|
61 |
- Chunks int |
|
62 |
- MasterImage string |
|
63 |
- WorkerImage string |
|
64 |
- Volume string |
|
65 |
- Shuffle bool |
|
66 |
- RandSeed int64 |
|
67 |
- DryRun bool |
|
60 |
+ Replicas int |
|
61 |
+ Chunks int |
|
62 |
+ MasterImage string |
|
63 |
+ WorkerImage string |
|
64 |
+ Volume string |
|
65 |
+ Shuffle bool |
|
66 |
+ RandSeed int64 |
|
67 |
+ DryRun bool |
|
68 |
+ KeepExecutor bool |
|
68 | 69 |
} |
69 | 70 |
|
70 | 71 |
type composeTemplateOptions struct { |
... | ... |
@@ -41,6 +41,7 @@ func xmain() error { |
41 | 41 |
randSeed := flag.Int64("rand-seed", int64(0), "Random seed used for shuffling (0 == curent time)") |
42 | 42 |
filtersFile := flag.String("filters-file", "", "Path to optional file composed of `-check.f` filter strings") |
43 | 43 |
dryRun := flag.Bool("dry-run", false, "Dry run") |
44 |
+ keepExecutor := flag.Bool("keep-executor", false, "Do not auto-remove executor containers, which is used for running privileged programs on Swarm") |
|
44 | 45 |
flag.Parse() |
45 | 46 |
if *chunks == 0 { |
46 | 47 |
*chunks = *replicas |
... | ... |
@@ -72,14 +73,15 @@ func xmain() error { |
72 | 72 |
workerImageForStack = *pushWorkerImage |
73 | 73 |
} |
74 | 74 |
compose, err := createCompose("", cli, composeOptions{ |
75 |
- Replicas: *replicas, |
|
76 |
- Chunks: *chunks, |
|
77 |
- MasterImage: defaultMasterImageName, |
|
78 |
- WorkerImage: workerImageForStack, |
|
79 |
- Volume: defaultVolumeName, |
|
80 |
- Shuffle: *shuffle, |
|
81 |
- RandSeed: *randSeed, |
|
82 |
- DryRun: *dryRun, |
|
75 |
+ Replicas: *replicas, |
|
76 |
+ Chunks: *chunks, |
|
77 |
+ MasterImage: defaultMasterImageName, |
|
78 |
+ WorkerImage: workerImageForStack, |
|
79 |
+ Volume: defaultVolumeName, |
|
80 |
+ Shuffle: *shuffle, |
|
81 |
+ RandSeed: *randSeed, |
|
82 |
+ DryRun: *dryRun, |
|
83 |
+ KeepExecutor: *keepExecutor, |
|
83 | 84 |
}) |
84 | 85 |
if err != nil { |
85 | 86 |
return err |