func (t *TtyConsole) attach(command *execdriver.Command, pipes *execdriver.Pipes) error { command.Stdout = t.slave command.Stderr = t.slave command.Console = t.slave.Name() go func() { if wb, ok := pipes.Stdout.(interface { CloseWriters() error }); ok { defer wb.CloseWriters() } io.Copy(pipes.Stdout, t.master) }() if pipes.Stdin != nil { command.Stdin = t.slave command.SysProcAttr.Setctty = true go func() { defer pipes.Stdin.Close() io.Copy(t.master, pipes.Stdin) }() } return nil }
func (d *driver) Run(c *execdriver.Command, startCallback execdriver.StartCallback) (int, error) { params := []string{ "chroot", c.Rootfs, "/.dockerinit", "-driver", DriverName, } params = append(params, c.Entrypoint) params = append(params, c.Arguments...) var ( name = params[0] arg = params[1:] ) aname, err := exec.LookPath(name) if err != nil { aname = name } c.Path = aname c.Args = append([]string{name}, arg...) if err := c.Start(); err != nil { return -1, err } if startCallback != nil { startCallback(c) } err = c.Wait() return c.GetExitCode(), err }
func (d *driver) Restore(c *execdriver.Command) error { var nspid int f, err := os.Open(filepath.Join(d.root, c.ID, "pid")) if err != nil { return err } defer d.removeContainerRoot(c.ID) if _, err := fmt.Fscanf(f, "%d", &nspid); err != nil { f.Close() return err } f.Close() if _, err := os.FindProcess(nspid); err != nil { return fmt.Errorf("finding existing pid %d %s", nspid, err) } c.Process = &os.Process{ Pid: nspid, } ticker := time.NewTicker(500 * time.Millisecond) defer ticker.Stop() for _ = range ticker.C { if err := syscall.Kill(nspid, 0); err != nil { if strings.Contains(err.Error(), "no such process") { return nil } return fmt.Errorf("signal error %s", err) } } return nil }
func (s *StdConsole) attach(command *execdriver.Command, pipes *execdriver.Pipes) error { command.Stdout = pipes.Stdout command.Stderr = pipes.Stderr if pipes.Stdin != nil { stdin, err := command.StdinPipe() if err != nil { return err } go func() { defer stdin.Close() io.Copy(stdin, pipes.Stdin) }() } return nil }
func SetTerminal(command *execdriver.Command, pipes *execdriver.Pipes) error { var ( term execdriver.Terminal err error ) if command.Tty { term, err = NewTtyConsole(command, pipes) } else { term, err = NewStdConsole(command, pipes) } if err != nil { return err } command.Terminal = term return nil }
func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) { if err := d.validateCommand(c); err != nil { return -1, err } var ( term nsinit.Terminal container = createContainer(c) factory = &dockerCommandFactory{c: c, driver: d} stateWriter = &dockerStateWriter{ callback: startCallback, c: c, dsw: &nsinit.DefaultStateWriter{filepath.Join(d.root, c.ID)}, } ns = nsinit.NewNsInit(factory, stateWriter) args = append([]string{c.Entrypoint}, c.Arguments...) ) if err := d.createContainerRoot(c.ID); err != nil { return -1, err } defer d.removeContainerRoot(c.ID) if c.Tty { term = &dockerTtyTerm{ pipes: pipes, } } else { term = &dockerStdTerm{ pipes: pipes, } } c.Terminal = term if err := d.writeContainerFile(container, c.ID); err != nil { return -1, err } return ns.Exec(container, term, args) }
func (d *driver) Run(c *execdriver.Command, startCallback execdriver.StartCallback) (int, error) { configPath, err := d.generateLXCConfig(c) if err != nil { return -1, err } params := []string{ "lxc-start", "-n", c.ID, "-f", configPath, "--", c.InitPath, "-driver", DriverName, } if c.Network != nil { params = append(params, "-g", c.Network.Gateway, "-i", fmt.Sprintf("%s/%d", c.Network.IPAddress, c.Network.IPPrefixLen), "-mtu", strconv.Itoa(c.Network.Mtu), ) } if c.User != "" { params = append(params, "-u", c.User) } if c.Privileged { if d.apparmor { params[0] = path.Join(d.root, "lxc-start-unconfined") } params = append(params, "-privileged") } if c.WorkingDir != "" { params = append(params, "-w", c.WorkingDir) } params = append(params, "--", c.Entrypoint) params = append(params, c.Arguments...) if d.sharedRoot { // lxc-start really needs / to be non-shared, or all kinds of stuff break // when lxc-start unmount things and those unmounts propagate to the main // mount namespace. // What we really want is to clone into a new namespace and then // mount / MS_REC|MS_SLAVE, but since we can't really clone or fork // without exec in go we have to do this horrible shell hack... shellString := "mount --make-rslave /; exec " + utils.ShellQuoteArguments(params) params = []string{ "unshare", "-m", "--", "/bin/sh", "-c", shellString, } } var ( name = params[0] arg = params[1:] ) aname, err := exec.LookPath(name) if err != nil { aname = name } c.Path = aname c.Args = append([]string{name}, arg...) if err := c.Start(); err != nil { return -1, err } var ( waitErr error waitLock = make(chan struct{}) ) go func() { if err := c.Wait(); err != nil { waitErr = err } close(waitLock) }() // Poll lxc for RUNNING status if err := d.waitForStart(c, waitLock); err != nil { return -1, err } if startCallback != nil { startCallback(c) } <-waitLock return c.GetExitCode(), waitErr }