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) {
ttyConsole, ok := container.command.Terminal.(*execdriver.TtyConsole)
ttyConsole, ok := container.command.Terminal.(execdriver.TtyTerminal)
if !ok {
return nil, ErrNoTTY
}
return ttyConsole.Master, nil
return ttyConsole.Master(), nil
}

View file

@ -2,6 +2,8 @@ package execdriver
import (
"errors"
"io"
"os"
"os/exec"
)
@ -57,6 +59,18 @@ type Info interface {
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 {
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
@ -99,8 +113,8 @@ type Command struct {
Config []string `json:"config"` // generic values that specific drivers can consume
Resources *Resources `json:"resources"`
Terminal Term `json:"-"`
Console string `json:"-"`
Terminal Terminal `json:"-"` // standard or tty terminal
Console string `json:"-"` // dev/console path
}
// 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) {
if err := execdriver.SetTerminal(c, pipes); err != nil {
if err := SetTerminal(c, pipes); err != nil {
return -1, err
}
configPath, err := d.generateLXCConfig(c)

View file

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