diff --git a/Dockerfile b/Dockerfile index 143dec64073f2..edd41b1c86459 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,7 +36,7 @@ RUN sed -ri "s/(httpredir|deb).debian.org/${APT_MIRROR:-deb.debian.org}/g" /etc/ FROM base AS criu ARG DEBIAN_FRONTEND # Install CRIU for checkpoint/restore support -ENV CRIU_VERSION 3.11 +ENV CRIU_VERSION 3.12 # Install dependency packages specific to criu RUN apt-get update && apt-get install -y --no-install-recommends \ libnet-dev \ @@ -281,8 +281,6 @@ COPY --from=djs55/vpnkit@sha256:e508a17cfacc8fd39261d5b4e397df2b953690da577e2c98 ENV PATH=/usr/local/cli:$PATH ENV DOCKER_BUILDTAGS apparmor seccomp selinux -# Options for hack/validate/gometalinter -ENV GOMETALINTER_OPTS="--deadline=2m" WORKDIR /go/src/github.com/docker/docker VOLUME /var/lib/docker # Wrap all commands in the "docker-in-docker" script to allow nested containers diff --git a/Dockerfile.windows b/Dockerfile.windows index f18b5260cc994..363c0e1318c73 100644 --- a/Dockerfile.windows +++ b/Dockerfile.windows @@ -214,7 +214,8 @@ RUN ` Download-File $location C:\gitsetup.zip; ` ` Write-Host INFO: Downloading go...; ` - Download-File $('https://golang.org/dl/go'+$Env:GO_VERSION+'.windows-amd64.zip') C:\go.zip; ` + $dlGoVersion=$Env:GO_VERSION -replace '\.0$',''; ` + Download-File "https://golang.org/dl/go${dlGoVersion}.windows-amd64.zip" C:\go.zip; ` ` Write-Host INFO: Downloading compiler 1 of 3...; ` Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/gcc.zip C:\gcc.zip; ` diff --git a/Jenkinsfile b/Jenkinsfile index 26cc9e352481b..efc859f3e22d9 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -22,15 +22,27 @@ pipeline { DOCKER_GRAPHDRIVER = 'overlay2' APT_MIRROR = 'cdn-fastly.deb.debian.org' CHECK_CONFIG_COMMIT = '78405559cfe5987174aa2cb6463b9b2c1b917255' + TESTDEBUG = '0' TIMEOUT = '120m' } stages { + stage('pr-hack') { + when { changeRequest() } + steps { + script { + echo "Workaround for PR auto-cancel feature. Borrowed from https://issues.jenkins-ci.org/browse/JENKINS-43353" + def buildNumber = env.BUILD_NUMBER as int + if (buildNumber > 1) milestone(buildNumber - 1) + milestone(buildNumber) + } + } + } stage('DCO-check') { when { beforeAgent true expression { !params.skip_dco } } - agent { label 'linux' } + agent { label 'amd64 && ubuntu-1804 && overlay2' } steps { sh ''' docker run --rm \ @@ -257,13 +269,13 @@ pipeline { run_tests() { [ -n "$TESTDEBUG" ] && rm= || rm=--rm; docker run $rm -t --privileged \ - -v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \ + -v "$WORKSPACE/bundles/${TEST_INTEGRATION_DEST}:/go/src/github.com/docker/docker/bundles" \ + -v "$WORKSPACE/bundles/dynbinary-daemon:/go/src/github.com/docker/docker/bundles/dynbinary-daemon" \ -v "$WORKSPACE/.git:/go/src/github.com/docker/docker/.git" \ --name "$CONTAINER_NAME" \ -e KEEPBUNDLE=1 \ -e TESTDEBUG \ -e TESTFLAGS \ - -e TEST_INTEGRATION_DEST \ -e TEST_SKIP_INTEGRATION \ -e TEST_SKIP_INTEGRATION_CLI \ -e DOCKER_GITCOMMIT=${GIT_COMMIT} \ @@ -308,6 +320,11 @@ pipeline { exit $c ''' } + post { + always { + junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true + } + } } } @@ -315,7 +332,8 @@ pipeline { always { sh ''' echo "Ensuring container killed." - docker rm -vf docker-pr$BUILD_NUMBER || true + cids=$(docker ps -aq -f name=docker-pr${BUILD_NUMBER}-*) + [ -n "$cids" ] && docker rm -vf $cids || true ''' sh ''' @@ -328,7 +346,7 @@ pipeline { bundleName=amd64 echo "Creating ${bundleName}-bundles.tar.gz" # exclude overlay2 directories - find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*.log' -o -name '*.prof' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz + find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz ''' archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true @@ -397,6 +415,7 @@ pipeline { -e DOCKER_EXPERIMENTAL \ -e DOCKER_GITCOMMIT=${GIT_COMMIT} \ -e DOCKER_GRAPHDRIVER \ + -e TESTDEBUG \ -e TEST_SKIP_INTEGRATION_CLI \ -e TIMEOUT \ docker:${GIT_COMMIT} \ @@ -405,6 +424,11 @@ pipeline { test-integration ''' } + post { + always { + junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true + } + } } } @@ -425,7 +449,7 @@ pipeline { bundleName=s390x-integration echo "Creating ${bundleName}-bundles.tar.gz" # exclude overlay2 directories - find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*.log' -o -name '*.prof' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz + find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz ''' archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true @@ -483,6 +507,11 @@ pipeline { test-integration ''' } + post { + always { + junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true + } + } } } @@ -503,7 +532,7 @@ pipeline { bundleName=s390x-integration-cli echo "Creating ${bundleName}-bundles.tar.gz" # exclude overlay2 directories - find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*.log' -o -name '*.prof' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz + find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz ''' archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true @@ -570,6 +599,7 @@ pipeline { -e DOCKER_EXPERIMENTAL \ -e DOCKER_GITCOMMIT=${GIT_COMMIT} \ -e DOCKER_GRAPHDRIVER \ + -e TESTDEBUG \ -e TEST_SKIP_INTEGRATION_CLI \ -e TIMEOUT \ docker:${GIT_COMMIT} \ @@ -578,6 +608,11 @@ pipeline { test-integration ''' } + post { + always { + junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true + } + } } } @@ -598,7 +633,7 @@ pipeline { bundleName=ppc64le-integration echo "Creating ${bundleName}-bundles.tar.gz" # exclude overlay2 directories - find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*.log' -o -name '*.prof' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz + find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz ''' archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true @@ -654,6 +689,11 @@ pipeline { test-integration ''' } + post { + always { + junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true + } + } } } @@ -662,8 +702,6 @@ pipeline { sh ''' echo "Ensuring container killed." docker rm -vf docker-pr$BUILD_NUMBER || true - cids=$(docker ps -aq -f name=docker-pr${BUILD_NUMBER}-*) - [ -n "$cids" ] && docker rm -vf $cids || true ''' sh ''' @@ -676,7 +714,7 @@ pipeline { bundleName=ppc64le-integration-cli echo "Creating ${bundleName}-bundles.tar.gz" # exclude overlay2 directories - find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*.log' -o -name '*.prof' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz + find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz ''' archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true @@ -699,11 +737,12 @@ pipeline { } environment { DOCKER_BUILDKIT = '0' + DOCKER_DUT_DEBUG = '1' SKIP_VALIDATION_TESTS = '1' SOURCES_DRIVE = 'd' SOURCES_SUBDIR = 'gopath' TESTRUN_DRIVE = 'd' - TESTRUN_SUBDIR = "CI-$BUILD_NUMBER" + TESTRUN_SUBDIR = "CI" WINDOWS_BASE_IMAGE = 'mcr.microsoft.com/windows/servercore' WINDOWS_BASE_IMAGE_TAG = 'ltsc2016' } @@ -732,6 +771,25 @@ pipeline { } } } + post { + always { + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') { + powershell ''' + $bundleName="windowsRS1-integration" + Write-Host -ForegroundColor Green "Creating ${bundleName}-bundles.zip" + + # archiveArtifacts does not support env-vars to , so save the artifacts in a fixed location + Compress-Archive -Path "${env:TEMP}/CIDUT.out", "${env:TEMP}/CIDUT.err" -CompressionLevel Optimal -DestinationPath "${bundleName}-bundles.zip" + ''' + + archiveArtifacts artifacts: '*-bundles.zip', allowEmptyArchive: true + } + } + cleanup { + sh 'make clean' + deleteDir() + } + } } stage('win-RS5') { when { @@ -740,11 +798,12 @@ pipeline { } environment { DOCKER_BUILDKIT = '0' + DOCKER_DUT_DEBUG = '1' SKIP_VALIDATION_TESTS = '1' SOURCES_DRIVE = 'd' SOURCES_SUBDIR = 'gopath' TESTRUN_DRIVE = 'd' - TESTRUN_SUBDIR = "CI-$BUILD_NUMBER" + TESTRUN_SUBDIR = "CI" WINDOWS_BASE_IMAGE = 'mcr.microsoft.com/windows/servercore' WINDOWS_BASE_IMAGE_TAG = 'ltsc2019' } @@ -772,6 +831,25 @@ pipeline { } } } + post { + always { + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') { + powershell ''' + $bundleName="windowsRS5-integration" + Write-Host -ForegroundColor Green "Creating ${bundleName}-bundles.zip" + + # archiveArtifacts does not support env-vars to , so save the artifacts in a fixed location + Compress-Archive -Path "${env:TEMP}/CIDUT.out", "${env:TEMP}/CIDUT.err" -CompressionLevel Optimal -DestinationPath "${bundleName}-bundles.zip" + ''' + + archiveArtifacts artifacts: '*-bundles.zip', allowEmptyArchive: true + } + } + cleanup { + sh 'make clean' + deleteDir() + } + } } } } diff --git a/MAINTAINERS b/MAINTAINERS index 93013e004d4d8..81494a4d2bac8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -111,7 +111,7 @@ # still stumble into him in our issue tracker, or on IRC. "erikh", - # Evan Hazlett is the creator of of the Shipyard and Interlock open source projects, + # Evan Hazlett is the creator of the Shipyard and Interlock open source projects, # and the author of "Orca", which became the foundation of Docker Universal Control # Plane (UCP). As a maintainer, Evan helped integrating SwarmKit (secrets, tasks) # into the Docker engine. diff --git a/Makefile b/Makefile index ed9372a16a9ab..71f12d176e713 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,6 @@ DOCKER_ENVS := \ -e DOCKER_TEST_HOST \ -e DOCKER_USERLANDPROXY \ -e DOCKERD_ARGS \ - -e TEST_INTEGRATION_DEST \ -e TEST_INTEGRATION_DIR \ -e TEST_SKIP_INTEGRATION \ -e TEST_SKIP_INTEGRATION_CLI \ diff --git a/api/swagger.yaml b/api/swagger.yaml index 6e0bc25b52d6a..0e021fed6656a 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -3262,7 +3262,7 @@ definitions:


- - "ingress" makes the target port accessible on on every node, + - "ingress" makes the target port accessible on every node, regardless of whether there is a task for the service running on that node or not. - "host" bypasses the routing mesh and publish the port directly on diff --git a/builder/dockerfile/evaluator_test.go b/builder/dockerfile/evaluator_test.go index 28607ead0d220..ebd9d8d7f1e1b 100644 --- a/builder/dockerfile/evaluator_test.go +++ b/builder/dockerfile/evaluator_test.go @@ -24,8 +24,11 @@ func init() { reexec.Init() } -func initDispatchTestCases() []dispatchTestCase { - dispatchTestCases := []dispatchTestCase{ +func TestDispatch(t *testing.T) { + if runtime.GOOS != "windows" { + skip.If(t, os.Getuid() != 0, "skipping test that requires root") + } + testCases := []dispatchTestCase{ { name: "ADD multiple files to file", cmd: &instructions.AddCommand{SourcesAndDest: instructions.SourcesAndDest{ @@ -92,56 +95,46 @@ func initDispatchTestCases() []dispatchTestCase { }}, expectedError: "source can't be a URL for COPY", files: nil, - }} - - return dispatchTestCases -} - -func TestDispatch(t *testing.T) { - if runtime.GOOS != "windows" { - skip.If(t, os.Getuid() != 0, "skipping test that requires root") + }, } - testCases := initDispatchTestCases() - for _, testCase := range testCases { - executeTestCase(t, testCase) - } -} + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") + defer cleanup() -func executeTestCase(t *testing.T, testCase dispatchTestCase) { - contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") - defer cleanup() + for filename, content := range tc.files { + createTestTempFile(t, contextDir, filename, content, 0777) + } - for filename, content := range testCase.files { - createTestTempFile(t, contextDir, filename, content, 0777) - } + tarStream, err := archive.Tar(contextDir, archive.Uncompressed) - tarStream, err := archive.Tar(contextDir, archive.Uncompressed) + if err != nil { + t.Fatalf("Error when creating tar stream: %s", err) + } - if err != nil { - t.Fatalf("Error when creating tar stream: %s", err) - } - - defer func() { - if err = tarStream.Close(); err != nil { - t.Fatalf("Error when closing tar stream: %s", err) - } - }() + defer func() { + if err = tarStream.Close(); err != nil { + t.Fatalf("Error when closing tar stream: %s", err) + } + }() - context, err := remotecontext.FromArchive(tarStream) + context, err := remotecontext.FromArchive(tarStream) - if err != nil { - t.Fatalf("Error when creating tar context: %s", err) - } + if err != nil { + t.Fatalf("Error when creating tar context: %s", err) + } - defer func() { - if err = context.Close(); err != nil { - t.Fatalf("Error when closing tar context: %s", err) - } - }() + defer func() { + if err = context.Close(); err != nil { + t.Fatalf("Error when closing tar context: %s", err) + } + }() - b := newBuilderWithMockBackend() - sb := newDispatchRequest(b, '`', context, NewBuildArgs(make(map[string]*string)), newStagesBuildResults()) - err = dispatch(sb, testCase.cmd) - assert.Check(t, is.ErrorContains(err, testCase.expectedError)) + b := newBuilderWithMockBackend() + sb := newDispatchRequest(b, '`', context, NewBuildArgs(make(map[string]*string)), newStagesBuildResults()) + err = dispatch(sb, tc.cmd) + assert.Check(t, is.ErrorContains(err, tc.expectedError)) + }) + } } diff --git a/cmd/dockerd/config.go b/cmd/dockerd/config.go index b28ac1cdc4ddf..c6c6b8a7a1c73 100644 --- a/cmd/dockerd/config.go +++ b/cmd/dockerd/config.go @@ -3,8 +3,10 @@ package main import ( "runtime" + "github.com/docker/docker/daemon" "github.com/docker/docker/daemon/config" "github.com/docker/docker/opts" + "github.com/docker/docker/plugin/executor/containerd" "github.com/docker/docker/registry" "github.com/spf13/pflag" ) @@ -85,7 +87,13 @@ func installCommonConfigFlags(conf *config.Config, flags *pflag.FlagSet) error { conf.MaxConcurrentDownloads = &maxConcurrentDownloads conf.MaxConcurrentUploads = &maxConcurrentUploads - return nil + + flags.StringVar(&conf.ContainerdNamespace, "containerd-namespace", daemon.ContainersNamespace, "Containerd namespace to use") + if err := flags.MarkHidden("containerd-namespace"); err != nil { + return err + } + flags.StringVar(&conf.ContainerdPluginNamespace, "containerd-plugins-namespace", containerd.PluginNamespace, "Containerd namespace to use for plugins") + return flags.MarkHidden("containerd-plugins-namespace") } func installRegistryServiceFlags(options *registry.ServiceOptions, flags *pflag.FlagSet) { diff --git a/daemon/config/config.go b/daemon/config/config.go index 3b23d7aecb55b..9ccb7b2362476 100644 --- a/daemon/config/config.go +++ b/daemon/config/config.go @@ -235,6 +235,9 @@ type CommonConfig struct { Features map[string]bool `json:"features,omitempty"` Builder BuilderConfig `json:"builder,omitempty"` + + ContainerdNamespace string `json:"containerd-namespace,omitempty"` + ContainerdPluginNamespace string `json:"containerd-plugin-namespace,omitempty"` } // IsValueSet returns true if a configuration value diff --git a/daemon/daemon.go b/daemon/daemon.go index e14aa0aeff7a0..014ec970a98a4 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -875,7 +875,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)), } if config.ContainerdAddr != "" { - d.containerdCli, err = containerd.New(config.ContainerdAddr, containerd.WithDefaultNamespace(ContainersNamespace), containerd.WithDialOpts(gopts), containerd.WithTimeout(60*time.Second)) + d.containerdCli, err = containerd.New(config.ContainerdAddr, containerd.WithDefaultNamespace(config.ContainerdNamespace), containerd.WithDialOpts(gopts), containerd.WithTimeout(60*time.Second)) if err != nil { return nil, errors.Wrapf(err, "failed to dial %q", config.ContainerdAddr) } @@ -887,13 +887,13 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S // Windows is not currently using containerd, keep the // client as nil if config.ContainerdAddr != "" { - pluginCli, err = containerd.New(config.ContainerdAddr, containerd.WithDefaultNamespace(pluginexec.PluginNamespace), containerd.WithDialOpts(gopts), containerd.WithTimeout(60*time.Second)) + pluginCli, err = containerd.New(config.ContainerdAddr, containerd.WithDefaultNamespace(config.ContainerdPluginNamespace), containerd.WithDialOpts(gopts), containerd.WithTimeout(60*time.Second)) if err != nil { return nil, errors.Wrapf(err, "failed to dial %q", config.ContainerdAddr) } } - return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, m) + return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, config.ContainerdPluginNamespace, m) } // Plugin system initialization should happen before restore. Do not change order. @@ -1041,7 +1041,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S go d.execCommandGC() - d.containerd, err = libcontainerd.NewClient(ctx, d.containerdCli, filepath.Join(config.ExecRoot, "containerd"), ContainersNamespace, d) + d.containerd, err = libcontainerd.NewClient(ctx, d.containerdCli, filepath.Join(config.ExecRoot, "containerd"), config.ContainerdNamespace, d) if err != nil { return nil, err } diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index f3c68a2d2f7bd..066d52328faed 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -736,6 +736,9 @@ func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error // verifyDaemonSettings performs validation of daemon config struct func verifyDaemonSettings(conf *config.Config) error { + if conf.ContainerdNamespace == conf.ContainerdPluginNamespace { + return errors.New("containers namespace and plugins namespace cannot be the same") + } // Check for mutually incompatible config options if conf.BridgeConfig.Iface != "" && conf.BridgeConfig.IP != "" { return fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one") diff --git a/daemon/logger/awslogs/cloudwatchlogs_test.go b/daemon/logger/awslogs/cloudwatchlogs_test.go index 7ed52ee19dca2..1a32f881e8432 100644 --- a/daemon/logger/awslogs/cloudwatchlogs_test.go +++ b/daemon/logger/awslogs/cloudwatchlogs_test.go @@ -285,6 +285,9 @@ func TestLogClosed(t *testing.T) { } } +// TestLogBlocking tests that the Log method blocks appropriately when +// non-blocking behavior is not enabled. Blocking is achieved through an +// internal channel that must be drained for Log to return. func TestLogBlocking(t *testing.T) { mockClient := newMockClient() stream := &logStream{ @@ -299,18 +302,20 @@ func TestLogBlocking(t *testing.T) { err := stream.Log(&logger.Message{}) errorCh <- err }() + // block until the goroutine above has started <-started select { case err := <-errorCh: t.Fatal("Expected stream.Log to block: ", err) default: - break } + // assuming it is blocked, we can now try to drain the internal channel and + // unblock it select { - case <-stream.messages: - break - default: + case <-time.After(10 * time.Millisecond): + // if we're unable to drain the channel within 10ms, something seems broken t.Fatal("Expected to be able to read from stream.messages but was unable to") + case <-stream.messages: } select { case err := <-errorCh: diff --git a/daemon/logger/splunk/splunk_test.go b/daemon/logger/splunk/splunk_test.go index 654e96a309648..db1e905a737a2 100644 --- a/daemon/logger/splunk/splunk_test.go +++ b/daemon/logger/splunk/splunk_test.go @@ -925,7 +925,12 @@ func TestFrequency(t *testing.T) { // 1 to verify connection and 10 to verify that we have sent messages with required frequency, // but because frequency is too small (to keep test quick), instead of 11, use 9 if context switches will be slow - if hec.numOfRequests < 9 { + expectedRequests := 9 + if runtime.GOOS == "windows" { + // sometimes in Windows, this test fails with number of requests showing 8. So be more conservative. + expectedRequests = 7 + } + if hec.numOfRequests < expectedRequests { t.Fatalf("Unexpected number of requests %d", hec.numOfRequests) } diff --git a/hack/ci/windows.ps1 b/hack/ci/windows.ps1 index 705a23b1d3e6a..19929f326a697 100644 --- a/hack/ci/windows.ps1 +++ b/hack/ci/windows.ps1 @@ -15,6 +15,11 @@ if ($env:BUILD_TAG -match "-LoW") { $env:LCOW_MODE=1 } if ($env:BUILD_TAG -match "-WoW") { $env:LCOW_MODE="" } +Write-Host -ForegroundColor Red "DEBUG: print all environment variables to check how Jenkins runs this script" +$allArgs = [Environment]::GetCommandLineArgs() +Write-Host -ForegroundColor Red $allArgs +Write-Host -ForegroundColor Red "----------------------------------------------------------------------------" + # ------------------------------------------------------------------------------------------- # When executed, we rely on four variables being set in the environment: # @@ -46,10 +51,24 @@ if ($env:BUILD_TAG -match "-WoW") { $env:LCOW_MODE="" } # TESTRUN_DRIVE\TESTRUN_SUBDIR\CI- or # d:\CI\CI- # +# Optional environment variables help in CI: +# +# BUILD_NUMBER + BRANCH_NAME are optional variables to be added to the directory below TESTRUN_SUBDIR +# to have individual folder per CI build. If some files couldn't be +# cleaned up and we want to re-run the build in CI. +# Hence, the daemon under test is run under +# TESTRUN_DRIVE\TESTRUN_SUBDIR\PR-\ or +# d:\CI\PR-\ +# # In addition, the following variables can control the run configuration: # # DOCKER_DUT_DEBUG if defined starts the daemon under test in debug mode. # +# DOCKER_STORAGE_OPTS comma-separated list of optional storage driver options for the daemon under test +# examples: +# DOCKER_STORAGE_OPTS="size=40G" +# DOCKER_STORAGE_OPTS="lcow.globalmode=false,lcow.kernel=kernel.efi" +# # SKIP_VALIDATION_TESTS if defined skips the validation tests # # SKIP_UNIT_TESTS if defined skips the unit tests @@ -266,7 +285,7 @@ Try { } } } Catch {} - if ($defender) { Throw "ERROR: Windows Defender real time protection must be disabled for integration tests" } + if ($defender) { Write-Host -ForegroundColor Magenta "WARN: Windows Defender real time protection is enabled, which may cause some integration tests to fail" } # Make sure SOURCES_DRIVE is set if ($null -eq $env:SOURCES_DRIVE) { Throw "ERROR: Environment variable SOURCES_DRIVE is not set" } @@ -418,7 +437,12 @@ Try { # Redirect to a temporary location. $TEMPORIG=$env:TEMP - $env:TEMP="$env:TESTRUN_DRIVE`:\$env:TESTRUN_SUBDIR\CI-$COMMITHASH" + if ($null -eq $env:BUILD_NUMBER) { + $env:TEMP="$env:TESTRUN_DRIVE`:\$env:TESTRUN_SUBDIR\CI-$COMMITHASH" + } else { + # individual temporary location per CI build that better matches the BUILD_URL + $env:TEMP="$env:TESTRUN_DRIVE`:\$env:TESTRUN_SUBDIR\$env:BRANCH_NAME\$env:BUILD_NUMBER" + } $env:LOCALAPPDATA="$env:TEMP\localappdata" $errorActionPreference='Stop' New-Item -ItemType Directory "$env:TEMP" -ErrorAction SilentlyContinue | Out-Null @@ -580,6 +604,15 @@ Try { $dutArgs += "--exec-opt isolation=hyperv" } + # Arguments: Allow setting optional storage-driver options + # example usage: DOCKER_STORAGE_OPTS="lcow.globalmode=false,lcow.kernel=kernel.efi" + if (-not ("$env:DOCKER_STORAGE_OPTS" -eq "")) { + Write-Host -ForegroundColor Green "INFO: Running the daemon under test with storage-driver options ${env:DOCKER_STORAGE_OPTS}" + $env:DOCKER_STORAGE_OPTS.Split(",") | ForEach { + $dutArgs += "--storage-opt $_" + } + } + # Start the daemon under test, ensuring everything is redirected to folders under $TEMP. # Important - we launch the -$COMMITHASH version so that we can kill it without # killing the control daemon. @@ -608,7 +641,8 @@ Try { # Start tailing the daemon under test if the command is installed if ($null -ne (Get-Command "tail" -ErrorAction SilentlyContinue)) { - $tail = start-process "tail" -ArgumentList "-f $env:TEMP\dut.out" -ErrorAction SilentlyContinue + Write-Host -ForegroundColor green "INFO: Start tailing logs of the daemon under tests" + $tail = Start-Process "tail" -ArgumentList "-f $env:TEMP\dut.out" -PassThru -ErrorAction SilentlyContinue } # Verify we can get the daemon under test to respond @@ -717,7 +751,7 @@ Try { # Inspect the pulled or loaded image to get the version directly $ErrorActionPreference = "SilentlyContinue" - $dutimgVersion = $(&"$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" inspect $($env:WINDOWS_BASE_IMAGE) --format "{{.OsVersion}}") + $dutimgVersion = $(&"$env:TEMP\binary\docker-$COMMITHASH" "-H=$($DASHH_CUT)" inspect "$($env:WINDOWS_BASE_IMAGE):$env:WINDOWS_BASE_IMAGE_TAG" --format "{{.OsVersion}}") $ErrorActionPreference = "Stop" Write-Host -ForegroundColor Green $("INFO: Version of $($env:WINDOWS_BASE_IMAGE):$env:WINDOWS_BASE_IMAGE_TAG is '"+$dutimgVersion+"'") } @@ -944,6 +978,12 @@ Try { Remove-Item "$env:TEMP\docker.pid" -force -ErrorAction SilentlyContinue } + # Stop the tail process (if started) + if ($null -ne $tail) { + Write-Host -ForegroundColor green "INFO: Stop tailing logs of the daemon under tests" + Stop-Process -InputObject $tail -Force + } + Write-Host -ForegroundColor Green "INFO: executeCI.ps1 Completed successfully at $(Get-Date)." } Catch [Exception] { @@ -960,6 +1000,9 @@ Catch [Exception] { Throw $_ } Finally { + # Preserve the LastExitCode of the tests + $tmpLastExitCode = $LastExitCode + $ErrorActionPreference="SilentlyContinue" $global:ProgressPreference=$origProgressPreference Write-Host -ForegroundColor Green "INFO: Tidying up at end of run" @@ -991,6 +1034,12 @@ Finally { Set-Location "$env:SOURCES_DRIVE\$env:SOURCES_SUBDIR" -ErrorAction SilentlyContinue Nuke-Everything + + # Restore the TEMP path + if ($null -ne $TEMPORIG) { $env:TEMP="$TEMPORIG" } + $Dur=New-TimeSpan -Start $StartTime -End $(Get-Date) Write-Host -ForegroundColor $FinallyColour "`nINFO: executeCI.ps1 exiting at $(date). Duration $dur`n" + + exit $tmpLastExitCode } diff --git a/hack/make.ps1 b/hack/make.ps1 index 63fdbb32ad0b1..e8ea35d7984b7 100644 --- a/hack/make.ps1 +++ b/hack/make.ps1 @@ -134,7 +134,7 @@ Function Check-InContainer() { # outside of a container where it may be out of date with master. Function Verify-GoVersion() { Try { - $goVersionDockerfile=(Select-String -Path ".\Dockerfile" -Pattern "^ARG[\s]+GO_VERSION=(.*)$").Matches.groups[1].Value.TrimEnd(".0") + $goVersionDockerfile=(Select-String -Path ".\Dockerfile" -Pattern "^ARG[\s]+GO_VERSION=(.*)$").Matches.groups[1].Value -replace '\.0$','' $goVersionInstalled=(go version).ToString().Split(" ")[2].SubString(2) } Catch [Exception] { diff --git a/hack/make.sh b/hack/make.sh index 29e39122351b0..f019e910f9e90 100755 --- a/hack/make.sh +++ b/hack/make.sh @@ -28,30 +28,6 @@ export SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" export MAKEDIR="$SCRIPTDIR/make" export PKG_CONFIG=${PKG_CONFIG:-pkg-config} -# We're a nice, sexy, little shell script, and people might try to run us; -# but really, they shouldn't. We want to be in a container! -inContainer="AssumeSoInitially" -if [ "$(go env GOHOSTOS)" = 'windows' ]; then - if [ -z "$FROM_DOCKERFILE" ]; then - unset inContainer - fi -else - if [ "$PWD" != "/go/src/$DOCKER_PKG" ]; then - unset inContainer - fi -fi - -if [ -z "$inContainer" ]; then - { - echo "# WARNING! I don't seem to be running in a Docker container." - echo "# The result of this command might be an incorrect build, and will not be" - echo "# officially supported." - echo "#" - echo "# Try this instead: make all" - echo "#" - } >&2 -fi - echo # List of bundles to create when no argument is passed diff --git a/hack/make/.integration-test-helpers b/hack/make/.integration-test-helpers index f430df9aa1ef7..91179c94a31b2 100644 --- a/hack/make/.integration-test-helpers +++ b/hack/make/.integration-test-helpers @@ -72,9 +72,27 @@ run_test_integration_suites() { for dir in ${integration_api_dirs}; do if ! ( cd "$dir" - echo "Running $PWD flags=${flags}" + # Create a useful package name based on the tests's $dir. We need to take + # into account that "$dir" can be either an absolute (/go/src/github.com/docker/docker/integration/foo) + # or relative (./integration/foo) path. To account for both, first we strip + # the absolute path, then remove any leading periods and slashes. + pkgname="${dir}" + pkgname="${pkgname#*${GOPATH}/src/${DOCKER_PKG}}" + pkgname="${pkgname#*.}" + pkgname="${pkgname#*\/}" + + # Finally, we use periods as separator (instead of slashes) to be more + # in line with Java package names (which is what junit.xml was designed for) + pkgname="$(go env GOARCH).${pkgname//\//.}" + echo "Running $PWD (${pkgname}) flags=${flags}" + [ -n "$TESTDEBUG" ] && set -x # shellcheck disable=SC2086 - test_env ./test.main ${flags} + test_env gotestsum \ + --format=standard-verbose \ + --jsonfile="${ABS_DEST}/${pkgname//./-}-go-test-report.json" \ + --junitfile="${ABS_DEST}/${pkgname//./-}-junit-report.xml" \ + --raw-command \ + -- go tool test2json -p "${pkgname}" -t ./test.main ${flags} ); then exit 1; fi done } diff --git a/hack/make/binary-daemon b/hack/make/binary-daemon index 003bd4feef589..3b360a9e03df7 100644 --- a/hack/make/binary-daemon +++ b/hack/make/binary-daemon @@ -15,16 +15,16 @@ copy_binaries() { fi echo "Copying nested executables into $dir" for file in containerd containerd-shim ctr runc docker-init docker-proxy rootlesskit rootlesskit-docker-proxy dockerd-rootless.sh; do - cp -f `which "$file"` "$dir/" - if [ "$hash" == "hash" ]; then + cp -f "$(command -v "$file")" "$dir/" + if [ "$hash" = "hash" ]; then hash_files "$dir/$file" fi done # vpnkit is amd64 only - if which "vpnkit.$(uname -m)" 2>&1 >/dev/null; then - cp -f `which "vpnkit.$(uname -m)"` "$dir/vpnkit" - if [ "$hash" == "hash" ]; then + if command -v "vpnkit.$(uname -m)" 2>&1 >/dev/null; then + cp -f "$(command -v "vpnkit.$(uname -m)")" "$dir/vpnkit" + if [ "$hash" = "hash" ]; then hash_files "$dir/vpnkit" fi fi diff --git a/hack/make/test-docker-py b/hack/make/test-docker-py index 9625f47e619c8..da51928e9d601 100644 --- a/hack/make/test-docker-py +++ b/hack/make/test-docker-py @@ -13,6 +13,7 @@ source hack/make/.integration-test-helpers # TODO remove these skip once we update to a docker-py version that has https://github.com/docker/docker-py/pull/2369, https://github.com/docker/docker-py/pull/2380, https://github.com/docker/docker-py/pull/2382 : "${PY_TEST_OPTIONS:=\ --deselect=tests/integration/api_swarm_test.py::SwarmTest::test_init_swarm_data_path_addr \ +--deselect=tests/integration/api_container_test.py::AttachContainerTest::test_attach_no_stream \ --deselect=tests/integration/api_exec_test.py::ExecTest::test_detach_with_arg \ --deselect=tests/integration/api_exec_test.py::ExecDemuxTest::test_exec_command_tty_stream_no_demux \ --deselect=tests/integration/api_build_test.py::BuildTest::test_build_invalid_platform \ diff --git a/hack/make/test-integration b/hack/make/test-integration index 039afc9526f85..5ea41b0a3220a 100755 --- a/hack/make/test-integration +++ b/hack/make/test-integration @@ -1,12 +1,6 @@ #!/usr/bin/env bash set -e -o pipefail -if [ -n "$TEST_INTEGRATION_DEST" ]; then - export DEST="$ABS_DEST/$TEST_INTEGRATION_DEST" - export DOCKER_INTEGRATION_DAEMON_DEST="$DEST" - mkdir -p "$DEST" -fi - source hack/make/.integration-test-helpers if [ ! -z "${TEST_SKIP_INTEGRATION}" ] && [ ! -z "${TEST_SKIP_INTEGRATION_CLI}" ]; then diff --git a/hack/validate/gometalinter b/hack/validate/gometalinter index 0c0ae0d7ee9bc..4300b67a11a63 100755 --- a/hack/validate/gometalinter +++ b/hack/validate/gometalinter @@ -4,10 +4,11 @@ set -e -o pipefail SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # CI platforms differ, so per-platform GOMETALINTER_OPTS can be set -# from a platform-specific Dockerfile, otherwise let's just set +# in the Jenkinsfile, otherwise let's just set a # (somewhat pessimistic) default of 10 minutes. -: ${GOMETALINTER_OPTS=--deadline=10m} +: "${GOMETALINTER_OPTS=--deadline=10m}" +# shellcheck disable=SC2086 gometalinter \ ${GOMETALINTER_OPTS} \ - --config ${SCRIPTDIR}/gometalinter.json ./... + --config "${SCRIPTDIR}/gometalinter.json" ./... diff --git a/integration-cli/benchmark_test.go b/integration-cli/benchmark_test.go index ed51f79ead656..47f164ff38be8 100644 --- a/integration-cli/benchmark_test.go +++ b/integration-cli/benchmark_test.go @@ -28,7 +28,7 @@ func (s *DockerSuite) BenchmarkConcurrentContainerActions(c *check.C) { go func() { defer innerGroup.Done() for i := 0; i < numIterations; i++ { - args := []string{"run", "-d", defaultSleepImage} + args := []string{"run", "-d", "busybox"} args = append(args, sleepCommandForDaemonPlatform()...) out, _, err := dockerCmdWithError(args...) if err != nil { diff --git a/integration-cli/check_test.go b/integration-cli/check_test.go index 2a0b1a25d53bd..4fd9a1062d86e 100644 --- a/integration-cli/check_test.go +++ b/integration-cli/check_test.go @@ -304,8 +304,8 @@ func init() { type DockerSwarmSuite struct { server *httptest.Server ds *DockerSuite + daemonsLock sync.Mutex // protect access to daemons and portIndex daemons []*daemon.Daemon - daemonsLock sync.Mutex // protect access to daemons portIndex int } @@ -333,11 +333,11 @@ func (s *DockerSwarmSuite) AddDaemon(c *check.C, joinSwarm, manager bool) *daemo d.StartAndSwarmInit(c) } } else { - d.StartNode(c) + d.StartNodeWithBusybox(c) } - s.portIndex++ s.daemonsLock.Lock() + s.portIndex++ s.daemons = append(s.daemons, d) s.daemonsLock.Unlock() @@ -354,9 +354,8 @@ func (s *DockerSwarmSuite) TearDownTest(c *check.C) { } } s.daemons = nil - s.daemonsLock.Unlock() - s.portIndex = 0 + s.daemonsLock.Unlock() s.ds.TearDownTest(c) } diff --git a/integration-cli/daemon/daemon_swarm.go b/integration-cli/daemon/daemon_swarm.go index 0c2f003bbdc4d..bbb124dd86300 100644 --- a/integration-cli/daemon/daemon_swarm.go +++ b/integration-cli/daemon/daemon_swarm.go @@ -189,3 +189,25 @@ func (d *Daemon) CheckLeader(c *check.C) (interface{}, check.CommentInterface) { } return fmt.Errorf("no leader"), check.Commentf("could not find leader") } + +// CmdRetryOutOfSequence tries the specified command against the current daemon +// up to 10 times, retrying if it encounters an "update out of sequence" error. +func (d *Daemon) CmdRetryOutOfSequence(args ...string) (string, error) { + var ( + output string + err error + ) + + for i := 0; i < 10; i++ { + output, err = d.Cmd(args...) + // error, no error, whatever. if we don't have "update out of + // sequence", we don't retry, we just return. + if !strings.Contains(output, "update out of sequence") { + return output, err + } + } + + // otherwise, once all of our attempts have been exhausted, just return + // whatever the last values were. + return output, err +} diff --git a/integration-cli/docker_api_exec_test.go b/integration-cli/docker_api_exec_test.go index dcb14af6def4f..78c89f17b14c7 100644 --- a/integration-cli/docker_api_exec_test.go +++ b/integration-cli/docker_api_exec_test.go @@ -1,5 +1,3 @@ -// +build !test_no_exec - package main import ( diff --git a/integration-cli/docker_api_images_test.go b/integration-cli/docker_api_images_test.go index 9e4f84a581f1c..a281ce20c783f 100644 --- a/integration-cli/docker_api_images_test.go +++ b/integration-cli/docker_api_images_test.go @@ -62,8 +62,8 @@ func (s *DockerSuite) TestAPIImagesSaveAndLoad(c *check.C) { v, err := kernel.GetKernelVersion() assert.NilError(c, err) build, _ := strconv.Atoi(strings.Split(strings.SplitN(v.String(), " ", 3)[2][1:], ".")[0]) - if build == 16299 { - c.Skip("Temporarily disabled on RS3 builds") + if build <= 16299 { + c.Skip("Temporarily disabled on RS3 and older because they are too slow. See #39909") } } diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go index 0ff2882cff9e2..5f192afa88dbf 100644 --- a/integration-cli/docker_cli_build_test.go +++ b/integration-cli/docker_cli_build_test.go @@ -4535,17 +4535,17 @@ func (s *DockerSuite) TestBuildBuildTimeArgEnv(c *check.C) { ARG FOO6 ARG FO10 RUN env - RUN [ "$FOO1" == "fromcmd" ] - RUN [ "$FOO2" == "" ] - RUN [ "$FOO3" == "fromenv" ] - RUN [ "$FOO4" == "fromfile" ] - RUN [ "$FOO5" == "fromcmd" ] + RUN [ "$FOO1" = "fromcmd" ] + RUN [ "$FOO2" = "" ] + RUN [ "$FOO3" = "fromenv" ] + RUN [ "$FOO4" = "fromfile" ] + RUN [ "$FOO5" = "fromcmd" ] # The following should not exist at all in the env - RUN [ "$(env | grep FOO6)" == "" ] - RUN [ "$(env | grep FOO7)" == "" ] - RUN [ "$(env | grep FOO8)" == "" ] - RUN [ "$(env | grep FOO9)" == "" ] - RUN [ "$FO10" == "" ] + RUN [ "$(env | grep FOO6)" = "" ] + RUN [ "$(env | grep FOO7)" = "" ] + RUN [ "$(env | grep FOO8)" = "" ] + RUN [ "$(env | grep FOO9)" = "" ] + RUN [ "$FO10" = "" ] ` result := buildImage("testbuildtimeargenv", cli.WithFlags( @@ -4615,9 +4615,9 @@ func (s *DockerSuite) TestBuildBuildTimeArgEmptyValVariants(c *check.C) { ARG %s= ARG %s="" ARG %s='' - RUN [ "$%s" == "$%s" ] - RUN [ "$%s" == "$%s" ] - RUN [ "$%s" == "$%s" ]`, envKey, envKey1, envKey2, envKey, envKey1, envKey1, envKey2, envKey, envKey2) + RUN [ "$%s" = "$%s" ] + RUN [ "$%s" = "$%s" ] + RUN [ "$%s" = "$%s" ]`, envKey, envKey1, envKey2, envKey, envKey1, envKey1, envKey2, envKey, envKey2) buildImageSuccessfully(c, imgName, build.WithDockerfile(dockerfile)) } @@ -5952,7 +5952,7 @@ func (s *DockerSuite) TestBuildCopyFromWindowsIsCaseInsensitive(c *check.C) { } // #33176 -func (s *DockerSuite) TestBuildMulitStageResetScratch(c *check.C) { +func (s *DockerSuite) TestBuildMultiStageResetScratch(c *check.C) { testRequires(c, DaemonIsLinux) dockerfile := ` diff --git a/integration-cli/docker_cli_create_test.go b/integration-cli/docker_cli_create_test.go index 2b1681d32bdf7..cb8171be63863 100644 --- a/integration-cli/docker_cli_create_test.go +++ b/integration-cli/docker_cli_create_test.go @@ -309,7 +309,15 @@ func (s *DockerSuite) TestCreateWithWorkdir(c *check.C) { // Windows does not create the workdir until the container is started if testEnv.OSType == "windows" { dockerCmd(c, "start", name) + if IsolationIsHyperv() { + // Hyper-V isolated containers do not allow file-operations on a + // running container. This test currently uses `docker cp` to verify + // that the WORKDIR was automatically created, which cannot be done + // while the container is running. + dockerCmd(c, "stop", name) + } } + // TODO: rewrite this test to not use `docker cp` for verifying that the WORKDIR was created dockerCmd(c, "cp", fmt.Sprintf("%s:%s", name, dir), prefix+slash+"tmp") } diff --git a/integration-cli/docker_cli_daemon_plugins_test.go b/integration-cli/docker_cli_daemon_plugins_test.go index 355313f013101..033db85d70539 100644 --- a/integration-cli/docker_cli_daemon_plugins_test.go +++ b/integration-cli/docker_cli_daemon_plugins_test.go @@ -121,7 +121,7 @@ func (s *DockerDaemonSuite) TestDaemonShutdownLiveRestoreWithPlugins(c *check.C) // TestDaemonShutdownWithPlugins shuts down running plugins. func (s *DockerDaemonSuite) TestDaemonShutdownWithPlugins(c *check.C) { - testRequires(c, IsAmd64, Network, testEnv.IsLocalDaemon) + testRequires(c, IsAmd64, Network) s.d.Start(c) if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName); err != nil { @@ -159,7 +159,7 @@ func (s *DockerDaemonSuite) TestDaemonShutdownWithPlugins(c *check.C) { // TestDaemonKillWithPlugins leaves plugins running. func (s *DockerDaemonSuite) TestDaemonKillWithPlugins(c *check.C) { - testRequires(c, IsAmd64, Network, testEnv.IsLocalDaemon) + testRequires(c, IsAmd64, Network) s.d.Start(c) if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pName); err != nil { @@ -232,7 +232,7 @@ func (s *DockerDaemonSuite) TestVolumePlugin(c *check.C) { } func (s *DockerDaemonSuite) TestPluginVolumeRemoveOnRestart(c *check.C) { - testRequires(c, DaemonIsLinux, Network, IsAmd64) + testRequires(c, IsAmd64, Network) s.d.Start(c, "--live-restore=true") diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index 9d84d9c7dd37b..d27e7d7e57fe6 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -26,7 +26,6 @@ import ( "github.com/cloudflare/cfssl/helpers" "github.com/creack/pty" "github.com/docker/docker/api/types" - moby_daemon "github.com/docker/docker/daemon" "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli" "github.com/docker/docker/integration-cli/cli/build" @@ -826,7 +825,6 @@ func (s *DockerDaemonSuite) TestDaemonDefaultGatewayIPv4ExplicitOutsideContainer } func (s *DockerDaemonSuite) TestDaemonDefaultNetworkInvalidClusterConfig(c *check.C) { - testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon) // Start daemon without docker0 bridge defaultNetworkBridge := "docker0" @@ -967,7 +965,6 @@ func (s *DockerDaemonSuite) TestDaemonLinksIpTablesRulesWhenLinkAndUnlink(c *che } func (s *DockerDaemonSuite) TestDaemonUlimitDefaults(c *check.C) { - testRequires(c, DaemonIsLinux) s.d.StartWithBusybox(c, "--default-ulimit", "nofile=42:42", "--default-ulimit", "nproc=1024:1024") @@ -1457,7 +1454,7 @@ func (s *DockerDaemonSuite) TestCleanupMountsAfterDaemonAndContainerKill(c *chec // kill the container icmd.RunCommand(ctrBinary, "--address", containerdSocket, - "--namespace", moby_daemon.ContainersNamespace, "tasks", "kill", id).Assert(c, icmd.Success) + "--namespace", d.ContainersNamespace(), "tasks", "kill", id).Assert(c, icmd.Success) // restart daemon. d.Restart(c) @@ -1977,7 +1974,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithKilledRunningContainer(t *check // kill the container icmd.RunCommand(ctrBinary, "--address", containerdSocket, - "--namespace", moby_daemon.ContainersNamespace, "tasks", "kill", cid).Assert(t, icmd.Success) + "--namespace", s.d.ContainersNamespace(), "tasks", "kill", cid).Assert(t, icmd.Success) // Give time to containerd to process the command if we don't // the exit event might be received after we do the inspect @@ -2080,7 +2077,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithUnpausedRunningContainer(t *che result := icmd.RunCommand( ctrBinary, "--address", containerdSocket, - "--namespace", moby_daemon.ContainersNamespace, + "--namespace", s.d.ContainersNamespace(), "tasks", "resume", cid) result.Assert(t, icmd.Success) diff --git a/integration-cli/docker_cli_events_unix_test.go b/integration-cli/docker_cli_events_unix_test.go index aaa7a91f1ef11..44252c9ac6fa3 100644 --- a/integration-cli/docker_cli_events_unix_test.go +++ b/integration-cli/docker_cli_events_unix_test.go @@ -388,7 +388,6 @@ func (s *DockerSuite) TestEventsFilterNetworkID(c *check.C) { } func (s *DockerDaemonSuite) TestDaemonEvents(c *check.C) { - testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux) // daemon config file configFilePath := "test.json" @@ -457,7 +456,6 @@ func (s *DockerDaemonSuite) TestDaemonEvents(c *check.C) { } func (s *DockerDaemonSuite) TestDaemonEventsWithFilters(c *check.C) { - testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux) // daemon config file configFilePath := "test.json" diff --git a/integration-cli/docker_cli_exec_test.go b/integration-cli/docker_cli_exec_test.go index f6d4e3cf20e00..72fa092824b0e 100644 --- a/integration-cli/docker_cli_exec_test.go +++ b/integration-cli/docker_cli_exec_test.go @@ -1,5 +1,3 @@ -// +build !test_no_exec - package main import ( @@ -81,8 +79,7 @@ func (s *DockerSuite) TestExecAfterContainerRestart(c *check.C) { } func (s *DockerDaemonSuite) TestExecAfterDaemonRestart(c *check.C) { - // TODO Windows CI: Requires a little work to get this ported. - testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon) + // TODO Windows CI: DockerDaemonSuite doesn't run on Windows, and requires a little work to get this ported. s.d.StartWithBusybox(c) out, err := s.d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top") diff --git a/integration-cli/docker_cli_exec_unix_test.go b/integration-cli/docker_cli_exec_unix_test.go index c36cf56519293..f2f89f2be090e 100644 --- a/integration-cli/docker_cli_exec_unix_test.go +++ b/integration-cli/docker_cli_exec_unix_test.go @@ -1,4 +1,4 @@ -// +build !windows,!test_no_exec +// +build !windows package main diff --git a/integration-cli/docker_cli_info_test.go b/integration-cli/docker_cli_info_test.go index 24d9c61a3c0e0..c569a0d1dfebe 100644 --- a/integration-cli/docker_cli_info_test.go +++ b/integration-cli/docker_cli_info_test.go @@ -211,7 +211,6 @@ func (s *DockerSuite) TestInsecureRegistries(c *check.C) { } func (s *DockerDaemonSuite) TestRegistryMirrors(c *check.C) { - testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux) registryMirror1 := "https://192.168.1.2" registryMirror2 := "http://registry.mirror.com:5000" diff --git a/integration-cli/docker_cli_links_test.go b/integration-cli/docker_cli_links_test.go index 9be3ea117a1f3..8966caed1c97a 100644 --- a/integration-cli/docker_cli_links_test.go +++ b/integration-cli/docker_cli_links_test.go @@ -140,7 +140,7 @@ func (s *DockerSuite) TestLinksNotStartedParentNotFail(c *check.C) { func (s *DockerSuite) TestLinksHostsFilesInject(c *check.C) { testRequires(c, DaemonIsLinux) - testRequires(c, testEnv.IsLocalDaemon, ExecSupport) + testRequires(c, testEnv.IsLocalDaemon) out, _ := dockerCmd(c, "run", "-itd", "--name", "one", "busybox", "top") idOne := strings.TrimSpace(out) @@ -158,7 +158,7 @@ func (s *DockerSuite) TestLinksHostsFilesInject(c *check.C) { func (s *DockerSuite) TestLinksUpdateOnRestart(c *check.C) { testRequires(c, DaemonIsLinux) - testRequires(c, testEnv.IsLocalDaemon, ExecSupport) + testRequires(c, testEnv.IsLocalDaemon) dockerCmd(c, "run", "-d", "--name", "one", "busybox", "top") out, _ := dockerCmd(c, "run", "-d", "--name", "two", "--link", "one:onetwo", "--link", "one:one", "busybox", "top") id := strings.TrimSpace(string(out)) diff --git a/integration-cli/docker_cli_network_unix_test.go b/integration-cli/docker_cli_network_unix_test.go index fd0355adb5a57..cbc953e581a8d 100644 --- a/integration-cli/docker_cli_network_unix_test.go +++ b/integration-cli/docker_cli_network_unix_test.go @@ -805,7 +805,6 @@ func (s *DockerNetworkSuite) TestDockerPluginV2NetworkDriver(c *check.C) { } func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *check.C) { - testRequires(c, ExecSupport) // On default bridge network built-in service discovery should not happen hostsFile := "/etc/hosts" bridgeName := "external-bridge" @@ -863,7 +862,7 @@ func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c * } func (s *DockerNetworkSuite) TestDockerNetworkAnonymousEndpoint(c *check.C) { - testRequires(c, ExecSupport, NotArm) + testRequires(c, NotArm) hostsFile := "/etc/hosts" cstmBridgeNw := "custom-bridge-nw" cstmBridgeNw1 := "custom-bridge-nw1" @@ -1665,7 +1664,6 @@ func (s *DockerNetworkSuite) TestDockerNetworkCreateDeleteSpecialCharacters(c *c } func (s *DockerDaemonSuite) TestDaemonRestartRestoreBridgeNetwork(t *check.C) { - testRequires(t, DaemonIsLinux) s.d.StartWithBusybox(t, "--live-restore") defer s.d.Stop(t) oldCon := "old" diff --git a/integration-cli/docker_cli_proxy_test.go b/integration-cli/docker_cli_proxy_test.go index d7bb1c8fbeba5..c444b611b51a8 100644 --- a/integration-cli/docker_cli_proxy_test.go +++ b/integration-cli/docker_cli_proxy_test.go @@ -21,7 +21,6 @@ func (s *DockerSuite) TestCLIProxyDisableProxyUnixSock(c *check.C) { // Can't use localhost here since go has a special case to not use proxy if connecting to localhost // See https://golang.org/pkg/net/http/#ProxyFromEnvironment func (s *DockerDaemonSuite) TestCLIProxyProxyTCPSock(c *check.C) { - testRequires(c, testEnv.IsLocalDaemon) // get the IP to use to connect since we can't use localhost addrs, err := net.InterfaceAddrs() assert.NilError(c, err) diff --git a/integration-cli/docker_cli_restart_test.go b/integration-cli/docker_cli_restart_test.go index 566532583cff5..f6c41d5519080 100644 --- a/integration-cli/docker_cli_restart_test.go +++ b/integration-cli/docker_cli_restart_test.go @@ -292,7 +292,7 @@ func (s *DockerSuite) TestRestartContainerwithRestartPolicy(c *check.C) { dockerCmd(c, "start", id1) dockerCmd(c, "start", id2) - // Kill the containers, making sure the are stopped at the end of the test + // Kill the containers, making sure they are stopped at the end of the test dockerCmd(c, "kill", id1) dockerCmd(c, "kill", id2) err = waitInspect(id1, "{{ .State.Restarting }} {{ .State.Running }}", "false false", waitTimeout) diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 1a5204ff67603..46e731a60924b 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -1792,16 +1792,14 @@ func (s *DockerSuite) TestRunExitOnStdinClose(c *check.C) { func (s *DockerSuite) TestRunInteractiveWithRestartPolicy(c *check.C) { name := "test-inter-restart" - result := icmd.StartCmd(icmd.Cmd{ + result := icmd.RunCmd(icmd.Cmd{ Command: []string{dockerBinary, "run", "-i", "--name", name, "--restart=always", "busybox", "sh"}, Stdin: bytes.NewBufferString("exit 11"), }) - assert.NilError(c, result.Error) defer func() { - dockerCmdWithResult("stop", name).Assert(c, icmd.Success) + cli.Docker(cli.Args("stop", name)).Assert(c, icmd.Success) }() - result = icmd.WaitOnCmd(60*time.Second, result) result.Assert(c, icmd.Expected{ExitCode: 11}) } @@ -3430,7 +3428,7 @@ func (s *DockerSuite) TestRunLoopbackWhenNetworkDisabled(c *check.C) { func (s *DockerSuite) TestRunModeNetContainerHostname(c *check.C) { // Windows does not support --net=container - testRequires(c, DaemonIsLinux, ExecSupport) + testRequires(c, DaemonIsLinux) dockerCmd(c, "run", "-i", "-d", "--name", "parent", "busybox", "top") out, _ := dockerCmd(c, "exec", "parent", "cat", "/etc/hostname") diff --git a/integration-cli/docker_cli_run_unix_test.go b/integration-cli/docker_cli_run_unix_test.go index b35d62a2060d5..1675418633de5 100644 --- a/integration-cli/docker_cli_run_unix_test.go +++ b/integration-cli/docker_cli_run_unix_test.go @@ -1442,7 +1442,7 @@ func (s *DockerSuite) TestRunUserDeviceAllowed(c *check.C) { } func (s *DockerDaemonSuite) TestRunSeccompJSONNewFormat(c *check.C) { - testRequires(c, testEnv.IsLocalDaemon, seccompEnabled) + testRequires(c, seccompEnabled) s.d.StartWithBusybox(c) @@ -1467,7 +1467,7 @@ func (s *DockerDaemonSuite) TestRunSeccompJSONNewFormat(c *check.C) { } func (s *DockerDaemonSuite) TestRunSeccompJSONNoNameAndNames(c *check.C) { - testRequires(c, testEnv.IsLocalDaemon, seccompEnabled) + testRequires(c, seccompEnabled) s.d.StartWithBusybox(c) @@ -1493,7 +1493,7 @@ func (s *DockerDaemonSuite) TestRunSeccompJSONNoNameAndNames(c *check.C) { } func (s *DockerDaemonSuite) TestRunSeccompJSONNoArchAndArchMap(c *check.C) { - testRequires(c, testEnv.IsLocalDaemon, seccompEnabled) + testRequires(c, seccompEnabled) s.d.StartWithBusybox(c) @@ -1530,7 +1530,7 @@ func (s *DockerDaemonSuite) TestRunSeccompJSONNoArchAndArchMap(c *check.C) { } func (s *DockerDaemonSuite) TestRunWithDaemonDefaultSeccompProfile(c *check.C) { - testRequires(c, testEnv.IsLocalDaemon, seccompEnabled) + testRequires(c, seccompEnabled) s.d.StartWithBusybox(c) diff --git a/integration-cli/docker_cli_service_health_test.go b/integration-cli/docker_cli_service_health_test.go index 8f6a69b0bc4ab..d72ad3fcf02a8 100644 --- a/integration-cli/docker_cli_service_health_test.go +++ b/integration-cli/docker_cli_service_health_test.go @@ -28,7 +28,7 @@ func (s *DockerSwarmSuite) TestServiceHealthRun(c *check.C) { result := cli.BuildCmd(c, imageName, cli.Daemon(d), build.WithDockerfile(`FROM busybox RUN touch /status - HEALTHCHECK --interval=1s --timeout=1s --retries=1\ + HEALTHCHECK --interval=1s --timeout=5s --retries=1\ CMD cat /status`), ) result.Assert(c, icmd.Success) diff --git a/integration-cli/docker_cli_service_scale_test.go b/integration-cli/docker_cli_service_scale_test.go index f02bc738aad93..25a0e145c1823 100644 --- a/integration-cli/docker_cli_service_scale_test.go +++ b/integration-cli/docker_cli_service_scale_test.go @@ -14,11 +14,11 @@ func (s *DockerSwarmSuite) TestServiceScale(c *check.C) { d := s.AddDaemon(c, true, true) service1Name := "TestService1" - service1Args := append([]string{"service", "create", "--detach", "--no-resolve-image", "--name", service1Name, defaultSleepImage}, sleepCommandForDaemonPlatform()...) + service1Args := append([]string{"service", "create", "--detach", "--no-resolve-image", "--name", service1Name, "busybox"}, sleepCommandForDaemonPlatform()...) // global mode service2Name := "TestService2" - service2Args := append([]string{"service", "create", "--detach", "--no-resolve-image", "--name", service2Name, "--mode=global", defaultSleepImage}, sleepCommandForDaemonPlatform()...) + service2Args := append([]string{"service", "create", "--detach", "--no-resolve-image", "--name", service2Name, "--mode=global", "busybox"}, sleepCommandForDaemonPlatform()...) // Create services _, err := d.Cmd(service1Args...) diff --git a/integration-cli/docker_cli_swarm_test.go b/integration-cli/docker_cli_swarm_test.go index 64d4fade55a8e..9800b5fbd10d1 100644 --- a/integration-cli/docker_cli_swarm_test.go +++ b/integration-cli/docker_cli_swarm_test.go @@ -277,19 +277,23 @@ func (s *DockerSwarmSuite) TestSwarmPublishAdd(c *check.C) { d := s.AddDaemon(c, true, true) name := "top" + // this first command does not have to be retried because service creates + // don't return out of sequence errors. out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--label", "x=y", "busybox", "top") assert.NilError(c, err, out) assert.Assert(c, strings.TrimSpace(out) != "") - out, err = d.Cmd("service", "update", "--detach", "--publish-add", "80:80", name) + out, err = d.CmdRetryOutOfSequence("service", "update", "--detach", "--publish-add", "80:80", name) assert.NilError(c, err, out) - out, err = d.Cmd("service", "update", "--detach", "--publish-add", "80:80", name) + out, err = d.CmdRetryOutOfSequence("service", "update", "--detach", "--publish-add", "80:80", name) assert.NilError(c, err, out) - _, err = d.Cmd("service", "update", "--detach", "--publish-add", "80:80", "--publish-add", "80:20", name) + _, err = d.CmdRetryOutOfSequence("service", "update", "--detach", "--publish-add", "80:80", "--publish-add", "80:20", name) assert.ErrorContains(c, err, "") + // this last command does not have to be retried because service inspect + // does not return out of sequence errors. out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.EndpointSpec.Ports }}", name) assert.NilError(c, err, out) assert.Equal(c, strings.TrimSpace(out), "[{ tcp 80 80 ingress}]") @@ -838,7 +842,7 @@ func (s *DockerSwarmSuite) TestSwarmServiceTTY(c *check.C) { name := "top" - ttyCheck := "if [ -t 0 ]; then echo TTY > /status && top; else echo none > /status && top; fi" + ttyCheck := "if [ -t 0 ]; then echo TTY > /status; else echo none > /status; fi; exec top" // Without --tty expectedOutput := "none" diff --git a/integration-cli/docker_cli_userns_test.go b/integration-cli/docker_cli_userns_test.go index 1cbf367fe4dc7..c423f5cd433d3 100644 --- a/integration-cli/docker_cli_userns_test.go +++ b/integration-cli/docker_cli_userns_test.go @@ -23,7 +23,7 @@ import ( // 1. validate uid/gid maps are set properly // 2. verify that files created are owned by remapped root func (s *DockerDaemonSuite) TestDaemonUserNamespaceRootSetting(c *check.C) { - testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon, UserNamespaceInKernel) + testRequires(c, UserNamespaceInKernel) s.d.StartWithBusybox(c, "--userns-remap", "default") diff --git a/integration-cli/docker_utils_test.go b/integration-cli/docker_utils_test.go index c142564483974..a95246f141224 100644 --- a/integration-cli/docker_utils_test.go +++ b/integration-cli/docker_utils_test.go @@ -63,7 +63,7 @@ func getContainerCount(c *check.C) int { for _, line := range lines { if strings.Contains(line, containers) { output := strings.TrimSpace(line) - output = strings.TrimLeft(output, containers) + output = strings.TrimPrefix(output, containers) output = strings.Trim(output, " ") containerCount, err := strconv.Atoi(output) assert.NilError(c, err) @@ -347,7 +347,7 @@ func getInspectBody(c *check.C, version, id string) []byte { // Run a long running idle task in a background container using the // system-specific default image and command. func runSleepingContainer(c *check.C, extraArgs ...string) string { - return runSleepingContainerInImage(c, defaultSleepImage, extraArgs...) + return runSleepingContainerInImage(c, "busybox", extraArgs...) } // Run a long running idle task in a background container using the specified diff --git a/integration-cli/requirements_test.go b/integration-cli/requirements_test.go index 98220cfdecb1f..fd3f4efaad5d8 100644 --- a/integration-cli/requirements_test.go +++ b/integration-cli/requirements_test.go @@ -80,10 +80,6 @@ func UnixCli() bool { return isUnixCli } -func ExecSupport() bool { - return supportsExec -} - func Network() bool { // Set a timeout on the GET at 15s var timeout = time.Duration(15 * time.Second) diff --git a/integration-cli/requirements_unix_test.go b/integration-cli/requirements_unix_test.go index cea1db1e6d73c..c309824de7523 100644 --- a/integration-cli/requirements_unix_test.go +++ b/integration-cli/requirements_unix_test.go @@ -84,20 +84,11 @@ func bridgeNfIptables() bool { return !SysInfo.BridgeNFCallIPTablesDisabled } -func bridgeNfIP6tables() bool { - return !SysInfo.BridgeNFCallIP6TablesDisabled -} - func unprivilegedUsernsClone() bool { content, err := ioutil.ReadFile("/proc/sys/kernel/unprivileged_userns_clone") return err != nil || !strings.Contains(string(content), "0") } -func ambientCapabilities() bool { - content, err := ioutil.ReadFile("/proc/self/status") - return err != nil || strings.Contains(string(content), "CapAmb:") -} - func overlayFSSupported() bool { cmd := exec.Command(dockerBinary, "run", "--rm", "busybox", "/bin/sh", "-c", "cat /proc/filesystems") out, err := cmd.CombinedOutput() @@ -107,20 +98,6 @@ func overlayFSSupported() bool { return bytes.Contains(out, []byte("overlay\n")) } -func overlay2Supported() bool { - if !overlayFSSupported() { - return false - } - - daemonV, err := kernel.ParseRelease(testEnv.DaemonInfo.KernelVersion) - if err != nil { - return false - } - requiredV := kernel.VersionInfo{Kernel: 4} - return kernel.CompareKernelVersion(*daemonV, requiredV) > -1 - -} - func init() { if testEnv.IsLocalDaemon() { SysInfo = sysinfo.New(true) diff --git a/integration-cli/test_vars_exec_test.go b/integration-cli/test_vars_exec_test.go deleted file mode 100644 index 7633b346ba9bd..0000000000000 --- a/integration-cli/test_vars_exec_test.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !test_no_exec - -package main - -const ( - // indicates docker daemon tested supports 'docker exec' - supportsExec = true -) diff --git a/integration-cli/test_vars_noexec_test.go b/integration-cli/test_vars_noexec_test.go deleted file mode 100644 index 08450905247f2..0000000000000 --- a/integration-cli/test_vars_noexec_test.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build test_no_exec - -package main - -const ( - // indicates docker daemon tested supports 'docker exec' - supportsExec = false -) diff --git a/integration-cli/test_vars_unix_test.go b/integration-cli/test_vars_unix_test.go index f9ecc01123cd9..1ab8a5ca48700 100644 --- a/integration-cli/test_vars_unix_test.go +++ b/integration-cli/test_vars_unix_test.go @@ -7,8 +7,4 @@ const ( isUnixCli = true expectedFileChmod = "-rw-r--r--" - - // On Unix variants, the busybox image comes with the `top` command which - // runs indefinitely while still being interruptible by a signal. - defaultSleepImage = "busybox" ) diff --git a/integration-cli/test_vars_windows_test.go b/integration-cli/test_vars_windows_test.go index bfc9a5a915c09..f81ac53cc31e5 100644 --- a/integration-cli/test_vars_windows_test.go +++ b/integration-cli/test_vars_windows_test.go @@ -8,8 +8,4 @@ const ( // this is the expected file permission set on windows: gh#11395 expectedFileChmod = "-rwxr-xr-x" - - // On Windows, the busybox image doesn't have the `top` command, so we rely - // on `sleep` with a high duration. - defaultSleepImage = "busybox" ) diff --git a/integration/build/build_session_test.go b/integration/build/build_session_test.go index db5124f4c796c..578ea2102c8bc 100644 --- a/integration/build/build_session_test.go +++ b/integration/build/build_session_test.go @@ -9,8 +9,8 @@ import ( "testing" "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/versions" dclient "github.com/docker/docker/client" - "github.com/docker/docker/internal/test/daemon" "github.com/docker/docker/internal/test/fakecontext" "github.com/docker/docker/internal/test/request" "github.com/moby/buildkit/session" @@ -23,18 +23,9 @@ import ( func TestBuildWithSession(t *testing.T) { skip.If(t, testEnv.DaemonInfo.OSType == "windows") + skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.39"), "experimental in older versions") - var client dclient.APIClient - if !testEnv.DaemonInfo.ExperimentalBuild { - skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon") - - d := daemon.New(t, daemon.WithExperimental) - d.StartWithBusybox(t) - defer d.Stop(t) - client = d.NewClientT(t) - } else { - client = testEnv.APIClient() - } + client := testEnv.APIClient() dockerfile := ` FROM busybox diff --git a/integration/build/build_squash_test.go b/integration/build/build_squash_test.go index 4398ebc7b7712..788589d612cd4 100644 --- a/integration/build/build_squash_test.go +++ b/integration/build/build_squash_test.go @@ -100,7 +100,7 @@ func TestBuildSquashParent(t *testing.T) { ) container.Run(ctx, t, client, container.WithImage(name), - container.WithCmd("/bin/sh", "-c", `[ "$(echo $HELLO)" == "world" ]`), + container.WithCmd("/bin/sh", "-c", `[ "$(echo $HELLO)" = "world" ]`), ) origHistory, err := client.ImageHistory(ctx, origID) diff --git a/integration/network/ipvlan/ipvlan_test.go b/integration/network/ipvlan/ipvlan_test.go index a02b0db2a6b84..e8cfb14d6eff0 100644 --- a/integration/network/ipvlan/ipvlan_test.go +++ b/integration/network/ipvlan/ipvlan_test.go @@ -1,6 +1,6 @@ // +build !windows -package ipvlan +package ipvlan // import "github.com/docker/docker/integration/network/ipvlan" import ( "context" @@ -22,11 +22,10 @@ import ( func TestDockerNetworkIpvlanPersistance(t *testing.T) { // verify the driver automatically provisions the 802.1q link (di-dummy0.70) - skip.If(t, testEnv.DaemonInfo.OSType == "windows") skip.If(t, testEnv.IsRemoteDaemon) skip.If(t, !ipvlanKernelSupport(t), "Kernel doesn't support ipvlan") - d := daemon.New(t, daemon.WithExperimental) + d := daemon.New(t) d.StartWithBusybox(t) defer d.Stop(t) @@ -50,7 +49,6 @@ func TestDockerNetworkIpvlanPersistance(t *testing.T) { } func TestDockerNetworkIpvlan(t *testing.T) { - skip.If(t, testEnv.DaemonInfo.OSType == "windows") skip.If(t, testEnv.IsRemoteDaemon) skip.If(t, !ipvlanKernelSupport(t), "Kernel doesn't support ipvlan") @@ -87,7 +85,7 @@ func TestDockerNetworkIpvlan(t *testing.T) { test: testIpvlanAddressing, }, } { - d := daemon.New(t, daemon.WithExperimental) + d := daemon.New(t) d.StartWithBusybox(t) c := d.NewClientT(t) diff --git a/integration/network/ipvlan/main_test.go b/integration/network/ipvlan/main_test.go index 2d5f62453c4ba..0936647959dc8 100644 --- a/integration/network/ipvlan/main_test.go +++ b/integration/network/ipvlan/main_test.go @@ -1,3 +1,5 @@ +// +build !windows + package ipvlan // import "github.com/docker/docker/integration/network/ipvlan" import ( diff --git a/integration/network/ipvlan/main_windows_test.go b/integration/network/ipvlan/main_windows_test.go new file mode 100644 index 0000000000000..d016a04b66905 --- /dev/null +++ b/integration/network/ipvlan/main_windows_test.go @@ -0,0 +1 @@ +package ipvlan // import "github.com/docker/docker/integration/network/ipvlan" diff --git a/integration/network/macvlan/macvlan_test.go b/integration/network/macvlan/macvlan_test.go index cb1f70a78f59e..b734cad82e8c8 100644 --- a/integration/network/macvlan/macvlan_test.go +++ b/integration/network/macvlan/macvlan_test.go @@ -1,6 +1,6 @@ // +build !windows -package macvlan +package macvlan // import "github.com/docker/docker/integration/network/macvlan" import ( "context" @@ -20,7 +20,6 @@ import ( func TestDockerNetworkMacvlanPersistance(t *testing.T) { // verify the driver automatically provisions the 802.1q link (dm-dummy0.60) skip.If(t, testEnv.IsRemoteDaemon) - skip.If(t, !macvlanKernelSupport(), "Kernel doesn't support macvlan") d := daemon.New(t) d.StartWithBusybox(t) @@ -43,7 +42,6 @@ func TestDockerNetworkMacvlanPersistance(t *testing.T) { func TestDockerNetworkMacvlan(t *testing.T) { skip.If(t, testEnv.IsRemoteDaemon) - skip.If(t, !macvlanKernelSupport(), "Kernel doesn't support macvlan") for _, tc := range []struct { name string @@ -271,8 +269,3 @@ func testMacvlanAddressing(client client.APIClient) func(*testing.T) { assert.Check(t, strings.Contains(result.Combined(), "default via 2001:db8:abca::254 dev eth0")) } } - -// ensure Kernel version is >= v3.9 for macvlan support -func macvlanKernelSupport() bool { - return n.CheckKernelMajorVersionGreaterOrEqualThen(3, 9) -} diff --git a/integration/network/macvlan/main_test.go b/integration/network/macvlan/main_test.go index 31cf111b22af7..15bdc323b5ecf 100644 --- a/integration/network/macvlan/main_test.go +++ b/integration/network/macvlan/main_test.go @@ -1,3 +1,5 @@ +// +build !windows + package macvlan // import "github.com/docker/docker/integration/network/macvlan" import ( diff --git a/integration/network/macvlan/main_windows_test.go b/integration/network/macvlan/main_windows_test.go new file mode 100644 index 0000000000000..367cd2c540679 --- /dev/null +++ b/integration/network/macvlan/main_windows_test.go @@ -0,0 +1 @@ +package macvlan // import "github.com/docker/docker/integration/network/macvlan" diff --git a/integration/service/inspect_test.go b/integration/service/inspect_test.go index c79751f93082f..a4e196e52481d 100644 --- a/integration/service/inspect_test.go +++ b/integration/service/inspect_test.go @@ -7,9 +7,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/filters" swarmtypes "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/client" "github.com/docker/docker/integration/internal/swarm" "github.com/google/go-cmp/cmp" "gotest.tools/assert" @@ -38,7 +36,7 @@ func TestInspect(t *testing.T) { assert.NilError(t, err) id := resp.ID - poll.WaitOn(t, serviceContainerCount(client, id, instances)) + poll.WaitOn(t, swarm.RunningTasksCount(client, id, instances)) service, _, err := client.ServiceInspectWithRaw(ctx, id, types.ServiceInspectOptions{}) assert.NilError(t, err) @@ -134,21 +132,3 @@ func fullSwarmServiceSpec(name string, replicas uint64) swarmtypes.ServiceSpec { }, } } - -func serviceContainerCount(client client.ServiceAPIClient, id string, count uint64) func(log poll.LogT) poll.Result { - return func(log poll.LogT) poll.Result { - filter := filters.NewArgs() - filter.Add("service", id) - tasks, err := client.TaskList(context.Background(), types.TaskListOptions{ - Filters: filter, - }) - switch { - case err != nil: - return poll.Error(err) - case len(tasks) == int(count): - return poll.Success() - default: - return poll.Continue("task count at %d waiting for %d", len(tasks), count) - } - } -} diff --git a/integration/session/session_test.go b/integration/session/session_test.go index f5602f944904e..2f8d79c0e784f 100644 --- a/integration/session/session_test.go +++ b/integration/session/session_test.go @@ -4,7 +4,7 @@ import ( "net/http" "testing" - "github.com/docker/docker/internal/test/daemon" + "github.com/docker/docker/api/types/versions" req "github.com/docker/docker/internal/test/request" "gotest.tools/assert" is "gotest.tools/assert/cmp" @@ -13,17 +13,10 @@ import ( func TestSessionCreate(t *testing.T) { skip.If(t, testEnv.OSType == "windows", "FIXME") + skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.39"), "experimental in older versions") defer setupTest(t)() daemonHost := req.DaemonHost() - if !testEnv.DaemonInfo.ExperimentalBuild { - skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon") - - d := daemon.New(t, daemon.WithExperimental) - d.StartWithBusybox(t) - defer d.Stop(t) - daemonHost = d.Sock() - } res, body, err := req.Post("/session", req.Host(daemonHost), @@ -41,17 +34,10 @@ func TestSessionCreate(t *testing.T) { func TestSessionCreateWithBadUpgrade(t *testing.T) { skip.If(t, testEnv.OSType == "windows", "FIXME") + skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.39"), "experimental in older versions") defer setupTest(t)() daemonHost := req.DaemonHost() - if !testEnv.DaemonInfo.ExperimentalBuild { - skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon") - - d := daemon.New(t, daemon.WithExperimental) - d.StartWithBusybox(t) - defer d.Stop(t) - daemonHost = d.Sock() - } res, body, err := req.Post("/session", req.Host(daemonHost)) assert.NilError(t, err) diff --git a/internal/test/daemon/daemon.go b/internal/test/daemon/daemon.go index 8e6b33c98f963..7ad377347989c 100644 --- a/internal/test/daemon/daemon.go +++ b/internal/test/daemon/daemon.go @@ -147,6 +147,11 @@ func New(t testingT, ops ...func(*Daemon)) *Daemon { return d } +// ContainersNamespace returns the containerd namespace used for containers. +func (d *Daemon) ContainersNamespace() string { + return d.id +} + // RootDir returns the root directory of the daemon. func (d *Daemon) RootDir() string { return d.Root @@ -231,12 +236,15 @@ func (d *Daemon) StartWithLogFile(out *os.File, providedArgs ...string) error { if err != nil { return errors.Wrapf(err, "[%s] could not find docker binary in $PATH", d.id) } + args := append(d.GlobalFlags, "--containerd", containerdSocket, "--data-root", d.Root, "--exec-root", d.execRoot, "--pidfile", fmt.Sprintf("%s/docker.pid", d.Folder), fmt.Sprintf("--userland-proxy=%t", d.userlandProxy), + "--containerd-namespace", d.id, + "--containerd-plugins-namespace", d.id+"p", ) if d.experimental { args = append(args, "--experimental") @@ -313,7 +321,7 @@ func (d *Daemon) StartWithLogFile(out *os.File, providedArgs ...string) error { defer cancel() // make sure daemon is ready to receive requests - for { + for i := 0; ; i++ { d.log.Logf("[%s] waiting for daemon to start", d.id) select { @@ -327,9 +335,14 @@ func (d *Daemon) StartWithLogFile(out *os.File, providedArgs ...string) error { resp, err := client.Do(req.WithContext(rctx)) if err != nil { - d.log.Logf("[%s] error pinging daemon on start: %v", d.id, err) - - time.Sleep(500 * time.Millisecond) + if i > 2 { // don't log the first couple, this ends up just being noise + d.log.Logf("[%s] error pinging daemon on start: %v", d.id, err) + } + + select { + case <-ctx.Done(): + case <-time.After(500 * time.Millisecond): + } continue } @@ -700,8 +713,10 @@ func cleanupRaftDir(t testingT, rootPath string) { if ht, ok := t.(test.HelperT); ok { ht.Helper() } - walDir := filepath.Join(rootPath, "swarm/raft/wal") - if err := os.RemoveAll(walDir); err != nil { - t.Logf("error removing %v: %v", walDir, err) + for _, p := range []string{"wal", "wal-v3-encrypted", "snap-v3-encrypted"} { + dir := filepath.Join(rootPath, "swarm/raft", p) + if err := os.RemoveAll(dir); err != nil { + t.Logf("error removing %v: %v", dir, err) + } } } diff --git a/internal/test/daemon/swarm.go b/internal/test/daemon/swarm.go index b37593a3fb44f..20300a1f4a5a4 100644 --- a/internal/test/daemon/swarm.go +++ b/internal/test/daemon/swarm.go @@ -20,12 +20,19 @@ var ( startArgs = []string{"--iptables=false", "--swarm-default-advertise-addr=lo"} ) -// StartNode starts daemon to be used as a swarm node +// StartNode (re)starts the daemon func (d *Daemon) StartNode(t testingT) { if ht, ok := t.(test.HelperT); ok { ht.Helper() } - // avoid networking conflicts + d.Start(t, startArgs...) +} + +// StartNodeWithBusybox starts daemon to be used as a swarm node, and loads the busybox image +func (d *Daemon) StartNodeWithBusybox(t testingT) { + if ht, ok := t.(test.HelperT); ok { + ht.Helper() + } d.StartWithBusybox(t, startArgs...) } @@ -36,24 +43,28 @@ func (d *Daemon) RestartNode(t testingT) { } // avoid networking conflicts d.Stop(t) - d.StartWithBusybox(t, startArgs...) + d.Start(t, startArgs...) } // StartAndSwarmInit starts the daemon (with busybox) and init the swarm func (d *Daemon) StartAndSwarmInit(t testingT) { - d.StartNode(t) + d.StartNodeWithBusybox(t) d.SwarmInit(t, swarm.InitRequest{}) } // StartAndSwarmJoin starts the daemon (with busybox) and join the specified swarm as worker or manager func (d *Daemon) StartAndSwarmJoin(t testingT, leader *Daemon, manager bool) { - d.StartNode(t) + if th, ok := t.(test.HelperT); ok { + th.Helper() + } + d.StartNodeWithBusybox(t) tokens := leader.JoinTokens(t) token := tokens.Worker if manager { token = tokens.Manager } + t.Logf("[%s] joining swarm manager [%s]@%s, swarm listen addr %s", d.id, leader.id, leader.SwarmListenAddr(), d.SwarmListenAddr()) d.SwarmJoin(t, swarm.JoinRequest{ RemoteAddrs: []string{leader.SwarmListenAddr()}, JoinToken: token, @@ -106,7 +117,7 @@ func (d *Daemon) SwarmJoin(t assert.TestingT, req swarm.JoinRequest) { cli := d.NewClientT(t) defer cli.Close() err := cli.SwarmJoin(context.Background(), req) - assert.NilError(t, err, "initializing swarm") + assert.NilError(t, err, "[%s] joining swarm", d.id) d.CachedInfo = d.Info(t) } diff --git a/pkg/term/proxy_test.go b/pkg/term/proxy_test.go index df588fe15bb00..8f8e4cb6d4442 100644 --- a/pkg/term/proxy_test.go +++ b/pkg/term/proxy_test.go @@ -2,7 +2,6 @@ package term // import "github.com/docker/docker/pkg/term" import ( "bytes" - "fmt" "testing" "gotest.tools/assert" @@ -10,106 +9,143 @@ import ( ) func TestEscapeProxyRead(t *testing.T) { - escapeKeys, _ := ToBytes("") - keys, _ := ToBytes("a") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - buf := make([]byte, len(keys)) - nr, err := reader.Read(buf) - assert.NilError(t, err) - assert.Equal(t, nr, len(keys), fmt.Sprintf("nr %d should be equal to the number of %d", nr, len(keys))) - assert.DeepEqual(t, keys, buf) - - keys, _ = ToBytes("a,b,c") - reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - buf = make([]byte, len(keys)) - nr, err = reader.Read(buf) - assert.NilError(t, err) - assert.Equal(t, nr, len(keys), fmt.Sprintf("nr %d should be equal to the number of %d", nr, len(keys))) - assert.DeepEqual(t, keys, buf) - - keys, _ = ToBytes("") - reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - buf = make([]byte, len(keys)) - nr, err = reader.Read(buf) - assert.Assert(t, is.ErrorContains(err, ""), "Should throw error when no keys are to read") - assert.Equal(t, nr, 0, "nr should be zero") - assert.Check(t, is.Len(keys, 0)) - assert.Check(t, is.Len(buf, 0)) - - escapeKeys, _ = ToBytes("DEL") - keys, _ = ToBytes("a,b,c,+") - reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - buf = make([]byte, len(keys)) - nr, err = reader.Read(buf) - assert.NilError(t, err) - assert.Equal(t, nr, len(keys), fmt.Sprintf("nr %d should be equal to the number of %d", nr, len(keys))) - assert.DeepEqual(t, keys, buf) - - keys, _ = ToBytes("") - reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - buf = make([]byte, len(keys)) - nr, err = reader.Read(buf) - assert.Assert(t, is.ErrorContains(err, ""), "Should throw error when no keys are to read") - assert.Equal(t, nr, 0, "nr should be zero") - assert.Check(t, is.Len(keys, 0)) - assert.Check(t, is.Len(buf, 0)) - - escapeKeys, _ = ToBytes("ctrl-x,ctrl-@") - keys, _ = ToBytes("DEL") - reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - buf = make([]byte, len(keys)) - nr, err = reader.Read(buf) - assert.NilError(t, err) - assert.Equal(t, nr, 1, fmt.Sprintf("nr %d should be equal to the number of 1", nr)) - assert.DeepEqual(t, keys, buf) - - escapeKeys, _ = ToBytes("ctrl-c") - keys, _ = ToBytes("ctrl-c") - reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - buf = make([]byte, len(keys)) - nr, err = reader.Read(buf) - assert.Error(t, err, "read escape sequence") - assert.Equal(t, nr, 0, "nr should be equal to 0") - assert.DeepEqual(t, keys, buf) - - escapeKeys, _ = ToBytes("ctrl-c,ctrl-z") - keys, _ = ToBytes("ctrl-c,ctrl-z") - reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - buf = make([]byte, 1) - nr, err = reader.Read(buf) - assert.NilError(t, err) - assert.Equal(t, nr, 0, "nr should be equal to 0") - assert.DeepEqual(t, keys[0:1], buf) - nr, err = reader.Read(buf) - assert.Error(t, err, "read escape sequence") - assert.Equal(t, nr, 0, "nr should be equal to 0") - assert.DeepEqual(t, keys[1:], buf) - - escapeKeys, _ = ToBytes("ctrl-c,ctrl-z") - keys, _ = ToBytes("ctrl-c,DEL,+") - reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - buf = make([]byte, 1) - nr, err = reader.Read(buf) - assert.NilError(t, err) - assert.Equal(t, nr, 0, "nr should be equal to 0") - assert.DeepEqual(t, keys[0:1], buf) - buf = make([]byte, len(keys)) - nr, err = reader.Read(buf) - assert.NilError(t, err) - assert.Equal(t, nr, len(keys), fmt.Sprintf("nr should be equal to %d", len(keys))) - assert.DeepEqual(t, keys, buf) - - escapeKeys, _ = ToBytes("ctrl-c,ctrl-z") - keys, _ = ToBytes("ctrl-c,DEL") - reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - buf = make([]byte, 1) - nr, err = reader.Read(buf) - assert.NilError(t, err) - assert.Equal(t, nr, 0, "nr should be equal to 0") - assert.DeepEqual(t, keys[0:1], buf) - buf = make([]byte, len(keys)) - nr, err = reader.Read(buf) - assert.NilError(t, err) - assert.Equal(t, nr, len(keys), fmt.Sprintf("nr should be equal to %d", len(keys))) - assert.DeepEqual(t, keys, buf) + t.Run("no escape keys, keys a", func(t *testing.T) { + escapeKeys, _ := ToBytes("") + keys, _ := ToBytes("a") + reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + + buf := make([]byte, len(keys)) + nr, err := reader.Read(buf) + assert.NilError(t, err) + assert.Equal(t, nr, len(keys)) + assert.DeepEqual(t, keys, buf) + }) + + t.Run("no escape keys, keys a,b,c", func(t *testing.T) { + escapeKeys, _ := ToBytes("") + keys, _ := ToBytes("a,b,c") + reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + + buf := make([]byte, len(keys)) + nr, err := reader.Read(buf) + assert.NilError(t, err) + assert.Equal(t, nr, len(keys)) + assert.DeepEqual(t, keys, buf) + }) + + t.Run("no escape keys, no keys", func(t *testing.T) { + escapeKeys, _ := ToBytes("") + keys, _ := ToBytes("") + reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + + buf := make([]byte, len(keys)) + nr, err := reader.Read(buf) + assert.Assert(t, is.ErrorContains(err, ""), "Should throw error when no keys are to read") + assert.Equal(t, nr, 0) + assert.Check(t, is.Len(keys, 0)) + assert.Check(t, is.Len(buf, 0)) + }) + + t.Run("DEL escape key, keys a,b,c,+", func(t *testing.T) { + escapeKeys, _ := ToBytes("DEL") + keys, _ := ToBytes("a,b,c,+") + reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + + buf := make([]byte, len(keys)) + nr, err := reader.Read(buf) + assert.NilError(t, err) + assert.Equal(t, nr, len(keys)) + assert.DeepEqual(t, keys, buf) + }) + + t.Run("DEL escape key, no keys", func(t *testing.T) { + escapeKeys, _ := ToBytes("DEL") + keys, _ := ToBytes("") + reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + + buf := make([]byte, len(keys)) + nr, err := reader.Read(buf) + assert.Assert(t, is.ErrorContains(err, ""), "Should throw error when no keys are to read") + assert.Equal(t, nr, 0) + assert.Check(t, is.Len(keys, 0)) + assert.Check(t, is.Len(buf, 0)) + }) + + t.Run("ctrl-x,ctrl-@ escape key, keys DEL", func(t *testing.T) { + escapeKeys, _ := ToBytes("ctrl-x,ctrl-@") + keys, _ := ToBytes("DEL") + reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + + buf := make([]byte, len(keys)) + nr, err := reader.Read(buf) + assert.NilError(t, err) + assert.Equal(t, nr, 1) + assert.DeepEqual(t, keys, buf) + }) + + t.Run("ctrl-c escape key, keys ctrl-c", func(t *testing.T) { + escapeKeys, _ := ToBytes("ctrl-c") + keys, _ := ToBytes("ctrl-c") + reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + + buf := make([]byte, len(keys)) + nr, err := reader.Read(buf) + assert.Error(t, err, "read escape sequence") + assert.Equal(t, nr, 0) + assert.DeepEqual(t, keys, buf) + }) + + t.Run("ctrl-c,ctrl-z escape key, keys ctrl-c,ctrl-z", func(t *testing.T) { + escapeKeys, _ := ToBytes("ctrl-c,ctrl-z") + keys, _ := ToBytes("ctrl-c,ctrl-z") + reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + + buf := make([]byte, 1) + nr, err := reader.Read(buf) + assert.NilError(t, err) + assert.Equal(t, nr, 0) + assert.DeepEqual(t, keys[0:1], buf) + + nr, err = reader.Read(buf) + assert.Error(t, err, "read escape sequence") + assert.Equal(t, nr, 0) + assert.DeepEqual(t, keys[1:], buf) + }) + + t.Run("ctrl-c,ctrl-z escape key, keys ctrl-c,DEL,+", func(t *testing.T) { + escapeKeys, _ := ToBytes("ctrl-c,ctrl-z") + keys, _ := ToBytes("ctrl-c,DEL,+") + reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + + buf := make([]byte, 1) + nr, err := reader.Read(buf) + assert.NilError(t, err) + assert.Equal(t, nr, 0) + assert.DeepEqual(t, keys[0:1], buf) + + buf = make([]byte, len(keys)) + nr, err = reader.Read(buf) + assert.NilError(t, err) + assert.Equal(t, nr, len(keys)) + assert.DeepEqual(t, keys, buf) + }) + + t.Run("ctrl-c,ctrl-z escape key, keys ctrl-c,DEL", func(t *testing.T) { + escapeKeys, _ := ToBytes("ctrl-c,ctrl-z") + keys, _ := ToBytes("ctrl-c,DEL") + reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + + buf := make([]byte, 1) + nr, err := reader.Read(buf) + assert.NilError(t, err) + assert.Equal(t, nr, 0) + assert.DeepEqual(t, keys[0:1], buf) + + buf = make([]byte, len(keys)) + nr, err = reader.Read(buf) + assert.NilError(t, err) + assert.Equal(t, nr, len(keys)) + assert.DeepEqual(t, keys, buf) + }) + } diff --git a/plugin/executor/containerd/containerd.go b/plugin/executor/containerd/containerd.go index 23418558d8b03..85a159f1ac20c 100644 --- a/plugin/executor/containerd/containerd.go +++ b/plugin/executor/containerd/containerd.go @@ -26,13 +26,13 @@ type ExitHandler interface { } // New creates a new containerd plugin executor -func New(ctx context.Context, rootDir string, cli *containerd.Client, exitHandler ExitHandler) (*Executor, error) { +func New(ctx context.Context, rootDir string, cli *containerd.Client, ns string, exitHandler ExitHandler) (*Executor, error) { e := &Executor{ rootDir: rootDir, exitHandler: exitHandler, } - client, err := libcontainerd.NewClient(ctx, cli, rootDir, PluginNamespace, e) + client, err := libcontainerd.NewClient(ctx, cli, rootDir, ns, e) if err != nil { return nil, errors.Wrap(err, "error creating containerd exec client") }