diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 50c7446a4..000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,64 +0,0 @@ -version: "{build}" - -image: Visual Studio 2017 - -clone_folder: c:\gopath\src\github.com\containerd\containerd - -branches: - only: - - master - - /release\/.*/ - -environment: - GOPATH: C:\gopath - CGO_ENABLED: 0 - matrix: - - GO_VERSION: 1.13.11 - -before_build: - - choco install --no-progress -y mingw --version 5.3.0 - # Install Go - - rd C:\Go /s /q - - appveyor DownloadFile https://storage.googleapis.com/golang/go%GO_VERSION%.windows-amd64.zip - - 7z x go%GO_VERSION%.windows-amd64.zip -oC:\ >nul - - go version - - choco install --no-progress codecov - # Clone hcsshim at the vendored version - - bash.exe -elc "export PATH=/c/tools/mingw64/bin:$PATH; - rm -rf /c/gopath/src/github.com/Microsoft/hcsshim; - git clone -q https://github.com/Microsoft/hcsshim.git /c/gopath/src/github.com/Microsoft/hcsshim; - export HCSSHIM_VERSION=`grep Microsoft/hcsshim vendor.conf | awk '{print $2}'`; - echo Using Microsoft/hcsshim $HCSSHIM_VERSION; - pushd /c/gopath/src/github.com/Microsoft/hcsshim; - git checkout $HCSSHIM_VERSION; - popd" - # Print host version. TODO: Remove this when containerd has a way to get host version - - ps: $psversiontable - -build_script: - # Build containerd-shim-runhcs-v1.exe and runhcs.exe from Microsoft/hcsshim - - bash.exe -elc "export PATH=/c/tools/mingw64/bin:$PATH; - export GOBIN=/c/gopath/src/github.com/Microsoft/hcsshim/bin; - mkdir $GOBIN; - pushd /c/gopath/src/github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1; - go install; - cd ../runhcs; - go install; - ls -al $GOBIN; - popd" - - bash.exe -elc "export PATH=/c/tools/mingw64/bin:/c/gopath/bin:$PATH; - script/setup/install-dev-tools; - mingw32-make.exe check" - - bash.exe -elc "export PATH=/c/tools/mingw64/bin:$PATH ; mingw32-make.exe build binaries" - -# These scripts run with CGO_ENABLED=1 in order to support the Race Detector (-race flag), enabled in Makefile.windows -test_script: - # TODO: need an equivalent of TRAVIS_COMMIT_RANGE - # - GIT_CHECK_EXCLUDE="./vendor" TRAVIS_COMMIT_RANGE="${TRAVIS_COMMIT_RANGE/.../..}" C:\MinGW\bin\mingw32-make.exe dco - - bash.exe -lc "export CGO_ENABLED=1 PATH=/c/tools/mingw64/bin:/c/gopath/src/github.com/containerd/containerd/bin:$PATH ; mingw32-make.exe coverage root-coverage" - # - bash.exe -elc "export CGO_ENABLED=1 PATH=/c/tools/mingw64/bin:/c/gopath/src/github.com/containerd/containerd/bin:$PATH ; mingw32-make.exe integration" - # Run the integration suite a second time. See discussion in github.com/containerd/containerd/pull/1759 - # - bash.exe -elc "export CGO_ENABLED=1 PATH=/c/tools/mingw64/bin:/c/gopath/src/github.com/containerd/containerd/bin:$PATH; TESTFLAGS_PARALLEL=1 mingw32-make.exe integration" - -on_success: - - codecov --flag windows -f coverage.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f2a85b08..b9f671d6f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -249,8 +249,74 @@ jobs: # # Integration and CRI tests # - integration: - name: Integration + integration-windows: + name: Windows Integration + runs-on: windows-2019 + timeout-minutes: 30 + needs: [project, linters, protos, man] + + strategy: + matrix: + runtime: [v1] + + steps: + - name: Install Go + uses: actions/setup-go@v1 + with: + go-version: '1.13.11' + + - name: Set env + shell: bash + run: | + echo "::set-env name=GOPATH::${{ github.workspace }}" + echo "::add-path::${{ github.workspace }}/src/github.com/containerd/containerd/bin" + + - name: Checkout containerd + uses: actions/checkout@v2 + with: + path: src/github.com/containerd/containerd + - name: Checkout Microsoft/hcsshim + uses: actions/checkout@v2 + with: + repository: Microsoft/hcsshim + path: src/github.com/Microsoft/hcsshim + + - name: Install Build Deps + shell: bash + run: | + cd src/github.com/containerd/containerd + script/setup/install-dev-tools + - name: Binaries + shell: bash + run: | + set -o xtrace + export CGO_ENABLED=1 + cd src/github.com/containerd/containerd + mingw32-make.exe binaries + bindir="$(pwd)" + SHIM_COMMIT=$(grep Microsoft/hcsshim vendor.conf | awk '{print $2}') + cd ../../Microsoft/hcsshim + git fetch --tags origin "${SHIM_COMMIT}" + git checkout "${SHIM_COMMIT}" + GO111MODULE=on go build -mod=vendor -o "${bindir}/containerd-shim-runhcs-v1.exe" ./cmd/containerd-shim-runhcs-v1 + - name: Integration 1 + shell: bash + run: | + cp src/github.com/Microsoft/hcsshim/test/functional/manifest/rsrc_amd64.syso src/github.com/containerd/containerd/ + cd src/github.com/containerd/containerd + export CGO_ENABLED=1 + mingw32-make.exe integration + # Run the integration suite a second time. See discussion in github.com/containerd/containerd/pull/175 + - name: Integration 2 + shell: bash + run: | + cd src/github.com/containerd/containerd + export TESTFLAGS_PARALLEL=1 + export CGO_ENABLED=1 + mingw32-make.exe integration + + integration-linux: + name: Linux Integration runs-on: ubuntu-18.04 timeout-minutes: 15 needs: [project, linters, protos, man] diff --git a/client_unix_test.go b/client_unix_test.go index fdd6b5335..3d88715d8 100644 --- a/client_unix_test.go +++ b/client_unix_test.go @@ -32,7 +32,9 @@ const ( ) var ( - testImage string + testImage string + shortCommand = withProcessArgs("true") + longCommand = withProcessArgs("/bin/sh", "-c", "while true; do sleep 1; done") ) func init() { diff --git a/client_windows_test.go b/client_windows_test.go index 25f092bf9..dc92767c3 100644 --- a/client_windows_test.go +++ b/client_windows_test.go @@ -17,16 +17,41 @@ package containerd import ( + "fmt" "os" "path/filepath" + + "github.com/Microsoft/hcsshim/osversion" ) const ( defaultAddress = `\\.\pipe\containerd-containerd-test` - testImage = "mcr.microsoft.com/windows/nanoserver:sac2016" ) var ( defaultRoot = filepath.Join(os.Getenv("programfiles"), "containerd", "root-test") defaultState = filepath.Join(os.Getenv("programfiles"), "containerd", "state-test") + testImage string + shortCommand = withTrue() + longCommand = withProcessArgs("ping", "-t", "localhost") ) + +func init() { + b := osversion.Build() + switch b { + case osversion.RS1: + testImage = "mcr.microsoft.com/windows/nanoserver:sac2016" + case osversion.RS3: + testImage = "mcr.microsoft.com/windows/nanoserver:1709" + case osversion.RS4: + testImage = "mcr.microsoft.com/windows/nanoserver:1803" + case osversion.RS5: + testImage = "mcr.microsoft.com/windows/nanoserver:1809" + case osversion.V19H1: + testImage = "mcr.microsoft.com/windows/nanoserver:1903" + case 18363: // this isn't in osversion yet, but the image should be available + testImage = "mcr.microsoft.com/windows/nanoserver:1909" + } + + fmt.Println("Windows test image:", testImage, ", Windows build version:", b) +} diff --git a/container_test.go b/container_test.go index 2ebfc3a99..0ed808948 100644 --- a/container_test.go +++ b/container_test.go @@ -140,9 +140,13 @@ func TestContainerStart(t *testing.T) { t.Fatal(err) } - if pid := task.Pid(); pid < 1 { - t.Errorf("invalid task pid %d", pid) + if runtime.GOOS != "windows" { + // task.Pid not implemented on Windows + if pid := task.Pid(); pid < 1 { + t.Errorf("invalid task pid %d", pid) + } } + if err := task.Start(ctx); err != nil { t.Error(err) task.Delete(ctx) @@ -256,7 +260,7 @@ func TestContainerExec(t *testing.T) { t.Fatal(err) } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) if err != nil { t.Fatal(err) } @@ -341,7 +345,7 @@ func TestContainerLargeExecArgs(t *testing.T) { t.Fatal(err) } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) if err != nil { t.Fatal(err) } @@ -417,7 +421,7 @@ func TestContainerPids(t *testing.T) { t.Fatal(err) } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) if err != nil { t.Fatal(err) } @@ -450,8 +454,9 @@ func TestContainerPids(t *testing.T) { if err != nil { t.Fatal(err) } - if l := len(processes); l != 1 { - t.Errorf("expected 1 process but received %d", l) + // 2 processes, 1 for sh and one for sleep + if l := len(processes); l != 2 { + t.Errorf("expected 2 process but received %d", l) } if len(processes) > 0 { actual := processes[0].Pid @@ -461,6 +466,11 @@ func TestContainerPids(t *testing.T) { } } if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + select { + case s := <-statusC: + t.Log(s.Result()) + default: + } t.Error(err) } <-statusC @@ -543,7 +553,7 @@ func TestDeleteRunningContainer(t *testing.T) { t.Fatal(err) } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) if err != nil { t.Fatal(err) } @@ -598,7 +608,7 @@ func TestContainerKill(t *testing.T) { t.Fatal(err) } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "10"))) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) if err != nil { t.Fatal(err) } @@ -635,6 +645,10 @@ func TestContainerKill(t *testing.T) { func TestKillContainerDeletedByRunc(t *testing.T) { t.Parallel() + if runtime.GOOS == "windows" { + t.Skip("Test relies on runc and is not supported on Windows") + } + // We skip this case when runtime is crun. // More information in https://github.com/containerd/containerd/pull/4214#discussion_r422769497 if os.Getenv("RUNC_FLAVOR") == "crun" { @@ -661,7 +675,7 @@ func TestKillContainerDeletedByRunc(t *testing.T) { } container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "10")), + WithNewSpec(oci.WithImageConfig(image), longCommand), WithRuntime(client.runtime, &options.Options{Root: runcRoot})) if err != nil { t.Fatal(err) @@ -772,7 +786,7 @@ func TestContainerExecNoBinaryExists(t *testing.T) { t.Fatal(err) } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) if err != nil { t.Fatal(err) } @@ -854,8 +868,11 @@ func TestWaitStoppedTask(t *testing.T) { t.Fatal(err) } - if pid := task.Pid(); pid < 1 { - t.Errorf("invalid task pid %d", pid) + if runtime.GOOS != "windows" { + // Getting the pid is not currently implemented on windows + if pid := task.Pid(); pid < 1 { + t.Errorf("invalid task pid %d", pid) + } } if err := task.Start(ctx); err != nil { t.Error(err) @@ -900,7 +917,7 @@ func TestWaitStoppedProcess(t *testing.T) { t.Fatal(err) } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) if err != nil { t.Fatal(err) } @@ -987,7 +1004,7 @@ func TestTaskForceDelete(t *testing.T) { if err != nil { t.Fatal(err) } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"))) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) if err != nil { t.Fatal(err) } @@ -1028,7 +1045,7 @@ func TestProcessForceDelete(t *testing.T) { if err != nil { t.Fatal(err) } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"))) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) if err != nil { t.Fatal(err) } @@ -1055,7 +1072,11 @@ func TestProcessForceDelete(t *testing.T) { } processSpec := spec.Process - withExecArgs(processSpec, "sleep", "20") + if runtime.GOOS == "windows" { + withExecArgs(processSpec, "cmd", "/c", "ping -t localhost") + } else { + withExecArgs(processSpec, "/bin/sh", "-c", "while true; do sleep 1; done") + } execID := t.Name() + "_exec" process, err := task.Exec(ctx, execID, processSpec, empty()) if err != nil { @@ -1226,7 +1247,7 @@ func TestDeleteContainerExecCreated(t *testing.T) { t.Fatal(err) } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) if err != nil { t.Fatal(err) } @@ -1297,7 +1318,7 @@ func TestContainerMetrics(t *testing.T) { } container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "30"))) + WithNewSpec(oci.WithImageConfig(image), longCommand)) if err != nil { t.Fatal(err) } @@ -1655,6 +1676,10 @@ func TestShimSockLength(t *testing.T) { } func TestContainerExecLargeOutputWithTTY(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("Test does not run on Windows") + } + t.Parallel() client, err := newClient(t, address) @@ -1675,7 +1700,7 @@ func TestContainerExecLargeOutputWithTTY(t *testing.T) { t.Fatal(err) } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "999"))) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) if err != nil { t.Fatal(err) } @@ -1771,7 +1796,7 @@ func TestShortRunningTaskPid(t *testing.T) { t.Fatal(err) } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("true"))) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), shortCommand)) if err != nil { t.Fatal(err) } diff --git a/helpers_windows_test.go b/helpers_windows_test.go index 3bef21ccd..d3ca35358 100644 --- a/helpers_windows_test.go +++ b/helpers_windows_test.go @@ -31,13 +31,13 @@ const newLine = "\r\n" func withExitStatus(es int) oci.SpecOpts { return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { - s.Process.Args = []string{"powershell", "-noprofile", "exit", strconv.Itoa(es)} + s.Process.Args = []string{"cmd", "/c", "exit", strconv.Itoa(es)} return nil } } func withProcessArgs(args ...string) oci.SpecOpts { - return oci.WithProcessArgs(append([]string{"powershell", "-noprofile"}, args...)...) + return oci.WithProcessArgs(append([]string{"cmd", "/c"}, args...)...) } func withCat() oci.SpecOpts { @@ -49,9 +49,9 @@ func withTrue() oci.SpecOpts { } func withExecExitStatus(s *specs.Process, es int) { - s.Args = []string{"powershell", "-noprofile", "exit", strconv.Itoa(es)} + s.Args = []string{"cmd", "/c", "exit", strconv.Itoa(es)} } func withExecArgs(s *specs.Process, args ...string) { - s.Args = append([]string{"powershell", "-noprofile"}, args...) + s.Args = append([]string{"cmd", "/c"}, args...) }