1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #31683 from AkihiroSuda/it-on-swarm-easy-analysis

integration-cli-on-swarm: new CLI flag: -keep-executor
This commit is contained in:
Vincent Demeester 2017-03-28 15:50:52 +02:00 committed by GitHub
commit 917cb0d9d0
5 changed files with 85 additions and 73 deletions

View file

@ -64,3 +64,4 @@ Flags for debugging IT on Swarm itself:
- `-rand-seed N`: the random seed. This flag is useful for deterministic replaying. By default(0), the timestamp is used. - `-rand-seed N`: the random seed. This flag is useful for deterministic replaying. By default(0), the timestamp is used.
- `-filters-file FILE`: the file contains `-check.f` strings. By default, the file is automatically generated. - `-filters-file FILE`: the file contains `-check.f` strings. By default, the file is automatically generated.
- `-dry-run`: skip the actual workload - `-dry-run`: skip the actual workload
- `keep-executor`: do not auto-remove executor containers, which is used for running privileged programs on Swarm

View file

@ -19,69 +19,76 @@ import (
// image needs to be the worker image itself. testFlags are OR-set of regexp for filtering tests. // image needs to be the worker image itself. testFlags are OR-set of regexp for filtering tests.
type testChunkExecutor func(image string, tests []string) (int64, string, error) type testChunkExecutor func(image string, tests []string) (int64, string, error)
func dryTestChunkExecutor(image string, tests []string) (int64, string, error) { func dryTestChunkExecutor() testChunkExecutor {
return 0, fmt.Sprintf("DRY RUN (image=%q, tests=%v)", image, tests), nil return func(image string, tests []string) (int64, string, error) {
return 0, fmt.Sprintf("DRY RUN (image=%q, tests=%v)", image, tests), nil
}
} }
// privilegedTestChunkExecutor invokes a privileged container from the worker // privilegedTestChunkExecutor invokes a privileged container from the worker
// service via bind-mounted API socket so as to execute the test chunk // service via bind-mounted API socket so as to execute the test chunk
func privilegedTestChunkExecutor(image string, tests []string) (int64, string, error) { func privilegedTestChunkExecutor(autoRemove bool) testChunkExecutor {
cli, err := client.NewEnvClient() return func(image string, tests []string) (int64, string, error) {
if err != nil { cli, err := client.NewEnvClient()
return 0, "", err
}
// propagate variables from the host (needs to be defined in the compose file)
experimental := os.Getenv("DOCKER_EXPERIMENTAL")
graphdriver := os.Getenv("DOCKER_GRAPHDRIVER")
if graphdriver == "" {
info, err := cli.Info(context.Background())
if err != nil { if err != nil {
return 0, "", err return 0, "", err
} }
graphdriver = info.Driver // propagate variables from the host (needs to be defined in the compose file)
} experimental := os.Getenv("DOCKER_EXPERIMENTAL")
// `daemon_dest` is similar to `$DEST` (e.g. `bundles/VERSION/test-integration-cli`) graphdriver := os.Getenv("DOCKER_GRAPHDRIVER")
// but it exists outside of `bundles` so as to make `$DOCKER_GRAPHDRIVER` work. if graphdriver == "" {
// info, err := cli.Info(context.Background())
// Without this hack, `$DOCKER_GRAPHDRIVER` fails because of (e.g.) `overlay2 is not supported over overlayfs` if err != nil {
// return 0, "", err
// see integration-cli/daemon/daemon.go }
daemonDest := "/daemon_dest" graphdriver = info.Driver
config := container.Config{ }
Image: image, // `daemon_dest` is similar to `$DEST` (e.g. `bundles/VERSION/test-integration-cli`)
Env: []string{ // but it exists outside of `bundles` so as to make `$DOCKER_GRAPHDRIVER` work.
"TESTFLAGS=-check.f " + strings.Join(tests, "|"), //
"KEEPBUNDLE=1", // Without this hack, `$DOCKER_GRAPHDRIVER` fails because of (e.g.) `overlay2 is not supported over overlayfs`
"DOCKER_INTEGRATION_TESTS_VERIFIED=1", // for avoiding rebuilding integration-cli //
"DOCKER_EXPERIMENTAL=" + experimental, // see integration-cli/daemon/daemon.go
"DOCKER_GRAPHDRIVER=" + graphdriver, daemonDest := "/daemon_dest"
"DOCKER_INTEGRATION_DAEMON_DEST=" + daemonDest, config := container.Config{
}, Image: image,
// TODO: set label? Env: []string{
Entrypoint: []string{"hack/dind"}, "TESTFLAGS=-check.f " + strings.Join(tests, "|"),
Cmd: []string{"hack/make.sh", "test-integration-cli"}, "KEEPBUNDLE=1",
} "DOCKER_INTEGRATION_TESTS_VERIFIED=1", // for avoiding rebuilding integration-cli
hostConfig := container.HostConfig{ "DOCKER_EXPERIMENTAL=" + experimental,
AutoRemove: true, "DOCKER_GRAPHDRIVER=" + graphdriver,
Privileged: true, "DOCKER_INTEGRATION_DAEMON_DEST=" + daemonDest,
Mounts: []mount.Mount{
{
Type: mount.TypeVolume,
Target: daemonDest,
}, },
}, Labels: map[string]string{
"org.dockerproject.integration-cli-on-swarm": "",
"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.",
},
Entrypoint: []string{"hack/dind"},
Cmd: []string{"hack/make.sh", "test-integration-cli"},
}
hostConfig := container.HostConfig{
AutoRemove: autoRemove,
Privileged: true,
Mounts: []mount.Mount{
{
Type: mount.TypeVolume,
Target: daemonDest,
},
},
}
id, stream, err := runContainer(context.Background(), cli, config, hostConfig)
if err != nil {
return 0, "", err
}
var b bytes.Buffer
teeContainerStream(&b, os.Stdout, os.Stderr, stream)
rc, err := cli.ContainerWait(context.Background(), id)
if err != nil {
return 0, "", err
}
return rc, b.String(), nil
} }
id, stream, err := runContainer(context.Background(), cli, config, hostConfig)
if err != nil {
return 0, "", err
}
var b bytes.Buffer
teeContainerStream(&b, os.Stdout, os.Stderr, stream)
rc, err := cli.ContainerWait(context.Background(), id)
if err != nil {
return 0, "", err
}
return rc, b.String(), nil
} }
func runContainer(ctx context.Context, cli *client.Client, config container.Config, hostConfig container.HostConfig) (string, io.ReadCloser, error) { func runContainer(ctx context.Context, cli *client.Client, config container.Config, hostConfig container.HostConfig) (string, io.ReadCloser, error) {

View file

@ -24,6 +24,7 @@ func validImageDigest(s string) bool {
func xmain() error { func xmain() error {
workerImageDigest := flag.String("worker-image-digest", "", "Needs to be the digest of this worker image itself") workerImageDigest := flag.String("worker-image-digest", "", "Needs to be the digest of this worker image itself")
dryRun := flag.Bool("dry-run", false, "Dry run") dryRun := flag.Bool("dry-run", false, "Dry run")
keepExecutor := flag.Bool("keep-executor", false, "Do not auto-remove executor containers, which is used for running privileged programs on Swarm")
flag.Parse() flag.Parse()
if !validImageDigest(*workerImageDigest) { if !validImageDigest(*workerImageDigest) {
// Because of issue #29582. // Because of issue #29582.
@ -31,9 +32,9 @@ func xmain() error {
// So, `docker run localregistry.example.com/blahblah:latest` fails: `Unable to find image 'localregistry.example.com/blahblah:latest' locally` // So, `docker run localregistry.example.com/blahblah:latest` fails: `Unable to find image 'localregistry.example.com/blahblah:latest' locally`
return fmt.Errorf("worker-image-digest must be a digest, got %q", *workerImageDigest) return fmt.Errorf("worker-image-digest must be a digest, got %q", *workerImageDigest)
} }
executor := privilegedTestChunkExecutor executor := privilegedTestChunkExecutor(!*keepExecutor)
if *dryRun { if *dryRun {
executor = dryTestChunkExecutor executor = dryTestChunkExecutor()
} }
return handle(*workerImageDigest, executor) return handle(*workerImageDigest, executor)
} }

View file

@ -16,7 +16,7 @@ version: "3"
services: services:
worker: worker:
image: "{{.WorkerImage}}" image: "{{.WorkerImage}}"
command: ["-worker-image-digest={{.WorkerImageDigest}}", "-dry-run={{.DryRun}}"] command: ["-worker-image-digest={{.WorkerImageDigest}}", "-dry-run={{.DryRun}}", "-keep-executor={{.KeepExecutor}}"]
networks: networks:
- net - net
volumes: volumes:
@ -57,14 +57,15 @@ volumes:
` `
type composeOptions struct { type composeOptions struct {
Replicas int Replicas int
Chunks int Chunks int
MasterImage string MasterImage string
WorkerImage string WorkerImage string
Volume string Volume string
Shuffle bool Shuffle bool
RandSeed int64 RandSeed int64
DryRun bool DryRun bool
KeepExecutor bool
} }
type composeTemplateOptions struct { type composeTemplateOptions struct {

View file

@ -42,6 +42,7 @@ func xmain() (int, error) {
randSeed := flag.Int64("rand-seed", int64(0), "Random seed used for shuffling (0 == curent time)") randSeed := flag.Int64("rand-seed", int64(0), "Random seed used for shuffling (0 == curent time)")
filtersFile := flag.String("filters-file", "", "Path to optional file composed of `-check.f` filter strings") filtersFile := flag.String("filters-file", "", "Path to optional file composed of `-check.f` filter strings")
dryRun := flag.Bool("dry-run", false, "Dry run") dryRun := flag.Bool("dry-run", false, "Dry run")
keepExecutor := flag.Bool("keep-executor", false, "Do not auto-remove executor containers, which is used for running privileged programs on Swarm")
flag.Parse() flag.Parse()
if *chunks == 0 { if *chunks == 0 {
*chunks = *replicas *chunks = *replicas
@ -73,14 +74,15 @@ func xmain() (int, error) {
workerImageForStack = *pushWorkerImage workerImageForStack = *pushWorkerImage
} }
compose, err := createCompose("", cli, composeOptions{ compose, err := createCompose("", cli, composeOptions{
Replicas: *replicas, Replicas: *replicas,
Chunks: *chunks, Chunks: *chunks,
MasterImage: defaultMasterImageName, MasterImage: defaultMasterImageName,
WorkerImage: workerImageForStack, WorkerImage: workerImageForStack,
Volume: defaultVolumeName, Volume: defaultVolumeName,
Shuffle: *shuffle, Shuffle: *shuffle,
RandSeed: *randSeed, RandSeed: *randSeed,
DryRun: *dryRun, DryRun: *dryRun,
KeepExecutor: *keepExecutor,
}) })
if err != nil { if err != nil {
return 1, err return 1, err