зеркало из https://github.com/microsoft/docker.git
Change Console to Terminal
Move creation and attach to driver Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
This commit is contained in:
Родитель
8c783c1c13
Коммит
1e74287698
27
container.go
27
container.go
|
@ -55,7 +55,6 @@ type Container struct {
|
|||
Driver string
|
||||
|
||||
command *execdriver.Command
|
||||
console execdriver.Console
|
||||
stdout *utils.WriteBroadcaster
|
||||
stderr *utils.WriteBroadcaster
|
||||
stdin io.ReadCloser
|
||||
|
@ -531,6 +530,9 @@ func (container *Container) Start() (err error) {
|
|||
}
|
||||
|
||||
populateCommand(container)
|
||||
if err := execdriver.NewTerminal(container.command); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Setup logging of stdout and stderr to disk
|
||||
if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
|
||||
|
@ -541,16 +543,6 @@ func (container *Container) Start() (err error) {
|
|||
}
|
||||
container.waitLock = make(chan struct{})
|
||||
|
||||
container.console, err = execdriver.NewConsole(
|
||||
container.stdin, container.stdout, container.stderr,
|
||||
container.Config.OpenStdin, container.Config.Tty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.console.AttachTo(container.command); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
callbackLock := make(chan struct{})
|
||||
callback := func(command *execdriver.Command) {
|
||||
container.State.SetRunning(command.Pid())
|
||||
|
@ -790,7 +782,8 @@ func (container *Container) monitor(callback execdriver.StartCallback) error {
|
|||
populateCommand(container)
|
||||
err = container.runtime.RestoreCommand(container)
|
||||
} else {
|
||||
exitCode, err = container.runtime.Run(container, callback)
|
||||
pipes := execdriver.NewPipes(container.stdin, container.stdout, container.stderr, container.Config.OpenStdin)
|
||||
exitCode, err = container.runtime.Run(container, pipes, callback)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -845,9 +838,9 @@ func (container *Container) cleanup() {
|
|||
if err := container.stderr.Close(); err != nil {
|
||||
utils.Errorf("%s: Error close stderr: %s", container.ID, err)
|
||||
}
|
||||
if container.console != nil {
|
||||
if err := container.console.Close(); err != nil {
|
||||
utils.Errorf("%s: Error closing console: %s", container.ID, err)
|
||||
if container.command.Terminal != nil {
|
||||
if err := container.command.Terminal.Close(); err != nil {
|
||||
utils.Errorf("%s: Error closing terminal: %s", container.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -939,7 +932,7 @@ func (container *Container) Wait() int {
|
|||
}
|
||||
|
||||
func (container *Container) Resize(h, w int) error {
|
||||
return container.console.Resize(h, w)
|
||||
return container.command.Terminal.Resize(h, w)
|
||||
}
|
||||
|
||||
func (container *Container) ExportRw() (archive.Archive, error) {
|
||||
|
@ -1143,7 +1136,7 @@ func (container *Container) Exposes(p nat.Port) bool {
|
|||
}
|
||||
|
||||
func (container *Container) GetPtyMaster() (*os.File, error) {
|
||||
ttyConsole, ok := container.console.(*execdriver.TtyConsole)
|
||||
ttyConsole, ok := container.command.Terminal.(*execdriver.TtyConsole)
|
||||
if !ok {
|
||||
return nil, ErrNoTTY
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ func NewDriver() (*driver, error) {
|
|||
return &driver{}, nil
|
||||
}
|
||||
|
||||
func (d *driver) Run(c *execdriver.Command, startCallback execdriver.StartCallback) (int, error) {
|
||||
func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
||||
params := []string{
|
||||
"chroot",
|
||||
c.Rootfs,
|
||||
|
|
|
@ -1,137 +0,0 @@
|
|||
package execdriver
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/pkg/term"
|
||||
"github.com/kr/pty"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Console interface {
|
||||
io.Closer
|
||||
Resize(height, width int) error
|
||||
AttachTo(command *Command) error
|
||||
}
|
||||
|
||||
type pipes struct {
|
||||
Stdin io.ReadCloser
|
||||
Stdout, Stderr io.WriteCloser
|
||||
}
|
||||
|
||||
func (p *pipes) Close() error {
|
||||
if p.Stderr != nil {
|
||||
p.Stdin.Close()
|
||||
}
|
||||
if p.Stdout != nil {
|
||||
p.Stdout.Close()
|
||||
}
|
||||
if p.Stderr != nil {
|
||||
p.Stderr.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewConsole(stdin io.ReadCloser, stdout, stderr io.WriteCloser, useStdin, tty bool) (Console, error) {
|
||||
p := &pipes{
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
}
|
||||
if useStdin {
|
||||
p.Stdin = stdin
|
||||
}
|
||||
if tty {
|
||||
return NewTtyConsole(p)
|
||||
}
|
||||
return NewStdConsole(p)
|
||||
}
|
||||
|
||||
type TtyConsole struct {
|
||||
Master *os.File
|
||||
Slave *os.File
|
||||
pipes *pipes
|
||||
}
|
||||
|
||||
func NewTtyConsole(p *pipes) (*TtyConsole, error) {
|
||||
ptyMaster, ptySlave, err := pty.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tty := &TtyConsole{
|
||||
Master: ptyMaster,
|
||||
Slave: ptySlave,
|
||||
pipes: p,
|
||||
}
|
||||
return tty, nil
|
||||
}
|
||||
|
||||
func (t *TtyConsole) Resize(h, w int) error {
|
||||
return term.SetWinsize(t.Master.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
|
||||
|
||||
}
|
||||
|
||||
func (t *TtyConsole) AttachTo(command *Command) error {
|
||||
command.Stdout = t.Slave
|
||||
command.Stderr = t.Slave
|
||||
|
||||
command.Console = t.Slave.Name()
|
||||
|
||||
go func() {
|
||||
defer t.pipes.Stdout.Close()
|
||||
io.Copy(t.pipes.Stdout, t.Master)
|
||||
}()
|
||||
|
||||
if t.pipes.Stdin != nil {
|
||||
command.Stdin = t.Slave
|
||||
command.SysProcAttr.Setctty = true
|
||||
|
||||
go func() {
|
||||
defer t.pipes.Stdin.Close()
|
||||
io.Copy(t.Master, t.pipes.Stdin)
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TtyConsole) Close() error {
|
||||
err := t.Slave.Close()
|
||||
if merr := t.Master.Close(); err == nil {
|
||||
err = merr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type StdConsole struct {
|
||||
pipes *pipes
|
||||
}
|
||||
|
||||
func NewStdConsole(p *pipes) (*StdConsole, error) {
|
||||
return &StdConsole{p}, nil
|
||||
}
|
||||
|
||||
func (s *StdConsole) AttachTo(command *Command) error {
|
||||
command.Stdout = s.pipes.Stdout
|
||||
command.Stderr = s.pipes.Stderr
|
||||
|
||||
if s.pipes.Stdin != nil {
|
||||
stdin, err := command.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer stdin.Close()
|
||||
io.Copy(stdin, s.pipes.Stdin)
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StdConsole) Resize(h, w int) error {
|
||||
// we do not need to reside a non tty
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StdConsole) Close() error {
|
||||
// nothing to close here
|
||||
return nil
|
||||
}
|
|
@ -58,7 +58,7 @@ type Info interface {
|
|||
}
|
||||
|
||||
type Driver interface {
|
||||
Run(c *Command, startCallback StartCallback) (int, error) // Run executes the process and blocks until the process exits and returns the exit code
|
||||
Run(c *Command, pipes *Pipes, startCallback StartCallback) (int, error) // Run executes the process and blocks until the process exits and returns the exit code
|
||||
Kill(c *Command, sig int) error
|
||||
Restore(c *Command) error // Wait and try to re-attach on an out of process command
|
||||
Name() string // Driver name
|
||||
|
@ -82,7 +82,6 @@ type Resources struct {
|
|||
}
|
||||
|
||||
// Process wrapps an os/exec.Cmd to add more metadata
|
||||
// TODO: Rename to Command
|
||||
type Command struct {
|
||||
exec.Cmd `json:"-"`
|
||||
|
||||
|
@ -100,7 +99,8 @@ type Command struct {
|
|||
Config []string `json:"config"` // generic values that specific drivers can consume
|
||||
Resources *Resources `json:"resources"`
|
||||
|
||||
Console string `json:"-"`
|
||||
Terminal Term `json:"-"`
|
||||
Console string `json:"-"`
|
||||
}
|
||||
|
||||
// Return the pid of the process
|
||||
|
|
|
@ -76,7 +76,12 @@ func (d *driver) Name() string {
|
|||
return fmt.Sprintf("%s-%s", DriverName, version)
|
||||
}
|
||||
|
||||
func (d *driver) Run(c *execdriver.Command, startCallback execdriver.StartCallback) (int, error) {
|
||||
func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
||||
if c.Terminal != nil {
|
||||
if err := c.Terminal.Attach(pipes); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
configPath, err := d.generateLXCConfig(c)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
package execdriver
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/pkg/term"
|
||||
"github.com/kr/pty"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Term interface {
|
||||
io.Closer
|
||||
Resize(height, width int) error
|
||||
Attach(pipes *Pipes) error
|
||||
}
|
||||
|
||||
type Pipes struct {
|
||||
Stdin io.ReadCloser
|
||||
Stdout, Stderr io.WriteCloser
|
||||
}
|
||||
|
||||
func NewPipes(stdin io.ReadCloser, stdout, stderr io.WriteCloser, useStdin bool) *Pipes {
|
||||
p := &Pipes{
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
}
|
||||
if useStdin {
|
||||
p.Stdin = stdin
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func NewTerminal(command *Command) error {
|
||||
var (
|
||||
term Term
|
||||
err error
|
||||
)
|
||||
if command.Tty {
|
||||
term, err = NewTtyConsole(command)
|
||||
} else {
|
||||
term, err = NewStdConsole(command)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
command.Terminal = term
|
||||
return nil
|
||||
}
|
||||
|
||||
type TtyConsole struct {
|
||||
command *Command
|
||||
Master *os.File
|
||||
Slave *os.File
|
||||
}
|
||||
|
||||
func NewTtyConsole(command *Command) (*TtyConsole, error) {
|
||||
ptyMaster, ptySlave, err := pty.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tty := &TtyConsole{
|
||||
Master: ptyMaster,
|
||||
Slave: ptySlave,
|
||||
command: command,
|
||||
}
|
||||
return tty, nil
|
||||
}
|
||||
|
||||
func (t *TtyConsole) Resize(h, w int) error {
|
||||
return term.SetWinsize(t.Master.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
|
||||
}
|
||||
|
||||
func (t *TtyConsole) Attach(pipes *Pipes) error {
|
||||
t.command.Stdout = t.Slave
|
||||
t.command.Stderr = t.Slave
|
||||
|
||||
t.command.Console = t.Slave.Name()
|
||||
|
||||
go func() {
|
||||
defer pipes.Stdout.Close()
|
||||
io.Copy(pipes.Stdout, t.Master)
|
||||
}()
|
||||
|
||||
if pipes.Stdin != nil {
|
||||
t.command.Stdin = t.Slave
|
||||
t.command.SysProcAttr.Setctty = true
|
||||
|
||||
go func() {
|
||||
defer pipes.Stdin.Close()
|
||||
io.Copy(t.Master, pipes.Stdin)
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TtyConsole) Close() error {
|
||||
err := t.Slave.Close()
|
||||
if merr := t.Master.Close(); err == nil {
|
||||
err = merr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type StdConsole struct {
|
||||
command *Command
|
||||
}
|
||||
|
||||
func NewStdConsole(command *Command) (*StdConsole, error) {
|
||||
return &StdConsole{command}, nil
|
||||
}
|
||||
|
||||
func (s *StdConsole) Attach(pipes *Pipes) error {
|
||||
s.command.Stdout = pipes.Stdout
|
||||
s.command.Stderr = pipes.Stderr
|
||||
|
||||
if pipes.Stdin != nil {
|
||||
stdin, err := s.command.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer stdin.Close()
|
||||
io.Copy(stdin, pipes.Stdin)
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StdConsole) Resize(h, w int) error {
|
||||
// we do not need to reside a non tty
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StdConsole) Close() error {
|
||||
// nothing to close here
|
||||
return nil
|
||||
}
|
|
@ -812,8 +812,8 @@ func (runtime *Runtime) Diff(container *Container) (archive.Archive, error) {
|
|||
}), nil
|
||||
}
|
||||
|
||||
func (runtime *Runtime) Run(c *Container, startCallback execdriver.StartCallback) (int, error) {
|
||||
return runtime.execDriver.Run(c.command, startCallback)
|
||||
func (runtime *Runtime) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
||||
return runtime.execDriver.Run(c.command, pipes, startCallback)
|
||||
}
|
||||
|
||||
func (runtime *Runtime) Kill(c *Container, sig int) error {
|
||||
|
|
Загрузка…
Ссылка в новой задаче