Browse code

Make native driver use Exec func with different CreateCommand Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)

Michael Crosby authored on 2014/05/01 10:49:24
Showing 5 changed files
... ...
@@ -90,9 +90,6 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
90 90
 	d.activeContainers[c.ID] = &c.Cmd
91 91
 
92 92
 	var (
93
-		master  *os.File
94
-		console string
95
-
96 93
 		dataPath = filepath.Join(d.root, c.ID)
97 94
 		args     = append([]string{c.Entrypoint}, c.Arguments...)
98 95
 	)
... ...
@@ -105,72 +102,36 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
105 105
 		return -1, err
106 106
 	}
107 107
 
108
-	// create a pipe so that we can syncronize with the namespaced process and
109
-	// pass the veth name to the child
110
-	syncPipe, err := nsinit.NewSyncPipe()
111
-	if err != nil {
112
-		return -1, err
113
-	}
114 108
 	term := getTerminal(c, pipes)
115 109
 
116
-	if container.Tty {
117
-		master, console, err = system.CreateMasterAndConsole()
118
-		if err != nil {
119
-			return -1, err
120
-		}
121
-		term.SetMaster(master)
122
-	}
123
-
124
-	setupCommand(d, c, container, console, syncPipe.Child(), args)
125
-	if err := term.Attach(&c.Cmd); err != nil {
126
-		return -1, err
127
-	}
128
-	defer term.Close()
129
-
130
-	if err := c.Start(); err != nil {
131
-		return -1, err
132
-	}
133
-
134
-	started, err := system.GetProcessStartTime(c.Process.Pid)
135
-	if err != nil {
136
-		return -1, err
137
-	}
138
-	if err := nsinit.WritePid(dataPath, c.Process.Pid, started); err != nil {
139
-		c.Process.Kill()
140
-		return -1, err
141
-	}
142
-	defer nsinit.DeletePid(dataPath)
143
-
144
-	// Do this before syncing with child so that no children
145
-	// can escape the cgroup
146
-	cleaner, err := nsinit.SetupCgroups(container, c.Process.Pid)
147
-	if err != nil {
148
-		c.Process.Kill()
149
-		return -1, err
150
-	}
151
-	if cleaner != nil {
152
-		defer cleaner.Cleanup()
153
-	}
154
-
155
-	if err := nsinit.InitializeNetworking(container, c.Process.Pid, syncPipe); err != nil {
156
-		c.Process.Kill()
157
-		return -1, err
158
-	}
159
-
160
-	// Sync with child
161
-	syncPipe.Close()
162
-
163
-	if startCallback != nil {
164
-		startCallback(c)
165
-	}
166
-
167
-	if err := c.Wait(); err != nil {
168
-		if _, ok := err.(*exec.ExitError); !ok {
169
-			return -1, err
110
+	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 {
111
+		// we need to join the rootfs because nsinit will setup the rootfs and chroot
112
+		initPath := filepath.Join(c.Rootfs, c.InitPath)
113
+
114
+		c.Path = d.initPath
115
+		c.Args = append([]string{
116
+			initPath,
117
+			"-driver", DriverName,
118
+			"-console", console,
119
+			"-pipe", "3",
120
+			"-root", filepath.Join(d.root, c.ID),
121
+			"--",
122
+		}, args...)
123
+
124
+		// set this to nil so that when we set the clone flags anything else is reset
125
+		c.SysProcAttr = nil
126
+		system.SetCloneFlags(&c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces)))
127
+		c.ExtraFiles = []*os.File{child}
128
+
129
+		c.Env = container.Env
130
+		c.Dir = c.Rootfs
131
+
132
+		return &c.Cmd
133
+	}, func() {
134
+		if startCallback != nil {
135
+			startCallback(c)
170 136
 		}
171
-	}
172
-	return c.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
173
-
137
+	})
174 138
 }
175 139
 
176 140
 func (d *driver) Kill(p *execdriver.Command, sig int) error {
... ...
@@ -297,26 +258,3 @@ func getTerminal(c *execdriver.Command, pipes *execdriver.Pipes) nsinit.Terminal
297 297
 	c.Terminal = term
298 298
 	return term
299 299
 }
300
-
301
-func setupCommand(d *driver, c *execdriver.Command, container *libcontainer.Container, console string, syncFile *os.File, args []string) {
302
-	// we need to join the rootfs because nsinit will setup the rootfs and chroot
303
-	initPath := filepath.Join(c.Rootfs, c.InitPath)
304
-
305
-	c.Path = d.initPath
306
-	c.Args = append([]string{
307
-		initPath,
308
-		"-driver", DriverName,
309
-		"-console", console,
310
-		"-pipe", "3",
311
-		"-root", filepath.Join(d.root, c.ID),
312
-		"--",
313
-	}, args...)
314
-
315
-	// set this to nil so that when we set the clone flags anything else is reset
316
-	c.SysProcAttr = nil
317
-	system.SetCloneFlags(&c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces)))
318
-	c.ExtraFiles = []*os.File{syncFile}
319
-
320
-	c.Env = container.Env
321
-	c.Dir = c.Rootfs
322
-}
323 300
new file mode 100644
... ...
@@ -0,0 +1,10 @@
0
+package nsinit
1
+
2
+import (
3
+	"os"
4
+	"os/exec"
5
+
6
+	"github.com/dotcloud/docker/pkg/libcontainer"
7
+)
8
+
9
+type CreateCommand func(container *libcontainer.Container, console, rootfs, dataPath, init string, childPipe *os.File, args []string) *exec.Cmd
... ...
@@ -17,7 +17,7 @@ import (
17 17
 
18 18
 // Exec performes setup outside of a namespace so that a container can be
19 19
 // executed.  Exec is a high level function for working with container namespaces.
20
-func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath string, args []string, startCallback func()) (int, error) {
20
+func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) {
21 21
 	var (
22 22
 		master  *os.File
23 23
 		console string
... ...
@@ -39,7 +39,7 @@ func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath str
39 39
 		term.SetMaster(master)
40 40
 	}
41 41
 
42
-	command := CreateCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.child, args)
42
+	command := createCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.child, args)
43 43
 	if err := term.Attach(command); err != nil {
44 44
 		return -1, err
45 45
 	}
... ...
@@ -90,7 +90,7 @@ func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath str
90 90
 	return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
91 91
 }
92 92
 
93
-// CreateCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
93
+// DefaultCreateCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
94 94
 // defined on the container's configuration and use the current binary as the init with the
95 95
 // args provided
96 96
 //
... ...
@@ -99,7 +99,7 @@ func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath str
99 99
 // root: the path to the container json file and information
100 100
 // pipe: sync pipe to syncronize the parent and child processes
101 101
 // args: the arguemnts to pass to the container to run as the user's program
102
-func CreateCommand(container *libcontainer.Container, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
102
+func DefaultCreateCommand(container *libcontainer.Container, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
103 103
 	// get our binary name from arg0 so we can always reexec ourself
104 104
 	env := []string{
105 105
 		"console=" + console,
... ...
@@ -39,7 +39,7 @@ func main() {
39 39
 			exitCode, err = nsinit.ExecIn(container, nspid, os.Args[2:])
40 40
 		} else {
41 41
 			term := nsinit.NewTerminal(os.Stdin, os.Stdout, os.Stderr, container.Tty)
42
-			exitCode, err = nsinit.Exec(container, term, "", dataPath, os.Args[2:], nil)
42
+			exitCode, err = nsinit.Exec(container, term, "", dataPath, os.Args[2:], nsinit.DefaultCreateCommand, nil)
43 43
 		}
44 44
 
45 45
 		if err != nil {
... ...
@@ -7,6 +7,10 @@ import (
7 7
 	"github.com/dotcloud/docker/pkg/libcontainer"
8 8
 )
9 9
 
10
+func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) {
11
+	return -1, libcontainer.ErrUnsupported
12
+}
13
+
10 14
 func Init(container *libcontainer.Container, uncleanRootfs, consolePath string, syncPipe *SyncPipe, args []string) error {
11 15
 	return libcontainer.ErrUnsupported
12 16
 }