Enable integration tests on Windows using snapshotter and differ

Signed-off-by: Darren Stahl <darst@microsoft.com>
This commit is contained in:
Darren Stahl 2018-01-16 16:33:26 -08:00
parent acf2087db9
commit e6280a7c82
9 changed files with 129 additions and 255 deletions

View File

@ -9,7 +9,6 @@ import (
golog "log"
"os"
"os/exec"
"runtime"
"testing"
"time"
@ -17,6 +16,7 @@ import (
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/sys"
"github.com/containerd/containerd/testutil"
"github.com/sirupsen/logrus"
)
@ -62,7 +62,7 @@ func TestMain(m *testing.M) {
defer cancel()
if !noDaemon {
os.RemoveAll(defaultRoot)
sys.ForceRemoveAll(defaultRoot)
err := ctrd.start("containerd", address, []string{
"--root", defaultRoot,
@ -99,19 +99,12 @@ func TestMain(m *testing.M) {
}).Info("running tests against containerd")
// pull a seed image
if runtime.GOOS != "windows" { // TODO: remove once pull is supported on windows
if _, err = client.Pull(ctx, testImage, WithPullUnpack); err != nil {
ctrd.Stop()
ctrd.Wait()
fmt.Fprintf(os.Stderr, "%s: %s\n", err, buf.String())
os.Exit(1)
}
}
if err := platformTestSetup(client); err != nil {
fmt.Fprintln(os.Stderr, "platform test setup failed", err)
os.Exit(1)
}
if err := client.Close(); err != nil {
fmt.Fprintln(os.Stderr, "failed to close client", err)
@ -132,7 +125,7 @@ func TestMain(m *testing.M) {
fmt.Fprintln(os.Stderr, "failed to wait for containerd", err)
}
}
if err := os.RemoveAll(defaultRoot); err != nil {
if err := sys.ForceRemoveAll(defaultRoot); err != nil {
fmt.Fprintln(os.Stderr, "failed to remove test root dir", err)
os.Exit(1)
}
@ -169,11 +162,6 @@ func TestNewClient(t *testing.T) {
// All the container's tests depends on this, we need it to run first.
func TestImagePull(t *testing.T) {
if runtime.GOOS == "windows" {
// TODO: remove once Windows has a snapshotter
t.Skip("Windows does not have a snapshotter yet")
}
client, err := newClient(t, address)
if err != nil {
t.Fatal(err)

View File

@ -16,10 +16,6 @@ var (
testImage string
)
func platformTestSetup(client *Client) error {
return nil
}
func init() {
switch runtime.GOARCH {
case "386":

View File

@ -1,88 +1,16 @@
package containerd
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"github.com/pkg/errors"
)
const (
defaultAddress = `\\.\pipe\containerd-containerd-test`
testImage = "docker.io/library/go:nanoserver"
testImage = "docker.io/microsoft/nanoserver:latest"
)
var (
dockerLayerFolders []string
defaultRoot = filepath.Join(os.Getenv("programfiles"), "containerd", "root-test")
defaultState = filepath.Join(os.Getenv("programfiles"), "containerd", "state-test")
)
func platformTestSetup(client *Client) error {
var (
roots []string
layerChains = make(map[string]string)
)
// Since we can't pull images yet, we'll piggyback on the default
// docker's images
wfPath := `C:\ProgramData\docker\windowsfilter`
wf, err := os.Open(wfPath)
if err != nil {
return errors.Wrapf(err, "failed to access docker layers @ %s", wfPath)
}
defer wf.Close()
entries, err := wf.Readdirnames(0)
if err != nil {
return errors.Wrapf(err, "failed to read %s entries", wfPath)
}
for _, fn := range entries {
layerChainPath := filepath.Join(wfPath, fn, "layerchain.json")
lfi, err := os.Stat(layerChainPath)
switch {
case err == nil && lfi.Mode().IsRegular():
f, err := os.OpenFile(layerChainPath, os.O_RDONLY, 0660)
if err != nil {
fmt.Fprintln(os.Stderr,
errors.Wrapf(err, "failed to open %s", layerChainPath))
continue
}
defer f.Close()
l := make([]string, 0)
if err := json.NewDecoder(f).Decode(&l); err != nil {
fmt.Fprintln(os.Stderr,
errors.Wrapf(err, "failed to decode %s", layerChainPath))
continue
}
switch {
case len(l) == 1:
layerChains[l[0]] = filepath.Join(wfPath, fn)
case len(l) > 1:
fmt.Fprintf(os.Stderr, "Too many entries in %s: %d", layerChainPath, len(l))
case len(l) == 0:
roots = append(roots, filepath.Join(wfPath, fn))
}
case os.IsNotExist(err):
// keep on going
default:
return errors.Wrapf(err, "error trying to access %s", layerChainPath)
}
}
// They'll be 2 roots, just take the first one
l := roots[0]
dockerLayerFolders = append(dockerLayerFolders, l)
for {
l = layerChains[l]
if l == "" {
break
}
dockerLayerFolders = append([]string{l}, dockerLayerFolders...)
}
return nil
}

View File

@ -187,7 +187,7 @@ func TestDaemonRestart(t *testing.T) {
t.Fatal(err)
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "30")), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30")), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -266,7 +266,7 @@ func TestContainerAttach(t *testing.T) {
t.Fatal(err)
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withCat()), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withCat()), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -427,8 +427,8 @@ func TestContainerUsername(t *testing.T) {
// squid user in the alpine image has a uid of 31
container, err := client.NewContainer(ctx, id,
withNewSnapshot(id, image),
WithNewSpec(withImageConfig(image), oci.WithUsername("squid"), oci.WithProcessArgs("id", "-u")),
WithNewSnapshot(id, image),
WithNewSpec(oci.WithImageConfig(image), oci.WithUsername("squid"), oci.WithProcessArgs("id", "-u")),
)
if err != nil {
t.Fatal(err)
@ -487,7 +487,7 @@ func TestContainerAttachProcess(t *testing.T) {
t.Fatal(err)
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100")), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -620,8 +620,8 @@ func TestContainerUserID(t *testing.T) {
// adm user in the alpine image has a uid of 3 and gid of 4.
container, err := client.NewContainer(ctx, id,
withNewSnapshot(id, image),
WithNewSpec(withImageConfig(image), oci.WithUserID(3), oci.WithProcessArgs("sh", "-c", "echo $(id -u):$(id -g)")),
WithNewSnapshot(id, image),
WithNewSpec(oci.WithImageConfig(image), oci.WithUserID(3), oci.WithProcessArgs("sh", "-c", "echo $(id -u):$(id -g)")),
)
if err != nil {
t.Fatal(err)
@ -674,8 +674,8 @@ func TestContainerKillAll(t *testing.T) {
}
container, err := client.NewContainer(ctx, id,
withNewSnapshot(id, image),
WithNewSpec(withImageConfig(image),
WithNewSnapshot(id, image),
WithNewSpec(oci.WithImageConfig(image),
withProcessArgs("sh", "-c", "top"),
oci.WithHostNamespace(specs.PIDNamespace),
),
@ -730,7 +730,7 @@ func TestShimSigkilled(t *testing.T) {
if err != nil {
t.Fatal(err)
}
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image)), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image)), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -793,7 +793,7 @@ func TestDaemonRestartWithRunningShim(t *testing.T) {
if err != nil {
t.Fatal(err)
}
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "100")), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "100")), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -877,8 +877,8 @@ func TestContainerRuntimeOptions(t *testing.T) {
container, err := client.NewContainer(
ctx, id,
WithNewSpec(withImageConfig(image), withExitStatus(7)),
withNewSnapshot(id, image),
WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)),
WithNewSnapshot(id, image),
WithRuntime("io.containerd.runtime.v1.linux", &runctypes.RuncOptions{Runtime: "no-runc"}),
)
if err != nil {
@ -917,8 +917,8 @@ func TestContainerKillInitPidHost(t *testing.T) {
}
container, err := client.NewContainer(ctx, id,
withNewSnapshot(id, image),
WithNewSpec(withImageConfig(image),
WithNewSnapshot(id, image),
WithNewSpec(oci.WithImageConfig(image),
withProcessArgs("sh", "-c", "sleep 42; echo hi"),
oci.WithHostNamespace(specs.PIDNamespace),
),
@ -1007,7 +1007,7 @@ func testUserNamespaces(t *testing.T, readonlyRootFS bool) {
t.Fatal(err)
}
opts := []NewContainerOpts{WithNewSpec(withImageConfig(image),
opts := []NewContainerOpts{WithNewSpec(oci.WithImageConfig(image),
withExitStatus(7),
oci.WithUserNamespace(0, 1000, 10000),
)}
@ -1081,13 +1081,11 @@ func TestTaskResize(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withExitStatus(7)), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}

View File

@ -97,13 +97,11 @@ func TestContainerStart(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withExitStatus(7)), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -163,13 +161,11 @@ func TestContainerOutput(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("echo", expected)), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("echo", expected)), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -233,14 +229,12 @@ func TestContainerExec(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100")), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -320,14 +314,12 @@ func TestContainerLargeExecArgs(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100")), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -398,14 +390,12 @@ func TestContainerPids(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100")), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -477,14 +467,12 @@ func TestContainerCloseIO(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withCat()), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withCat()), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -535,14 +523,12 @@ func TestDeleteRunningContainer(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100")), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -592,14 +578,12 @@ func TestContainerKill(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "10")), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "10")), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -649,16 +633,14 @@ func TestContainerNoBinaryExists(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id,
WithNewSpec(withImageConfig(image), oci.WithProcessArgs("nothing")),
withNewSnapshot(id, image))
WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("nothing")),
WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -698,14 +680,12 @@ func TestContainerExecNoBinaryExists(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100")), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -765,14 +745,12 @@ func TestWaitStoppedTask(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withExitStatus(7)), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -830,14 +808,12 @@ func TestWaitStoppedProcess(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100")), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -920,13 +896,11 @@ func TestTaskForceDelete(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "30")), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30")), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -963,13 +937,11 @@ func TestProcessForceDelete(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "30")), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30")), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -1034,18 +1006,16 @@ func TestContainerHostname(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image),
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image),
withProcessArgs("hostname"),
oci.WithHostname(expected),
),
withNewSnapshot(id, image))
WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -1105,14 +1075,12 @@ func TestContainerExitedAtSet(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withTrue()), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withTrue()), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -1167,14 +1135,12 @@ func TestDeleteContainerExecCreated(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100")), WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -1239,15 +1205,13 @@ func TestContainerMetrics(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id,
WithNewSpec(withImageConfig(image), oci.WithProcessArgs("sleep", "30")),
withNewSnapshot(id, image))
WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "30")),
WithNewSnapshot(id, image))
if err != nil {
t.Fatal(err)
}
@ -1297,15 +1261,13 @@ func TestDeletedContainerMetrics(t *testing.T) {
)
defer cancel()
if runtime.GOOS != "windows" {
image, err = client.GetImage(ctx, testImage)
if err != nil {
t.Fatal(err)
}
}
container, err := client.NewContainer(ctx, id,
WithNewSpec(withImageConfig(image), withExitStatus(0)),
withNewSnapshot(id, image),
WithNewSpec(oci.WithImageConfig(image), withExitStatus(0)),
WithNewSnapshot(id, image),
)
if err != nil {
t.Fatal(err)

View File

@ -39,8 +39,3 @@ func withExecExitStatus(s *specs.Process, es int) {
func withExecArgs(s *specs.Process, args ...string) {
s.Args = args
}
var (
withNewSnapshot = WithNewSnapshot
withImageConfig = oci.WithImageConfig
)

View File

@ -39,17 +39,3 @@ func withExecExitStatus(s *specs.Process, es int) {
func withExecArgs(s *specs.Process, args ...string) {
s.Args = append([]string{"powershell", "-noprofile"}, args...)
}
func withImageConfig(i Image) oci.SpecOpts {
return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error {
s.Windows.LayerFolders = dockerLayerFolders
return nil
}
}
func withNewSnapshot(id string, i Image) NewContainerOpts {
// TODO: when windows has a snapshotter remove the withNewSnapshot helper
return func(ctx context.Context, client *Client, c *containers.Container) error {
return nil
}
}

10
sys/filesys_unix.go Normal file
View File

@ -0,0 +1,10 @@
// +build !windows
package sys
import "os"
// ForceRemoveAll on unix is just a wrapper for os.RemoveAll
func ForceRemoveAll(path string) error {
return os.RemoveAll(path)
}

View File

@ -11,6 +11,7 @@ import (
"unsafe"
winio "github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim"
)
// MkdirAllWithACL is a wrapper for MkdirAll that creates a directory
@ -234,3 +235,13 @@ func syscallOpenSequential(path string, mode int, _ uint32) (fd syscall.Handle,
h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, fileFlagSequentialScan, 0)
return h, e
}
// ForceRemoveAll is the same as os.RemoveAll, but uses hcsshim.DestroyLayer in order
// to delete container layers.
func ForceRemoveAll(path string) error {
info := hcsshim.DriverInfo{
HomeDir: filepath.Dir(path),
}
return hcsshim.DestroyLayer(info, filepath.Base(path))
}