summaryrefslogtreecommitdiffhomepage
path: root/runsc/container/multi_container_test.go
diff options
context:
space:
mode:
authorFabricio Voznika <fvoznika@google.com>2018-11-05 21:28:45 -0800
committerShentubot <shentubot@google.com>2018-11-05 21:29:37 -0800
commit86b3f0cd243918f92bd59cfc5de3204d960b5917 (patch)
treeab53efa0af9982fe79e89c847fa135c196477e36 /runsc/container/multi_container_test.go
parenta467f092616122f1f718df2a375ba66e97997594 (diff)
Fix race between start and destroy
Before this change, a container starting up could race with destroy (aka delete) and leave processes behind. Now, whenever a container is created, Loader.processes gets a new entry. Start now expects the entry to be there, and if it's not it means that the container was deleted. I've also fixed Loader.waitPID to search for the process using the init process's PID namespace. We could use a few more tests for signal and wait. I'll send them in another cl. PiperOrigin-RevId: 220224290 Change-Id: I15146079f69904dc07d43c3b66cc343a2dab4cc4
Diffstat (limited to 'runsc/container/multi_container_test.go')
-rw-r--r--runsc/container/multi_container_test.go118
1 files changed, 118 insertions, 0 deletions
diff --git a/runsc/container/multi_container_test.go b/runsc/container/multi_container_test.go
index 4548eb106..8af3d535d 100644
--- a/runsc/container/multi_container_test.go
+++ b/runsc/container/multi_container_test.go
@@ -612,3 +612,121 @@ func TestMultiContainerKillAll(t *testing.T) {
}
}
}
+
+func TestMultiContainerDestroyNotStarted(t *testing.T) {
+ specs, ids := createSpecs(
+ []string{"/bin/sleep", "100"},
+ []string{"/bin/sleep", "100"})
+ conf := testutil.TestConfig()
+
+ rootDir, err := testutil.SetupRootDir()
+ if err != nil {
+ t.Fatalf("error creating root dir: %v", err)
+ }
+ defer os.RemoveAll(rootDir)
+
+ // Create and start root container.
+ rootBundleDir, err := testutil.SetupContainerInRoot(rootDir, specs[0], conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(rootBundleDir)
+
+ root, err := Create(ids[0], specs[0], conf, rootBundleDir, "", "", "")
+ if err != nil {
+ t.Fatalf("error creating root container: %v", err)
+ }
+ defer root.Destroy()
+ if err := root.Start(conf); err != nil {
+ t.Fatalf("error starting root container: %v", err)
+ }
+
+ // Create and destroy sub-container.
+ bundleDir, err := testutil.SetupContainerInRoot(rootDir, specs[1], conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(bundleDir)
+
+ cont, err := Create(ids[1], specs[1], conf, bundleDir, "", "", "")
+ if err != nil {
+ t.Fatalf("error creating container: %v", err)
+ }
+
+ // Check that container can be destroyed.
+ if err := cont.Destroy(); err != nil {
+ t.Fatalf("deleting non-started container failed: %v", err)
+ }
+}
+
+// TestMultiContainerDestroyStarting attempts to force a race between start
+// and destroy.
+func TestMultiContainerDestroyStarting(t *testing.T) {
+ cmds := make([][]string, 10)
+ for i := range cmds {
+ cmds[i] = []string{"/bin/sleep", "100"}
+ }
+ specs, ids := createSpecs(cmds...)
+ conf := testutil.TestConfig()
+
+ rootDir, err := testutil.SetupRootDir()
+ if err != nil {
+ t.Fatalf("error creating root dir: %v", err)
+ }
+ defer os.RemoveAll(rootDir)
+
+ // Create and start root container.
+ rootBundleDir, err := testutil.SetupContainerInRoot(rootDir, specs[0], conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(rootBundleDir)
+
+ root, err := Create(ids[0], specs[0], conf, rootBundleDir, "", "", "")
+ if err != nil {
+ t.Fatalf("error creating root container: %v", err)
+ }
+ defer root.Destroy()
+ if err := root.Start(conf); err != nil {
+ t.Fatalf("error starting root container: %v", err)
+ }
+
+ wg := sync.WaitGroup{}
+ for i := range cmds {
+ if i == 0 {
+ continue // skip root container
+ }
+
+ bundleDir, err := testutil.SetupContainerInRoot(rootDir, specs[i], conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(bundleDir)
+
+ cont, err := Create(ids[i], specs[i], conf, bundleDir, "", "", "")
+ if err != nil {
+ t.Fatalf("error creating container: %v", err)
+ }
+
+ // Container is not thread safe, so load another instance to run in
+ // concurrently.
+ startCont, err := Load(rootDir, ids[i])
+ if err != nil {
+ t.Fatalf("error loading container: %v", err)
+ }
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ startCont.Start(conf) // ignore failures, start can fail if destroy runs first.
+ }()
+
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ if err := cont.Destroy(); err != nil {
+ t.Errorf("deleting non-started container failed: %v", err)
+ }
+ }()
+ }
+ wg.Wait()
+}