Browse code

Refactor to remove cmd from container

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)

Michael Crosby authored on 2014/02/20 13:35:04
Showing 6 changed files
... ...
@@ -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
+}