add support for testing execin
when the test binary starts, it detects whether it should run the container initialization code or the execin initialization code based on the suppplied arguments. The execin initialization code is taken from docker. also added a sample test for execin process. Docker-DCO-1.1-Signed-off-by: Daniel, Dao Quang Minh <dqminh89@gmail.com> (github: dqminh)
This commit is contained in:
parent
58fc93160e
commit
2f1b2ce204
|
@ -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
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/docker/libcontainer"
|
||||||
"github.com/docker/libcontainer/namespaces"
|
"github.com/docker/libcontainer/namespaces"
|
||||||
|
_ "github.com/docker/libcontainer/namespaces/nsenter"
|
||||||
)
|
)
|
||||||
|
|
||||||
// init runs the libcontainer initialization code because of the busybox style needs
|
// init runs the libcontainer initialization code because of the busybox style needs
|
||||||
// to work around the go runtime and the issues with forking
|
// to work around the go runtime and the issues with forking
|
||||||
func init() {
|
func init() {
|
||||||
if len(os.Args) < 2 || os.Args[1] != "init" {
|
if len(os.Args) < 2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
runtime.LockOSThread()
|
// handle init
|
||||||
|
if len(os.Args) >= 2 && os.Args[1] == "init" {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
|
||||||
container, err := loadConfig()
|
container, err := loadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
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()
|
// handle execin
|
||||||
if err != nil {
|
if len(os.Args) >= 2 && os.Args[0] == "nsenter-exec" {
|
||||||
log.Fatal(err)
|
runtime.LockOSThread()
|
||||||
}
|
|
||||||
|
|
||||||
if err := namespaces.Init(container, rootfs, "", os.NewFile(3, "pipe"), os.Args[3:]); err != nil {
|
// User args are passed after '--' in the command line.
|
||||||
log.Fatalf("unable to initialize for container: %s", err)
|
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