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:
parent
43484e8b50
commit
6882c78ce4
3 changed files with 39 additions and 16 deletions
16
commands.go
16
commands.go
|
@ -799,7 +799,8 @@ func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout io.Writer, args ...stri
|
||||||
if container == nil {
|
if container == nil {
|
||||||
return fmt.Errorf("No such container: %s", name)
|
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
|
// 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 (
|
var (
|
||||||
cStdin io.Reader
|
cStdin io.ReadCloser
|
||||||
cStdout, cStderr io.Writer
|
cStdout, cStderr io.Writer
|
||||||
)
|
)
|
||||||
if config.AttachStdin {
|
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 {
|
if config.AttachStdout {
|
||||||
cStdout = stdout
|
cStdout = stdout
|
||||||
|
@ -913,7 +920,8 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
|
||||||
if config.AttachStderr {
|
if config.AttachStderr {
|
||||||
cStderr = stdout // FIXME: rcli can't differentiate stdout from stderr
|
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")
|
Debugf("Starting\n")
|
||||||
if err := container.Start(); err != nil {
|
if err := container.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -93,9 +93,7 @@ func TestRunExit(t *testing.T) {
|
||||||
stdout, stdoutPipe := io.Pipe()
|
stdout, stdoutPipe := io.Pipe()
|
||||||
c1 := make(chan struct{})
|
c1 := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
if err := srv.CmdRun(stdin, stdoutPipe, "-i", GetTestImage(runtime).Id, "/bin/cat"); err != nil {
|
srv.CmdRun(stdin, stdoutPipe, "-i", GetTestImage(runtime).Id, "/bin/cat")
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
close(c1)
|
close(c1)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -123,11 +121,8 @@ func TestRunExit(t *testing.T) {
|
||||||
|
|
||||||
// Make sure that the client has been disconnected
|
// 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() {
|
setTimeout(t, "The client should have been disconnected once the remote process exited.", 2*time.Second, func() {
|
||||||
if _, err := stdin.Read([]byte{}); err != nil {
|
// Expecting pipe i/o error, just check that read does not block
|
||||||
if err != io.EOF {
|
stdin.Read([]byte{})
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Cleanup pipes
|
// Cleanup pipes
|
||||||
|
@ -293,6 +288,7 @@ func TestAttachDisconnect(t *testing.T) {
|
||||||
setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
|
setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
|
||||||
<-c1
|
<-c1
|
||||||
})
|
})
|
||||||
|
|
||||||
// We closed stdin, expect /bin/cat to still be running
|
// We closed stdin, expect /bin/cat to still be running
|
||||||
// Wait a little bit to make sure container.monitor() did his thing
|
// Wait a little bit to make sure container.monitor() did his thing
|
||||||
err = container.WaitTimeout(500 * time.Millisecond)
|
err = container.WaitTimeout(500 * time.Millisecond)
|
||||||
|
|
27
container.go
27
container.go
|
@ -257,9 +257,9 @@ func (container *Container) start() error {
|
||||||
return container.cmd.Start()
|
return container.cmd.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) Attach(stdin io.Reader, 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 io.ReadCloser
|
var cStdout, cStderr io.ReadCloser
|
||||||
var cStderr io.ReadCloser
|
|
||||||
var nJobs int
|
var nJobs int
|
||||||
errors := make(chan error, 3)
|
errors := make(chan error, 3)
|
||||||
if stdin != nil && container.Config.OpenStdin {
|
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 {
|
if err != nil {
|
||||||
Debugf("[error] attach stdout: %s\n", err)
|
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() {
|
go func() {
|
||||||
Debugf("[start] attach stdout\n")
|
Debugf("[start] attach stdout\n")
|
||||||
defer Debugf("[end] 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)
|
_, err := io.Copy(stdout, cStdout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Debugf("[error] attach stdout: %s\n", err)
|
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() {
|
go func() {
|
||||||
Debugf("[start] attach stderr\n")
|
Debugf("[start] attach stderr\n")
|
||||||
defer Debugf("[end] 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)
|
_, err := io.Copy(stderr, cStderr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Debugf("[error] attach stderr: %s\n", err)
|
Debugf("[error] attach stderr: %s\n", err)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue