Merge pull request #287 from dqminh/execin-test
add support for testing execin
This commit is contained in:
commit
0d0402712b
|
@ -0,0 +1,83 @@
|
|||
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)
|
||||
}
|
||||
|
||||
// start the container
|
||||
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()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -1,33 +1,76 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/libcontainer"
|
||||
"github.com/docker/libcontainer/namespaces"
|
||||
_ "github.com/docker/libcontainer/namespaces/nsenter"
|
||||
)
|
||||
|
||||
// init runs the libcontainer initialization code because of the busybox style needs
|
||||
// to work around the go runtime and the issues with forking
|
||||
func init() {
|
||||
if len(os.Args) < 2 || os.Args[1] != "init" {
|
||||
if len(os.Args) < 2 {
|
||||
return
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
// handle init
|
||||
if len(os.Args) >= 2 && os.Args[1] == "init" {
|
||||
runtime.LockOSThread()
|
||||
|
||||
container, err := loadConfig()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
container, err := loadConfig()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
rootfs, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if err := namespaces.Init(container, rootfs, "", os.NewFile(3, "pipe"), os.Args[3:]); err != nil {
|
||||
log.Fatalf("unable to initialize for container: %s", err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
rootfs, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// handle execin
|
||||
if len(os.Args) >= 2 && os.Args[0] == "nsenter-exec" {
|
||||
runtime.LockOSThread()
|
||||
|
||||
if err := namespaces.Init(container, rootfs, "", os.NewFile(3, "pipe"), os.Args[3:]); err != nil {
|
||||
log.Fatalf("unable to initialize for container: %s", err)
|
||||
// User args are passed after '--' in the command line.
|
||||
userArgs := findUserArgs()
|
||||
|
||||
config, err := loadConfigFromFd()
|
||||
if err != nil {
|
||||
log.Fatalf("docker-exec: unable to receive config from sync pipe: %s", err)
|
||||
}
|
||||
|
||||
if err := namespaces.FinalizeSetns(config, userArgs); err != nil {
|
||||
log.Fatalf("docker-exec: failed to exec: %s", err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func findUserArgs() []string {
|
||||
for i, a := range os.Args {
|
||||
if a == "--" {
|
||||
return os.Args[i+1:]
|
||||
}
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// loadConfigFromFd loads a container's config from the sync pipe that is provided by
|
||||
// fd 3 when running a process
|
||||
func loadConfigFromFd() (*libcontainer.Config, error) {
|
||||
var config *libcontainer.Config
|
||||
if err := json.NewDecoder(os.NewFile(3, "child")).Decode(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue