Move console into execdriver
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
This commit is contained in:
parent
81cd2054f6
commit
8c783c1c13
4 changed files with 155 additions and 79 deletions
93
container.go
93
container.go
|
@ -10,10 +10,8 @@ import (
|
|||
"github.com/dotcloud/docker/graphdriver"
|
||||
"github.com/dotcloud/docker/links"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"github.com/dotcloud/docker/pkg/term"
|
||||
"github.com/dotcloud/docker/runconfig"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"github.com/kr/pty"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
@ -57,11 +55,11 @@ type Container struct {
|
|||
Driver string
|
||||
|
||||
command *execdriver.Command
|
||||
console execdriver.Console
|
||||
stdout *utils.WriteBroadcaster
|
||||
stderr *utils.WriteBroadcaster
|
||||
stdin io.ReadCloser
|
||||
stdinPipe io.WriteCloser
|
||||
ptyMaster io.Closer
|
||||
|
||||
runtime *Runtime
|
||||
|
||||
|
@ -213,56 +211,6 @@ func (container *Container) generateEnvConfig(env []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) setupPty() error {
|
||||
ptyMaster, ptySlave, err := pty.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
container.ptyMaster = ptyMaster
|
||||
container.command.Stdout = ptySlave
|
||||
container.command.Stderr = ptySlave
|
||||
container.command.Console = ptySlave.Name()
|
||||
|
||||
// Copy the PTYs to our broadcasters
|
||||
go func() {
|
||||
defer container.stdout.CloseWriters()
|
||||
utils.Debugf("startPty: begin of stdout pipe")
|
||||
io.Copy(container.stdout, ptyMaster)
|
||||
utils.Debugf("startPty: end of stdout pipe")
|
||||
}()
|
||||
|
||||
// stdin
|
||||
if container.Config.OpenStdin {
|
||||
container.command.Stdin = ptySlave
|
||||
container.command.SysProcAttr.Setctty = true
|
||||
go func() {
|
||||
defer container.stdin.Close()
|
||||
utils.Debugf("startPty: begin of stdin pipe")
|
||||
io.Copy(ptyMaster, container.stdin)
|
||||
utils.Debugf("startPty: end of stdin pipe")
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) setupStd() error {
|
||||
container.command.Stdout = container.stdout
|
||||
container.command.Stderr = container.stderr
|
||||
if container.Config.OpenStdin {
|
||||
stdin, err := container.command.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
defer stdin.Close()
|
||||
utils.Debugf("start: begin of stdin pipe")
|
||||
io.Copy(stdin, container.stdin)
|
||||
utils.Debugf("start: end of stdin pipe")
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
|
||||
var cStdout, cStderr io.ReadCloser
|
||||
|
||||
|
@ -593,14 +541,13 @@ func (container *Container) Start() (err error) {
|
|||
}
|
||||
container.waitLock = make(chan struct{})
|
||||
|
||||
// Setuping pipes and/or Pty
|
||||
var setup func() error
|
||||
if container.Config.Tty {
|
||||
setup = container.setupPty
|
||||
} else {
|
||||
setup = container.setupStd
|
||||
container.console, err = execdriver.NewConsole(
|
||||
container.stdin, container.stdout, container.stderr,
|
||||
container.Config.OpenStdin, container.Config.Tty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setup(); err != nil {
|
||||
if err := container.console.AttachTo(container.command); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -887,22 +834,20 @@ func (container *Container) cleanup() {
|
|||
link.Disable()
|
||||
}
|
||||
}
|
||||
|
||||
if container.Config.OpenStdin {
|
||||
if err := container.stdin.Close(); err != nil {
|
||||
utils.Errorf("%s: Error close stdin: %s", container.ID, err)
|
||||
}
|
||||
}
|
||||
if err := container.stdout.CloseWriters(); err != nil {
|
||||
if err := container.stdout.Close(); err != nil {
|
||||
utils.Errorf("%s: Error close stdout: %s", container.ID, err)
|
||||
}
|
||||
if err := container.stderr.CloseWriters(); err != nil {
|
||||
if err := container.stderr.Close(); err != nil {
|
||||
utils.Errorf("%s: Error close stderr: %s", container.ID, err)
|
||||
}
|
||||
|
||||
if container.ptyMaster != nil {
|
||||
if err := container.ptyMaster.Close(); err != nil {
|
||||
utils.Errorf("%s: Error closing Pty master: %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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -994,11 +939,7 @@ func (container *Container) Wait() int {
|
|||
}
|
||||
|
||||
func (container *Container) Resize(h, w int) error {
|
||||
pty, ok := container.ptyMaster.(*os.File)
|
||||
if !ok {
|
||||
return fmt.Errorf("ptyMaster does not have Fd() method")
|
||||
}
|
||||
return term.SetWinsize(pty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
|
||||
return container.console.Resize(h, w)
|
||||
}
|
||||
|
||||
func (container *Container) ExportRw() (archive.Archive, error) {
|
||||
|
@ -1202,11 +1143,9 @@ func (container *Container) Exposes(p nat.Port) bool {
|
|||
}
|
||||
|
||||
func (container *Container) GetPtyMaster() (*os.File, error) {
|
||||
if container.ptyMaster == nil {
|
||||
ttyConsole, ok := container.console.(*execdriver.TtyConsole)
|
||||
if !ok {
|
||||
return nil, ErrNoTTY
|
||||
}
|
||||
if pty, ok := container.ptyMaster.(*os.File); ok {
|
||||
return pty, nil
|
||||
}
|
||||
return nil, ErrNotATTY
|
||||
return ttyConsole.Master, nil
|
||||
}
|
||||
|
|
137
execdriver/console.go
Normal file
137
execdriver/console.go
Normal file
|
@ -0,0 +1,137 @@
|
|||
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
|
||||
}
|
|
@ -388,7 +388,7 @@ func (w *WriteBroadcaster) Write(p []byte) (n int, err error) {
|
|||
return len(p), nil
|
||||
}
|
||||
|
||||
func (w *WriteBroadcaster) CloseWriters() error {
|
||||
func (w *WriteBroadcaster) Close() error {
|
||||
w.Lock()
|
||||
defer w.Unlock()
|
||||
for sw := range w.writers {
|
||||
|
|
|
@ -110,7 +110,7 @@ func TestWriteBroadcaster(t *testing.T) {
|
|||
t.Errorf("Buffer contains %v", bufferC.String())
|
||||
}
|
||||
|
||||
writer.CloseWriters()
|
||||
writer.Close()
|
||||
}
|
||||
|
||||
type devNullCloser int
|
||||
|
|
Loading…
Reference in a new issue