summaryrefslogtreecommitdiffhomepage
path: root/runsc/container
diff options
context:
space:
mode:
Diffstat (limited to 'runsc/container')
-rw-r--r--runsc/container/container.go8
-rw-r--r--runsc/container/container_test.go4
-rw-r--r--runsc/container/multi_container_test.go94
3 files changed, 96 insertions, 10 deletions
diff --git a/runsc/container/container.go b/runsc/container/container.go
index 792b7967b..a24c6cc31 100644
--- a/runsc/container/container.go
+++ b/runsc/container/container.go
@@ -398,22 +398,22 @@ func (c *Container) Wait() (syscall.WaitStatus, error) {
// WaitRootPID waits for process 'pid' in the sandbox's PID namespace and
// returns its WaitStatus.
-func (c *Container) WaitRootPID(pid int32) (syscall.WaitStatus, error) {
+func (c *Container) WaitRootPID(pid int32, clearStatus bool) (syscall.WaitStatus, error) {
log.Debugf("Wait on pid %d in sandbox %q", pid, c.Sandbox.ID)
if c.Sandbox == nil || !c.Sandbox.IsRunning() {
return 0, fmt.Errorf("container sandbox is not running")
}
- return c.Sandbox.WaitPID(pid, c.Sandbox.ID)
+ return c.Sandbox.WaitPID(c.Sandbox.ID, pid, clearStatus)
}
// WaitPID waits for process 'pid' in the container's PID namespace and returns
// its WaitStatus.
-func (c *Container) WaitPID(pid int32) (syscall.WaitStatus, error) {
+func (c *Container) WaitPID(pid int32, clearStatus bool) (syscall.WaitStatus, error) {
log.Debugf("Wait on pid %d in container %q", pid, c.ID)
if c.Sandbox == nil || !c.Sandbox.IsRunning() {
return 0, fmt.Errorf("container sandbox is not running")
}
- return c.Sandbox.WaitPID(pid, c.ID)
+ return c.Sandbox.WaitPID(c.ID, pid, clearStatus)
}
// Signal sends the signal to the container.
diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go
index ab1823f1c..5fe80f20f 100644
--- a/runsc/container/container_test.go
+++ b/runsc/container/container_test.go
@@ -551,7 +551,7 @@ func TestExec(t *testing.T) {
args := &control.ExecArgs{
Filename: "/bin/sleep",
- Argv: []string{"sleep", "5"},
+ Argv: []string{"/bin/sleep", "5"},
WorkingDirectory: "/",
KUID: uid,
}
@@ -1598,7 +1598,7 @@ func (cont *Container) executeSync(args *control.ExecArgs) (syscall.WaitStatus,
if err != nil {
return 0, fmt.Errorf("error executing: %v", err)
}
- ws, err := cont.WaitPID(pid)
+ ws, err := cont.WaitPID(pid, true /* clearStatus */)
if err != nil {
return 0, fmt.Errorf("error waiting: %v", err)
}
diff --git a/runsc/container/multi_container_test.go b/runsc/container/multi_container_test.go
index 84e0ec080..09888cb86 100644
--- a/runsc/container/multi_container_test.go
+++ b/runsc/container/multi_container_test.go
@@ -163,16 +163,15 @@ func TestMultiContainerWait(t *testing.T) {
go func(c *Container) {
defer wg.Done()
const pid = 2
- if ws, err := c.WaitPID(pid); err != nil {
+ if ws, err := c.WaitPID(pid, true /* clearStatus */); err != nil {
t.Errorf("failed to wait for PID %d: %v", pid, err)
} else if es := ws.ExitStatus(); es != 0 {
t.Errorf("PID %d exited with non-zero status %d", pid, es)
}
- if _, err := c.WaitPID(pid); err == nil {
+ if _, err := c.WaitPID(pid, true /* clearStatus */); err == nil {
t.Errorf("wait for stopped PID %d should fail", pid)
}
- // TODO: use 'container[1]' when PID namespace is supported.
- }(containers[0])
+ }(containers[1])
}
wg.Wait()
@@ -184,6 +183,93 @@ func TestMultiContainerWait(t *testing.T) {
}
}
+// TestExecWait ensures what we can wait containers and individual processes in the
+// sandbox that have already exited.
+func TestExecWait(t *testing.T) {
+ rootDir, err := testutil.SetupRootDir()
+ if err != nil {
+ t.Fatalf("error creating root dir: %v", err)
+ }
+ defer os.RemoveAll(rootDir)
+
+ // The first container should run the entire duration of the test.
+ cmd1 := []string{"sleep", "100"}
+ // We'll wait on the second container, which is much shorter lived.
+ cmd2 := []string{"sleep", "1"}
+ specs, ids := createSpecs(cmd1, cmd2)
+
+ // Setup the containers.
+ var containers []*Container
+ for i, spec := range specs {
+ conf := testutil.TestConfig()
+ bundleDir, err := testutil.SetupContainerInRoot(rootDir, spec, conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer os.RemoveAll(bundleDir)
+ cont, err := Create(ids[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)
+ }
+
+ // Check via ps that multiple processes are running.
+ expectedPL := []*control.Process{
+ {PID: 1, Cmd: "sleep"},
+ {PID: 2, Cmd: "sleep"},
+ }
+ if err := waitForProcessList(containers[0], expectedPL); err != nil {
+ t.Fatalf("failed to wait for sleep to start: %v", err)
+ }
+
+ // Wait for the second container to finish.
+ if err := waitForProcessList(containers[0], expectedPL[:1]); err != nil {
+ t.Fatalf("failed to wait for second container to stop: %v", err)
+ }
+
+ // Get the second container exit status.
+ if ws, err := containers[1].Wait(); err != nil {
+ t.Fatalf("failed to wait for process %s: %v", containers[1].Spec.Process.Args, err)
+ } else if es := ws.ExitStatus(); es != 0 {
+ t.Fatalf("process %s exited with non-zero status %d", containers[1].Spec.Process.Args, es)
+ }
+ if _, err := containers[1].Wait(); err == nil {
+ t.Fatalf("wait for stopped process %s should fail", containers[1].Spec.Process.Args)
+ }
+
+ // Execute another process in the first container.
+ args := &control.ExecArgs{
+ Filename: "/bin/sleep",
+ Argv: []string{"/bin/sleep", "1"},
+ WorkingDirectory: "/",
+ KUID: 0,
+ }
+ pid, err := containers[0].Execute(args)
+ if err != nil {
+ t.Fatalf("error executing: %v", err)
+ }
+
+ // Wait for the exec'd process to exit.
+ if err := waitForProcessList(containers[0], expectedPL[:1]); err != nil {
+ t.Fatalf("failed to wait for second container to stop: %v", err)
+ }
+
+ // Get the exit status from the exec'd process.
+ if ws, err := containers[0].WaitPID(pid, true /* clearStatus */); err != nil {
+ t.Fatalf("failed to wait for process %+v with pid %d: %v", args, pid, err)
+ } else if es := ws.ExitStatus(); es != 0 {
+ t.Fatalf("process %+v exited with non-zero status %d", args, es)
+ }
+ if _, err := containers[0].WaitPID(pid, true /* clearStatus */); err == nil {
+ t.Fatalf("wait for stopped process %+v should fail", args)
+ }
+}
+
// TestMultiContainerMount tests that bind mounts can be used with multiple
// containers.
func TestMultiContainerMount(t *testing.T) {