Pass the container's command via args
Remove execin function and just look for an
existing nspid file to join the namespace
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
| ... | ... |
@@ -5,17 +5,12 @@ type Container struct {
|
| 5 | 5 |
ReadonlyFs bool `json:"readonly_fs,omitempty"` |
| 6 | 6 |
User string `json:"user,omitempty"` |
| 7 | 7 |
WorkingDir string `json:"working_dir,omitempty"` |
| 8 |
- Command *Command `json:"command,omitempty"` |
|
| 8 |
+ Env []string `json:"environment,omitempty"` |
|
| 9 | 9 |
Namespaces Namespaces `json:"namespaces,omitempty"` |
| 10 | 10 |
Capabilities Capabilities `json:"capabilities,omitempty"` |
| 11 | 11 |
Network *Network `json:"network,omitempty"` |
| 12 | 12 |
} |
| 13 | 13 |
|
| 14 |
-type Command struct {
|
|
| 15 |
- Args []string `json:"args,omitempty"` |
|
| 16 |
- Env []string `json:"environment,omitempty"` |
|
| 17 |
-} |
|
| 18 |
- |
|
| 19 | 14 |
type Network struct {
|
| 20 | 15 |
IP string `json:"ip,omitempty"` |
| 21 | 16 |
Gateway string `json:"gateway,omitempty"` |
| ... | ... |
@@ -1,16 +1,11 @@ |
| 1 | 1 |
{
|
| 2 | 2 |
"hostname": "koye", |
| 3 |
- "command": {
|
|
| 4 |
- "args": [ |
|
| 5 |
- "/bin/bash" |
|
| 6 |
- ], |
|
| 7 |
- "environment": [ |
|
| 8 |
- "HOME=/", |
|
| 9 |
- "PATH=PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin", |
|
| 10 |
- "container=docker", |
|
| 11 |
- "TERM=xterm-256color" |
|
| 12 |
- ] |
|
| 13 |
- }, |
|
| 3 |
+ "environment": [ |
|
| 4 |
+ "HOME=/", |
|
| 5 |
+ "PATH=PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin", |
|
| 6 |
+ "container=docker", |
|
| 7 |
+ "TERM=xterm-256color" |
|
| 8 |
+ ], |
|
| 14 | 9 |
"namespaces": [ |
| 15 | 10 |
"NEWIPC", |
| 16 | 11 |
"NEWNS", |
| ... | ... |
@@ -16,17 +16,13 @@ import ( |
| 16 | 16 |
"syscall" |
| 17 | 17 |
) |
| 18 | 18 |
|
| 19 |
-func execCommand(container *libcontainer.Container) (int, error) {
|
|
| 19 |
+func execCommand(container *libcontainer.Container, args []string) (int, error) {
|
|
| 20 | 20 |
master, console, err := createMasterAndConsole() |
| 21 | 21 |
if err != nil {
|
| 22 | 22 |
return -1, err |
| 23 | 23 |
} |
| 24 | 24 |
|
| 25 |
- command := exec.Command("nsinit", "init", console)
|
|
| 26 |
- command.SysProcAttr = &syscall.SysProcAttr{
|
|
| 27 |
- Cloneflags: uintptr(getNamespaceFlags(container.Namespaces) | syscall.CLONE_VFORK), // we need CLONE_VFORK so we can wait on the child |
|
| 28 |
- } |
|
| 29 |
- |
|
| 25 |
+ command := createCommand(container, console, args) |
|
| 30 | 26 |
// create a pipe so that we can syncronize with the namespaced process and |
| 31 | 27 |
// pass the veth name to the child |
| 32 | 28 |
inPipe, err := command.StdinPipe() |
| ... | ... |
@@ -39,6 +35,7 @@ func execCommand(container *libcontainer.Container) (int, error) {
|
| 39 | 39 |
if err := writePidFile(command); err != nil {
|
| 40 | 40 |
return -1, err |
| 41 | 41 |
} |
| 42 |
+ defer deletePidFile() |
|
| 42 | 43 |
|
| 43 | 44 |
if container.Network != nil {
|
| 44 | 45 |
vethPair, err := setupVeth(container.Network.Bridge, command.Process.Pid) |
| ... | ... |
@@ -134,3 +131,15 @@ func createVethPair() (name1 string, name2 string, err error) {
|
| 134 | 134 |
func writePidFile(command *exec.Cmd) error {
|
| 135 | 135 |
return ioutil.WriteFile(".nspid", []byte(fmt.Sprint(command.Process.Pid)), 0655)
|
| 136 | 136 |
} |
| 137 |
+ |
|
| 138 |
+func deletePidFile() error {
|
|
| 139 |
+ return os.Remove(".nspid")
|
|
| 140 |
+} |
|
| 141 |
+ |
|
| 142 |
+func createCommand(container *libcontainer.Container, console string, args []string) *exec.Cmd {
|
|
| 143 |
+ command := exec.Command("nsinit", append([]string{"init", console}, args...)...)
|
|
| 144 |
+ command.SysProcAttr = &syscall.SysProcAttr{
|
|
| 145 |
+ Cloneflags: uintptr(getNamespaceFlags(container.Namespaces) | syscall.CLONE_VFORK), // we need CLONE_VFORK so we can wait on the child |
|
| 146 |
+ } |
|
| 147 |
+ return command |
|
| 148 |
+} |
| ... | ... |
@@ -5,19 +5,13 @@ import ( |
| 5 | 5 |
"github.com/dotcloud/docker/pkg/libcontainer" |
| 6 | 6 |
"github.com/dotcloud/docker/pkg/libcontainer/capabilities" |
| 7 | 7 |
"github.com/dotcloud/docker/pkg/system" |
| 8 |
- "io/ioutil" |
|
| 9 | 8 |
"os" |
| 10 | 9 |
"path/filepath" |
| 11 | 10 |
"strconv" |
| 12 | 11 |
"syscall" |
| 13 | 12 |
) |
| 14 | 13 |
|
| 15 |
-func execinCommand(container *libcontainer.Container) (int, error) {
|
|
| 16 |
- nspid, err := readPid() |
|
| 17 |
- if err != nil {
|
|
| 18 |
- return -1, err |
|
| 19 |
- } |
|
| 20 |
- |
|
| 14 |
+func execinCommand(container *libcontainer.Container, nspid int, args []string) (int, error) {
|
|
| 21 | 15 |
for _, ns := range container.Namespaces {
|
| 22 | 16 |
if err := system.Unshare(namespaceMap[ns]); err != nil {
|
| 23 | 17 |
return -1, err |
| ... | ... |
@@ -67,7 +61,7 @@ func execinCommand(container *libcontainer.Container) (int, error) {
|
| 67 | 67 |
if err := capabilities.DropCapabilities(container); err != nil {
|
| 68 | 68 |
return -1, fmt.Errorf("drop capabilities %s", err)
|
| 69 | 69 |
} |
| 70 |
- if err := system.Exec(container.Command.Args[0], container.Command.Args[0:], container.Command.Env); err != nil {
|
|
| 70 |
+ if err := system.Exec(args[0], args[0:], container.Env); err != nil {
|
|
| 71 | 71 |
return -1, err |
| 72 | 72 |
} |
| 73 | 73 |
} |
| ... | ... |
@@ -84,24 +78,12 @@ func execinCommand(container *libcontainer.Container) (int, error) {
|
| 84 | 84 |
if err := capabilities.DropCapabilities(container); err != nil {
|
| 85 | 85 |
return -1, fmt.Errorf("drop capabilities %s", err)
|
| 86 | 86 |
} |
| 87 |
- if err := system.Exec(container.Command.Args[0], container.Command.Args[0:], container.Command.Env); err != nil {
|
|
| 87 |
+ if err := system.Exec(args[0], args[0:], container.Env); err != nil {
|
|
| 88 | 88 |
return -1, err |
| 89 | 89 |
} |
| 90 | 90 |
panic("unreachable")
|
| 91 | 91 |
} |
| 92 | 92 |
|
| 93 |
-func readPid() (int, error) {
|
|
| 94 |
- data, err := ioutil.ReadFile(".nspid")
|
|
| 95 |
- if err != nil {
|
|
| 96 |
- return -1, err |
|
| 97 |
- } |
|
| 98 |
- pid, err := strconv.Atoi(string(data)) |
|
| 99 |
- if err != nil {
|
|
| 100 |
- return -1, err |
|
| 101 |
- } |
|
| 102 |
- return pid, nil |
|
| 103 |
-} |
|
| 104 |
- |
|
| 105 | 93 |
func getNsFds(pid int, container *libcontainer.Container) ([]uintptr, error) {
|
| 106 | 94 |
fds := make([]uintptr, len(container.Namespaces)) |
| 107 | 95 |
for i, ns := range container.Namespaces {
|
| ... | ... |
@@ -14,7 +14,7 @@ import ( |
| 14 | 14 |
"syscall" |
| 15 | 15 |
) |
| 16 | 16 |
|
| 17 |
-func initCommand(container *libcontainer.Container, console string) error {
|
|
| 17 |
+func initCommand(container *libcontainer.Container, console string, args []string) error {
|
|
| 18 | 18 |
rootfs, err := resolveRootfs() |
| 19 | 19 |
if err != nil {
|
| 20 | 20 |
return err |
| ... | ... |
@@ -72,7 +72,7 @@ func initCommand(container *libcontainer.Container, console string) error {
|
| 72 | 72 |
return fmt.Errorf("chdir to %s %s", container.WorkingDir, err)
|
| 73 | 73 |
} |
| 74 | 74 |
} |
| 75 |
- if err := system.Exec(container.Command.Args[0], container.Command.Args[0:], container.Command.Env); err != nil {
|
|
| 75 |
+ if err := system.Exec(args[0], args[0:], container.Env); err != nil {
|
|
| 76 | 76 |
return fmt.Errorf("exec %s", err)
|
| 77 | 77 |
} |
| 78 | 78 |
panic("unreachable")
|
| ... | ... |
@@ -4,8 +4,10 @@ import ( |
| 4 | 4 |
"encoding/json" |
| 5 | 5 |
"errors" |
| 6 | 6 |
"github.com/dotcloud/docker/pkg/libcontainer" |
| 7 |
+ "io/ioutil" |
|
| 7 | 8 |
"log" |
| 8 | 9 |
"os" |
| 10 |
+ "strconv" |
|
| 9 | 11 |
) |
| 10 | 12 |
|
| 11 | 13 |
var ( |
| ... | ... |
@@ -25,24 +27,29 @@ func main() {
|
| 25 | 25 |
} |
| 26 | 26 |
switch os.Args[1] {
|
| 27 | 27 |
case "exec": |
| 28 |
- exitCode, err := execCommand(container) |
|
| 28 |
+ var exitCode int |
|
| 29 |
+ nspid, err := readPid() |
|
| 30 |
+ if err != nil {
|
|
| 31 |
+ if !os.IsNotExist(err) {
|
|
| 32 |
+ log.Fatal(err) |
|
| 33 |
+ } |
|
| 34 |
+ } |
|
| 35 |
+ if nspid > 0 {
|
|
| 36 |
+ exitCode, err = execinCommand(container, nspid, os.Args[2:]) |
|
| 37 |
+ } else {
|
|
| 38 |
+ exitCode, err = execCommand(container, os.Args[2:]) |
|
| 39 |
+ } |
|
| 29 | 40 |
if err != nil {
|
| 30 | 41 |
log.Fatal(err) |
| 31 | 42 |
} |
| 32 | 43 |
os.Exit(exitCode) |
| 33 | 44 |
case "init": |
| 34 |
- if argc != 3 {
|
|
| 45 |
+ if argc < 3 {
|
|
| 35 | 46 |
log.Fatal(ErrWrongArguments) |
| 36 | 47 |
} |
| 37 |
- if err := initCommand(container, os.Args[2]); err != nil {
|
|
| 48 |
+ if err := initCommand(container, os.Args[2], os.Args[3:]); err != nil {
|
|
| 38 | 49 |
log.Fatal(err) |
| 39 | 50 |
} |
| 40 |
- case "execin": |
|
| 41 |
- exitCode, err := execinCommand(container) |
|
| 42 |
- if err != nil {
|
|
| 43 |
- log.Fatal(err) |
|
| 44 |
- } |
|
| 45 |
- os.Exit(exitCode) |
|
| 46 | 51 |
default: |
| 47 | 52 |
log.Fatalf("command not supported for nsinit %s", os.Args[1])
|
| 48 | 53 |
} |
| ... | ... |
@@ -61,3 +68,15 @@ func loadContainer() (*libcontainer.Container, error) {
|
| 61 | 61 |
} |
| 62 | 62 |
return container, nil |
| 63 | 63 |
} |
| 64 |
+ |
|
| 65 |
+func readPid() (int, error) {
|
|
| 66 |
+ data, err := ioutil.ReadFile(".nspid")
|
|
| 67 |
+ if err != nil {
|
|
| 68 |
+ return -1, err |
|
| 69 |
+ } |
|
| 70 |
+ pid, err := strconv.Atoi(string(data)) |
|
| 71 |
+ if err != nil {
|
|
| 72 |
+ return -1, err |
|
| 73 |
+ } |
|
| 74 |
+ return pid, nil |
|
| 75 |
+} |