зеркало из https://github.com/microsoft/docker.git
Merge pull request #2242 from jpetazzo/remove-spurious-errors-and-errclosedpipe
Fix error/debug messages in Container.Attach and recover from ErrClosedPipe
This commit is contained in:
Коммит
3ba9893786
77
container.go
77
container.go
|
@ -390,9 +390,9 @@ func (container *Container) startPty() error {
|
||||||
// Copy the PTYs to our broadcasters
|
// Copy the PTYs to our broadcasters
|
||||||
go func() {
|
go func() {
|
||||||
defer container.stdout.CloseWriters()
|
defer container.stdout.CloseWriters()
|
||||||
utils.Debugf("[startPty] Begin of stdout pipe")
|
utils.Debugf("startPty: begin of stdout pipe")
|
||||||
io.Copy(container.stdout, ptyMaster)
|
io.Copy(container.stdout, ptyMaster)
|
||||||
utils.Debugf("[startPty] End of stdout pipe")
|
utils.Debugf("startPty: end of stdout pipe")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// stdin
|
// stdin
|
||||||
|
@ -401,9 +401,9 @@ func (container *Container) startPty() error {
|
||||||
container.cmd.SysProcAttr.Setctty = true
|
container.cmd.SysProcAttr.Setctty = true
|
||||||
go func() {
|
go func() {
|
||||||
defer container.stdin.Close()
|
defer container.stdin.Close()
|
||||||
utils.Debugf("[startPty] Begin of stdin pipe")
|
utils.Debugf("startPty: begin of stdin pipe")
|
||||||
io.Copy(ptyMaster, container.stdin)
|
io.Copy(ptyMaster, container.stdin)
|
||||||
utils.Debugf("[startPty] End of stdin pipe")
|
utils.Debugf("startPty: end of stdin pipe")
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
if err := container.cmd.Start(); err != nil {
|
if err := container.cmd.Start(); err != nil {
|
||||||
|
@ -423,9 +423,9 @@ func (container *Container) start() error {
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
defer stdin.Close()
|
defer stdin.Close()
|
||||||
utils.Debugf("Begin of stdin pipe [start]")
|
utils.Debugf("start: begin of stdin pipe")
|
||||||
io.Copy(stdin, container.stdin)
|
io.Copy(stdin, container.stdin)
|
||||||
utils.Debugf("End of stdin pipe [start]")
|
utils.Debugf("start: end of stdin pipe")
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
return container.cmd.Start()
|
return container.cmd.Start()
|
||||||
|
@ -442,8 +442,8 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
|
||||||
errors <- err
|
errors <- err
|
||||||
} else {
|
} else {
|
||||||
go func() {
|
go func() {
|
||||||
utils.Debugf("[start] attach stdin\n")
|
utils.Debugf("attach: stdin: begin")
|
||||||
defer utils.Debugf("[end] attach stdin\n")
|
defer utils.Debugf("attach: stdin: end")
|
||||||
// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
|
// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
|
||||||
if container.Config.StdinOnce && !container.Config.Tty {
|
if container.Config.StdinOnce && !container.Config.Tty {
|
||||||
defer cStdin.Close()
|
defer cStdin.Close()
|
||||||
|
@ -461,7 +461,7 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
|
||||||
_, err = io.Copy(cStdin, stdin)
|
_, err = io.Copy(cStdin, stdin)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Errorf("[error] attach stdin: %s\n", err)
|
utils.Errorf("attach: stdin: %s", err)
|
||||||
}
|
}
|
||||||
// Discard error, expecting pipe error
|
// Discard error, expecting pipe error
|
||||||
errors <- nil
|
errors <- nil
|
||||||
|
@ -475,8 +475,8 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
|
||||||
} else {
|
} else {
|
||||||
cStdout = p
|
cStdout = p
|
||||||
go func() {
|
go func() {
|
||||||
utils.Debugf("[start] attach stdout\n")
|
utils.Debugf("attach: stdout: begin")
|
||||||
defer utils.Debugf("[end] attach stdout\n")
|
defer utils.Debugf("attach: stdout: end")
|
||||||
// If we are in StdinOnce mode, then close stdin
|
// If we are in StdinOnce mode, then close stdin
|
||||||
if container.Config.StdinOnce && stdin != nil {
|
if container.Config.StdinOnce && stdin != nil {
|
||||||
defer stdin.Close()
|
defer stdin.Close()
|
||||||
|
@ -485,8 +485,11 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
|
||||||
defer stdinCloser.Close()
|
defer stdinCloser.Close()
|
||||||
}
|
}
|
||||||
_, err := io.Copy(stdout, cStdout)
|
_, err := io.Copy(stdout, cStdout)
|
||||||
|
if err == io.ErrClosedPipe {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Errorf("[error] attach stdout: %s\n", err)
|
utils.Errorf("attach: stdout: %s", err)
|
||||||
}
|
}
|
||||||
errors <- err
|
errors <- err
|
||||||
}()
|
}()
|
||||||
|
@ -496,9 +499,8 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
|
||||||
if stdinCloser != nil {
|
if stdinCloser != nil {
|
||||||
defer stdinCloser.Close()
|
defer stdinCloser.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
if cStdout, err := container.StdoutPipe(); err != nil {
|
if cStdout, err := container.StdoutPipe(); err != nil {
|
||||||
utils.Errorf("Error stdout pipe")
|
utils.Errorf("attach: stdout pipe: %s", err)
|
||||||
} else {
|
} else {
|
||||||
io.Copy(&utils.NopWriter{}, cStdout)
|
io.Copy(&utils.NopWriter{}, cStdout)
|
||||||
}
|
}
|
||||||
|
@ -511,8 +513,8 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
|
||||||
} else {
|
} else {
|
||||||
cStderr = p
|
cStderr = p
|
||||||
go func() {
|
go func() {
|
||||||
utils.Debugf("[start] attach stderr\n")
|
utils.Debugf("attach: stderr: begin")
|
||||||
defer utils.Debugf("[end] attach stderr\n")
|
defer utils.Debugf("attach: stderr: end")
|
||||||
// If we are in StdinOnce mode, then close stdin
|
// If we are in StdinOnce mode, then close stdin
|
||||||
if container.Config.StdinOnce && stdin != nil {
|
if container.Config.StdinOnce && stdin != nil {
|
||||||
defer stdin.Close()
|
defer stdin.Close()
|
||||||
|
@ -521,8 +523,11 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
|
||||||
defer stdinCloser.Close()
|
defer stdinCloser.Close()
|
||||||
}
|
}
|
||||||
_, err := io.Copy(stderr, cStderr)
|
_, err := io.Copy(stderr, cStderr)
|
||||||
|
if err == io.ErrClosedPipe {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Errorf("[error] attach stderr: %s\n", err)
|
utils.Errorf("attach: stderr: %s", err)
|
||||||
}
|
}
|
||||||
errors <- err
|
errors <- err
|
||||||
}()
|
}()
|
||||||
|
@ -534,7 +539,7 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
|
||||||
}
|
}
|
||||||
|
|
||||||
if cStderr, err := container.StderrPipe(); err != nil {
|
if cStderr, err := container.StderrPipe(); err != nil {
|
||||||
utils.Errorf("Error stdout pipe")
|
utils.Errorf("attach: stdout pipe: %s", err)
|
||||||
} else {
|
} else {
|
||||||
io.Copy(&utils.NopWriter{}, cStderr)
|
io.Copy(&utils.NopWriter{}, cStderr)
|
||||||
}
|
}
|
||||||
|
@ -548,17 +553,17 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
|
||||||
if cStderr != nil {
|
if cStderr != nil {
|
||||||
defer cStderr.Close()
|
defer cStderr.Close()
|
||||||
}
|
}
|
||||||
// FIXME: how do clean up the stdin goroutine without the unwanted side effect
|
// FIXME: how to clean up the stdin goroutine without the unwanted side effect
|
||||||
// of closing the passed stdin? Add an intermediary io.Pipe?
|
// of closing the passed stdin? Add an intermediary io.Pipe?
|
||||||
for i := 0; i < nJobs; i += 1 {
|
for i := 0; i < nJobs; i += 1 {
|
||||||
utils.Debugf("Waiting for job %d/%d\n", i+1, nJobs)
|
utils.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
|
||||||
if err := <-errors; err != nil {
|
if err := <-errors; err != nil {
|
||||||
utils.Errorf("Job %d returned error %s. Aborting all jobs\n", i+1, err)
|
utils.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
utils.Debugf("Job %d completed successfully\n", i+1)
|
utils.Debugf("attach: job %d completed successfully", i+1)
|
||||||
}
|
}
|
||||||
utils.Debugf("All jobs completed successfully\n")
|
utils.Debugf("attach: all jobs completed successfully")
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -853,9 +858,14 @@ func (container *Container) Output() (output []byte, err error) {
|
||||||
return output, err
|
return output, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// StdinPipe() returns a pipe connected to the standard input of the container's
|
// Container.StdinPipe returns a WriteCloser which can be used to feed data
|
||||||
// active process.
|
// to the standard input of the container's active process.
|
||||||
//
|
// Container.StdoutPipe and Container.StderrPipe each return a ReadCloser
|
||||||
|
// which can be used to retrieve the standard output (and error) generated
|
||||||
|
// by the container's active process. The output (and error) are actually
|
||||||
|
// copied and delivered to all StdoutPipe and StderrPipe consumers, using
|
||||||
|
// a kind of "broadcaster".
|
||||||
|
|
||||||
func (container *Container) StdinPipe() (io.WriteCloser, error) {
|
func (container *Container) StdinPipe() (io.WriteCloser, error) {
|
||||||
return container.stdinPipe, nil
|
return container.stdinPipe, nil
|
||||||
}
|
}
|
||||||
|
@ -957,20 +967,23 @@ func (container *Container) waitLxc() error {
|
||||||
|
|
||||||
func (container *Container) monitor(hostConfig *HostConfig) {
|
func (container *Container) monitor(hostConfig *HostConfig) {
|
||||||
// Wait for the program to exit
|
// Wait for the program to exit
|
||||||
utils.Debugf("Waiting for process")
|
|
||||||
|
|
||||||
// If the command does not exists, try to wait via lxc
|
// If the command does not exist, try to wait via lxc
|
||||||
|
// (This probably happens only for ghost containers, i.e. containers that were running when Docker started)
|
||||||
if container.cmd == nil {
|
if container.cmd == nil {
|
||||||
|
utils.Debugf("monitor: waiting for container %s using waitLxc", container.ID)
|
||||||
if err := container.waitLxc(); err != nil {
|
if err := container.waitLxc(); err != nil {
|
||||||
utils.Errorf("%s: Process: %s", container.ID, err)
|
utils.Errorf("monitor: while waiting for container %s, waitLxc had a problem: %s", container.ID, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
utils.Debugf("monitor: waiting for container %s using cmd.Wait", container.ID)
|
||||||
if err := container.cmd.Wait(); err != nil {
|
if err := container.cmd.Wait(); err != nil {
|
||||||
// Discard the error as any signals or non 0 returns will generate an error
|
// Since non-zero exit status and signal terminations will cause err to be non-nil,
|
||||||
utils.Errorf("%s: Process: %s", container.ID, err)
|
// we have to actually discard it. Still, log it anyway, just in case.
|
||||||
|
utils.Debugf("monitor: cmd.Wait reported exit status %s for container %s", err, container.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
utils.Debugf("Process finished")
|
utils.Debugf("monitor: container %s finished", container.ID)
|
||||||
|
|
||||||
exitCode := -1
|
exitCode := -1
|
||||||
if container.cmd != nil {
|
if container.cmd != nil {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче