|
@@ -0,0 +1,140 @@
|
|
|
|
+package integration
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "os"
|
|
|
|
+ "os/exec"
|
|
|
|
+ "strings"
|
|
|
|
+ "sync"
|
|
|
|
+ "testing"
|
|
|
|
+
|
|
|
|
+ "github.com/docker/libcontainer"
|
|
|
|
+ "github.com/docker/libcontainer/namespaces"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+func TestExecIn(t *testing.T) {
|
|
|
|
+ if testing.Short() {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rootfs, err := newRootFs()
|
|
|
|
+ if err != nil {
|
|
|
|
+ t.Fatal(err)
|
|
|
|
+ }
|
|
|
|
+ defer remove(rootfs)
|
|
|
|
+
|
|
|
|
+ config := newTemplateConfig(rootfs)
|
|
|
|
+ if err := writeConfig(config); err != nil {
|
|
|
|
+ t.Fatalf("failed to write config %s", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ containerCmd, statePath, containerErr := startLongRunningContainer(config)
|
|
|
|
+ defer func() {
|
|
|
|
+ // kill the container
|
|
|
|
+ if containerCmd.Process != nil {
|
|
|
|
+ containerCmd.Process.Kill()
|
|
|
|
+ }
|
|
|
|
+ if err := <-containerErr; err != nil {
|
|
|
|
+ t.Fatal(err)
|
|
|
|
+ }
|
|
|
|
+ }()
|
|
|
|
+
|
|
|
|
+ // start the exec process
|
|
|
|
+ state, err := libcontainer.GetState(statePath)
|
|
|
|
+ if err != nil {
|
|
|
|
+ t.Fatalf("failed to get state %s", err)
|
|
|
|
+ }
|
|
|
|
+ buffers := newStdBuffers()
|
|
|
|
+ execErr := make(chan error, 1)
|
|
|
|
+ go func() {
|
|
|
|
+ _, err := namespaces.ExecIn(config, state, []string{"ps"},
|
|
|
|
+ os.Args[0], "exec", buffers.Stdin, buffers.Stdout, buffers.Stderr,
|
|
|
|
+ "", nil)
|
|
|
|
+ execErr <- err
|
|
|
|
+ }()
|
|
|
|
+ if err := <-execErr; err != nil {
|
|
|
|
+ t.Fatalf("exec finished with error %s", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ out := buffers.Stdout.String()
|
|
|
|
+ if !strings.Contains(out, "sleep 10") || !strings.Contains(out, "ps") {
|
|
|
|
+ t.Fatalf("unexpected running process, output %q", out)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func TestExecInRlimit(t *testing.T) {
|
|
|
|
+ if testing.Short() {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rootfs, err := newRootFs()
|
|
|
|
+ if err != nil {
|
|
|
|
+ t.Fatal(err)
|
|
|
|
+ }
|
|
|
|
+ defer remove(rootfs)
|
|
|
|
+
|
|
|
|
+ config := newTemplateConfig(rootfs)
|
|
|
|
+ if err := writeConfig(config); err != nil {
|
|
|
|
+ t.Fatalf("failed to write config %s", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ containerCmd, statePath, containerErr := startLongRunningContainer(config)
|
|
|
|
+ defer func() {
|
|
|
|
+ // kill the container
|
|
|
|
+ if containerCmd.Process != nil {
|
|
|
|
+ containerCmd.Process.Kill()
|
|
|
|
+ }
|
|
|
|
+ if err := <-containerErr; err != nil {
|
|
|
|
+ t.Fatal(err)
|
|
|
|
+ }
|
|
|
|
+ }()
|
|
|
|
+
|
|
|
|
+ // start the exec process
|
|
|
|
+ state, err := libcontainer.GetState(statePath)
|
|
|
|
+ if err != nil {
|
|
|
|
+ t.Fatalf("failed to get state %s", err)
|
|
|
|
+ }
|
|
|
|
+ buffers := newStdBuffers()
|
|
|
|
+ execErr := make(chan error, 1)
|
|
|
|
+ go func() {
|
|
|
|
+ _, err := namespaces.ExecIn(config, state, []string{"/bin/sh", "-c", "ulimit -n"},
|
|
|
|
+ os.Args[0], "exec", buffers.Stdin, buffers.Stdout, buffers.Stderr,
|
|
|
|
+ "", nil)
|
|
|
|
+ execErr <- err
|
|
|
|
+ }()
|
|
|
|
+ if err := <-execErr; err != nil {
|
|
|
|
+ t.Fatalf("exec finished with error %s", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ out := buffers.Stdout.String()
|
|
|
|
+ if limit := strings.TrimSpace(out); limit != "1024" {
|
|
|
|
+ t.Fatalf("expected rlimit to be 1024, got %s", limit)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// start a long-running container so we have time to inspect execin processes
|
|
|
|
+func startLongRunningContainer(config *libcontainer.Config) (*exec.Cmd, string, chan error) {
|
|
|
|
+ containerErr := make(chan error, 1)
|
|
|
|
+ containerCmd := &exec.Cmd{}
|
|
|
|
+ var statePath string
|
|
|
|
+
|
|
|
|
+ createCmd := func(container *libcontainer.Config, console, dataPath, init string,
|
|
|
|
+ pipe *os.File, args []string) *exec.Cmd {
|
|
|
|
+ containerCmd = namespaces.DefaultCreateCommand(container, console, dataPath, init, pipe, args)
|
|
|
|
+ statePath = dataPath
|
|
|
|
+ return containerCmd
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var containerStart sync.WaitGroup
|
|
|
|
+ containerStart.Add(1)
|
|
|
|
+ go func() {
|
|
|
|
+ buffers := newStdBuffers()
|
|
|
|
+ _, err := namespaces.Exec(config,
|
|
|
|
+ buffers.Stdin, buffers.Stdout, buffers.Stderr,
|
|
|
|
+ "", config.RootFs, []string{"sleep", "10"},
|
|
|
|
+ createCmd, containerStart.Done)
|
|
|
|
+ containerErr <- err
|
|
|
|
+ }()
|
|
|
|
+ containerStart.Wait()
|
|
|
|
+
|
|
|
|
+ return containerCmd, statePath, containerErr
|
|
|
|
+}
|