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/graphdriver"
|
||||||
"github.com/dotcloud/docker/links"
|
"github.com/dotcloud/docker/links"
|
||||||
"github.com/dotcloud/docker/nat"
|
"github.com/dotcloud/docker/nat"
|
||||||
"github.com/dotcloud/docker/pkg/term"
|
|
||||||
"github.com/dotcloud/docker/runconfig"
|
"github.com/dotcloud/docker/runconfig"
|
||||||
"github.com/dotcloud/docker/utils"
|
"github.com/dotcloud/docker/utils"
|
||||||
"github.com/kr/pty"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
@ -57,11 +55,11 @@ type Container struct {
|
||||||
Driver string
|
Driver string
|
||||||
|
|
||||||
command *execdriver.Command
|
command *execdriver.Command
|
||||||
|
console execdriver.Console
|
||||||
stdout *utils.WriteBroadcaster
|
stdout *utils.WriteBroadcaster
|
||||||
stderr *utils.WriteBroadcaster
|
stderr *utils.WriteBroadcaster
|
||||||
stdin io.ReadCloser
|
stdin io.ReadCloser
|
||||||
stdinPipe io.WriteCloser
|
stdinPipe io.WriteCloser
|
||||||
ptyMaster io.Closer
|
|
||||||
|
|
||||||
runtime *Runtime
|
runtime *Runtime
|
||||||
|
|
||||||
|
@ -213,56 +211,6 @@ func (container *Container) generateEnvConfig(env []string) error {
|
||||||
return nil
|
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 {
|
func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
|
||||||
var cStdout, cStderr io.ReadCloser
|
var cStdout, cStderr io.ReadCloser
|
||||||
|
|
||||||
|
@ -593,14 +541,13 @@ func (container *Container) Start() (err error) {
|
||||||
}
|
}
|
||||||
container.waitLock = make(chan struct{})
|
container.waitLock = make(chan struct{})
|
||||||
|
|
||||||
// Setuping pipes and/or Pty
|
container.console, err = execdriver.NewConsole(
|
||||||
var setup func() error
|
container.stdin, container.stdout, container.stderr,
|
||||||
if container.Config.Tty {
|
container.Config.OpenStdin, container.Config.Tty)
|
||||||
setup = container.setupPty
|
if err != nil {
|
||||||
} else {
|
return err
|
||||||
setup = container.setupStd
|
|
||||||
}
|
}
|
||||||
if err := setup(); err != nil {
|
if err := container.console.AttachTo(container.command); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -887,22 +834,20 @@ func (container *Container) cleanup() {
|
||||||
link.Disable()
|
link.Disable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.Config.OpenStdin {
|
if container.Config.OpenStdin {
|
||||||
if err := container.stdin.Close(); err != nil {
|
if err := container.stdin.Close(); err != nil {
|
||||||
utils.Errorf("%s: Error close stdin: %s", container.ID, err)
|
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)
|
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)
|
utils.Errorf("%s: Error close stderr: %s", container.ID, err)
|
||||||
}
|
}
|
||||||
|
if container.console != nil {
|
||||||
if container.ptyMaster != nil {
|
if err := container.console.Close(); err != nil {
|
||||||
if err := container.ptyMaster.Close(); err != nil {
|
utils.Errorf("%s: Error closing console: %s", container.ID, err)
|
||||||
utils.Errorf("%s: Error closing Pty master: %s", container.ID, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,11 +939,7 @@ func (container *Container) Wait() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) Resize(h, w int) error {
|
func (container *Container) Resize(h, w int) error {
|
||||||
pty, ok := container.ptyMaster.(*os.File)
|
return container.console.Resize(h, w)
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("ptyMaster does not have Fd() method")
|
|
||||||
}
|
|
||||||
return term.SetWinsize(pty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) ExportRw() (archive.Archive, error) {
|
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) {
|
func (container *Container) GetPtyMaster() (*os.File, error) {
|
||||||
if container.ptyMaster == nil {
|
ttyConsole, ok := container.console.(*execdriver.TtyConsole)
|
||||||
|
if !ok {
|
||||||
return nil, ErrNoTTY
|
return nil, ErrNoTTY
|
||||||
}
|
}
|
||||||
if pty, ok := container.ptyMaster.(*os.File); ok {
|
return ttyConsole.Master, nil
|
||||||
return pty, nil
|
|
||||||
}
|
|
||||||
return nil, ErrNotATTY
|
|
||||||
}
|
}
|
||||||
|
|
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
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WriteBroadcaster) CloseWriters() error {
|
func (w *WriteBroadcaster) Close() error {
|
||||||
w.Lock()
|
w.Lock()
|
||||||
defer w.Unlock()
|
defer w.Unlock()
|
||||||
for sw := range w.writers {
|
for sw := range w.writers {
|
||||||
|
|
|
@ -110,7 +110,7 @@ func TestWriteBroadcaster(t *testing.T) {
|
||||||
t.Errorf("Buffer contains %v", bufferC.String())
|
t.Errorf("Buffer contains %v", bufferC.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.CloseWriters()
|
writer.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
type devNullCloser int
|
type devNullCloser int
|
||||||
|
|
Loading…
Reference in a new issue