summaryrefslogtreecommitdiffhomepage
path: root/runsc/container
diff options
context:
space:
mode:
authorKevin Krakauer <krakauer@google.com>2018-09-12 15:22:24 -0700
committerShentubot <shentubot@google.com>2018-09-12 15:23:35 -0700
commit2eff1fdd061be9cfabc36532dda8cbefeb02e534 (patch)
tree009e2a9cbca191a2d2a471b30380888cd50c0b4a /runsc/container
parent0efde2bfbde2fea78134a32f5fb34332ec0ce531 (diff)
runsc: Add exec flag that specifies where to save the sandbox-internal pid.
This is different from the existing -pid-file flag, which saves a host pid. PiperOrigin-RevId: 212713968 Change-Id: I2c486de8dd5cfd9b923fb0970165ef7c5fc597f0
Diffstat (limited to 'runsc/container')
-rw-r--r--runsc/container/container.go9
-rw-r--r--runsc/container/container_test.go84
2 files changed, 56 insertions, 37 deletions
diff --git a/runsc/container/container.go b/runsc/container/container.go
index 9a05a1dc5..38848d02f 100644
--- a/runsc/container/container.go
+++ b/runsc/container/container.go
@@ -353,13 +353,14 @@ func Run(id string, spec *specs.Spec, conf *boot.Config, bundleDir, consoleSocke
return c.Wait()
}
-// Execute runs the specified command in the container.
-func (c *Container) Execute(e *control.ExecArgs) (syscall.WaitStatus, error) {
- log.Debugf("Execute in container %q, args: %+v", c.ID, e)
+// Execute runs the specified command in the container. It returns the pid of
+// the newly created process.
+func (c *Container) Execute(args *control.ExecArgs) (int32, error) {
+ log.Debugf("Execute in container %q, args: %+v", c.ID, args)
if c.Status != Created && c.Status != Running {
return 0, fmt.Errorf("cannot exec in container in state %s", c.Status)
}
- return c.Sandbox.Execute(c.ID, e)
+ return c.Sandbox.Execute(c.ID, args)
}
// Event returns events for the container.
diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go
index c45eb79a3..790334249 100644
--- a/runsc/container/container_test.go
+++ b/runsc/container/container_test.go
@@ -49,11 +49,11 @@ func init() {
}
// waitForProcessList waits for the given process list to show up in the container.
-func waitForProcessList(s *Container, expected []*control.Process) error {
+func waitForProcessList(cont *Container, expected []*control.Process) error {
var got []*control.Process
for start := time.Now(); time.Now().Sub(start) < 10*time.Second; {
var err error
- got, err = s.Processes()
+ got, err = cont.Processes()
if err != nil {
return fmt.Errorf("error getting process data from container: %v", err)
}
@@ -485,12 +485,12 @@ func TestExec(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create and start the container.
- s, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ cont, err := 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 {
+ defer cont.Destroy()
+ if err := cont.Start(conf); err != nil {
t.Fatalf("error starting container: %v", err)
}
@@ -513,11 +513,11 @@ func TestExec(t *testing.T) {
}
// Verify that "sleep 100" is running.
- if err := waitForProcessList(s, expectedPL[:1]); err != nil {
+ if err := waitForProcessList(cont, expectedPL[:1]); err != nil {
t.Error(err)
}
- execArgs := control.ExecArgs{
+ args := &control.ExecArgs{
Filename: "/bin/sleep",
Argv: []string{"sleep", "5"},
WorkingDirectory: "/",
@@ -528,17 +528,19 @@ func TestExec(t *testing.T) {
// First, start running exec (whick blocks).
status := make(chan error, 1)
go func() {
- exitStatus, err := s.Execute(&execArgs)
+ exitStatus, err := cont.executeSync(args)
if err != nil {
+ log.Debugf("error executing: %v", err)
status <- err
} else if exitStatus != 0 {
+ log.Debugf("bad status: %d", exitStatus)
status <- fmt.Errorf("failed with exit status: %v", exitStatus)
} else {
status <- nil
}
}()
- if err := waitForProcessList(s, expectedPL); err != nil {
+ if err := waitForProcessList(cont, expectedPL); err != nil {
t.Fatal(err)
}
@@ -548,7 +550,7 @@ func TestExec(t *testing.T) {
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)
+ t.Errorf("container failed to exec %v: %v", args, err)
}
}
}
@@ -884,15 +886,18 @@ func TestPauseResume(t *testing.T) {
}
script := fmt.Sprintf("while [[ -f %q ]]; do sleep 0.1; done", lock.Name())
- execArgs := control.ExecArgs{
+ args := &control.ExecArgs{
Filename: "/bin/bash",
Argv: []string{"bash", "-c", script},
WorkingDirectory: "/",
KUID: uid,
}
- // First, start running exec (which blocks).
- go cont.Execute(&execArgs)
+ // First, start running exec.
+ _, err = cont.Execute(args)
+ if err != nil {
+ t.Fatalf("error executing: %v", err)
+ }
// Verify that "sleep 5" is running.
if err := waitForProcessList(cont, expectedPL); err != nil {
@@ -1022,12 +1027,12 @@ func TestCapabilities(t *testing.T) {
defer os.RemoveAll(bundleDir)
// Create and start the container.
- s, err := Create(testutil.UniqueContainerID(), spec, conf, bundleDir, "", "")
+ cont, err := 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 {
+ defer cont.Destroy()
+ if err := cont.Start(conf); err != nil {
t.Fatalf("error starting container: %v", err)
}
@@ -1048,7 +1053,7 @@ func TestCapabilities(t *testing.T) {
Cmd: "exe",
},
}
- if err := waitForProcessList(s, expectedPL[:1]); err != nil {
+ if err := waitForProcessList(cont, expectedPL[:1]); err != nil {
t.Fatalf("Failed to wait for sleep to start, err: %v", err)
}
@@ -1064,7 +1069,7 @@ func TestCapabilities(t *testing.T) {
// Need to traverse the intermediate directory.
os.Chmod(rootDir, 0755)
- execArgs := control.ExecArgs{
+ args := &control.ExecArgs{
Filename: exePath,
Argv: []string{exePath},
WorkingDirectory: "/",
@@ -1074,17 +1079,17 @@ func TestCapabilities(t *testing.T) {
}
// "exe" should fail because we don't have the necessary permissions.
- if _, err := s.Execute(&execArgs); err == nil {
+ if _, err := cont.executeSync(args); 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{
+ args.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)
+ if _, err := cont.executeSync(args); err != nil {
+ t.Fatalf("container failed to exec %v: %v", args, err)
}
}
}
@@ -1404,11 +1409,11 @@ func TestContainerVolumeContentsShared(t *testing.T) {
filename := filepath.Join(dir, "file")
// File does not exist yet. Reading from the sandbox should fail.
- execArgsTestFile := control.ExecArgs{
+ argsTestFile := &control.ExecArgs{
Filename: "/usr/bin/test",
Argv: []string{"test", "-f", filename},
}
- if ws, err := c.Execute(&execArgsTestFile); err != nil {
+ if ws, err := c.executeSync(argsTestFile); err != nil {
t.Fatalf("unexpected error testing file %q: %v", filename, err)
} else if ws.ExitStatus() == 0 {
t.Errorf("test %q exited with code %v, wanted not zero", ws.ExitStatus(), err)
@@ -1420,7 +1425,7 @@ func TestContainerVolumeContentsShared(t *testing.T) {
}
// Now we should be able to test the file from within the sandbox.
- if ws, err := c.Execute(&execArgsTestFile); err != nil {
+ if ws, err := c.executeSync(argsTestFile); err != nil {
t.Fatalf("unexpected error testing file %q: %v", filename, err)
} else if ws.ExitStatus() != 0 {
t.Errorf("test %q exited with code %v, wanted zero", filename, ws.ExitStatus())
@@ -1433,18 +1438,18 @@ func TestContainerVolumeContentsShared(t *testing.T) {
}
// File should no longer exist at the old path within the sandbox.
- if ws, err := c.Execute(&execArgsTestFile); err != nil {
+ if ws, err := c.executeSync(argsTestFile); err != nil {
t.Fatalf("unexpected error testing file %q: %v", filename, err)
} else if ws.ExitStatus() == 0 {
t.Errorf("test %q exited with code %v, wanted not zero", filename, ws.ExitStatus())
}
// We should be able to test the new filename from within the sandbox.
- execArgsTestNewFile := control.ExecArgs{
+ argsTestNewFile := &control.ExecArgs{
Filename: "/usr/bin/test",
Argv: []string{"test", "-f", newFilename},
}
- if ws, err := c.Execute(&execArgsTestNewFile); err != nil {
+ if ws, err := c.executeSync(argsTestNewFile); err != nil {
t.Fatalf("unexpected error testing file %q: %v", newFilename, err)
} else if ws.ExitStatus() != 0 {
t.Errorf("test %q exited with code %v, wanted zero", newFilename, ws.ExitStatus())
@@ -1456,20 +1461,20 @@ func TestContainerVolumeContentsShared(t *testing.T) {
}
// Renamed file should no longer exist at the old path within the sandbox.
- if ws, err := c.Execute(&execArgsTestNewFile); err != nil {
+ if ws, err := c.executeSync(argsTestNewFile); err != nil {
t.Fatalf("unexpected error testing file %q: %v", newFilename, err)
} else if ws.ExitStatus() == 0 {
t.Errorf("test %q exited with code %v, wanted not zero", newFilename, ws.ExitStatus())
}
// Now create the file from WITHIN the sandbox.
- execArgsTouch := control.ExecArgs{
+ argsTouch := &control.ExecArgs{
Filename: "/usr/bin/touch",
Argv: []string{"touch", filename},
KUID: auth.KUID(os.Getuid()),
KGID: auth.KGID(os.Getgid()),
}
- if ws, err := c.Execute(&execArgsTouch); err != nil {
+ if ws, err := c.executeSync(argsTouch); err != nil {
t.Fatalf("unexpected error touching file %q: %v", filename, err)
} else if ws.ExitStatus() != 0 {
t.Errorf("touch %q exited with code %v, wanted zero", filename, ws.ExitStatus())
@@ -1486,11 +1491,11 @@ func TestContainerVolumeContentsShared(t *testing.T) {
}
// Delete the file from within the sandbox.
- execArgsRemove := control.ExecArgs{
+ argsRemove := &control.ExecArgs{
Filename: "/bin/rm",
Argv: []string{"rm", filename},
}
- if ws, err := c.Execute(&execArgsRemove); err != nil {
+ if ws, err := c.executeSync(argsRemove); err != nil {
t.Fatalf("unexpected error removing file %q: %v", filename, err)
} else if ws.ExitStatus() != 0 {
t.Errorf("remove %q exited with code %v, wanted zero", filename, ws.ExitStatus())
@@ -1547,6 +1552,19 @@ func TestGoferExits(t *testing.T) {
}
}
+// executeSync synchronously executes a new process.
+func (cont *Container) executeSync(args *control.ExecArgs) (syscall.WaitStatus, error) {
+ pid, err := cont.Execute(args)
+ if err != nil {
+ return 0, fmt.Errorf("error executing: %v", err)
+ }
+ ws, err := cont.WaitPID(pid)
+ if err != nil {
+ return 0, fmt.Errorf("error waiting: %v", err)
+ }
+ return ws, nil
+}
+
func TestMain(m *testing.M) {
testutil.RunAsRoot(m)
}