|
@@ -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) {
|
|
|
|
- return 0, fmt.Sprintf("DRY RUN (image=%q, tests=%v)", image, tests), nil
|
|
|
|
|
|
+func dryTestChunkExecutor() testChunkExecutor {
|
|
|
|
+ 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) {
|
|
|
|
- cli, err := client.NewEnvClient()
|
|
|
|
- if err != nil {
|
|
|
|
- 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())
|
|
|
|
|
|
+func privilegedTestChunkExecutor(autoRemove bool) testChunkExecutor {
|
|
|
|
+ return func(image string, tests []string) (int64, string, error) {
|
|
|
|
+ cli, err := client.NewEnvClient()
|
|
if err != nil {
|
|
if err != nil {
|
|
return 0, "", err
|
|
return 0, "", err
|
|
}
|
|
}
|
|
- graphdriver = info.Driver
|
|
|
|
- }
|
|
|
|
- // `daemon_dest` is similar to `$DEST` (e.g. `bundles/VERSION/test-integration-cli`)
|
|
|
|
- // but it exists outside of `bundles` so as to make `$DOCKER_GRAPHDRIVER` work.
|
|
|
|
- //
|
|
|
|
- // Without this hack, `$DOCKER_GRAPHDRIVER` fails because of (e.g.) `overlay2 is not supported over overlayfs`
|
|
|
|
- //
|
|
|
|
- // see integration-cli/daemon/daemon.go
|
|
|
|
- daemonDest := "/daemon_dest"
|
|
|
|
- config := container.Config{
|
|
|
|
- Image: image,
|
|
|
|
- Env: []string{
|
|
|
|
- "TESTFLAGS=-check.f " + strings.Join(tests, "|"),
|
|
|
|
- "KEEPBUNDLE=1",
|
|
|
|
- "DOCKER_INTEGRATION_TESTS_VERIFIED=1", // for avoiding rebuilding integration-cli
|
|
|
|
- "DOCKER_EXPERIMENTAL=" + experimental,
|
|
|
|
- "DOCKER_GRAPHDRIVER=" + graphdriver,
|
|
|
|
- "DOCKER_INTEGRATION_DAEMON_DEST=" + daemonDest,
|
|
|
|
- },
|
|
|
|
- // TODO: set label?
|
|
|
|
- Entrypoint: []string{"hack/dind"},
|
|
|
|
- Cmd: []string{"hack/make.sh", "test-integration-cli"},
|
|
|
|
- }
|
|
|
|
- hostConfig := container.HostConfig{
|
|
|
|
- AutoRemove: true,
|
|
|
|
- Privileged: true,
|
|
|
|
- Mounts: []mount.Mount{
|
|
|
|
- {
|
|
|
|
- Type: mount.TypeVolume,
|
|
|
|
- Target: daemonDest,
|
|
|
|
|
|
+ // 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 {
|
|
|
|
+ return 0, "", err
|
|
|
|
+ }
|
|
|
|
+ graphdriver = info.Driver
|
|
|
|
+ }
|
|
|
|
+ // `daemon_dest` is similar to `$DEST` (e.g. `bundles/VERSION/test-integration-cli`)
|
|
|
|
+ // but it exists outside of `bundles` so as to make `$DOCKER_GRAPHDRIVER` work.
|
|
|
|
+ //
|
|
|
|
+ // Without this hack, `$DOCKER_GRAPHDRIVER` fails because of (e.g.) `overlay2 is not supported over overlayfs`
|
|
|
|
+ //
|
|
|
|
+ // see integration-cli/daemon/daemon.go
|
|
|
|
+ daemonDest := "/daemon_dest"
|
|
|
|
+ config := container.Config{
|
|
|
|
+ Image: image,
|
|
|
|
+ Env: []string{
|
|
|
|
+ "TESTFLAGS=-check.f " + strings.Join(tests, "|"),
|
|
|
|
+ "KEEPBUNDLE=1",
|
|
|
|
+ "DOCKER_INTEGRATION_TESTS_VERIFIED=1", // for avoiding rebuilding integration-cli
|
|
|
|
+ "DOCKER_EXPERIMENTAL=" + experimental,
|
|
|
|
+ "DOCKER_GRAPHDRIVER=" + graphdriver,
|
|
|
|
+ "DOCKER_INTEGRATION_DAEMON_DEST=" + 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
|
|
|
|
|
|
+ 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
|
|
}
|
|
}
|
|
- 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) {
|