Skip to content
This repository was archived by the owner on Dec 13, 2018. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions integration/execin_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
65 changes: 54 additions & 11 deletions integration/init_test.go
Original file line number Diff line number Diff line change
@@ -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()

// 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)
}
}

func findUserArgs() []string {
for i, a := range os.Args {
if a == "--" {
return os.Args[i+1:]
}
}
return []string{}
}

if err := namespaces.Init(container, rootfs, "", os.NewFile(3, "pipe"), os.Args[3:]); err != nil {
log.Fatalf("unable to initialize for container: %s", err)
// 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
}
os.Exit(1)
return config, nil
}