Browse code

integration-cli-on-swarm: new CLI flag: -keep-executor

Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>

Akihiro Suda authored on 2017/03/09 17:13:13
Showing 5 changed files
... ...
@@ -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