summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pkg/sentry/platform/kvm/kvm.go2
-rw-r--r--runsc/container/BUILD6
-rw-r--r--runsc/container/container_test.go1473
-rw-r--r--runsc/sandbox/sandbox_test.go3
-rw-r--r--runsc/test/testutil/BUILD1
-rw-r--r--runsc/test/testutil/testutil.go42
-rw-r--r--runsc/test/testutil/testutil_race.go21
7 files changed, 830 insertions, 718 deletions
diff --git a/pkg/sentry/platform/kvm/kvm.go b/pkg/sentry/platform/kvm/kvm.go
index 3ed057881..2dc3239a5 100644
--- a/pkg/sentry/platform/kvm/kvm.go
+++ b/pkg/sentry/platform/kvm/kvm.go
@@ -66,7 +66,7 @@ func New() (*KVM, error) {
ring0.Init(cpuid.HostFeatureSet())
})
if globalErr != nil {
- return nil, err
+ return nil, globalErr
}
// Create a new VM fd.
diff --git a/runsc/container/BUILD b/runsc/container/BUILD
index 679d7e097..7ec68f573 100644
--- a/runsc/container/BUILD
+++ b/runsc/container/BUILD
@@ -26,17 +26,21 @@ go_library(
go_test(
name = "container_test",
- size = "small",
+ size = "medium",
srcs = ["container_test.go"],
data = [
"//runsc",
],
+ tags = [
+ "requires-kvm",
+ ],
deps = [
"//pkg/abi/linux",
"//pkg/log",
"//pkg/sentry/control",
"//pkg/sentry/kernel/auth",
"//pkg/unet",
+ "//runsc/boot",
"//runsc/container",
"//runsc/specutils",
"//runsc/test/testutil",
diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go
index 62a681ac2..34febe038 100644
--- a/runsc/container/container_test.go
+++ b/runsc/container/container_test.go
@@ -36,6 +36,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/control"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/auth"
"gvisor.googlesource.com/gvisor/pkg/unet"
+ "gvisor.googlesource.com/gvisor/runsc/boot"
"gvisor.googlesource.com/gvisor/runsc/container"
"gvisor.googlesource.com/gvisor/runsc/specutils"
"gvisor.googlesource.com/gvisor/runsc/test/testutil"
@@ -159,8 +160,8 @@ func readOutputNum(f *os.File, first bool) (int, error) {
// run starts the sandbox and waits for it to exit, checking that the
// application succeeded.
-func run(spec *specs.Spec) error {
- rootDir, bundleDir, conf, err := testutil.SetupContainer(spec)
+func run(spec *specs.Spec, conf *boot.Config) error {
+ rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
if err != nil {
return fmt.Errorf("error setting up container: %v", err)
}
@@ -186,173 +187,207 @@ func run(spec *specs.Spec) error {
return nil
}
-// TestLifecycle tests the basic Create/Start/Signal/Destroy container lifecycle.
-// It verifies after each step that the container can be loaded from disk, and
-// has the correct status.
-func TestLifecycle(t *testing.T) {
- // The container will just sleep for a long time. We will kill it before
- // it finishes sleeping.
- spec := testutil.NewSpecWithArgs("sleep", "100")
+type configOptions int
- rootDir, bundleDir, conf, err := testutil.SetupContainer(spec)
- if err != nil {
- t.Fatalf("error setting up container: %v", err)
- }
- defer os.RemoveAll(rootDir)
- defer os.RemoveAll(bundleDir)
+const (
+ overlay configOptions = 1 << iota
+ kvm
+)
+const all = overlay | kvm
- // expectedPL lists the expected process state of the container.
- expectedPL := []*control.Process{
- {
- UID: 0,
- PID: 1,
- PPID: 0,
- C: 0,
- Cmd: "sleep",
- },
- }
- // Create the container.
- id := testutil.UniqueContainerID()
- if _, err := container.Create(id, spec, conf, bundleDir, "", ""); err != nil {
- t.Fatalf("error creating container: %v", err)
- }
+// configs generates different configurations to run tests.
+func configs(opts configOptions) []*boot.Config {
+ cs := []*boot.Config{testutil.TestConfig()}
- // Load the container from disk and check the status.
- s, err := container.Load(rootDir, id)
- if err != nil {
- t.Fatalf("error loading container: %v", err)
- }
- if got, want := s.Status, container.Created; got != want {
- t.Errorf("container status got %v, want %v", got, want)
+ if opts&overlay != 0 {
+ c := testutil.TestConfig()
+ c.Overlay = true
+ cs = append(cs, c)
}
- // List should return the container id.
- ids, err := container.List(rootDir)
- if err != nil {
- t.Fatalf("error listing containers: %v", err)
- }
- if got, want := ids, []string{id}; !reflect.DeepEqual(got, want) {
- t.Errorf("container list got %v, want %v", got, want)
+ // TODO: KVM doesn't work with --race.
+ if !testutil.RaceEnabled && opts&kvm != 0 {
+ c := testutil.TestConfig()
+ c.Platform = boot.PlatformKVM
+ cs = append(cs, c)
}
- // Start the container.
- if err := s.Start(conf); err != nil {
- t.Fatalf("error starting container: %v", err)
- }
- // Load the container from disk and check the status.
- s, err = container.Load(rootDir, id)
- if err != nil {
- t.Fatalf("error loading container: %v", err)
- }
- if got, want := s.Status, container.Running; got != want {
- t.Errorf("container status got %v, want %v", got, want)
- }
+ return cs
+}
- // Verify that "sleep 100" is running.
- if err := waitForProcessList(s, expectedPL); err != nil {
- t.Error(err)
- }
+// TestLifecycle tests the basic Create/Start/Signal/Destroy container lifecycle.
+// It verifies after each step that the container can be loaded from disk, and
+// has the correct status.
+func TestLifecycle(t *testing.T) {
+ for _, conf := range configs(all) {
+ t.Logf("Running test with conf: %+v", conf)
+ // The container will just sleep for a long time. We will kill it before
+ // it finishes sleeping.
+ spec := testutil.NewSpecWithArgs("sleep", "100")
- // Wait on the container.
- var wg sync.WaitGroup
- wg.Add(1)
- ch := make(chan struct{})
- go func() {
- ch <- struct{}{}
- ws, err := s.Wait()
+ rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
if err != nil {
- t.Fatalf("error waiting on container: %v", err)
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(rootDir)
+ defer os.RemoveAll(bundleDir)
+
+ // expectedPL lists the expected process state of the container.
+ expectedPL := []*control.Process{
+ {
+ UID: 0,
+ PID: 1,
+ PPID: 0,
+ C: 0,
+ Cmd: "sleep",
+ },
}
- if got, want := ws.Signal(), syscall.SIGTERM; got != want {
- t.Fatalf("got signal %v, want %v", got, want)
+ // Create the container.
+ id := testutil.UniqueContainerID()
+ if _, err := container.Create(id, spec, conf, bundleDir, "", ""); err != nil {
+ t.Fatalf("error creating container: %v", err)
}
- wg.Done()
- }()
- // Wait a bit to ensure that we've started waiting on the container
- // before we signal.
- <-ch
- time.Sleep(100 * time.Millisecond)
- // Send the container a SIGTERM which will cause it to stop.
- if err := s.Signal(syscall.SIGTERM); err != nil {
- t.Fatalf("error sending signal %v to container: %v", syscall.SIGTERM, err)
- }
- // Wait for it to die.
- wg.Wait()
+ // Load the container from disk and check the status.
+ s, err := container.Load(rootDir, id)
+ if err != nil {
+ t.Fatalf("error loading container: %v", err)
+ }
+ if got, want := s.Status, container.Created; got != want {
+ t.Errorf("container status got %v, want %v", got, want)
+ }
- // The sandbox process should have exited by now, but it is a zombie.
- // In normal runsc usage, it will be parented to init, and init will
- // reap the sandbox. However, in this case the test runner is the
- // parent and will not reap the sandbox process, so we must do it
- // ourselves.
- p, _ := os.FindProcess(s.Sandbox.Pid)
- p.Wait()
- g, _ := os.FindProcess(s.Sandbox.GoferPid)
- g.Wait()
-
- // Load the container from disk and check the status.
- s, err = container.Load(rootDir, id)
- if err != nil {
- t.Fatalf("error loading container: %v", err)
- }
- if got, want := s.Status, container.Stopped; got != want {
- t.Errorf("container status got %v, want %v", got, want)
- }
+ // List should return the container id.
+ ids, err := container.List(rootDir)
+ if err != nil {
+ t.Fatalf("error listing containers: %v", err)
+ }
+ if got, want := ids, []string{id}; !reflect.DeepEqual(got, want) {
+ t.Errorf("container list got %v, want %v", got, want)
+ }
- // Destroy the container.
- if err := s.Destroy(); err != nil {
- t.Fatalf("error destroying container: %v", err)
- }
+ // Start the container.
+ if err := s.Start(conf); err != nil {
+ t.Fatalf("error starting container: %v", err)
+ }
+ // Load the container from disk and check the status.
+ s, err = container.Load(rootDir, id)
+ if err != nil {
+ t.Fatalf("error loading container: %v", err)
+ }
+ if got, want := s.Status, container.Running; got != want {
+ t.Errorf("container status got %v, want %v", got, want)
+ }
- // List should not return the container id.
- ids, err = container.List(rootDir)
- if err != nil {
- t.Fatalf("error listing containers: %v", err)
- }
- if len(ids) != 0 {
- t.Errorf("expected container list to be empty, but got %v", ids)
- }
+ // Verify that "sleep 100" is running.
+ if err := waitForProcessList(s, expectedPL); err != nil {
+ t.Error(err)
+ }
- // Loading the container by id should fail.
- if _, err = container.Load(rootDir, id); err == nil {
- t.Errorf("expected loading destroyed container to fail, but it did not")
- }
-}
+ // Wait on the container.
+ var wg sync.WaitGroup
+ wg.Add(1)
+ ch := make(chan struct{})
+ go func() {
+ ch <- struct{}{}
+ ws, err := s.Wait()
+ if err != nil {
+ t.Fatalf("error waiting on container: %v", err)
+ }
+ if got, want := ws.Signal(), syscall.SIGTERM; got != want {
+ t.Fatalf("got signal %v, want %v", got, want)
+ }
+ wg.Done()
+ }()
-// Test the we can execute the application with different path formats.
-func TestExePath(t *testing.T) {
- for _, test := range []struct {
- path string
- success bool
- }{
- {path: "true", success: true},
- {path: "bin/true", success: true},
- {path: "/bin/true", success: true},
- {path: "thisfiledoesntexit", success: false},
- {path: "bin/thisfiledoesntexit", success: false},
- {path: "/bin/thisfiledoesntexit", success: false},
- } {
- spec := testutil.NewSpecWithArgs(test.path)
- rootDir, bundleDir, conf, err := testutil.SetupContainer(spec)
+ // Wait a bit to ensure that we've started waiting on the container
+ // before we signal.
+ <-ch
+ time.Sleep(100 * time.Millisecond)
+ // Send the container a SIGTERM which will cause it to stop.
+ if err := s.Signal(syscall.SIGTERM); err != nil {
+ t.Fatalf("error sending signal %v to container: %v", syscall.SIGTERM, err)
+ }
+ // Wait for it to die.
+ wg.Wait()
+
+ // The sandbox process should have exited by now, but it is a zombie.
+ // In normal runsc usage, it will be parented to init, and init will
+ // reap the sandbox. However, in this case the test runner is the
+ // parent and will not reap the sandbox process, so we must do it
+ // ourselves.
+ p, _ := os.FindProcess(s.Sandbox.Pid)
+ p.Wait()
+ g, _ := os.FindProcess(s.Sandbox.GoferPid)
+ g.Wait()
+
+ // Load the container from disk and check the status.
+ s, err = container.Load(rootDir, id)
if err != nil {
- t.Fatalf("exec: %s, error setting up container: %v", test.path, err)
+ t.Fatalf("error loading container: %v", err)
+ }
+ if got, want := s.Status, container.Stopped; got != want {
+ t.Errorf("container status got %v, want %v", got, want)
}
- ws, err := container.Run(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ // Destroy the container.
+ if err := s.Destroy(); err != nil {
+ t.Fatalf("error destroying container: %v", err)
+ }
- os.RemoveAll(rootDir)
- os.RemoveAll(bundleDir)
+ // List should not return the container id.
+ ids, err = container.List(rootDir)
+ if err != nil {
+ t.Fatalf("error listing containers: %v", err)
+ }
+ if len(ids) != 0 {
+ t.Errorf("expected container list to be empty, but got %v", ids)
+ }
+
+ // Loading the container by id should fail.
+ if _, err = container.Load(rootDir, id); err == nil {
+ t.Errorf("expected loading destroyed container to fail, but it did not")
+ }
+ }
+}
- if test.success {
+// Test the we can execute the application with different path formats.
+func TestExePath(t *testing.T) {
+ for _, conf := range configs(overlay) {
+ t.Logf("Running test with conf: %+v", conf)
+ for _, test := range []struct {
+ path string
+ success bool
+ }{
+ {path: "true", success: true},
+ {path: "bin/true", success: true},
+ {path: "/bin/true", success: true},
+ {path: "thisfiledoesntexit", success: false},
+ {path: "bin/thisfiledoesntexit", success: false},
+ {path: "/bin/thisfiledoesntexit", success: false},
+ } {
+ spec := testutil.NewSpecWithArgs(test.path)
+ rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
if err != nil {
- t.Errorf("exec: %s, error running container: %v", test.path, err)
+ t.Fatalf("exec: %s, error setting up container: %v", test.path, err)
}
- if ws.ExitStatus() != 0 {
- t.Errorf("exec: %s, got exit status %v want %v", test.path, ws.ExitStatus(), 0)
- }
- } else {
- if err == nil {
- t.Errorf("exec: %s, got: no error, want: error", test.path)
+
+ ws, err := container.Run(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+
+ os.RemoveAll(rootDir)
+ os.RemoveAll(bundleDir)
+
+ if test.success {
+ if err != nil {
+ t.Errorf("exec: %s, error running container: %v", test.path, err)
+ }
+ if ws.ExitStatus() != 0 {
+ t.Errorf("exec: %s, got exit status %v want %v", test.path, ws.ExitStatus(), 0)
+ }
+ } else {
+ if err == nil {
+ t.Errorf("exec: %s, got: no error, want: error", test.path)
+ }
}
}
}
@@ -362,8 +397,8 @@ func TestExePath(t *testing.T) {
func TestAppExitStatus(t *testing.T) {
// First container will succeed.
succSpec := testutil.NewSpecWithArgs("true")
-
- rootDir, bundleDir, conf, err := testutil.SetupContainer(succSpec)
+ conf := testutil.TestConfig()
+ rootDir, bundleDir, err := testutil.SetupContainer(succSpec, conf)
if err != nil {
t.Fatalf("error setting up container: %v", err)
}
@@ -382,7 +417,7 @@ func TestAppExitStatus(t *testing.T) {
wantStatus := 123
errSpec := testutil.NewSpecWithArgs("bash", "-c", fmt.Sprintf("exit %d", wantStatus))
- rootDir2, bundleDir2, conf, err := testutil.SetupContainer(errSpec)
+ rootDir2, bundleDir2, err := testutil.SetupContainer(errSpec, conf)
if err != nil {
t.Fatalf("error setting up container: %v", err)
}
@@ -400,82 +435,86 @@ func TestAppExitStatus(t *testing.T) {
// TestExec verifies that a container can exec a new program.
func TestExec(t *testing.T) {
- const uid = 343
- spec := testutil.NewSpecWithArgs("sleep", "100")
+ for _, conf := range configs(overlay) {
+ t.Logf("Running test with conf: %+v", conf)
- rootDir, bundleDir, conf, err := testutil.SetupContainer(spec)
- if err != nil {
- t.Fatalf("error setting up container: %v", err)
- }
- defer os.RemoveAll(rootDir)
- defer os.RemoveAll(bundleDir)
+ const uid = 343
+ spec := testutil.NewSpecWithArgs("sleep", "100")
- // Create and start the container.
- s, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
- if err != nil {
- t.Fatalf("error creating container: %v", err)
- }
- defer s.Destroy()
- if err := s.Start(conf); err != nil {
- t.Fatalf("error starting container: %v", err)
- }
+ rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(rootDir)
+ defer os.RemoveAll(bundleDir)
- // expectedPL lists the expected process state of the container.
- expectedPL := []*control.Process{
- {
- UID: 0,
- PID: 1,
- PPID: 0,
- C: 0,
- Cmd: "sleep",
- },
- {
- UID: uid,
- PID: 2,
- PPID: 0,
- C: 0,
- Cmd: "sleep",
- },
- }
+ // Create and start the container.
+ s, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ if err != nil {
+ t.Fatalf("error creating container: %v", err)
+ }
+ defer s.Destroy()
+ if err := s.Start(conf); err != nil {
+ t.Fatalf("error starting container: %v", err)
+ }
- // Verify that "sleep 100" is running.
- if err := waitForProcessList(s, expectedPL[:1]); err != nil {
- t.Error(err)
- }
+ // expectedPL lists the expected process state of the container.
+ expectedPL := []*control.Process{
+ {
+ UID: 0,
+ PID: 1,
+ PPID: 0,
+ C: 0,
+ Cmd: "sleep",
+ },
+ {
+ UID: uid,
+ PID: 2,
+ PPID: 0,
+ C: 0,
+ Cmd: "sleep",
+ },
+ }
- execArgs := control.ExecArgs{
- Filename: "/bin/sleep",
- Argv: []string{"sleep", "5"},
- Envv: []string{"PATH=" + os.Getenv("PATH")},
- WorkingDirectory: "/",
- KUID: uid,
- }
+ // Verify that "sleep 100" is running.
+ if err := waitForProcessList(s, expectedPL[:1]); err != nil {
+ t.Error(err)
+ }
- // Verify that "sleep 100" and "sleep 5" are running after exec.
- // First, start running exec (whick blocks).
- status := make(chan error, 1)
- go func() {
- exitStatus, err := s.Execute(&execArgs)
- if err != nil {
- status <- err
- } else if exitStatus != 0 {
- status <- fmt.Errorf("failed with exit status: %v", exitStatus)
- } else {
- status <- nil
+ execArgs := control.ExecArgs{
+ Filename: "/bin/sleep",
+ Argv: []string{"sleep", "5"},
+ Envv: []string{"PATH=" + os.Getenv("PATH")},
+ WorkingDirectory: "/",
+ KUID: uid,
}
- }()
- if err := waitForProcessList(s, expectedPL); err != nil {
- t.Fatal(err)
- }
+ // Verify that "sleep 100" and "sleep 5" are running after exec.
+ // First, start running exec (whick blocks).
+ status := make(chan error, 1)
+ go func() {
+ exitStatus, err := s.Execute(&execArgs)
+ if err != nil {
+ status <- err
+ } else if exitStatus != 0 {
+ status <- fmt.Errorf("failed with exit status: %v", exitStatus)
+ } else {
+ status <- nil
+ }
+ }()
- // Ensure that exec finished without error.
- select {
- case <-time.After(10 * time.Second):
- t.Fatalf("container timed out waiting for exec to finish.")
- case st := <-status:
- if st != nil {
- t.Errorf("container failed to exec %v: %v", execArgs, err)
+ if err := waitForProcessList(s, expectedPL); err != nil {
+ t.Fatal(err)
+ }
+
+ // Ensure that exec finished without error.
+ select {
+ case <-time.After(10 * time.Second):
+ t.Fatalf("container timed out waiting for exec to finish.")
+ case st := <-status:
+ if st != nil {
+ t.Errorf("container failed to exec %v: %v", execArgs, err)
+ }
}
}
}
@@ -486,129 +525,136 @@ func TestExec(t *testing.T) {
// new containers and the first number printed from these containers is checked. Both should
// be the next consecutive number after the last number from the checkpointed container.
func TestCheckpointRestore(t *testing.T) {
- outputPath := filepath.Join(os.TempDir(), "output")
- // Make sure it does not already exist.
- os.Remove(outputPath)
+ // Skip overlay because test requires writing to host file.
+ for _, conf := range configs(kvm) {
+ t.Logf("Running test with conf: %+v", conf)
- outputFile, err := createWriteableOutputFile(outputPath)
- if err != nil {
- t.Fatalf("error creating output file: %v", err)
- }
- defer outputFile.Close()
+ dir, err := ioutil.TempDir("", "checkpoint-test")
+ if err != nil {
+ t.Fatalf("ioutil.TempDir failed: %v", err)
+ }
+ if err := os.Chmod(dir, 0777); err != nil {
+ t.Fatalf("error chmoding file: %q, %v", dir, err)
+ }
- outputFileSandbox := strings.Replace(outputPath, os.TempDir(), "/tmp2", -1)
+ outputPath := filepath.Join(dir, "output")
+ outputFile, err := createWriteableOutputFile(outputPath)
+ if err != nil {
+ t.Fatalf("error creating output file: %v", err)
+ }
+ defer outputFile.Close()
- script := fmt.Sprintf("for ((i=0; ;i++)); do echo $i >> %s; sleep 1; done", outputFileSandbox)
- spec := testutil.NewSpecWithArgs("bash", "-c", script)
- spec.Mounts = append(spec.Mounts, specs.Mount{
- Type: "bind",
- Destination: "/tmp2",
- Source: os.TempDir(),
- })
+ script := "for ((i=0; ;i++)); do echo $i >> /tmp2/output; sleep 1; done"
+ spec := testutil.NewSpecWithArgs("bash", "-c", script)
+ spec.Mounts = append(spec.Mounts, specs.Mount{
+ Type: "bind",
+ Destination: "/tmp2",
+ Source: dir,
+ })
- rootDir, bundleDir, conf, err := testutil.SetupContainer(spec)
- if err != nil {
- t.Fatalf("error setting up container: %v", err)
- }
- defer os.RemoveAll(rootDir)
- defer os.RemoveAll(bundleDir)
+ rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(rootDir)
+ defer os.RemoveAll(bundleDir)
- // Create and start the container.
- cont, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
- if err != nil {
- t.Fatalf("error creating container: %v", err)
- }
- defer cont.Destroy()
- if err := cont.Start(conf); err != nil {
- t.Fatalf("error starting container: %v", err)
- }
+ // Create and start the container.
+ cont, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ if err != nil {
+ t.Fatalf("error creating container: %v", err)
+ }
+ defer cont.Destroy()
+ if err := cont.Start(conf); err != nil {
+ t.Fatalf("error starting container: %v", err)
+ }
- // Set the image path, which is where the checkpoint image will be saved.
- imagePath := filepath.Join(os.TempDir(), "test-image-file")
+ // Set the image path, which is where the checkpoint image will be saved.
+ imagePath := filepath.Join(dir, "test-image-file")
- // Create the image file and open for writing.
- file, err := os.OpenFile(imagePath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0644)
- if err != nil {
- t.Fatalf("error opening new file at imagePath: %v", err)
- }
- defer file.Close()
+ // Create the image file and open for writing.
+ file, err := os.OpenFile(imagePath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0644)
+ if err != nil {
+ t.Fatalf("error opening new file at imagePath: %v", err)
+ }
+ defer file.Close()
- time.Sleep(1 * time.Second)
+ time.Sleep(1 * time.Second)
- // Checkpoint running container; save state into new file.
- if err := cont.Checkpoint(file); err != nil {
- t.Fatalf("error checkpointing container to empty file: %v", err)
- }
- defer os.RemoveAll(imagePath)
+ // Checkpoint running container; save state into new file.
+ if err := cont.Checkpoint(file); err != nil {
+ t.Fatalf("error checkpointing container to empty file: %v", err)
+ }
+ defer os.RemoveAll(imagePath)
- lastNum, err := readOutputNum(outputFile, false)
- if err != nil {
- t.Fatalf("error with outputFile: %v", err)
- }
+ lastNum, err := readOutputNum(outputFile, false)
+ if err != nil {
+ t.Fatalf("error with outputFile: %v", err)
+ }
- // Delete and recreate file before restoring.
- if err := os.Remove(outputPath); err != nil {
- t.Fatalf("error removing file")
- }
- outputFile2, err := createWriteableOutputFile(outputPath)
- if err != nil {
- t.Fatalf("error creating output file: %v", err)
- }
- defer outputFile2.Close()
+ // Delete and recreate file before restoring.
+ if err := os.Remove(outputPath); err != nil {
+ t.Fatalf("error removing file")
+ }
+ outputFile2, err := createWriteableOutputFile(outputPath)
+ if err != nil {
+ t.Fatalf("error creating output file: %v", err)
+ }
+ defer outputFile2.Close()
- // Restore into a new container.
- cont2, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
- if err != nil {
- t.Fatalf("error creating container: %v", err)
- }
- defer cont2.Destroy()
+ // Restore into a new container.
+ cont2, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ if err != nil {
+ t.Fatalf("error creating container: %v", err)
+ }
+ defer cont2.Destroy()
- if err := cont2.Restore(spec, conf, imagePath); err != nil {
- t.Fatalf("error restoring container: %v", err)
- }
+ if err := cont2.Restore(spec, conf, imagePath); err != nil {
+ t.Fatalf("error restoring container: %v", err)
+ }
- firstNum, err := readOutputNum(outputFile2, true)
- if err != nil {
- t.Fatalf("error with outputFile: %v", err)
- }
+ firstNum, err := readOutputNum(outputFile2, true)
+ if err != nil {
+ t.Fatalf("error with outputFile: %v", err)
+ }
- // Check that lastNum is one less than firstNum and that the container picks up from where it left off.
- if lastNum+1 != firstNum {
- t.Errorf("error numbers not in order, previous: %d, next: %d", lastNum, firstNum)
- }
+ // Check that lastNum is one less than firstNum and that the container picks up from where it left off.
+ if lastNum+1 != firstNum {
+ t.Errorf("error numbers not in order, previous: %d, next: %d", lastNum, firstNum)
+ }
- // Restore into another container!
- // Delete and recreate file before restoring.
- if err := os.Remove(outputPath); err != nil {
- t.Fatalf("error removing file")
- }
- outputFile3, err := createWriteableOutputFile(outputPath)
- if err != nil {
- t.Fatalf("error creating output file: %v", err)
- }
- defer outputFile3.Close()
+ // Restore into another container!
+ // Delete and recreate file before restoring.
+ if err := os.Remove(outputPath); err != nil {
+ t.Fatalf("error removing file")
+ }
+ outputFile3, err := createWriteableOutputFile(outputPath)
+ if err != nil {
+ t.Fatalf("error creating output file: %v", err)
+ }
+ defer outputFile3.Close()
- // Restore into a new container.
- cont3, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
- if err != nil {
- t.Fatalf("error creating container: %v", err)
- }
- defer cont3.Destroy()
+ // Restore into a new container.
+ cont3, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ if err != nil {
+ t.Fatalf("error creating container: %v", err)
+ }
+ defer cont3.Destroy()
- if err := cont3.Restore(spec, conf, imagePath); err != nil {
- t.Fatalf("error restoring container: %v", err)
- }
+ if err := cont3.Restore(spec, conf, imagePath); err != nil {
+ t.Fatalf("error restoring container: %v", err)
+ }
- firstNum2, err := readOutputNum(outputFile3, true)
- if err != nil {
- t.Fatalf("error with outputFile: %v", err)
- }
+ firstNum2, err := readOutputNum(outputFile3, true)
+ if err != nil {
+ t.Fatalf("error with outputFile: %v", err)
+ }
- // Check that lastNum is one less than firstNum and that the container picks up from where it left off.
- if lastNum+1 != firstNum2 {
- t.Errorf("error numbers not in order, previous: %d, next: %d", lastNum, firstNum2)
+ // Check that lastNum is one less than firstNum and that the container picks up from where it left off.
+ if lastNum+1 != firstNum2 {
+ t.Errorf("error numbers not in order, previous: %d, next: %d", lastNum, firstNum2)
+ }
}
-
}
// TestPauseResume tests that we can successfully pause and resume a container.
@@ -617,102 +663,105 @@ func TestCheckpointRestore(t *testing.T) {
// It will then unpause and confirm that both processes are running. Then it will
// wait until one sleep completes and check to make sure the other is running.
func TestPauseResume(t *testing.T) {
- const uid = 343
- spec := testutil.NewSpecWithArgs("sleep", "20")
+ for _, conf := range configs(all) {
+ t.Logf("Running test with conf: %+v", conf)
+ const uid = 343
+ spec := testutil.NewSpecWithArgs("sleep", "20")
- rootDir, bundleDir, conf, err := testutil.SetupContainer(spec)
- if err != nil {
- t.Fatalf("error setting up container: %v", err)
- }
- defer os.RemoveAll(rootDir)
- defer os.RemoveAll(bundleDir)
+ rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(rootDir)
+ defer os.RemoveAll(bundleDir)
- // Create and start the container.
- cont, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
- if err != nil {
- t.Fatalf("error creating container: %v", err)
- }
- defer cont.Destroy()
- if err := cont.Start(conf); err != nil {
- t.Fatalf("error starting container: %v", err)
- }
+ // Create and start the container.
+ cont, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ if err != nil {
+ t.Fatalf("error creating container: %v", err)
+ }
+ defer cont.Destroy()
+ if err := cont.Start(conf); err != nil {
+ t.Fatalf("error starting container: %v", err)
+ }
- // expectedPL lists the expected process state of the container.
- expectedPL := []*control.Process{
- {
- UID: 0,
- PID: 1,
- PPID: 0,
- C: 0,
- Cmd: "sleep",
- },
- {
- UID: uid,
- PID: 2,
- PPID: 0,
- C: 0,
- Cmd: "sleep",
- },
- }
+ // expectedPL lists the expected process state of the container.
+ expectedPL := []*control.Process{
+ {
+ UID: 0,
+ PID: 1,
+ PPID: 0,
+ C: 0,
+ Cmd: "sleep",
+ },
+ {
+ UID: uid,
+ PID: 2,
+ PPID: 0,
+ C: 0,
+ Cmd: "sleep",
+ },
+ }
- execArgs := control.ExecArgs{
- Filename: "/bin/sleep",
- Argv: []string{"sleep", "5"},
- Envv: []string{"PATH=" + os.Getenv("PATH")},
- WorkingDirectory: "/",
- KUID: uid,
- }
+ execArgs := control.ExecArgs{
+ Filename: "/bin/sleep",
+ Argv: []string{"sleep", "5"},
+ Envv: []string{"PATH=" + os.Getenv("PATH")},
+ WorkingDirectory: "/",
+ KUID: uid,
+ }
- // First, start running exec (whick blocks).
- go cont.Execute(&execArgs)
+ // First, start running exec (whick blocks).
+ go cont.Execute(&execArgs)
- // Verify that "sleep 5" is running.
- if err := waitForProcessList(cont, expectedPL); err != nil {
- t.Fatal(err)
- }
+ // Verify that "sleep 5" is running.
+ if err := waitForProcessList(cont, expectedPL); err != nil {
+ t.Fatal(err)
+ }
- // Pause the running container.
- if err := cont.Pause(); err != nil {
- t.Errorf("error pausing container: %v", err)
- }
- if got, want := cont.Status, container.Paused; got != want {
- t.Errorf("container status got %v, want %v", got, want)
- }
+ // Pause the running container.
+ if err := cont.Pause(); err != nil {
+ t.Errorf("error pausing container: %v", err)
+ }
+ if got, want := cont.Status, container.Paused; got != want {
+ t.Errorf("container status got %v, want %v", got, want)
+ }
- time.Sleep(10 * time.Second)
+ time.Sleep(10 * time.Second)
- // Verify that the two processes still exist. Sleep 5 is paused so
- // it should still be in the process list after 10 seconds.
- if err := getAndCheckProcLists(cont, expectedPL); err != nil {
- t.Fatal(err)
- }
+ // Verify that the two processes still exist. Sleep 5 is paused so
+ // it should still be in the process list after 10 seconds.
+ if err := getAndCheckProcLists(cont, expectedPL); err != nil {
+ t.Fatal(err)
+ }
- // Resume the running container.
- if err := cont.Resume(); err != nil {
- t.Errorf("error pausing container: %v", err)
- }
- if got, want := cont.Status, container.Running; got != want {
- t.Errorf("container status got %v, want %v", got, want)
- }
+ // Resume the running container.
+ if err := cont.Resume(); err != nil {
+ t.Errorf("error pausing container: %v", err)
+ }
+ if got, want := cont.Status, container.Running; got != want {
+ t.Errorf("container status got %v, want %v", got, want)
+ }
- if err := getAndCheckProcLists(cont, expectedPL); err != nil {
- t.Fatal(err)
- }
+ if err := getAndCheckProcLists(cont, expectedPL); err != nil {
+ t.Fatal(err)
+ }
- expectedPL2 := []*control.Process{
- {
- UID: 0,
- PID: 1,
- PPID: 0,
- C: 0,
- Cmd: "sleep",
- },
- }
+ expectedPL2 := []*control.Process{
+ {
+ UID: 0,
+ PID: 1,
+ PPID: 0,
+ C: 0,
+ Cmd: "sleep",
+ },
+ }
- // Verify there is only one process left since we waited 10 at most seconds for
- // sleep 5 to end.
- if err := waitForProcessList(cont, expectedPL2); err != nil {
- t.Fatal(err)
+ // Verify there is only one process left since we waited 10 at most seconds for
+ // sleep 5 to end.
+ if err := waitForProcessList(cont, expectedPL2); err != nil {
+ t.Fatal(err)
+ }
}
}
@@ -721,8 +770,8 @@ func TestPauseResume(t *testing.T) {
// occurs given the correct state.
func TestPauseResumeStatus(t *testing.T) {
spec := testutil.NewSpecWithArgs("sleep", "20")
-
- rootDir, bundleDir, conf, err := testutil.SetupContainer(spec)
+ conf := testutil.TestConfig()
+ rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
if err != nil {
t.Fatalf("error setting up container: %v", err)
}
@@ -780,297 +829,321 @@ func TestPauseResumeStatus(t *testing.T) {
func TestCapabilities(t *testing.T) {
const uid = 343
const gid = 2401
- spec := testutil.NewSpecWithArgs("sleep", "100")
- // We generate files in the host temporary directory.
- spec.Mounts = append(spec.Mounts, specs.Mount{
- Destination: os.TempDir(),
- Source: os.TempDir(),
- Type: "bind",
- })
+ for _, conf := range configs(all) {
+ t.Logf("Running test with conf: %+v", conf)
- rootDir, bundleDir, conf, err := testutil.SetupContainer(spec)
- if err != nil {
- t.Fatalf("error setting up container: %v", err)
- }
- defer os.RemoveAll(rootDir)
- defer os.RemoveAll(bundleDir)
+ spec := testutil.NewSpecWithArgs("sleep", "100")
- // Create and start the container.
- s, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
- if err != nil {
- t.Fatalf("error creating container: %v", err)
- }
- defer s.Destroy()
- if err := s.Start(conf); err != nil {
- t.Fatalf("error starting container: %v", err)
- }
+ // We generate files in the host temporary directory.
+ spec.Mounts = append(spec.Mounts, specs.Mount{
+ Destination: os.TempDir(),
+ Source: os.TempDir(),
+ Type: "bind",
+ })
- // expectedPL lists the expected process state of the container.
- expectedPL := []*control.Process{
- {
- UID: 0,
- PID: 1,
- PPID: 0,
- C: 0,
- Cmd: "sleep",
- },
- {
- UID: uid,
- PID: 2,
- PPID: 0,
- C: 0,
- Cmd: "exe",
- },
- }
- if err := waitForProcessList(s, expectedPL[:1]); err != nil {
- t.Fatalf("Failed to wait for sleep to start, err: %v", err)
- }
+ rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(rootDir)
+ defer os.RemoveAll(bundleDir)
- // Create an executable that can't be run with the specified UID:GID.
- // This shouldn't be callable within the container until we add the
- // CAP_DAC_OVERRIDE capability to skip the access check.
- exePath := filepath.Join(rootDir, "exe")
- if err := ioutil.WriteFile(exePath, []byte("#!/bin/sh\necho hello"), 0770); err != nil {
- t.Fatalf("couldn't create executable: %v", err)
- }
- defer os.Remove(exePath)
+ // Create and start the container.
+ s, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ if err != nil {
+ t.Fatalf("error creating container: %v", err)
+ }
+ defer s.Destroy()
+ if err := s.Start(conf); err != nil {
+ t.Fatalf("error starting container: %v", err)
+ }
- // Need to traverse the intermediate directory.
- os.Chmod(rootDir, 0755)
+ // expectedPL lists the expected process state of the container.
+ expectedPL := []*control.Process{
+ {
+ UID: 0,
+ PID: 1,
+ PPID: 0,
+ C: 0,
+ Cmd: "sleep",
+ },
+ {
+ UID: uid,
+ PID: 2,
+ PPID: 0,
+ C: 0,
+ Cmd: "exe",
+ },
+ }
+ if err := waitForProcessList(s, expectedPL[:1]); err != nil {
+ t.Fatalf("Failed to wait for sleep to start, err: %v", err)
+ }
- execArgs := control.ExecArgs{
- Filename: exePath,
- Argv: []string{exePath},
- Envv: []string{"PATH=" + os.Getenv("PATH")},
- WorkingDirectory: "/",
- KUID: uid,
- KGID: gid,
- Capabilities: &auth.TaskCapabilities{},
- }
+ // Create an executable that can't be run with the specified UID:GID.
+ // This shouldn't be callable within the container until we add the
+ // CAP_DAC_OVERRIDE capability to skip the access check.
+ exePath := filepath.Join(rootDir, "exe")
+ if err := ioutil.WriteFile(exePath, []byte("#!/bin/sh\necho hello"), 0770); err != nil {
+ t.Fatalf("couldn't create executable: %v", err)
+ }
+ defer os.Remove(exePath)
+
+ // Need to traverse the intermediate directory.
+ os.Chmod(rootDir, 0755)
+
+ execArgs := control.ExecArgs{
+ Filename: exePath,
+ Argv: []string{exePath},
+ Envv: []string{"PATH=" + os.Getenv("PATH")},
+ WorkingDirectory: "/",
+ KUID: uid,
+ KGID: gid,
+ Capabilities: &auth.TaskCapabilities{},
+ }
- // "exe" should fail because we don't have the necessary permissions.
- if _, err := s.Execute(&execArgs); err == nil {
- t.Fatalf("container executed without error, but an error was expected")
- }
+ // "exe" should fail because we don't have the necessary permissions.
+ if _, err := s.Execute(&execArgs); err == nil {
+ t.Fatalf("container executed without error, but an error was expected")
+ }
- // Now we run with the capability enabled and should succeed.
- execArgs.Capabilities = &auth.TaskCapabilities{
- EffectiveCaps: auth.CapabilitySetOf(linux.CAP_DAC_OVERRIDE),
- }
- // "exe" should not fail this time.
- if _, err := s.Execute(&execArgs); err != nil {
- t.Fatalf("container failed to exec %v: %v", execArgs, err)
+ // Now we run with the capability enabled and should succeed.
+ execArgs.Capabilities = &auth.TaskCapabilities{
+ EffectiveCaps: auth.CapabilitySetOf(linux.CAP_DAC_OVERRIDE),
+ }
+ // "exe" should not fail this time.
+ if _, err := s.Execute(&execArgs); err != nil {
+ t.Fatalf("container failed to exec %v: %v", execArgs, err)
+ }
}
}
// Test that an tty FD is sent over the console socket if one is provided.
func TestConsoleSocket(t *testing.T) {
- spec := testutil.NewSpecWithArgs("true")
- rootDir, bundleDir, conf, err := testutil.SetupContainer(spec)
- if err != nil {
- t.Fatalf("error setting up container: %v", err)
- }
- defer os.RemoveAll(rootDir)
- defer os.RemoveAll(bundleDir)
+ for _, conf := range configs(all) {
+ t.Logf("Running test with conf: %+v", conf)
+ spec := testutil.NewSpecWithArgs("true")
+ rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(rootDir)
+ defer os.RemoveAll(bundleDir)
- // Create a named socket and start listening. We use a relative path
- // to avoid overflowing the unix path length limit (108 chars).
- socketPath := filepath.Join(bundleDir, "socket")
- cwd, err := os.Getwd()
- if err != nil {
- t.Fatalf("error getting cwd: %v", err)
- }
- socketRelPath, err := filepath.Rel(cwd, socketPath)
- if err != nil {
- t.Fatalf("error getting relative path for %q from cwd %q: %v", socketPath, cwd, err)
- }
- if len(socketRelPath) > len(socketPath) {
- socketRelPath = socketPath
- }
- srv, err := unet.BindAndListen(socketRelPath, false)
- if err != nil {
- t.Fatalf("error binding and listening to socket %q: %v", socketPath, err)
- }
- defer os.Remove(socketPath)
+ // Create a named socket and start listening. We use a relative path
+ // to avoid overflowing the unix path length limit (108 chars).
+ socketPath := filepath.Join(bundleDir, "socket")
+ cwd, err := os.Getwd()
+ if err != nil {
+ t.Fatalf("error getting cwd: %v", err)
+ }
+ socketRelPath, err := filepath.Rel(cwd, socketPath)
+ if err != nil {
+ t.Fatalf("error getting relative path for %q from cwd %q: %v", socketPath, cwd, err)
+ }
+ if len(socketRelPath) > len(socketPath) {
+ socketRelPath = socketPath
+ }
+ srv, err := unet.BindAndListen(socketRelPath, false)
+ if err != nil {
+ t.Fatalf("error binding and listening to socket %q: %v", socketPath, err)
+ }
+ defer os.Remove(socketPath)
- // Create the container and pass the socket name.
- id := testutil.UniqueContainerID()
- s, err := container.Create(id, spec, conf, bundleDir, socketRelPath, "")
- if err != nil {
- t.Fatalf("error creating container: %v", err)
- }
+ // Create the container and pass the socket name.
+ id := testutil.UniqueContainerID()
+ s, err := container.Create(id, spec, conf, bundleDir, socketRelPath, "")
+ if err != nil {
+ t.Fatalf("error creating container: %v", err)
+ }
- // Open the othe end of the socket.
- sock, err := srv.Accept()
- if err != nil {
- t.Fatalf("error accepting socket connection: %v", err)
- }
+ // Open the othe end of the socket.
+ sock, err := srv.Accept()
+ if err != nil {
+ t.Fatalf("error accepting socket connection: %v", err)
+ }
- // Allow 3 fds to be received. We only expect 1.
- r := sock.Reader(true /* blocking */)
- r.EnableFDs(1)
+ // Allow 3 fds to be received. We only expect 1.
+ r := sock.Reader(true /* blocking */)
+ r.EnableFDs(1)
- // The socket is closed right after sending the FD, so EOF is
- // an allowed error.
- b := [][]byte{{}}
- if _, err := r.ReadVec(b); err != nil && err != io.EOF {
- t.Fatalf("error reading from socket connection: %v", err)
- }
+ // The socket is closed right after sending the FD, so EOF is
+ // an allowed error.
+ b := [][]byte{{}}
+ if _, err := r.ReadVec(b); err != nil && err != io.EOF {
+ t.Fatalf("error reading from socket connection: %v", err)
+ }
- // We should have gotten a control message.
- fds, err := r.ExtractFDs()
- if err != nil {
- t.Fatalf("error extracting fds from socket connection: %v", err)
- }
- if len(fds) != 1 {
- t.Fatalf("got %d fds from socket, wanted 1", len(fds))
- }
+ // We should have gotten a control message.
+ fds, err := r.ExtractFDs()
+ if err != nil {
+ t.Fatalf("error extracting fds from socket connection: %v", err)
+ }
+ if len(fds) != 1 {
+ t.Fatalf("got %d fds from socket, wanted 1", len(fds))
+ }
- // Verify that the fd is a terminal.
- if _, err := unix.IoctlGetTermios(fds[0], unix.TCGETS); err != nil {
- t.Errorf("fd is not a terminal (ioctl TGGETS got %v)", err)
- }
+ // Verify that the fd is a terminal.
+ if _, err := unix.IoctlGetTermios(fds[0], unix.TCGETS); err != nil {
+ t.Errorf("fd is not a terminal (ioctl TGGETS got %v)", err)
+ }
- // Shut it down.
- if err := s.Destroy(); err != nil {
- t.Fatalf("error destroying container: %v", err)
- }
+ // Shut it down.
+ if err := s.Destroy(); err != nil {
+ t.Fatalf("error destroying container: %v", err)
+ }
- // Close socket.
- if err := srv.Close(); err != nil {
- t.Fatalf("error destroying container: %v", err)
+ // Close socket.
+ if err := srv.Close(); err != nil {
+ t.Fatalf("error destroying container: %v", err)
+ }
}
}
// TestRunNonRoot checks that sandbox can be configured when running as
// non-privileged user.
func TestRunNonRoot(t *testing.T) {
- spec := testutil.NewSpecWithArgs("/bin/true")
- spec.Process.User.UID = 343
- spec.Process.User.GID = 2401
+ for _, conf := range configs(kvm) {
+ t.Logf("Running test with conf: %+v", conf)
- // User that container runs as can't list '$TMP/blocked' and would fail to
- // mount it.
- dir, err := ioutil.TempDir("", "blocked")
- if err != nil {
- t.Fatalf("ioutil.TempDir() failed: %v", err)
- }
- if err := os.Chmod(dir, 0700); err != nil {
- t.Fatalf("os.MkDir(%q) failed: %v", dir, err)
- }
- dir = path.Join(dir, "test")
- if err := os.Mkdir(dir, 0755); err != nil {
- t.Fatalf("os.MkDir(%q) failed: %v", dir, err)
- }
+ spec := testutil.NewSpecWithArgs("/bin/true")
+ spec.Process.User.UID = 343
+ spec.Process.User.GID = 2401
+
+ // User that container runs as can't list '$TMP/blocked' and would fail to
+ // mount it.
+ dir, err := ioutil.TempDir("", "blocked")
+ if err != nil {
+ t.Fatalf("ioutil.TempDir() failed: %v", err)
+ }
+ if err := os.Chmod(dir, 0700); err != nil {
+ t.Fatalf("os.MkDir(%q) failed: %v", dir, err)
+ }
+ dir = path.Join(dir, "test")
+ if err := os.Mkdir(dir, 0755); err != nil {
+ t.Fatalf("os.MkDir(%q) failed: %v", dir, err)
+ }
- // We generate files in the host temporary directory.
- spec.Mounts = append(spec.Mounts, specs.Mount{
- Destination: dir,
- Source: dir,
- Type: "bind",
- })
+ // We generate files in the host temporary directory.
+ spec.Mounts = append(spec.Mounts, specs.Mount{
+ Destination: dir,
+ Source: dir,
+ Type: "bind",
+ })
- if err := run(spec); err != nil {
- t.Fatalf("error running sadbox: %v", err)
+ if err := run(spec, conf); err != nil {
+ t.Fatalf("error running sadbox: %v", err)
+ }
}
}
// TestMountNewDir checks that runsc will create destination directory if it
// doesn't exit.
func TestMountNewDir(t *testing.T) {
- srcDir := path.Join(os.TempDir(), "src", "newdir", "anotherdir")
- if err := os.MkdirAll(srcDir, 0755); err != nil {
- t.Fatalf("os.MkDir(%q) failed: %v", srcDir, err)
- }
+ for _, conf := range configs(overlay) {
+ t.Logf("Running test with conf: %+v", conf)
- // Attempt to remove dir to ensure it doesn't exist.
- mountDir := path.Join(os.TempDir(), "newdir")
- if err := os.RemoveAll(mountDir); err != nil {
- t.Fatalf("os.RemoveAll(%q) failed: %v", mountDir, err)
- }
- mountDir = path.Join(mountDir, "anotherdir")
+ srcDir := path.Join(os.TempDir(), "src", "newdir", "anotherdir")
+ if err := os.MkdirAll(srcDir, 0755); err != nil {
+ t.Fatalf("os.MkDir(%q) failed: %v", srcDir, err)
+ }
+
+ // Attempt to remove dir to ensure it doesn't exist.
+ mountDir := path.Join(os.TempDir(), "newdir")
+ if err := os.RemoveAll(mountDir); err != nil {
+ t.Fatalf("os.RemoveAll(%q) failed: %v", mountDir, err)
+ }
+ mountDir = path.Join(mountDir, "anotherdir")
- spec := testutil.NewSpecWithArgs("/bin/ls", mountDir)
- spec.Mounts = append(spec.Mounts, specs.Mount{
- Destination: mountDir,
- Source: srcDir,
- Type: "bind",
- })
+ spec := testutil.NewSpecWithArgs("/bin/ls", mountDir)
+ spec.Mounts = append(spec.Mounts, specs.Mount{
+ Destination: mountDir,
+ Source: srcDir,
+ Type: "bind",
+ })
- if err := run(spec); err != nil {
- t.Fatalf("error running sadbox: %v", err)
+ if err := run(spec, conf); err != nil {
+ t.Fatalf("error running sadbox: %v", err)
+ }
}
}
func TestReadonlyRoot(t *testing.T) {
- spec := testutil.NewSpecWithArgs("/bin/touch", "/foo")
- spec.Root.Readonly = true
- rootDir, bundleDir, conf, err := testutil.SetupContainer(spec)
- if err != nil {
- t.Fatalf("error setting up container: %v", err)
- }
- defer os.RemoveAll(rootDir)
- defer os.RemoveAll(bundleDir)
+ for _, conf := range configs(overlay) {
+ t.Logf("Running test with conf: %+v", conf)
- conf.Overlay = true
+ spec := testutil.NewSpecWithArgs("/bin/touch", "/foo")
+ spec.Root.Readonly = true
+ rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(rootDir)
+ defer os.RemoveAll(bundleDir)
- // Create, start and wait for the container.
- s, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
- if err != nil {
- t.Fatalf("error creating container: %v", err)
- }
- defer s.Destroy()
- if err := s.Start(conf); err != nil {
- t.Fatalf("error starting container: %v", err)
- }
- ws, err := s.Wait()
- if err != nil {
- t.Fatalf("error waiting on container: %v", err)
- }
- if !ws.Exited() || syscall.Errno(ws.ExitStatus()) != syscall.EPERM {
- t.Fatalf("container failed, waitStatus: %v", ws)
+ conf.Overlay = true
+
+ // Create, start and wait for the container.
+ s, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ if err != nil {
+ t.Fatalf("error creating container: %v", err)
+ }
+ defer s.Destroy()
+ if err := s.Start(conf); err != nil {
+ t.Fatalf("error starting container: %v", err)
+ }
+ ws, err := s.Wait()
+ if err != nil {
+ t.Fatalf("error waiting on container: %v", err)
+ }
+ if !ws.Exited() || syscall.Errno(ws.ExitStatus()) != syscall.EPERM {
+ t.Fatalf("container failed, waitStatus: %v", ws)
+ }
}
}
func TestReadonlyMount(t *testing.T) {
- spec := testutil.NewSpecWithArgs("/bin/touch", "/foo/file")
- dir, err := ioutil.TempDir("", "ro-mount")
- if err != nil {
- t.Fatalf("ioutil.TempDir() failed: %v", err)
- }
- spec.Mounts = append(spec.Mounts, specs.Mount{
- Destination: "/foo",
- Source: dir,
- Type: "bind",
- Options: []string{"ro"},
- })
- spec.Root.Readonly = false
+ for _, conf := range configs(overlay) {
+ t.Logf("Running test with conf: %+v", conf)
- rootDir, bundleDir, conf, err := testutil.SetupContainer(spec)
- if err != nil {
- t.Fatalf("error setting up container: %v", err)
- }
- defer os.RemoveAll(rootDir)
- defer os.RemoveAll(bundleDir)
+ spec := testutil.NewSpecWithArgs("/bin/touch", "/foo/file")
+ dir, err := ioutil.TempDir("", "ro-mount")
+ if err != nil {
+ t.Fatalf("ioutil.TempDir() failed: %v", err)
+ }
+ spec.Mounts = append(spec.Mounts, specs.Mount{
+ Destination: "/foo",
+ Source: dir,
+ Type: "bind",
+ Options: []string{"ro"},
+ })
+ spec.Root.Readonly = false
+
+ rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(rootDir)
+ defer os.RemoveAll(bundleDir)
- conf.Overlay = true
+ conf.Overlay = true
- // Create, start and wait for the container.
- s, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
- if err != nil {
- t.Fatalf("error creating container: %v", err)
- }
- defer s.Destroy()
- if err := s.Start(conf); err != nil {
- t.Fatalf("error starting container: %v", err)
- }
- ws, err := s.Wait()
- if err != nil {
- t.Fatalf("error waiting on container: %v", err)
- }
- if !ws.Exited() || syscall.Errno(ws.ExitStatus()) != syscall.EPERM {
- t.Fatalf("container failed, waitStatus: %v", ws)
+ // Create, start and wait for the container.
+ s, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ if err != nil {
+ t.Fatalf("error creating container: %v", err)
+ }
+ defer s.Destroy()
+ if err := s.Start(conf); err != nil {
+ t.Fatalf("error starting container: %v", err)
+ }
+ ws, err := s.Wait()
+ if err != nil {
+ t.Fatalf("error waiting on container: %v", err)
+ }
+ if !ws.Exited() || syscall.Errno(ws.ExitStatus()) != syscall.EPERM {
+ t.Fatalf("container failed, waitStatus: %v", ws)
+ }
}
}
@@ -1089,7 +1162,8 @@ func TestAbbreviatedIDs(t *testing.T) {
}
for _, cid := range cids {
spec := testutil.NewSpecWithArgs("sleep", "100")
- bundleDir, conf, err := testutil.SetupContainerInRoot(rootDir, spec)
+ conf := testutil.TestConfig()
+ bundleDir, err := testutil.SetupContainerInRoot(rootDir, spec, conf)
if err != nil {
t.Fatalf("error setting up container: %v", err)
}
@@ -1134,70 +1208,74 @@ func TestAbbreviatedIDs(t *testing.T) {
// TestMultiContainerSanity checks that it is possible to run 2 dead-simple
// containers in the same sandbox.
func TestMultiContainerSanity(t *testing.T) {
- containerIDs := []string{
- testutil.UniqueContainerID(),
- testutil.UniqueContainerID(),
- }
- containerAnnotations := []map[string]string{
- // The first container creates a sandbox.
- map[string]string{
- specutils.ContainerdContainerTypeAnnotation: specutils.ContainerdContainerTypeSandbox,
- },
- // The second container creates a container within the first
- // container's sandbox.
- map[string]string{
- specutils.ContainerdContainerTypeAnnotation: specutils.ContainerdContainerTypeContainer,
- specutils.ContainerdSandboxIDAnnotation: containerIDs[0],
- },
- }
+ for _, conf := range configs(all) {
+ t.Logf("Running test with conf: %+v", conf)
- rootDir, err := testutil.SetupRootDir()
- if err != nil {
- t.Fatalf("error creating root dir: %v", err)
- }
- defer os.RemoveAll(rootDir)
-
- // Setup the containers.
- containers := make([]*container.Container, 0, len(containerIDs))
- for i, annotations := range containerAnnotations {
- spec := testutil.NewSpecWithArgs("sleep", "100")
- spec.Annotations = annotations
- bundleDir, conf, err := testutil.SetupContainerInRoot(rootDir, spec)
- if err != nil {
- t.Fatalf("error setting up container: %v", err)
+ containerIDs := []string{
+ testutil.UniqueContainerID(),
+ testutil.UniqueContainerID(),
}
- defer os.RemoveAll(bundleDir)
- cont, err := container.Create(containerIDs[i], spec, conf, bundleDir, "", "")
+ containerAnnotations := []map[string]string{
+ // The first container creates a sandbox.
+ map[string]string{
+ specutils.ContainerdContainerTypeAnnotation: specutils.ContainerdContainerTypeSandbox,
+ },
+ // The second container creates a container within the first
+ // container's sandbox.
+ map[string]string{
+ specutils.ContainerdContainerTypeAnnotation: specutils.ContainerdContainerTypeContainer,
+ specutils.ContainerdSandboxIDAnnotation: containerIDs[0],
+ },
+ }
+
+ rootDir, err := testutil.SetupRootDir()
if err != nil {
- t.Fatalf("error creating container: %v", err)
+ t.Fatalf("error creating root dir: %v", err)
}
- defer cont.Destroy()
- if err := cont.Start(conf); err != nil {
- t.Fatalf("error starting container: %v", err)
+ defer os.RemoveAll(rootDir)
+
+ // Setup the containers.
+ containers := make([]*container.Container, 0, len(containerIDs))
+ for i, annotations := range containerAnnotations {
+ spec := testutil.NewSpecWithArgs("sleep", "100")
+ spec.Annotations = annotations
+ bundleDir, err := testutil.SetupContainerInRoot(rootDir, spec, conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(bundleDir)
+ cont, err := container.Create(containerIDs[i], spec, conf, bundleDir, "", "")
+ if err != nil {
+ t.Fatalf("error creating container: %v", err)
+ }
+ defer cont.Destroy()
+ if err := cont.Start(conf); err != nil {
+ t.Fatalf("error starting container: %v", err)
+ }
+ containers = append(containers, cont)
}
- containers = append(containers, cont)
- }
- expectedPL := []*control.Process{
- {
- UID: 0,
- PID: 1,
- PPID: 0,
- C: 0,
- Cmd: "sleep",
- },
- {
- UID: 0,
- PID: 2,
- PPID: 0,
- C: 0,
- Cmd: "sleep",
- },
- }
+ expectedPL := []*control.Process{
+ {
+ UID: 0,
+ PID: 1,
+ PPID: 0,
+ C: 0,
+ Cmd: "sleep",
+ },
+ {
+ UID: 0,
+ PID: 2,
+ PPID: 0,
+ C: 0,
+ Cmd: "sleep",
+ },
+ }
- // Check via ps that multiple processes are running.
- if err := waitForProcessList(containers[0], expectedPL); err != nil {
- t.Errorf("failed to wait for sleep to start: %v", err)
+ // Check via ps that multiple processes are running.
+ if err := waitForProcessList(containers[0], expectedPL); err != nil {
+ t.Errorf("failed to wait for sleep to start: %v", err)
+ }
}
}
@@ -1238,7 +1316,8 @@ func TestMultiContainerWait(t *testing.T) {
for i, annotations := range containerAnnotations {
spec := testutil.NewSpecWithArgs(args[i][0], args[i][1])
spec.Annotations = annotations
- bundleDir, conf, err := testutil.SetupContainerInRoot(rootDir, spec)
+ conf := testutil.TestConfig()
+ bundleDir, err := testutil.SetupContainerInRoot(rootDir, spec, conf)
if err != nil {
t.Fatalf("error setting up container: %v", err)
}
diff --git a/runsc/sandbox/sandbox_test.go b/runsc/sandbox/sandbox_test.go
index fee2de283..40337bc53 100644
--- a/runsc/sandbox/sandbox_test.go
+++ b/runsc/sandbox/sandbox_test.go
@@ -31,7 +31,8 @@ func init() {
func TestGoferExits(t *testing.T) {
spec := testutil.NewSpecWithArgs("/bin/sleep", "10000")
- rootDir, bundleDir, conf, err := testutil.SetupContainer(spec)
+ conf := testutil.TestConfig()
+ rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
if err != nil {
t.Fatalf("error setting up container: %v", err)
}
diff --git a/runsc/test/testutil/BUILD b/runsc/test/testutil/BUILD
index 6aec54abe..3ebcc1362 100644
--- a/runsc/test/testutil/BUILD
+++ b/runsc/test/testutil/BUILD
@@ -7,6 +7,7 @@ go_library(
srcs = [
"docker.go",
"testutil.go",
+ "testutil_race.go",
],
importpath = "gvisor.googlesource.com/gvisor/runsc/test/testutil",
visibility = [
diff --git a/runsc/test/testutil/testutil.go b/runsc/test/testutil/testutil.go
index 9d70d29f2..c7cef9c75 100644
--- a/runsc/test/testutil/testutil.go
+++ b/runsc/test/testutil/testutil.go
@@ -29,6 +29,9 @@ import (
"gvisor.googlesource.com/gvisor/runsc/specutils"
)
+// RaceEnabled is set to true if it was built with '--race' option.
+var RaceEnabled = false
+
// ConfigureExePath configures the executable for runsc in the test environment.
func ConfigureExePath() error {
@@ -66,6 +69,18 @@ func ConfigureExePath() error {
return nil
}
+// TestConfig return the default configuration to use in tests.
+func TestConfig() *boot.Config {
+ return &boot.Config{
+ Debug: true,
+ LogFormat: "text",
+ LogPackets: true,
+ Network: boot.NetworkNone,
+ Strace: true,
+ MultiContainer: true,
+ }
+}
+
// NewSpecWithArgs creates a simple spec with the given args suitable for use
// in tests.
func NewSpecWithArgs(args ...string) *specs.Spec {
@@ -96,38 +111,29 @@ func SetupRootDir() (string, error) {
// SetupContainer creates a bundle and root dir for the container, generates a
// test config, and writes the spec to config.json in the bundle dir.
-func SetupContainer(spec *specs.Spec) (rootDir, bundleDir string, conf *boot.Config, err error) {
+func SetupContainer(spec *specs.Spec, conf *boot.Config) (rootDir, bundleDir string, err error) {
rootDir, err = SetupRootDir()
if err != nil {
- return "", "", nil, err
+ return "", "", err
}
- bundleDir, conf, err = SetupContainerInRoot(rootDir, spec)
- return rootDir, bundleDir, conf, err
+ bundleDir, err = SetupContainerInRoot(rootDir, spec, conf)
+ return rootDir, bundleDir, err
}
// SetupContainerInRoot creates a bundle for the container, generates a test
// config, and writes the spec to config.json in the bundle dir.
-func SetupContainerInRoot(rootDir string, spec *specs.Spec) (bundleDir string, conf *boot.Config, err error) {
+func SetupContainerInRoot(rootDir string, spec *specs.Spec, conf *boot.Config) (bundleDir string, err error) {
bundleDir, err = ioutil.TempDir("", "bundle")
if err != nil {
- return "", nil, fmt.Errorf("error creating bundle dir: %v", err)
+ return "", fmt.Errorf("error creating bundle dir: %v", err)
}
if err = writeSpec(bundleDir, spec); err != nil {
- return "", nil, fmt.Errorf("error writing spec: %v", err)
- }
-
- conf = &boot.Config{
- Debug: true,
- LogFormat: "text",
- LogPackets: true,
- Network: boot.NetworkNone,
- RootDir: rootDir,
- Strace: true,
- MultiContainer: true,
+ return "", fmt.Errorf("error writing spec: %v", err)
}
- return bundleDir, conf, nil
+ conf.RootDir = rootDir
+ return bundleDir, nil
}
// writeSpec writes the spec to disk in the given directory.
diff --git a/runsc/test/testutil/testutil_race.go b/runsc/test/testutil/testutil_race.go
new file mode 100644
index 000000000..59cfdaa7b
--- /dev/null
+++ b/runsc/test/testutil/testutil_race.go
@@ -0,0 +1,21 @@
+// Copyright 2018 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build race
+
+package testutil
+
+func init() {
+ RaceEnabled = true
+}