diff --git a/container.go b/container.go index c8dbdd66..763526f6 100644 --- a/container.go +++ b/container.go @@ -5,17 +5,12 @@ type Container struct { ReadonlyFs bool `json:"readonly_fs,omitempty"` User string `json:"user,omitempty"` WorkingDir string `json:"working_dir,omitempty"` - Command *Command `json:"command,omitempty"` + Env []string `json:"environment,omitempty"` Namespaces Namespaces `json:"namespaces,omitempty"` Capabilities Capabilities `json:"capabilities,omitempty"` Network *Network `json:"network,omitempty"` } -type Command struct { - Args []string `json:"args,omitempty"` - Env []string `json:"environment,omitempty"` -} - type Network struct { IP string `json:"ip,omitempty"` Gateway string `json:"gateway,omitempty"` diff --git a/container.json b/container.json index c5807a7b..ccc9abb0 100644 --- a/container.json +++ b/container.json @@ -1,16 +1,11 @@ { "hostname": "koye", - "command": { - "args": [ - "/bin/bash" - ], - "environment": [ - "HOME=/", - "PATH=PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin", - "container=docker", - "TERM=xterm-256color" - ] - }, + "environment": [ + "HOME=/", + "PATH=PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin", + "container=docker", + "TERM=xterm-256color" + ], "namespaces": [ "NEWIPC", "NEWNS", diff --git a/nsinit/exec.go b/nsinit/exec.go index 4abebd29..67f907af 100644 --- a/nsinit/exec.go +++ b/nsinit/exec.go @@ -16,17 +16,13 @@ import ( "syscall" ) -func execCommand(container *libcontainer.Container) (int, error) { +func execCommand(container *libcontainer.Container, args []string) (int, error) { master, console, err := createMasterAndConsole() if err != nil { return -1, err } - command := exec.Command("nsinit", "init", console) - command.SysProcAttr = &syscall.SysProcAttr{ - Cloneflags: uintptr(getNamespaceFlags(container.Namespaces) | syscall.CLONE_VFORK), // we need CLONE_VFORK so we can wait on the child - } - + command := createCommand(container, console, args) // create a pipe so that we can syncronize with the namespaced process and // pass the veth name to the child inPipe, err := command.StdinPipe() @@ -39,6 +35,7 @@ func execCommand(container *libcontainer.Container) (int, error) { if err := writePidFile(command); err != nil { return -1, err } + defer deletePidFile() if container.Network != nil { vethPair, err := setupVeth(container.Network.Bridge, command.Process.Pid) @@ -134,3 +131,15 @@ func createVethPair() (name1 string, name2 string, err error) { func writePidFile(command *exec.Cmd) error { return ioutil.WriteFile(".nspid", []byte(fmt.Sprint(command.Process.Pid)), 0655) } + +func deletePidFile() error { + return os.Remove(".nspid") +} + +func createCommand(container *libcontainer.Container, console string, args []string) *exec.Cmd { + command := exec.Command("nsinit", append([]string{"init", console}, args...)...) + command.SysProcAttr = &syscall.SysProcAttr{ + Cloneflags: uintptr(getNamespaceFlags(container.Namespaces) | syscall.CLONE_VFORK), // we need CLONE_VFORK so we can wait on the child + } + return command +} diff --git a/nsinit/execin.go b/nsinit/execin.go index 362cf5af..7f32620c 100644 --- a/nsinit/execin.go +++ b/nsinit/execin.go @@ -5,19 +5,13 @@ import ( "github.com/dotcloud/docker/pkg/libcontainer" "github.com/dotcloud/docker/pkg/libcontainer/capabilities" "github.com/dotcloud/docker/pkg/system" - "io/ioutil" "os" "path/filepath" "strconv" "syscall" ) -func execinCommand(container *libcontainer.Container) (int, error) { - nspid, err := readPid() - if err != nil { - return -1, err - } - +func execinCommand(container *libcontainer.Container, nspid int, args []string) (int, error) { for _, ns := range container.Namespaces { if err := system.Unshare(namespaceMap[ns]); err != nil { return -1, err @@ -67,7 +61,7 @@ func execinCommand(container *libcontainer.Container) (int, error) { if err := capabilities.DropCapabilities(container); err != nil { return -1, fmt.Errorf("drop capabilities %s", err) } - if err := system.Exec(container.Command.Args[0], container.Command.Args[0:], container.Command.Env); err != nil { + if err := system.Exec(args[0], args[0:], container.Env); err != nil { return -1, err } } @@ -84,24 +78,12 @@ func execinCommand(container *libcontainer.Container) (int, error) { if err := capabilities.DropCapabilities(container); err != nil { return -1, fmt.Errorf("drop capabilities %s", err) } - if err := system.Exec(container.Command.Args[0], container.Command.Args[0:], container.Command.Env); err != nil { + if err := system.Exec(args[0], args[0:], container.Env); err != nil { return -1, err } panic("unreachable") } -func readPid() (int, error) { - data, err := ioutil.ReadFile(".nspid") - if err != nil { - return -1, err - } - pid, err := strconv.Atoi(string(data)) - if err != nil { - return -1, err - } - return pid, nil -} - func getNsFds(pid int, container *libcontainer.Container) ([]uintptr, error) { fds := make([]uintptr, len(container.Namespaces)) for i, ns := range container.Namespaces { diff --git a/nsinit/init.go b/nsinit/init.go index d853a32d..82706fda 100644 --- a/nsinit/init.go +++ b/nsinit/init.go @@ -14,7 +14,7 @@ import ( "syscall" ) -func initCommand(container *libcontainer.Container, console string) error { +func initCommand(container *libcontainer.Container, console string, args []string) error { rootfs, err := resolveRootfs() if err != nil { return err @@ -72,7 +72,7 @@ func initCommand(container *libcontainer.Container, console string) error { return fmt.Errorf("chdir to %s %s", container.WorkingDir, err) } } - if err := system.Exec(container.Command.Args[0], container.Command.Args[0:], container.Command.Env); err != nil { + if err := system.Exec(args[0], args[0:], container.Env); err != nil { return fmt.Errorf("exec %s", err) } panic("unreachable") diff --git a/nsinit/main.go b/nsinit/main.go index 8fe700e0..30c8b064 100644 --- a/nsinit/main.go +++ b/nsinit/main.go @@ -4,8 +4,10 @@ import ( "encoding/json" "errors" "github.com/dotcloud/docker/pkg/libcontainer" + "io/ioutil" "log" "os" + "strconv" ) var ( @@ -25,24 +27,29 @@ func main() { } switch os.Args[1] { case "exec": - exitCode, err := execCommand(container) + var exitCode int + nspid, err := readPid() + if err != nil { + if !os.IsNotExist(err) { + log.Fatal(err) + } + } + if nspid > 0 { + exitCode, err = execinCommand(container, nspid, os.Args[2:]) + } else { + exitCode, err = execCommand(container, os.Args[2:]) + } if err != nil { log.Fatal(err) } os.Exit(exitCode) case "init": - if argc != 3 { + if argc < 3 { log.Fatal(ErrWrongArguments) } - if err := initCommand(container, os.Args[2]); err != nil { + if err := initCommand(container, os.Args[2], os.Args[3:]); err != nil { log.Fatal(err) } - case "execin": - exitCode, err := execinCommand(container) - if err != nil { - log.Fatal(err) - } - os.Exit(exitCode) default: log.Fatalf("command not supported for nsinit %s", os.Args[1]) } @@ -61,3 +68,15 @@ func loadContainer() (*libcontainer.Container, error) { } return container, nil } + +func readPid() (int, error) { + data, err := ioutil.ReadFile(".nspid") + if err != nil { + return -1, err + } + pid, err := strconv.Atoi(string(data)) + if err != nil { + return -1, err + } + return pid, nil +}