From a3e96abb5aacaa763f3f9205316dd0aef1977f16 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 30 Apr 2014 17:02:45 -0700 Subject: [PATCH 1/8] Export syncpipe fields Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- pkg/libcontainer/nsinit/sync_pipe.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/libcontainer/nsinit/sync_pipe.go b/pkg/libcontainer/nsinit/sync_pipe.go index f724f525f0..d0bfdda865 100644 --- a/pkg/libcontainer/nsinit/sync_pipe.go +++ b/pkg/libcontainer/nsinit/sync_pipe.go @@ -3,9 +3,10 @@ package nsinit import ( "encoding/json" "fmt" - "github.com/dotcloud/docker/pkg/libcontainer" "io/ioutil" "os" + + "github.com/dotcloud/docker/pkg/libcontainer" ) // SyncPipe allows communication to and from the child processes @@ -36,6 +37,14 @@ func NewSyncPipeFromFd(parendFd, childFd uintptr) (*SyncPipe, error) { return s, nil } +func (s *SyncPipe) Child() *os.File { + return s.child +} + +func (s *SyncPipe) Parent() *os.File { + return s.parent +} + func (s *SyncPipe) SendToChild(context libcontainer.Context) error { data, err := json.Marshal(context) if err != nil { From aecb9c39ab0eb5f09ebab40001fe0ff639ef617b Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 30 Apr 2014 17:04:09 -0700 Subject: [PATCH 2/8] Split term files to make it easier to manage Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- pkg/libcontainer/nsinit/std_term.go | 49 ++++++++++++++++ pkg/libcontainer/nsinit/term.go | 89 ----------------------------- pkg/libcontainer/nsinit/tty_term.go | 55 ++++++++++++++++++ 3 files changed, 104 insertions(+), 89 deletions(-) create mode 100644 pkg/libcontainer/nsinit/std_term.go create mode 100644 pkg/libcontainer/nsinit/tty_term.go diff --git a/pkg/libcontainer/nsinit/std_term.go b/pkg/libcontainer/nsinit/std_term.go new file mode 100644 index 0000000000..2b8201a71b --- /dev/null +++ b/pkg/libcontainer/nsinit/std_term.go @@ -0,0 +1,49 @@ +package nsinit + +import ( + "io" + "os" + "os/exec" +) + +type StdTerminal struct { + stdin io.Reader + stdout, stderr io.Writer +} + +func (s *StdTerminal) SetMaster(*os.File) { + // no need to set master on non tty +} + +func (s *StdTerminal) Close() error { + return nil +} + +func (s *StdTerminal) Resize(h, w int) error { + return nil +} + +func (s *StdTerminal) Attach(command *exec.Cmd) error { + inPipe, err := command.StdinPipe() + if err != nil { + return err + } + outPipe, err := command.StdoutPipe() + if err != nil { + return err + } + errPipe, err := command.StderrPipe() + if err != nil { + return err + } + + go func() { + defer inPipe.Close() + io.Copy(inPipe, s.stdin) + }() + + go io.Copy(s.stdout, outPipe) + go io.Copy(s.stderr, errPipe) + + return nil +} diff --git a/pkg/libcontainer/nsinit/term.go b/pkg/libcontainer/nsinit/term.go index 58dccab2b8..5fc801ab53 100644 --- a/pkg/libcontainer/nsinit/term.go +++ b/pkg/libcontainer/nsinit/term.go @@ -1,7 +1,6 @@ package nsinit import ( - "github.com/dotcloud/docker/pkg/term" "io" "os" "os/exec" @@ -28,91 +27,3 @@ func NewTerminal(stdin io.Reader, stdout, stderr io.Writer, tty bool) Terminal { stderr: stderr, } } - -type TtyTerminal struct { - stdin io.Reader - stdout, stderr io.Writer - master *os.File - state *term.State -} - -func (t *TtyTerminal) Resize(h, w int) error { - return term.SetWinsize(t.master.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)}) -} - -func (t *TtyTerminal) SetMaster(master *os.File) { - t.master = master -} - -func (t *TtyTerminal) Attach(command *exec.Cmd) error { - go io.Copy(t.stdout, t.master) - go io.Copy(t.master, t.stdin) - - state, err := t.setupWindow(t.master, os.Stdin) - if err != nil { - command.Process.Kill() - return err - } - t.state = state - return err -} - -// SetupWindow gets the parent window size and sets the master -// pty to the current size and set the parents mode to RAW -func (t *TtyTerminal) setupWindow(master, parent *os.File) (*term.State, error) { - ws, err := term.GetWinsize(parent.Fd()) - if err != nil { - return nil, err - } - if err := term.SetWinsize(master.Fd(), ws); err != nil { - return nil, err - } - return term.SetRawTerminal(parent.Fd()) -} - -func (t *TtyTerminal) Close() error { - term.RestoreTerminal(os.Stdin.Fd(), t.state) - return t.master.Close() -} - -type StdTerminal struct { - stdin io.Reader - stdout, stderr io.Writer -} - -func (s *StdTerminal) SetMaster(*os.File) { - // no need to set master on non tty -} - -func (s *StdTerminal) Close() error { - return nil -} - -func (s *StdTerminal) Resize(h, w int) error { - return nil -} - -func (s *StdTerminal) Attach(command *exec.Cmd) error { - inPipe, err := command.StdinPipe() - if err != nil { - return err - } - outPipe, err := command.StdoutPipe() - if err != nil { - return err - } - errPipe, err := command.StderrPipe() - if err != nil { - return err - } - - go func() { - defer inPipe.Close() - io.Copy(inPipe, s.stdin) - }() - - go io.Copy(s.stdout, outPipe) - go io.Copy(s.stderr, errPipe) - - return nil -} diff --git a/pkg/libcontainer/nsinit/tty_term.go b/pkg/libcontainer/nsinit/tty_term.go new file mode 100644 index 0000000000..fcbd085c82 --- /dev/null +++ b/pkg/libcontainer/nsinit/tty_term.go @@ -0,0 +1,55 @@ +package nsinit + +import ( + "io" + "os" + "os/exec" + + "github.com/dotcloud/docker/pkg/term" +) + +type TtyTerminal struct { + stdin io.Reader + stdout, stderr io.Writer + master *os.File + state *term.State +} + +func (t *TtyTerminal) Resize(h, w int) error { + return term.SetWinsize(t.master.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)}) +} + +func (t *TtyTerminal) SetMaster(master *os.File) { + t.master = master +} + +func (t *TtyTerminal) Attach(command *exec.Cmd) error { + go io.Copy(t.stdout, t.master) + go io.Copy(t.master, t.stdin) + + state, err := t.setupWindow(t.master, os.Stdin) + if err != nil { + command.Process.Kill() + return err + } + t.state = state + return err +} + +// SetupWindow gets the parent window size and sets the master +// pty to the current size and set the parents mode to RAW +func (t *TtyTerminal) setupWindow(master, parent *os.File) (*term.State, error) { + ws, err := term.GetWinsize(parent.Fd()) + if err != nil { + return nil, err + } + if err := term.SetWinsize(master.Fd(), ws); err != nil { + return nil, err + } + return term.SetRawTerminal(parent.Fd()) +} + +func (t *TtyTerminal) Close() error { + term.RestoreTerminal(os.Stdin.Fd(), t.state) + return t.master.Close() +} From b6b0dfdba7bda13d630217830423580c3152899d Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 30 Apr 2014 17:18:07 -0700 Subject: [PATCH 3/8] Export more functions from libcontainer Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- pkg/libcontainer/nsinit/command.go | 16 +++------------- pkg/libcontainer/nsinit/exec.go | 11 +++++++++++ pkg/libcontainer/nsinit/execin.go | 2 +- pkg/libcontainer/nsinit/init.go | 15 +++++++-------- pkg/libcontainer/nsinit/unsupported.go | 4 ++++ 5 files changed, 26 insertions(+), 22 deletions(-) diff --git a/pkg/libcontainer/nsinit/command.go b/pkg/libcontainer/nsinit/command.go index 153a48ab59..3c7a0357c8 100644 --- a/pkg/libcontainer/nsinit/command.go +++ b/pkg/libcontainer/nsinit/command.go @@ -1,10 +1,11 @@ package nsinit import ( - "github.com/dotcloud/docker/pkg/libcontainer" - "github.com/dotcloud/docker/pkg/system" "os" "os/exec" + + "github.com/dotcloud/docker/pkg/libcontainer" + "github.com/dotcloud/docker/pkg/system" ) // CommandFactory takes the container's configuration and options passed by the @@ -34,14 +35,3 @@ func (c *DefaultCommandFactory) Create(container *libcontainer.Container, consol command.ExtraFiles = []*os.File{pipe} return command } - -// GetNamespaceFlags parses the container's Namespaces options to set the correct -// flags on clone, unshare, and setns -func GetNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) { - for _, ns := range namespaces { - if ns.Enabled { - flag |= ns.Value - } - } - return flag -} diff --git a/pkg/libcontainer/nsinit/exec.go b/pkg/libcontainer/nsinit/exec.go index 64d35e51c3..45a2a8b76a 100644 --- a/pkg/libcontainer/nsinit/exec.go +++ b/pkg/libcontainer/nsinit/exec.go @@ -142,3 +142,14 @@ func DeletePid(path string) error { } return err } + +// GetNamespaceFlags parses the container's Namespaces options to set the correct +// flags on clone, unshare, and setns +func GetNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) { + for _, ns := range namespaces { + if ns.Enabled { + flag |= ns.Value + } + } + return flag +} diff --git a/pkg/libcontainer/nsinit/execin.go b/pkg/libcontainer/nsinit/execin.go index c4ddb78ba0..8507d9bd11 100644 --- a/pkg/libcontainer/nsinit/execin.go +++ b/pkg/libcontainer/nsinit/execin.go @@ -82,7 +82,7 @@ func (ns *linuxNs) ExecIn(container *libcontainer.Container, nspid int, args []s os.Exit(state.Sys().(syscall.WaitStatus).ExitStatus()) } dropAndExec: - if err := finalizeNamespace(container); err != nil { + if err := FinalizeNamespace(container); err != nil { return -1, err } err = label.SetProcessLabel(processLabel) diff --git a/pkg/libcontainer/nsinit/init.go b/pkg/libcontainer/nsinit/init.go index 52708f4300..02785bf146 100644 --- a/pkg/libcontainer/nsinit/init.go +++ b/pkg/libcontainer/nsinit/init.go @@ -54,23 +54,22 @@ func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, consol } label.Init() + if err := mount.InitializeMountNamespace(rootfs, consolePath, container); err != nil { return fmt.Errorf("setup mount namespace %s", err) } if err := system.Sethostname(container.Hostname); err != nil { return fmt.Errorf("sethostname %s", err) } - if err := finalizeNamespace(container); err != nil { + if err := FinalizeNamespace(container); err != nil { return fmt.Errorf("finalize namespace %s", err) } - if profile := container.Context["apparmor_profile"]; profile != "" { - if err := apparmor.ApplyProfile(os.Getpid(), profile); err != nil { - return err - } - } runtime.LockOSThread() + if err := apparmor.ApplyProfile(os.Getpid(), container.Context["apparmor_profile"]); err != nil { + return err + } if err := label.SetProcessLabel(container.Context["process_label"]); err != nil { return fmt.Errorf("set process label %s", err) } @@ -113,10 +112,10 @@ func setupNetwork(container *libcontainer.Container, context libcontainer.Contex return nil } -// finalizeNamespace drops the caps, sets the correct user +// FinalizeNamespace drops the caps, sets the correct user // and working dir, and closes any leaky file descriptors // before execing the command inside the namespace -func finalizeNamespace(container *libcontainer.Container) error { +func FinalizeNamespace(container *libcontainer.Container) error { if err := capabilities.DropCapabilities(container); err != nil { return fmt.Errorf("drop capabilities %s", err) } diff --git a/pkg/libcontainer/nsinit/unsupported.go b/pkg/libcontainer/nsinit/unsupported.go index 135c0ef314..6274870bfc 100644 --- a/pkg/libcontainer/nsinit/unsupported.go +++ b/pkg/libcontainer/nsinit/unsupported.go @@ -17,3 +17,7 @@ func (ns *linuxNs) ExecIn(container *libcontainer.Container, nspid int, args []s func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, console string, syncPipe *SyncPipe, args []string) error { return libcontainer.ErrUnsupported } + +func GetNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) { + return 0 +} From 176c49d7a9e5a81b6c80e18dea84864148360597 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 30 Apr 2014 17:55:15 -0700 Subject: [PATCH 4/8] Remove command factory and NsInit interface from libcontainer Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- pkg/libcontainer/nsinit/command.go | 37 ------------- pkg/libcontainer/nsinit/exec.go | 49 ++++++++++++++--- pkg/libcontainer/nsinit/execin.go | 6 +-- pkg/libcontainer/nsinit/init.go | 20 ++++++- pkg/libcontainer/nsinit/nsinit.go | 22 -------- pkg/libcontainer/nsinit/nsinit/main.go | 74 ++++++++++---------------- pkg/libcontainer/nsinit/unsupported.go | 12 ----- 7 files changed, 94 insertions(+), 126 deletions(-) delete mode 100644 pkg/libcontainer/nsinit/command.go delete mode 100644 pkg/libcontainer/nsinit/nsinit.go diff --git a/pkg/libcontainer/nsinit/command.go b/pkg/libcontainer/nsinit/command.go deleted file mode 100644 index 3c7a0357c8..0000000000 --- a/pkg/libcontainer/nsinit/command.go +++ /dev/null @@ -1,37 +0,0 @@ -package nsinit - -import ( - "os" - "os/exec" - - "github.com/dotcloud/docker/pkg/libcontainer" - "github.com/dotcloud/docker/pkg/system" -) - -// CommandFactory takes the container's configuration and options passed by the -// parent processes and creates an *exec.Cmd that will be used to fork/exec the -// namespaced init process -type CommandFactory interface { - Create(container *libcontainer.Container, console string, syncFd *os.File, args []string) *exec.Cmd -} - -type DefaultCommandFactory struct { - Root string -} - -// Create will return an exec.Cmd with the Cloneflags set to the proper namespaces -// defined on the container's configuration and use the current binary as the init with the -// args provided -func (c *DefaultCommandFactory) Create(container *libcontainer.Container, console string, pipe *os.File, args []string) *exec.Cmd { - // get our binary name from arg0 so we can always reexec ourself - command := exec.Command(os.Args[0], append([]string{ - "-console", console, - "-pipe", "3", - "-root", c.Root, - "init"}, args...)...) - - system.SetCloneFlags(command, uintptr(GetNamespaceFlags(container.Namespaces))) - command.Env = container.Env - command.ExtraFiles = []*os.File{pipe} - return command -} diff --git a/pkg/libcontainer/nsinit/exec.go b/pkg/libcontainer/nsinit/exec.go index 45a2a8b76a..5aa98af58e 100644 --- a/pkg/libcontainer/nsinit/exec.go +++ b/pkg/libcontainer/nsinit/exec.go @@ -20,7 +20,7 @@ import ( // Exec performes setup outside of a namespace so that a container can be // executed. Exec is a high level function for working with container namespaces. -func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, pidRoot string, args []string, startCallback func()) (int, error) { +func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath string, args []string, startCallback func()) (int, error) { var ( master *os.File console string @@ -42,7 +42,7 @@ func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, pidRoo term.SetMaster(master) } - command := ns.commandFactory.Create(container, console, syncPipe.child, args) + command := CreateCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.child, args) if err := term.Attach(command); err != nil { return -1, err } @@ -56,11 +56,11 @@ func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, pidRoo if err != nil { return -1, err } - if err := WritePid(pidRoot, command.Process.Pid, started); err != nil { + if err := WritePid(dataPath, command.Process.Pid, started); err != nil { command.Process.Kill() return -1, err } - defer DeletePid(pidRoot) + defer DeletePid(dataPath) // Do this before syncing with child so that no children // can escape the cgroup @@ -90,8 +90,45 @@ func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, pidRoo return -1, err } } - status := command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() - return status, err + return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil +} + +// CreateCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces +// defined on the container's configuration and use the current binary as the init with the +// args provided +// +// console: the /dev/console to setup inside the container +// init: the progam executed inside the namespaces +// root: the path to the container json file and information +// pipe: sync pipe to syncronize the parent and child processes +// args: the arguemnts to pass to the container to run as the user's program +func CreateCommand(container *libcontainer.Container, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd { + // get our binary name from arg0 so we can always reexec ourself + env := []string{ + "console=" + console, + "pipe=3", + "data_path=" + dataPath, + } + + /* + TODO: move user and wd into env + if user != "" { + env = append(env, "user="+user) + } + if workingDir != "" { + env = append(env, "wd="+workingDir) + } + */ + + command := exec.Command(init, append([]string{"init"}, args...)...) + // make sure the process is executed inside the context of the rootfs + command.Dir = rootfs + command.Env = append(os.Environ(), env...) + + system.SetCloneFlags(command, uintptr(GetNamespaceFlags(container.Namespaces))) + command.ExtraFiles = []*os.File{pipe} + + return command } // SetupCgroups applies the cgroup restrictions to the process running in the contaienr based diff --git a/pkg/libcontainer/nsinit/execin.go b/pkg/libcontainer/nsinit/execin.go index 8507d9bd11..ac405e1a8d 100644 --- a/pkg/libcontainer/nsinit/execin.go +++ b/pkg/libcontainer/nsinit/execin.go @@ -16,7 +16,7 @@ import ( ) // ExecIn uses an existing pid and joins the pid's namespaces with the new command. -func (ns *linuxNs) ExecIn(container *libcontainer.Container, nspid int, args []string) (int, error) { +func ExecIn(container *libcontainer.Container, nspid int, args []string) (int, error) { for _, nsv := range container.Namespaces { // skip the PID namespace on unshare because it it not supported if nsv.Key != "NEWPID" { @@ -25,7 +25,7 @@ func (ns *linuxNs) ExecIn(container *libcontainer.Container, nspid int, args []s } } } - fds, err := ns.getNsFds(nspid, container) + fds, err := getNsFds(nspid, container) closeFds := func() { for _, f := range fds { system.Closefd(f) @@ -95,7 +95,7 @@ dropAndExec: panic("unreachable") } -func (ns *linuxNs) getNsFds(pid int, container *libcontainer.Container) ([]uintptr, error) { +func getNsFds(pid int, container *libcontainer.Container) ([]uintptr, error) { fds := make([]uintptr, len(container.Namespaces)) for i, ns := range container.Namespaces { f, err := os.OpenFile(filepath.Join("/proc/", strconv.Itoa(pid), "ns", ns.File), os.O_RDONLY, 0) diff --git a/pkg/libcontainer/nsinit/init.go b/pkg/libcontainer/nsinit/init.go index 02785bf146..faec12af32 100644 --- a/pkg/libcontainer/nsinit/init.go +++ b/pkg/libcontainer/nsinit/init.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "runtime" + "strings" "syscall" "github.com/dotcloud/docker/pkg/apparmor" @@ -22,12 +23,18 @@ import ( // Init is the init process that first runs inside a new namespace to setup mounts, users, networking, // and other options required for the new container. -func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error { +func Init(container *libcontainer.Container, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error { rootfs, err := utils.ResolveRootfs(uncleanRootfs) if err != nil { return err } + // clear the current processes env and replace it with the environment + // defined on the container + if err := LoadContainerEnvironment(container); err != nil { + return err + } + // We always read this as it is a way to sync with the parent as well context, err := syncPipe.ReadFromParent() if err != nil { @@ -132,3 +139,14 @@ func FinalizeNamespace(container *libcontainer.Container) error { } return nil } + +func LoadContainerEnvironment(container *libcontainer.Container) error { + os.Clearenv() + for _, pair := range container.Env { + p := strings.SplitN(pair, "=", 2) + if err := os.Setenv(p[0], p[1]); err != nil { + return err + } + } + return nil +} diff --git a/pkg/libcontainer/nsinit/nsinit.go b/pkg/libcontainer/nsinit/nsinit.go deleted file mode 100644 index 506a39eaed..0000000000 --- a/pkg/libcontainer/nsinit/nsinit.go +++ /dev/null @@ -1,22 +0,0 @@ -package nsinit - -import "github.com/dotcloud/docker/pkg/libcontainer" - -// NsInit is an interface with the public facing methods to provide high level -// exec operations on a container -type NsInit interface { - Exec(container *libcontainer.Container, term Terminal, pidRoot string, args []string, startCallback func()) (int, error) - ExecIn(container *libcontainer.Container, nspid int, args []string) (int, error) - Init(container *libcontainer.Container, uncleanRootfs, console string, syncPipe *SyncPipe, args []string) error -} - -type linuxNs struct { - root string - commandFactory CommandFactory -} - -func NewNsInit(command CommandFactory) NsInit { - return &linuxNs{ - commandFactory: command, - } -} diff --git a/pkg/libcontainer/nsinit/nsinit/main.go b/pkg/libcontainer/nsinit/nsinit/main.go index bcb0068ba9..6faa9c61cd 100644 --- a/pkg/libcontainer/nsinit/nsinit/main.go +++ b/pkg/libcontainer/nsinit/nsinit/main.go @@ -2,7 +2,6 @@ package main import ( "encoding/json" - "flag" "io/ioutil" "log" "os" @@ -14,76 +13,65 @@ import ( ) var ( - root, console, logs string - pipeFd int + dataPath = os.Getenv("data_path") + console = os.Getenv("console") + rawPipeFd = os.Getenv("pipe") ) -func registerFlags() { - flag.StringVar(&console, "console", "", "console (pty slave) path") - flag.IntVar(&pipeFd, "pipe", 0, "sync pipe fd") - flag.StringVar(&root, "root", ".", "root for storing configuration data") - flag.StringVar(&logs, "log", "none", "set stderr or a filepath to enable logging") - - flag.Parse() -} - func main() { - registerFlags() - - if flag.NArg() < 1 { - log.Fatalf("wrong number of arguments %d", flag.NArg()) + if len(os.Args) < 2 { + log.Fatalf("invalid number of arguments %d", len(os.Args)) } + container, err := loadContainer() if err != nil { - log.Fatalf("Unable to load container: %s", err) + log.Fatalf("unable to load container: %s", err) } - ns, err := newNsInit() - if err != nil { - log.Fatalf("Unable to initialize nsinit: %s", err) - } - - switch flag.Arg(0) { + switch os.Args[1] { case "exec": // this is executed outside of the namespace in the cwd - var exitCode int - nspid, err := readPid() - if err != nil { - if !os.IsNotExist(err) { - log.Fatalf("Unable to read pid: %s", err) - } + var nspid, exitCode int + if nspid, err = readPid(); err != nil && !os.IsNotExist(err) { + log.Fatalf("unable to read pid: %s", err) } + if nspid > 0 { - exitCode, err = ns.ExecIn(container, nspid, flag.Args()[1:]) + exitCode, err = nsinit.ExecIn(container, nspid, os.Args[2:]) } else { term := nsinit.NewTerminal(os.Stdin, os.Stdout, os.Stderr, container.Tty) - exitCode, err = ns.Exec(container, term, root, flag.Args()[1:], nil) + exitCode, err = nsinit.Exec(container, term, "", dataPath, os.Args[2:], nil) } + if err != nil { - log.Fatalf("Failed to exec: %s", err) + log.Fatalf("failed to exec: %s", err) } os.Exit(exitCode) case "init": // this is executed inside of the namespace to setup the container - cwd, err := os.Getwd() + // by default our current dir is always our rootfs + rootfs, err := os.Getwd() if err != nil { log.Fatal(err) } - if flag.NArg() < 2 { - log.Fatalf("wrong number of arguments %d", flag.NArg()) + + pipeFd, err := strconv.Atoi(rawPipeFd) + if err != nil { + log.Fatal(err) } syncPipe, err := nsinit.NewSyncPipeFromFd(0, uintptr(pipeFd)) if err != nil { - log.Fatalf("Unable to create sync pipe: %s", err) + log.Fatalf("unable to create sync pipe: %s", err) } - if err := ns.Init(container, cwd, console, syncPipe, flag.Args()[1:]); err != nil { - log.Fatalf("Unable to initialize for container: %s", err) + + if err := nsinit.Init(container, rootfs, console, syncPipe, os.Args[2:]); err != nil { + log.Fatalf("unable to initialize for container: %s", err) } default: - log.Fatalf("command not supported for nsinit %s", flag.Arg(0)) + log.Fatalf("command not supported for nsinit %s", os.Args[0]) } } func loadContainer() (*libcontainer.Container, error) { - f, err := os.Open(filepath.Join(root, "container.json")) + f, err := os.Open(filepath.Join(dataPath, "container.json")) if err != nil { return nil, err } @@ -97,7 +85,7 @@ func loadContainer() (*libcontainer.Container, error) { } func readPid() (int, error) { - data, err := ioutil.ReadFile(filepath.Join(root, "pid")) + data, err := ioutil.ReadFile(filepath.Join(dataPath, "pid")) if err != nil { return -1, err } @@ -107,7 +95,3 @@ func readPid() (int, error) { } return pid, nil } - -func newNsInit() (nsinit.NsInit, error) { - return nsinit.NewNsInit(&nsinit.DefaultCommandFactory{root}), nil -} diff --git a/pkg/libcontainer/nsinit/unsupported.go b/pkg/libcontainer/nsinit/unsupported.go index 6274870bfc..972d905cbb 100644 --- a/pkg/libcontainer/nsinit/unsupported.go +++ b/pkg/libcontainer/nsinit/unsupported.go @@ -6,18 +6,6 @@ import ( "github.com/dotcloud/docker/pkg/libcontainer" ) -func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, pidRoot string, args []string, startCallback func()) (int, error) { - return -1, libcontainer.ErrUnsupported -} - -func (ns *linuxNs) ExecIn(container *libcontainer.Container, nspid int, args []string) (int, error) { - return -1, libcontainer.ErrUnsupported -} - -func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, console string, syncPipe *SyncPipe, args []string) error { - return libcontainer.ErrUnsupported -} - func GetNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) { return 0 } From 60e4276f5af360dd3292e22993c0c132a86edc2e Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 30 Apr 2014 18:20:01 -0700 Subject: [PATCH 5/8] Integrate new structure into docker's native driver This duplicates some of the Exec code but I think it it worth it because the native driver is more straight forward and does not have the complexity have handling the type issues for now. Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- daemon/execdriver/native/driver.go | 140 +++++++++++++++++-------- pkg/libcontainer/nsinit/exec.go | 23 ---- pkg/libcontainer/nsinit/pid.go | 28 +++++ pkg/libcontainer/nsinit/unsupported.go | 13 +++ pkg/system/unsupported.go | 5 + 5 files changed, 143 insertions(+), 66 deletions(-) create mode 100644 pkg/libcontainer/nsinit/pid.go diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index 26c7d90474..c73eb0aec5 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -27,10 +27,7 @@ const ( func init() { execdriver.RegisterInitFunc(DriverName, func(args *execdriver.InitArgs) error { - var ( - container *libcontainer.Container - ns = nsinit.NewNsInit(&nsinit.DefaultCommandFactory{}) - ) + var container *libcontainer.Container f, err := os.Open(filepath.Join(args.Root, "container.json")) if err != nil { return err @@ -41,7 +38,7 @@ func init() { } f.Close() - cwd, err := os.Getwd() + rootfs, err := os.Getwd() if err != nil { return err } @@ -49,7 +46,7 @@ func init() { if err != nil { return err } - if err := ns.Init(container, cwd, args.Console, syncPipe, args.Args); err != nil { + if err := nsinit.Init(container, rootfs, args.Console, syncPipe, args.Args); err != nil { return err } return nil @@ -93,35 +90,87 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba d.activeContainers[c.ID] = &c.Cmd var ( - term nsinit.Terminal - factory = &dockerCommandFactory{c: c, driver: d} - pidRoot = filepath.Join(d.root, c.ID) - ns = nsinit.NewNsInit(factory) - args = append([]string{c.Entrypoint}, c.Arguments...) + master *os.File + console string + + dataPath = filepath.Join(d.root, c.ID) + args = append([]string{c.Entrypoint}, c.Arguments...) ) if err := d.createContainerRoot(c.ID); err != nil { return -1, err } defer d.removeContainerRoot(c.ID) - if c.Tty { - term = &dockerTtyTerm{ - pipes: pipes, - } - } else { - term = &dockerStdTerm{ - pipes: pipes, - } - } - c.Terminal = term if err := d.writeContainerFile(container, c.ID); err != nil { return -1, err } - return ns.Exec(container, term, pidRoot, args, func() { - if startCallback != nil { - startCallback(c) + + // create a pipe so that we can syncronize with the namespaced process and + // pass the veth name to the child + syncPipe, err := nsinit.NewSyncPipe() + if err != nil { + return -1, err + } + term := getTerminal(c, pipes) + + if container.Tty { + master, console, err = system.CreateMasterAndConsole() + if err != nil { + return -1, err } - }) + term.SetMaster(master) + } + + setupCommand(d, c, container, console, syncPipe.Child(), args) + if err := term.Attach(&c.Cmd); err != nil { + return -1, err + } + defer term.Close() + + if err := c.Start(); err != nil { + return -1, err + } + + started, err := system.GetProcessStartTime(c.Process.Pid) + if err != nil { + return -1, err + } + if err := nsinit.WritePid(dataPath, c.Process.Pid, started); err != nil { + c.Process.Kill() + return -1, err + } + defer nsinit.DeletePid(dataPath) + + // Do this before syncing with child so that no children + // can escape the cgroup + cleaner, err := nsinit.SetupCgroups(container, c.Process.Pid) + if err != nil { + c.Process.Kill() + return -1, err + } + if cleaner != nil { + defer cleaner.Cleanup() + } + + if err := nsinit.InitializeNetworking(container, c.Process.Pid, syncPipe); err != nil { + c.Process.Kill() + return -1, err + } + + // Sync with child + syncPipe.Close() + + if startCallback != nil { + startCallback(c) + } + + if err := c.Wait(); err != nil { + if _, ok := err.(*exec.ExitError); !ok { + return -1, err + } + } + return c.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil + } func (d *driver) Kill(p *execdriver.Command, sig int) error { @@ -234,35 +283,40 @@ func getEnv(key string, env []string) string { return "" } -type dockerCommandFactory struct { - c *execdriver.Command - driver *driver +func getTerminal(c *execdriver.Command, pipes *execdriver.Pipes) nsinit.Terminal { + var term nsinit.Terminal + if c.Tty { + term = &dockerTtyTerm{ + pipes: pipes, + } + } else { + term = &dockerStdTerm{ + pipes: pipes, + } + } + c.Terminal = term + return term } -// createCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces -// defined on the container's configuration and use the current binary as the init with the -// args provided -func (d *dockerCommandFactory) Create(container *libcontainer.Container, console string, syncFile *os.File, args []string) *exec.Cmd { +func setupCommand(d *driver, c *execdriver.Command, container *libcontainer.Container, console string, syncFile *os.File, args []string) { // we need to join the rootfs because nsinit will setup the rootfs and chroot - initPath := filepath.Join(d.c.Rootfs, d.c.InitPath) + initPath := filepath.Join(c.Rootfs, c.InitPath) - d.c.Path = d.driver.initPath - d.c.Args = append([]string{ + c.Path = d.initPath + c.Args = append([]string{ initPath, "-driver", DriverName, "-console", console, "-pipe", "3", - "-root", filepath.Join(d.driver.root, d.c.ID), + "-root", filepath.Join(d.root, c.ID), "--", }, args...) // set this to nil so that when we set the clone flags anything else is reset - d.c.SysProcAttr = nil - system.SetCloneFlags(&d.c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces))) - d.c.ExtraFiles = []*os.File{syncFile} + c.SysProcAttr = nil + system.SetCloneFlags(&c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces))) + c.ExtraFiles = []*os.File{syncFile} - d.c.Env = container.Env - d.c.Dir = d.c.Rootfs - - return &d.c.Cmd + c.Env = container.Env + c.Dir = c.Rootfs } diff --git a/pkg/libcontainer/nsinit/exec.go b/pkg/libcontainer/nsinit/exec.go index 5aa98af58e..078f277e80 100644 --- a/pkg/libcontainer/nsinit/exec.go +++ b/pkg/libcontainer/nsinit/exec.go @@ -3,11 +3,8 @@ package nsinit import ( - "fmt" - "io/ioutil" "os" "os/exec" - "path/filepath" "syscall" "github.com/dotcloud/docker/pkg/cgroups" @@ -160,26 +157,6 @@ func InitializeNetworking(container *libcontainer.Container, nspid int, pipe *Sy return pipe.SendToChild(context) } -// WritePid writes the namespaced processes pid to pid and it's start time -// to the path specified -func WritePid(path string, pid int, startTime string) error { - err := ioutil.WriteFile(filepath.Join(path, "pid"), []byte(fmt.Sprint(pid)), 0655) - if err != nil { - return err - } - return ioutil.WriteFile(filepath.Join(path, "start"), []byte(startTime), 0655) -} - -// DeletePid removes the pid and started file from disk when the container's process -// dies and the container is cleanly removed -func DeletePid(path string) error { - err := os.Remove(filepath.Join(path, "pid")) - if serr := os.Remove(filepath.Join(path, "start")); err == nil { - err = serr - } - return err -} - // GetNamespaceFlags parses the container's Namespaces options to set the correct // flags on clone, unshare, and setns func GetNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) { diff --git a/pkg/libcontainer/nsinit/pid.go b/pkg/libcontainer/nsinit/pid.go new file mode 100644 index 0000000000..bba2f10e1b --- /dev/null +++ b/pkg/libcontainer/nsinit/pid.go @@ -0,0 +1,28 @@ +package nsinit + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" +) + +// WritePid writes the namespaced processes pid to pid and it's start time +// to the path specified +func WritePid(path string, pid int, startTime string) error { + err := ioutil.WriteFile(filepath.Join(path, "pid"), []byte(fmt.Sprint(pid)), 0655) + if err != nil { + return err + } + return ioutil.WriteFile(filepath.Join(path, "start"), []byte(startTime), 0655) +} + +// DeletePid removes the pid and started file from disk when the container's process +// dies and the container is cleanly removed +func DeletePid(path string) error { + err := os.Remove(filepath.Join(path, "pid")) + if serr := os.Remove(filepath.Join(path, "start")); err == nil { + err = serr + } + return err +} diff --git a/pkg/libcontainer/nsinit/unsupported.go b/pkg/libcontainer/nsinit/unsupported.go index 972d905cbb..c99d881a59 100644 --- a/pkg/libcontainer/nsinit/unsupported.go +++ b/pkg/libcontainer/nsinit/unsupported.go @@ -3,9 +3,22 @@ package nsinit import ( + "github.com/dotcloud/docker/pkg/cgroups" "github.com/dotcloud/docker/pkg/libcontainer" ) +func Init(container *libcontainer.Container, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error { + return libcontainer.ErrUnsupported +} + +func InitializeNetworking(container *libcontainer.Container, nspid int, pipe *SyncPipe) error { + return libcontainer.ErrUnsupported +} + +func SetupCgroups(container *libcontainer.Container, nspid int) (cgroups.ActiveCgroup, error) { + return nil, libcontainer.ErrUnsupported +} + func GetNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) { return 0 } diff --git a/pkg/system/unsupported.go b/pkg/system/unsupported.go index 4ae2a488aa..96ebc858f5 100644 --- a/pkg/system/unsupported.go +++ b/pkg/system/unsupported.go @@ -3,6 +3,7 @@ package system import ( + "os" "os/exec" ) @@ -23,3 +24,7 @@ func GetClockTicks() int { // just return 100 return 100 } + +func CreateMasterAndConsole() (*os.File, string, error) { + return nil, "", ErrNotSupportedPlatform +} From aa9705f832d847d6e6ce76e19f3c952c194c167e Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 30 Apr 2014 18:24:47 -0700 Subject: [PATCH 6/8] Fix execin with environment and Enabled support Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- pkg/libcontainer/nsinit/execin.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/libcontainer/nsinit/execin.go b/pkg/libcontainer/nsinit/execin.go index ac405e1a8d..608437f855 100644 --- a/pkg/libcontainer/nsinit/execin.go +++ b/pkg/libcontainer/nsinit/execin.go @@ -17,9 +17,15 @@ import ( // ExecIn uses an existing pid and joins the pid's namespaces with the new command. func ExecIn(container *libcontainer.Container, nspid int, args []string) (int, error) { + // clear the current processes env and replace it with the environment + // defined on the container + if err := LoadContainerEnvironment(container); err != nil { + return -1, err + } + for _, nsv := range container.Namespaces { // skip the PID namespace on unshare because it it not supported - if nsv.Key != "NEWPID" { + if nsv.Enabled && nsv.Key != "NEWPID" { if err := system.Unshare(nsv.Value); err != nil { return -1, err } From da0d6dbd7b5b429b79ae4ea22957e8a14b4ca1ec Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 30 Apr 2014 18:49:24 -0700 Subject: [PATCH 7/8] Make native driver use Exec func with different CreateCommand Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- daemon/execdriver/native/driver.go | 116 ++++++------------------- pkg/libcontainer/nsinit/create.go | 10 +++ pkg/libcontainer/nsinit/exec.go | 8 +- pkg/libcontainer/nsinit/nsinit/main.go | 2 +- pkg/libcontainer/nsinit/unsupported.go | 4 + 5 files changed, 46 insertions(+), 94 deletions(-) create mode 100644 pkg/libcontainer/nsinit/create.go diff --git a/daemon/execdriver/native/driver.go b/daemon/execdriver/native/driver.go index c73eb0aec5..a397387f11 100644 --- a/daemon/execdriver/native/driver.go +++ b/daemon/execdriver/native/driver.go @@ -90,9 +90,6 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba d.activeContainers[c.ID] = &c.Cmd var ( - master *os.File - console string - dataPath = filepath.Join(d.root, c.ID) args = append([]string{c.Entrypoint}, c.Arguments...) ) @@ -105,72 +102,36 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba return -1, err } - // create a pipe so that we can syncronize with the namespaced process and - // pass the veth name to the child - syncPipe, err := nsinit.NewSyncPipe() - if err != nil { - return -1, err - } term := getTerminal(c, pipes) - if container.Tty { - master, console, err = system.CreateMasterAndConsole() - if err != nil { - return -1, err + return nsinit.Exec(container, term, c.Rootfs, dataPath, args, func(container *libcontainer.Container, console, rootfs, dataPath, init string, child *os.File, args []string) *exec.Cmd { + // we need to join the rootfs because nsinit will setup the rootfs and chroot + initPath := filepath.Join(c.Rootfs, c.InitPath) + + c.Path = d.initPath + c.Args = append([]string{ + initPath, + "-driver", DriverName, + "-console", console, + "-pipe", "3", + "-root", filepath.Join(d.root, c.ID), + "--", + }, args...) + + // set this to nil so that when we set the clone flags anything else is reset + c.SysProcAttr = nil + system.SetCloneFlags(&c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces))) + c.ExtraFiles = []*os.File{child} + + c.Env = container.Env + c.Dir = c.Rootfs + + return &c.Cmd + }, func() { + if startCallback != nil { + startCallback(c) } - term.SetMaster(master) - } - - setupCommand(d, c, container, console, syncPipe.Child(), args) - if err := term.Attach(&c.Cmd); err != nil { - return -1, err - } - defer term.Close() - - if err := c.Start(); err != nil { - return -1, err - } - - started, err := system.GetProcessStartTime(c.Process.Pid) - if err != nil { - return -1, err - } - if err := nsinit.WritePid(dataPath, c.Process.Pid, started); err != nil { - c.Process.Kill() - return -1, err - } - defer nsinit.DeletePid(dataPath) - - // Do this before syncing with child so that no children - // can escape the cgroup - cleaner, err := nsinit.SetupCgroups(container, c.Process.Pid) - if err != nil { - c.Process.Kill() - return -1, err - } - if cleaner != nil { - defer cleaner.Cleanup() - } - - if err := nsinit.InitializeNetworking(container, c.Process.Pid, syncPipe); err != nil { - c.Process.Kill() - return -1, err - } - - // Sync with child - syncPipe.Close() - - if startCallback != nil { - startCallback(c) - } - - if err := c.Wait(); err != nil { - if _, ok := err.(*exec.ExitError); !ok { - return -1, err - } - } - return c.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil - + }) } func (d *driver) Kill(p *execdriver.Command, sig int) error { @@ -297,26 +258,3 @@ func getTerminal(c *execdriver.Command, pipes *execdriver.Pipes) nsinit.Terminal c.Terminal = term return term } - -func setupCommand(d *driver, c *execdriver.Command, container *libcontainer.Container, console string, syncFile *os.File, args []string) { - // we need to join the rootfs because nsinit will setup the rootfs and chroot - initPath := filepath.Join(c.Rootfs, c.InitPath) - - c.Path = d.initPath - c.Args = append([]string{ - initPath, - "-driver", DriverName, - "-console", console, - "-pipe", "3", - "-root", filepath.Join(d.root, c.ID), - "--", - }, args...) - - // set this to nil so that when we set the clone flags anything else is reset - c.SysProcAttr = nil - system.SetCloneFlags(&c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces))) - c.ExtraFiles = []*os.File{syncFile} - - c.Env = container.Env - c.Dir = c.Rootfs -} diff --git a/pkg/libcontainer/nsinit/create.go b/pkg/libcontainer/nsinit/create.go new file mode 100644 index 0000000000..d5cba464d2 --- /dev/null +++ b/pkg/libcontainer/nsinit/create.go @@ -0,0 +1,10 @@ +package nsinit + +import ( + "os" + "os/exec" + + "github.com/dotcloud/docker/pkg/libcontainer" +) + +type CreateCommand func(container *libcontainer.Container, console, rootfs, dataPath, init string, childPipe *os.File, args []string) *exec.Cmd diff --git a/pkg/libcontainer/nsinit/exec.go b/pkg/libcontainer/nsinit/exec.go index 078f277e80..8886efeb32 100644 --- a/pkg/libcontainer/nsinit/exec.go +++ b/pkg/libcontainer/nsinit/exec.go @@ -17,7 +17,7 @@ import ( // Exec performes setup outside of a namespace so that a container can be // executed. Exec is a high level function for working with container namespaces. -func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath string, args []string, startCallback func()) (int, error) { +func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) { var ( master *os.File console string @@ -39,7 +39,7 @@ func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath str term.SetMaster(master) } - command := CreateCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.child, args) + command := createCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.child, args) if err := term.Attach(command); err != nil { return -1, err } @@ -90,7 +90,7 @@ func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath str return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil } -// CreateCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces +// DefaultCreateCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces // defined on the container's configuration and use the current binary as the init with the // args provided // @@ -99,7 +99,7 @@ func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath str // root: the path to the container json file and information // pipe: sync pipe to syncronize the parent and child processes // args: the arguemnts to pass to the container to run as the user's program -func CreateCommand(container *libcontainer.Container, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd { +func DefaultCreateCommand(container *libcontainer.Container, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd { // get our binary name from arg0 so we can always reexec ourself env := []string{ "console=" + console, diff --git a/pkg/libcontainer/nsinit/nsinit/main.go b/pkg/libcontainer/nsinit/nsinit/main.go index 6faa9c61cd..b5325d40b3 100644 --- a/pkg/libcontainer/nsinit/nsinit/main.go +++ b/pkg/libcontainer/nsinit/nsinit/main.go @@ -39,7 +39,7 @@ func main() { exitCode, err = nsinit.ExecIn(container, nspid, os.Args[2:]) } else { term := nsinit.NewTerminal(os.Stdin, os.Stdout, os.Stderr, container.Tty) - exitCode, err = nsinit.Exec(container, term, "", dataPath, os.Args[2:], nil) + exitCode, err = nsinit.Exec(container, term, "", dataPath, os.Args[2:], nsinit.DefaultCreateCommand, nil) } if err != nil { diff --git a/pkg/libcontainer/nsinit/unsupported.go b/pkg/libcontainer/nsinit/unsupported.go index c99d881a59..f213f2ec88 100644 --- a/pkg/libcontainer/nsinit/unsupported.go +++ b/pkg/libcontainer/nsinit/unsupported.go @@ -7,6 +7,10 @@ import ( "github.com/dotcloud/docker/pkg/libcontainer" ) +func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) { + return -1, libcontainer.ErrUnsupported +} + func Init(container *libcontainer.Container, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error { return libcontainer.ErrUnsupported } From d0bee7939482b982462c5848f24b2e5e9ad897ea Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 30 Apr 2014 18:52:15 -0700 Subject: [PATCH 8/8] Remove container.json from readme No need to duplicate this information when we already have a container.json file in the root of libcontainer Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- pkg/libcontainer/README.md | 151 +------------------------------------ 1 file changed, 1 insertion(+), 150 deletions(-) diff --git a/pkg/libcontainer/README.md b/pkg/libcontainer/README.md index 31031b26cd..8e89153bd7 100644 --- a/pkg/libcontainer/README.md +++ b/pkg/libcontainer/README.md @@ -13,160 +13,11 @@ a `container.json` file is placed with the runtime configuration for how the pro should be contained and ran. Environment, networking, and different capabilities for the process are specified in this file. The configuration is used for each process executed inside the container. -Sample `container.json` file: -```json -{ - "mounts" : [ - { - "type" : "devtmpfs" - } - ], - "tty" : true, - "environment" : [ - "HOME=/", - "PATH=PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin", - "container=docker", - "TERM=xterm-256color" - ], - "hostname" : "koye", - "cgroups" : { - "parent" : "docker", - "name" : "docker-koye" - }, - "capabilities_mask" : [ - { - "value" : 8, - "key" : "SETPCAP", - "enabled" : false - }, - { - "enabled" : false, - "value" : 16, - "key" : "SYS_MODULE" - }, - { - "value" : 17, - "key" : "SYS_RAWIO", - "enabled" : false - }, - { - "key" : "SYS_PACCT", - "value" : 20, - "enabled" : false - }, - { - "value" : 21, - "key" : "SYS_ADMIN", - "enabled" : false - }, - { - "value" : 23, - "key" : "SYS_NICE", - "enabled" : false - }, - { - "value" : 24, - "key" : "SYS_RESOURCE", - "enabled" : false - }, - { - "key" : "SYS_TIME", - "value" : 25, - "enabled" : false - }, - { - "enabled" : false, - "value" : 26, - "key" : "SYS_TTY_CONFIG" - }, - { - "key" : "AUDIT_WRITE", - "value" : 29, - "enabled" : false - }, - { - "value" : 30, - "key" : "AUDIT_CONTROL", - "enabled" : false - }, - { - "enabled" : false, - "key" : "MAC_OVERRIDE", - "value" : 32 - }, - { - "enabled" : false, - "key" : "MAC_ADMIN", - "value" : 33 - }, - { - "key" : "NET_ADMIN", - "value" : 12, - "enabled" : false - }, - { - "value" : 27, - "key" : "MKNOD", - "enabled" : true - } - ], - "networks" : [ - { - "mtu" : 1500, - "address" : "127.0.0.1/0", - "type" : "loopback", - "gateway" : "localhost" - }, - { - "mtu" : 1500, - "address" : "172.17.42.2/16", - "type" : "veth", - "context" : { - "bridge" : "docker0", - "prefix" : "veth" - }, - "gateway" : "172.17.42.1" - } - ], - "namespaces" : [ - { - "key" : "NEWNS", - "value" : 131072, - "enabled" : true, - "file" : "mnt" - }, - { - "key" : "NEWUTS", - "value" : 67108864, - "enabled" : true, - "file" : "uts" - }, - { - "enabled" : true, - "file" : "ipc", - "key" : "NEWIPC", - "value" : 134217728 - }, - { - "file" : "pid", - "enabled" : true, - "value" : 536870912, - "key" : "NEWPID" - }, - { - "enabled" : true, - "file" : "net", - "key" : "NEWNET", - "value" : 1073741824 - } - ] -} -``` +See the `container.json` file for what the configuration should look like. Using this configuration and the current directory holding the rootfs for a process, one can use libcontainer to exec the container. Running the life of the namespace, a `pid` file is written to the current directory with the pid of the namespaced process to the external world. A client can use this pid to wait, kill, or perform other operation with the container. If a user tries to run a new process inside an existing container with a live namespace, the namespace will be joined by the new process. - You may also specify an alternate root place where the `container.json` file is read and where the `pid` file will be saved. #### nsinit