| ... | ... |
@@ -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 |
} |