Przeglądaj źródła

Merge pull request #4925 from creack/fix_logs

Fix expending buffer in StdCopy
unclejack 11 lat temu
rodzic
commit
e76113be6c
2 zmienionych plików z 79 dodań i 2 usunięć
  1. 76 0
      integration-cli/docker_cli_logs_test.go
  2. 3 2
      utils/stdcopy.go

+ 76 - 0
integration-cli/docker_cli_logs_test.go

@@ -0,0 +1,76 @@
+package main
+
+import (
+	"fmt"
+	"os/exec"
+	"testing"
+)
+
+// This used to work, it test a log of PageSize-1 (gh#4851)
+func TestLogsContainerSmallerThanPage(t *testing.T) {
+	testLen := 32767
+	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
+	errorOut(err, t, fmt.Sprintf("run failed with errors: %v", err))
+
+	cleanedContainerID := stripTrailingCharacters(out)
+	exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
+
+	logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
+	out, _, _, err = runCommandWithStdoutStderr(logsCmd)
+	errorOut(err, t, fmt.Sprintf("failed to log container: %v %v", out, err))
+
+	if len(out) != testLen+1 {
+		t.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
+	}
+
+	go deleteContainer(cleanedContainerID)
+
+	logDone("logs - logs container running echo smaller than page size")
+}
+
+// Regression test: When going over the PageSize, it used to panic (gh#4851)
+func TestLogsContainerBiggerThanPage(t *testing.T) {
+	testLen := 32768
+	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
+	errorOut(err, t, fmt.Sprintf("run failed with errors: %v", err))
+
+	cleanedContainerID := stripTrailingCharacters(out)
+	exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
+
+	logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
+	out, _, _, err = runCommandWithStdoutStderr(logsCmd)
+	errorOut(err, t, fmt.Sprintf("failed to log container: %v %v", out, err))
+
+	if len(out) != testLen+1 {
+		t.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
+	}
+
+	go deleteContainer(cleanedContainerID)
+
+	logDone("logs - logs container running echo bigger than page size")
+}
+
+// Regression test: When going much over the PageSize, it used to block (gh#4851)
+func TestLogsContainerMuchBiggerThanPage(t *testing.T) {
+	testLen := 33000
+	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
+	errorOut(err, t, fmt.Sprintf("run failed with errors: %v", err))
+
+	cleanedContainerID := stripTrailingCharacters(out)
+	exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
+
+	logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
+	out, _, _, err = runCommandWithStdoutStderr(logsCmd)
+	errorOut(err, t, fmt.Sprintf("failed to log container: %v %v", out, err))
+
+	if len(out) != testLen+1 {
+		t.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
+	}
+
+	go deleteContainer(cleanedContainerID)
+
+	logDone("logs - logs container running echo much bigger than page size")
+}

+ 3 - 2
utils/stdcopy.go

@@ -108,12 +108,13 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error)
 
 		// Retrieve the size of the frame
 		frameSize = int(binary.BigEndian.Uint32(buf[StdWriterSizeIndex : StdWriterSizeIndex+4]))
+		Debugf("framesize: %d", frameSize)
 
 		// Check if the buffer is big enough to read the frame.
 		// Extend it if necessary.
 		if frameSize+StdWriterPrefixLen > bufLen {
-			Debugf("Extending buffer cap.")
-			buf = append(buf, make([]byte, frameSize-len(buf)+1)...)
+			Debugf("Extending buffer cap by %d (was %d)", frameSize+StdWriterPrefixLen-bufLen+1, len(buf))
+			buf = append(buf, make([]byte, frameSize+StdWriterPrefixLen-bufLen+1)...)
 			bufLen = len(buf)
 		}