summaryrefslogtreecommitdiffhomepage
path: root/runsc/container
diff options
context:
space:
mode:
Diffstat (limited to 'runsc/container')
-rw-r--r--runsc/container/container_test.go207
1 files changed, 180 insertions, 27 deletions
diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go
index 11edcd615..33c53e189 100644
--- a/runsc/container/container_test.go
+++ b/runsc/container/container_test.go
@@ -227,33 +227,43 @@ func findUDSApp() (string, error) {
return matches[0], nil
}
-type configOptions int
+type configOption int
const (
- overlay configOptions = 1 << iota
+ overlay configOption = iota
kvm
+ nonExclusiveFS
)
-const all = overlay | kvm
+
+var all = []configOption{overlay, kvm, nonExclusiveFS}
// configs generates different configurations to run tests.
-func configs(opts configOptions) []*boot.Config {
- cs := []*boot.Config{testutil.TestConfig(), testutil.TestConfig()}
- return cs
+func configs(opts ...configOption) []*boot.Config {
+ // Always load the default config.
+ cs := []*boot.Config{testutil.TestConfig()}
- if opts&overlay != 0 {
+ for _, o := range opts {
c := testutil.TestConfig()
- c.Overlay = true
+ switch o {
+ case overlay:
+ c.Overlay = true
+ case kvm:
+ // TODO: KVM tests are flaky. Disable until fixed.
+ continue
+
+ // TODO: KVM doesn't work with --race.
+ if testutil.RaceEnabled {
+ continue
+ }
+ c.Platform = boot.PlatformKVM
+ case nonExclusiveFS:
+ c.FileAccess = boot.FileAccessProxy
+ default:
+ panic(fmt.Sprintf("unknown config option %v", o))
+
+ }
cs = append(cs, c)
}
-
- // TODO: KVM tests are flaky. Disable until fixed.
- // // TODO: KVM doesn't work with --race.
- // if !testutil.RaceEnabled && opts&kvm != 0 {
- // c := testutil.TestConfig()
- // c.Platform = boot.PlatformKVM
- // cs = append(cs, c)
- // }
-
return cs
}
@@ -261,7 +271,7 @@ func configs(opts configOptions) []*boot.Config {
// 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) {
+ 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.
@@ -1049,10 +1059,11 @@ func TestPauseResumeStatus(t *testing.T) {
// - Running exec as non-root with CAP_DAC_OVERRIDE succeeds because it skips
// this check.
func TestCapabilities(t *testing.T) {
- const uid = 343
- const gid = 2401
+ // Pick uid/gid different than ours.
+ uid := auth.KUID(os.Getuid() + 1)
+ gid := auth.KGID(os.Getgid() + 1)
- for _, conf := range configs(all) {
+ for _, conf := range configs(all...) {
t.Logf("Running test with conf: %+v", conf)
spec := testutil.NewSpecWithArgs("sleep", "100")
@@ -1142,7 +1153,7 @@ func TestCapabilities(t *testing.T) {
// Test that an tty FD is sent over the console socket if one is provided.
func TestConsoleSocket(t *testing.T) {
- for _, conf := range configs(all) {
+ for _, conf := range configs(all...) {
t.Logf("Running test with conf: %+v", conf)
spec := testutil.NewSpecWithArgs("true")
rootDir, bundleDir, err := testutil.SetupContainer(spec, conf)
@@ -1303,8 +1314,6 @@ func TestReadonlyRoot(t *testing.T) {
defer os.RemoveAll(rootDir)
defer os.RemoveAll(bundleDir)
- conf.Overlay = true
-
// Create, start and wait for the container.
s, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
if err != nil {
@@ -1348,8 +1357,6 @@ func TestReadonlyMount(t *testing.T) {
defer os.RemoveAll(rootDir)
defer os.RemoveAll(bundleDir)
- conf.Overlay = true
-
// Create, start and wait for the container.
s, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
if err != nil {
@@ -1430,7 +1437,7 @@ 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) {
- for _, conf := range configs(all) {
+ for _, conf := range configs(all...) {
t.Logf("Running test with conf: %+v", conf)
containerIDs := []string{
@@ -1619,3 +1626,149 @@ func TestMultiContainerWait(t *testing.T) {
wg.Wait()
}
+
+// Check that modifications to a volume mount are propigated into and out of
+// the sandbox.
+func TestContainerVolumeContentsShared(t *testing.T) {
+ // Only run this test with shared proxy, since that is the only
+ // behavior it is testing.
+ conf := testutil.TestConfig()
+ conf.FileAccess = boot.FileAccessProxy
+ t.Logf("Running test with conf: %+v", conf)
+
+ // Main process just sleeps. We will use "exec" to probe the state of
+ // the filesystem.
+ spec := testutil.NewSpecWithArgs("sleep", "1000")
+
+ // Mount host temp dir inside the sandbox at '/tmp2'.
+ hostTmpDir, err := ioutil.TempDir("", "root-fs-test")
+ sandboxTmpDir := "/tmp2"
+ if err != nil {
+ t.Fatalf("TempDir failed: %v", err)
+ }
+ spec.Mounts = append(spec.Mounts, specs.Mount{
+ Type: "bind",
+ Destination: sandboxTmpDir,
+ Source: hostTmpDir,
+ })
+
+ 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.
+ c, err := container.Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ if err != nil {
+ t.Fatalf("error creating container: %v", err)
+ }
+ defer c.Destroy()
+ if err := c.Start(conf); err != nil {
+ t.Fatalf("error starting container: %v", err)
+ }
+
+ // File that will be used to check consistency inside/outside sandbox.
+ hostFilename := filepath.Join(hostTmpDir, "file")
+ sandboxFilename := filepath.Join(sandboxTmpDir, "file")
+
+ // File does not exist yet. Reading from the sandbox should fail.
+ execArgsTestFile := control.ExecArgs{
+ Filename: "/usr/bin/test",
+ Argv: []string{"test", "-f", sandboxFilename},
+ }
+ if ws, err := c.Execute(&execArgsTestFile); err != nil {
+ t.Fatalf("unexpected error testing file %q: %v", sandboxFilename, err)
+ } else if ws.ExitStatus() == 0 {
+ t.Errorf("test %q exited with code %v, wanted not zero", ws.ExitStatus(), err)
+ }
+
+ // Create the file from outside of the sandbox.
+ if err := ioutil.WriteFile(hostFilename, []byte("foobar"), 0777); err != nil {
+ t.Fatalf("error writing to file %q: %v", hostFilename, err)
+ }
+
+ // Now we should be able to test the file from within the sandbox.
+ if ws, err := c.Execute(&execArgsTestFile); err != nil {
+ t.Fatalf("unexpected error testing file %q: %v", sandboxFilename, err)
+ } else if ws.ExitStatus() != 0 {
+ t.Errorf("test %q exited with code %v, wanted zero", sandboxFilename, ws.ExitStatus())
+ }
+
+ // Rename the file from outside of the sandbox.
+ newHostFilename := filepath.Join(hostTmpDir, "newfile")
+ newSandboxFilename := filepath.Join(sandboxTmpDir, "newfile")
+ if err := os.Rename(hostFilename, newHostFilename); err != nil {
+ t.Fatalf("os.Rename(%q, %q) failed: %v", hostFilename, newHostFilename, err)
+ }
+
+ // File should no longer exist at the old path within the sandbox.
+ if ws, err := c.Execute(&execArgsTestFile); err != nil {
+ t.Fatalf("unexpected error testing file %q: %v", sandboxFilename, err)
+ } else if ws.ExitStatus() == 0 {
+ t.Errorf("test %q exited with code %v, wanted not zero", sandboxFilename, ws.ExitStatus())
+ }
+
+ // We should be able to test the new filename from within the sandbox.
+ execArgsTestNewFile := control.ExecArgs{
+ Filename: "/usr/bin/test",
+ Argv: []string{"test", "-f", newSandboxFilename},
+ }
+ if ws, err := c.Execute(&execArgsTestNewFile); err != nil {
+ t.Fatalf("unexpected error testing file %q: %v", newSandboxFilename, err)
+ } else if ws.ExitStatus() != 0 {
+ t.Errorf("test %q exited with code %v, wanted zero", newSandboxFilename, ws.ExitStatus())
+ }
+
+ // Delete the renamed file from outside of the sandbox.
+ if err := os.Remove(newHostFilename); err != nil {
+ t.Fatalf("error removing file %q: %v", hostFilename, err)
+ }
+
+ // Renamed file should no longer exist at the old path within the sandbox.
+ if ws, err := c.Execute(&execArgsTestNewFile); err != nil {
+ t.Fatalf("unexpected error testing file %q: %v", newSandboxFilename, err)
+ } else if ws.ExitStatus() == 0 {
+ t.Errorf("test %q exited with code %v, wanted not zero", newSandboxFilename, ws.ExitStatus())
+ }
+
+ // Now create the file from WITHIN the sandbox.
+ execArgsTouch := control.ExecArgs{
+ Filename: "/usr/bin/touch",
+ Argv: []string{"touch", sandboxFilename},
+ KUID: auth.KUID(os.Getuid()),
+ KGID: auth.KGID(os.Getgid()),
+ }
+ if ws, err := c.Execute(&execArgsTouch); err != nil {
+ t.Fatalf("unexpected error touching file %q: %v", sandboxFilename, err)
+ } else if ws.ExitStatus() != 0 {
+ t.Errorf("touch %q exited with code %v, wanted zero", sandboxFilename, ws.ExitStatus())
+ }
+
+ // File should exist outside the sandbox.
+ if _, err := os.Stat(hostFilename); err != nil {
+ t.Errorf("stat %q got error %v, wanted nil", hostFilename, err)
+ }
+
+ // File should exist outside the sandbox.
+ if _, err := os.Stat(hostFilename); err != nil {
+ t.Errorf("stat %q got error %v, wanted nil", hostFilename, err)
+ }
+
+ // Delete the file from within the sandbox.
+ execArgsRemove := control.ExecArgs{
+ Filename: "/bin/rm",
+ Argv: []string{"rm", sandboxFilename},
+ }
+ if ws, err := c.Execute(&execArgsRemove); err != nil {
+ t.Fatalf("unexpected error removing file %q: %v", sandboxFilename, err)
+ } else if ws.ExitStatus() != 0 {
+ t.Errorf("remove %q exited with code %v, wanted zero", sandboxFilename, ws.ExitStatus())
+ }
+
+ // File should not exist outside the sandbox.
+ if _, err := os.Stat(hostFilename); !os.IsNotExist(err) {
+ t.Errorf("stat %q got error %v, wanted ErrNotExist", hostFilename, err)
+ }
+}