Move current tty and pipe impl to lxc driver

Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
This commit is contained in:
Michael Crosby 2014-02-21 13:27:15 -08:00
parent 8e2284aaa2
commit aac702727e
5 changed files with 68 additions and 47 deletions

View File

@ -1133,9 +1133,9 @@ func (container *Container) Exposes(p nat.Port) bool {
} }
func (container *Container) GetPtyMaster() (*os.File, error) { func (container *Container) GetPtyMaster() (*os.File, error) {
ttyConsole, ok := container.command.Terminal.(*execdriver.TtyConsole) ttyConsole, ok := container.command.Terminal.(execdriver.TtyTerminal)
if !ok { if !ok {
return nil, ErrNoTTY return nil, ErrNoTTY
} }
return ttyConsole.Master, nil return ttyConsole.Master(), nil
} }

View File

@ -2,6 +2,8 @@ package execdriver
import ( import (
"errors" "errors"
"io"
"os"
"os/exec" "os/exec"
) )
@ -57,6 +59,18 @@ type Info interface {
IsRunning() bool IsRunning() bool
} }
// Terminal in an interface for drivers to implement
// if they want to support Close and Resize calls from
// the core
type Terminal interface {
io.Closer
Resize(height, width int) error
}
type TtyTerminal interface {
Master() *os.File
}
type Driver interface { type Driver interface {
Run(c *Command, pipes *Pipes, 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 Kill(c *Command, sig int) error
@ -99,8 +113,8 @@ type Command struct {
Config []string `json:"config"` // generic values that specific drivers can consume Config []string `json:"config"` // generic values that specific drivers can consume
Resources *Resources `json:"resources"` Resources *Resources `json:"resources"`
Terminal Term `json:"-"` Terminal Terminal `json:"-"` // standard or tty terminal
Console string `json:"-"` Console string `json:"-"` // dev/console path
} }
// Return the pid of the process // Return the pid of the process

View File

@ -77,7 +77,7 @@ func (d *driver) Name() string {
} }
func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) { func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
if err := execdriver.SetTerminal(c, pipes); err != nil { if err := SetTerminal(c, pipes); err != nil {
return -1, err return -1, err
} }
configPath, err := d.generateLXCConfig(c) configPath, err := d.generateLXCConfig(c)

View File

@ -1,36 +1,16 @@
package execdriver package lxc
import ( import (
"github.com/dotcloud/docker/execdriver"
"github.com/dotcloud/docker/pkg/term" "github.com/dotcloud/docker/pkg/term"
"github.com/kr/pty" "github.com/kr/pty"
"io" "io"
"os" "os"
) )
type Term interface { func SetTerminal(command *execdriver.Command, pipes *execdriver.Pipes) error {
io.Closer
Resize(height, width int) error
}
type Pipes struct {
Stdin io.ReadCloser
Stdout, Stderr io.Writer
}
func NewPipes(stdin io.ReadCloser, stdout, stderr io.Writer, useStdin bool) *Pipes {
p := &Pipes{
Stdout: stdout,
Stderr: stderr,
}
if useStdin {
p.Stdin = stdin
}
return p
}
func SetTerminal(command *Command, pipes *Pipes) error {
var ( var (
term Term term execdriver.Terminal
err error err error
) )
if command.Tty { if command.Tty {
@ -46,18 +26,18 @@ func SetTerminal(command *Command, pipes *Pipes) error {
} }
type TtyConsole struct { type TtyConsole struct {
Master *os.File master *os.File
Slave *os.File slave *os.File
} }
func NewTtyConsole(command *Command, pipes *Pipes) (*TtyConsole, error) { func NewTtyConsole(command *execdriver.Command, pipes *execdriver.Pipes) (*TtyConsole, error) {
ptyMaster, ptySlave, err := pty.Open() ptyMaster, ptySlave, err := pty.Open()
if err != nil { if err != nil {
return nil, err return nil, err
} }
tty := &TtyConsole{ tty := &TtyConsole{
Master: ptyMaster, master: ptyMaster,
Slave: ptySlave, slave: ptySlave,
} }
if err := tty.attach(command, pipes); err != nil { if err := tty.attach(command, pipes); err != nil {
tty.Close() tty.Close()
@ -66,14 +46,18 @@ func NewTtyConsole(command *Command, pipes *Pipes) (*TtyConsole, error) {
return tty, nil return tty, nil
} }
func (t *TtyConsole) Resize(h, w int) error { func (t *TtyConsole) Master() *os.File {
return term.SetWinsize(t.Master.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)}) return t.master
} }
func (t *TtyConsole) attach(command *Command, pipes *Pipes) error { func (t *TtyConsole) Resize(h, w int) error {
command.Stdout = t.Slave return term.SetWinsize(t.master.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
command.Stderr = t.Slave }
command.Console = t.Slave.Name()
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() { go func() {
if wb, ok := pipes.Stdout.(interface { if wb, ok := pipes.Stdout.(interface {
@ -81,30 +65,30 @@ func (t *TtyConsole) attach(command *Command, pipes *Pipes) error {
}); ok { }); ok {
defer wb.CloseWriters() defer wb.CloseWriters()
} }
io.Copy(pipes.Stdout, t.Master) io.Copy(pipes.Stdout, t.master)
}() }()
if pipes.Stdin != nil { if pipes.Stdin != nil {
command.Stdin = t.Slave command.Stdin = t.slave
command.SysProcAttr.Setctty = true command.SysProcAttr.Setctty = true
go func() { go func() {
defer pipes.Stdin.Close() defer pipes.Stdin.Close()
io.Copy(t.Master, pipes.Stdin) io.Copy(t.master, pipes.Stdin)
}() }()
} }
return nil return nil
} }
func (t *TtyConsole) Close() error { func (t *TtyConsole) Close() error {
t.Slave.Close() t.slave.Close()
return t.Master.Close() return t.master.Close()
} }
type StdConsole struct { type StdConsole struct {
} }
func NewStdConsole(command *Command, pipes *Pipes) (*StdConsole, error) { func NewStdConsole(command *execdriver.Command, pipes *execdriver.Pipes) (*StdConsole, error) {
std := &StdConsole{} std := &StdConsole{}
if err := std.attach(command, pipes); err != nil { if err := std.attach(command, pipes); err != nil {
@ -113,7 +97,7 @@ func NewStdConsole(command *Command, pipes *Pipes) (*StdConsole, error) {
return std, nil return std, nil
} }
func (s *StdConsole) attach(command *Command, pipes *Pipes) error { func (s *StdConsole) attach(command *execdriver.Command, pipes *execdriver.Pipes) error {
command.Stdout = pipes.Stdout command.Stdout = pipes.Stdout
command.Stderr = pipes.Stderr command.Stderr = pipes.Stderr

23
execdriver/pipes.go Normal file
View File

@ -0,0 +1,23 @@
package execdriver
import (
"io"
)
// Pipes is a wrapper around a containers output for
// stdin, stdout, stderr
type Pipes struct {
Stdin io.ReadCloser
Stdout, Stderr io.Writer
}
func NewPipes(stdin io.ReadCloser, stdout, stderr io.Writer, useStdin bool) *Pipes {
p := &Pipes{
Stdout: stdout,
Stderr: stderr,
}
if useStdin {
p.Stdin = stdin
}
return p
}