Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
| ... | ... |
@@ -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 |