Browse code

Fix error/debug messages in Container.Attach and recover from ErrClosedPipe conditions.

Jérôme Petazzoni authored on 2013/10/17 02:41:36
Showing 1 changed files
... ...
@@ -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 {