| ... | ... |
@@ -390,9 +390,9 @@ func (container *Container) startPty() error {
|
| 390 | 390 |
// Copy the PTYs to our broadcasters |
| 391 | 391 |
go func() {
|
| 392 | 392 |
defer container.stdout.CloseWriters() |
| 393 |
- utils.Debugf("[startPty] Begin of stdout pipe")
|
|
| 393 |
+ utils.Debugf("startPty: begin of stdout pipe")
|
|
| 394 | 394 |
io.Copy(container.stdout, ptyMaster) |
| 395 |
- utils.Debugf("[startPty] End of stdout pipe")
|
|
| 395 |
+ utils.Debugf("startPty: end of stdout pipe")
|
|
| 396 | 396 |
}() |
| 397 | 397 |
|
| 398 | 398 |
// stdin |
| ... | ... |
@@ -401,9 +401,9 @@ func (container *Container) startPty() error {
|
| 401 | 401 |
container.cmd.SysProcAttr.Setctty = true |
| 402 | 402 |
go func() {
|
| 403 | 403 |
defer container.stdin.Close() |
| 404 |
- utils.Debugf("[startPty] Begin of stdin pipe")
|
|
| 404 |
+ utils.Debugf("startPty: begin of stdin pipe")
|
|
| 405 | 405 |
io.Copy(ptyMaster, container.stdin) |
| 406 |
- utils.Debugf("[startPty] End of stdin pipe")
|
|
| 406 |
+ utils.Debugf("startPty: end of stdin pipe")
|
|
| 407 | 407 |
}() |
| 408 | 408 |
} |
| 409 | 409 |
if err := container.cmd.Start(); err != nil {
|
| ... | ... |
@@ -423,9 +423,9 @@ func (container *Container) start() error {
|
| 423 | 423 |
} |
| 424 | 424 |
go func() {
|
| 425 | 425 |
defer stdin.Close() |
| 426 |
- utils.Debugf("Begin of stdin pipe [start]")
|
|
| 426 |
+ utils.Debugf("start: begin of stdin pipe")
|
|
| 427 | 427 |
io.Copy(stdin, container.stdin) |
| 428 |
- utils.Debugf("End of stdin pipe [start]")
|
|
| 428 |
+ utils.Debugf("start: end of stdin pipe")
|
|
| 429 | 429 |
}() |
| 430 | 430 |
} |
| 431 | 431 |
return container.cmd.Start() |
| ... | ... |
@@ -442,8 +442,8 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s |
| 442 | 442 |
errors <- err |
| 443 | 443 |
} else {
|
| 444 | 444 |
go func() {
|
| 445 |
- utils.Debugf("[start] attach stdin\n")
|
|
| 446 |
- defer utils.Debugf("[end] attach stdin\n")
|
|
| 445 |
+ utils.Debugf("attach: stdin: begin")
|
|
| 446 |
+ defer utils.Debugf("attach: stdin: end")
|
|
| 447 | 447 |
// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr |
| 448 | 448 |
if container.Config.StdinOnce && !container.Config.Tty {
|
| 449 | 449 |
defer cStdin.Close() |
| ... | ... |
@@ -461,7 +461,7 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s |
| 461 | 461 |
_, err = io.Copy(cStdin, stdin) |
| 462 | 462 |
} |
| 463 | 463 |
if err != nil {
|
| 464 |
- utils.Errorf("[error] attach stdin: %s\n", err)
|
|
| 464 |
+ utils.Errorf("attach: stdin: %s", err)
|
|
| 465 | 465 |
} |
| 466 | 466 |
// Discard error, expecting pipe error |
| 467 | 467 |
errors <- nil |
| ... | ... |
@@ -475,8 +475,8 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s |
| 475 | 475 |
} else {
|
| 476 | 476 |
cStdout = p |
| 477 | 477 |
go func() {
|
| 478 |
- utils.Debugf("[start] attach stdout\n")
|
|
| 479 |
- defer utils.Debugf("[end] attach stdout\n")
|
|
| 478 |
+ utils.Debugf("attach: stdout: begin")
|
|
| 479 |
+ defer utils.Debugf("attach: stdout: end")
|
|
| 480 | 480 |
// If we are in StdinOnce mode, then close stdin |
| 481 | 481 |
if container.Config.StdinOnce && stdin != nil {
|
| 482 | 482 |
defer stdin.Close() |
| ... | ... |
@@ -485,8 +485,11 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s |
| 485 | 485 |
defer stdinCloser.Close() |
| 486 | 486 |
} |
| 487 | 487 |
_, err := io.Copy(stdout, cStdout) |
| 488 |
+ if err == io.ErrClosedPipe {
|
|
| 489 |
+ err = nil |
|
| 490 |
+ } |
|
| 488 | 491 |
if err != nil {
|
| 489 |
- utils.Errorf("[error] attach stdout: %s\n", err)
|
|
| 492 |
+ utils.Errorf("attach: stdout: %s", err)
|
|
| 490 | 493 |
} |
| 491 | 494 |
errors <- err |
| 492 | 495 |
}() |
| ... | ... |
@@ -496,9 +499,8 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s |
| 496 | 496 |
if stdinCloser != nil {
|
| 497 | 497 |
defer stdinCloser.Close() |
| 498 | 498 |
} |
| 499 |
- |
|
| 500 | 499 |
if cStdout, err := container.StdoutPipe(); err != nil {
|
| 501 |
- utils.Errorf("Error stdout pipe")
|
|
| 500 |
+ utils.Errorf("attach: stdout pipe: %s", err)
|
|
| 502 | 501 |
} else {
|
| 503 | 502 |
io.Copy(&utils.NopWriter{}, cStdout)
|
| 504 | 503 |
} |
| ... | ... |
@@ -511,8 +513,8 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s |
| 511 | 511 |
} else {
|
| 512 | 512 |
cStderr = p |
| 513 | 513 |
go func() {
|
| 514 |
- utils.Debugf("[start] attach stderr\n")
|
|
| 515 |
- defer utils.Debugf("[end] attach stderr\n")
|
|
| 514 |
+ utils.Debugf("attach: stderr: begin")
|
|
| 515 |
+ defer utils.Debugf("attach: stderr: end")
|
|
| 516 | 516 |
// If we are in StdinOnce mode, then close stdin |
| 517 | 517 |
if container.Config.StdinOnce && stdin != nil {
|
| 518 | 518 |
defer stdin.Close() |
| ... | ... |
@@ -521,8 +523,11 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s |
| 521 | 521 |
defer stdinCloser.Close() |
| 522 | 522 |
} |
| 523 | 523 |
_, err := io.Copy(stderr, cStderr) |
| 524 |
+ if err == io.ErrClosedPipe {
|
|
| 525 |
+ err = nil |
|
| 526 |
+ } |
|
| 524 | 527 |
if err != nil {
|
| 525 |
- utils.Errorf("[error] attach stderr: %s\n", err)
|
|
| 528 |
+ utils.Errorf("attach: stderr: %s", err)
|
|
| 526 | 529 |
} |
| 527 | 530 |
errors <- err |
| 528 | 531 |
}() |
| ... | ... |
@@ -534,7 +539,7 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s |
| 534 | 534 |
} |
| 535 | 535 |
|
| 536 | 536 |
if cStderr, err := container.StderrPipe(); err != nil {
|
| 537 |
- utils.Errorf("Error stdout pipe")
|
|
| 537 |
+ utils.Errorf("attach: stdout pipe: %s", err)
|
|
| 538 | 538 |
} else {
|
| 539 | 539 |
io.Copy(&utils.NopWriter{}, cStderr)
|
| 540 | 540 |
} |
| ... | ... |
@@ -548,17 +553,17 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s |
| 548 | 548 |
if cStderr != nil {
|
| 549 | 549 |
defer cStderr.Close() |
| 550 | 550 |
} |
| 551 |
- // FIXME: how do clean up the stdin goroutine without the unwanted side effect |
|
| 551 |
+ // FIXME: how to clean up the stdin goroutine without the unwanted side effect |
|
| 552 | 552 |
// of closing the passed stdin? Add an intermediary io.Pipe? |
| 553 | 553 |
for i := 0; i < nJobs; i += 1 {
|
| 554 |
- utils.Debugf("Waiting for job %d/%d\n", i+1, nJobs)
|
|
| 554 |
+ utils.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
|
|
| 555 | 555 |
if err := <-errors; err != nil {
|
| 556 |
- utils.Errorf("Job %d returned error %s. Aborting all jobs\n", i+1, err)
|
|
| 556 |
+ utils.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
|
|
| 557 | 557 |
return err |
| 558 | 558 |
} |
| 559 |
- utils.Debugf("Job %d completed successfully\n", i+1)
|
|
| 559 |
+ utils.Debugf("attach: job %d completed successfully", i+1)
|
|
| 560 | 560 |
} |
| 561 |
- utils.Debugf("All jobs completed successfully\n")
|
|
| 561 |
+ utils.Debugf("attach: all jobs completed successfully")
|
|
| 562 | 562 |
return nil |
| 563 | 563 |
}) |
| 564 | 564 |
} |
| ... | ... |
@@ -849,9 +854,14 @@ func (container *Container) Output() (output []byte, err error) {
|
| 849 | 849 |
return output, err |
| 850 | 850 |
} |
| 851 | 851 |
|
| 852 |
-// StdinPipe() returns a pipe connected to the standard input of the container's |
|
| 853 |
-// active process. |
|
| 854 |
-// |
|
| 852 |
+// Container.StdinPipe returns a WriteCloser which can be used to feed data |
|
| 853 |
+// to the standard input of the container's active process. |
|
| 854 |
+// Container.StdoutPipe and Container.StderrPipe each return a ReadCloser |
|
| 855 |
+// which can be used to retrieve the standard output (and error) generated |
|
| 856 |
+// by the container's active process. The output (and error) are actually |
|
| 857 |
+// copied and delivered to all StdoutPipe and StderrPipe consumers, using |
|
| 858 |
+// a kind of "broadcaster". |
|
| 859 |
+ |
|
| 855 | 860 |
func (container *Container) StdinPipe() (io.WriteCloser, error) {
|
| 856 | 861 |
return container.stdinPipe, nil |
| 857 | 862 |
} |
| ... | ... |
@@ -953,20 +963,23 @@ func (container *Container) waitLxc() error {
|
| 953 | 953 |
|
| 954 | 954 |
func (container *Container) monitor(hostConfig *HostConfig) {
|
| 955 | 955 |
// Wait for the program to exit |
| 956 |
- utils.Debugf("Waiting for process")
|
|
| 957 | 956 |
|
| 958 |
- // If the command does not exists, try to wait via lxc |
|
| 957 |
+ // If the command does not exist, try to wait via lxc |
|
| 958 |
+ // (This probably happens only for ghost containers, i.e. containers that were running when Docker started) |
|
| 959 | 959 |
if container.cmd == nil {
|
| 960 |
+ utils.Debugf("monitor: waiting for container %s using waitLxc", container.ID)
|
|
| 960 | 961 |
if err := container.waitLxc(); err != nil {
|
| 961 |
- utils.Errorf("%s: Process: %s", container.ID, err)
|
|
| 962 |
+ utils.Errorf("monitor: while waiting for container %s, waitLxc had a problem: %s", container.ID, err)
|
|
| 962 | 963 |
} |
| 963 | 964 |
} else {
|
| 965 |
+ utils.Debugf("monitor: waiting for container %s using cmd.Wait", container.ID)
|
|
| 964 | 966 |
if err := container.cmd.Wait(); err != nil {
|
| 965 |
- // Discard the error as any signals or non 0 returns will generate an error |
|
| 966 |
- utils.Errorf("%s: Process: %s", container.ID, err)
|
|
| 967 |
+ // Since non-zero exit status and signal terminations will cause err to be non-nil, |
|
| 968 |
+ // we have to actually discard it. Still, log it anyway, just in case. |
|
| 969 |
+ utils.Debugf("monitor: cmd.Wait reported exit status %s for container %s", err, container.ID)
|
|
| 967 | 970 |
} |
| 968 | 971 |
} |
| 969 |
- utils.Debugf("Process finished")
|
|
| 972 |
+ utils.Debugf("monitor: container %s finished", container.ID)
|
|
| 970 | 973 |
|
| 971 | 974 |
exitCode := -1 |
| 972 | 975 |
if container.cmd != nil {
|