1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Add a stdincloser to container.Attach in order to close the client connection when needed

This commit is contained in:
Guillaume J. Charmes 2013-04-02 12:18:20 -07:00
parent 43484e8b50
commit 6882c78ce4
3 changed files with 39 additions and 16 deletions

View file

@ -799,7 +799,8 @@ func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout io.Writer, args ...stri
if container == nil {
return fmt.Errorf("No such container: %s", name)
}
return <-container.Attach(stdin, stdout, stdout)
return <-container.Attach(stdin, nil, stdout, stdout)
}
// Ports type - Used to parse multiple -p flags
@ -901,11 +902,17 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
}
}
var (
cStdin io.Reader
cStdin io.ReadCloser
cStdout, cStderr io.Writer
)
if config.AttachStdin {
cStdin = stdin
r, w := io.Pipe()
go func() {
defer w.Close()
defer Debugf("Closing buffered stdin pipe")
io.Copy(w, stdin)
}()
cStdin = r
}
if config.AttachStdout {
cStdout = stdout
@ -913,7 +920,8 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
if config.AttachStderr {
cStderr = stdout // FIXME: rcli can't differentiate stdout from stderr
}
attachErr := container.Attach(cStdin, cStdout, cStderr)
attachErr := container.Attach(cStdin, stdin, cStdout, cStderr)
Debugf("Starting\n")
if err := container.Start(); err != nil {
return err

View file

@ -93,9 +93,7 @@ func TestRunExit(t *testing.T) {
stdout, stdoutPipe := io.Pipe()
c1 := make(chan struct{})
go func() {
if err := srv.CmdRun(stdin, stdoutPipe, "-i", GetTestImage(runtime).Id, "/bin/cat"); err != nil {
t.Error(err)
}
srv.CmdRun(stdin, stdoutPipe, "-i", GetTestImage(runtime).Id, "/bin/cat")
close(c1)
}()
@ -123,11 +121,8 @@ func TestRunExit(t *testing.T) {
// Make sure that the client has been disconnected
setTimeout(t, "The client should have been disconnected once the remote process exited.", 2*time.Second, func() {
if _, err := stdin.Read([]byte{}); err != nil {
if err != io.EOF {
t.Fatal(err)
}
}
// Expecting pipe i/o error, just check that read does not block
stdin.Read([]byte{})
})
// Cleanup pipes
@ -293,6 +288,7 @@ func TestAttachDisconnect(t *testing.T) {
setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
<-c1
})
// We closed stdin, expect /bin/cat to still be running
// Wait a little bit to make sure container.monitor() did his thing
err = container.WaitTimeout(500 * time.Millisecond)

View file

@ -257,9 +257,9 @@ func (container *Container) start() error {
return container.cmd.Start()
}
func (container *Container) Attach(stdin io.Reader, stdout io.Writer, stderr io.Writer) chan error {
var cStdout io.ReadCloser
var cStderr io.ReadCloser
func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
var cStdout, cStderr io.ReadCloser
var nJobs int
errors := make(chan error, 3)
if stdin != nil && container.Config.OpenStdin {
@ -277,7 +277,8 @@ func (container *Container) Attach(stdin io.Reader, stdout io.Writer, stderr io.
if err != nil {
Debugf("[error] attach stdout: %s\n", err)
}
errors <- err
// Discard error, expecting pipe error
errors <- nil
}()
}
}
@ -290,6 +291,15 @@ func (container *Container) Attach(stdin io.Reader, stdout io.Writer, stderr io.
go func() {
Debugf("[start] attach stdout\n")
defer Debugf("[end] attach stdout\n")
// If we are in StdinOnce mode, then close stdin
if container.Config.StdinOnce {
if stdin != nil {
defer stdin.Close()
}
if stdinCloser != nil {
defer stdinCloser.Close()
}
}
_, err := io.Copy(stdout, cStdout)
if err != nil {
Debugf("[error] attach stdout: %s\n", err)
@ -307,6 +317,15 @@ func (container *Container) Attach(stdin io.Reader, stdout io.Writer, stderr io.
go func() {
Debugf("[start] attach stderr\n")
defer Debugf("[end] attach stderr\n")
// If we are in StdinOnce mode, then close stdin
if container.Config.StdinOnce {
if stdin != nil {
defer stdin.Close()
}
if stdinCloser != nil {
defer stdinCloser.Close()
}
}
_, err := io.Copy(stderr, cStderr)
if err != nil {
Debugf("[error] attach stderr: %s\n", err)