diff --git a/hack/run-critest.sh b/hack/run-critest.sh index d6881ae431..3ed6c17e43 100755 --- a/hack/run-critest.sh +++ b/hack/run-critest.sh @@ -30,7 +30,8 @@ docker run --rm -v /usr/local/bin:/target jpetazzo/nsenter sleep 10 # Run e2e test cases -critest v +# Skip reopen container log test because docker doesn't support it. +critest --skip="runtime should support reopening container log" v # Run benchmark test cases critest b diff --git a/pkg/validate/container.go b/pkg/validate/container.go index 95bc2a83ca..38297cea6b 100644 --- a/pkg/validate/container.go +++ b/pkg/validate/container.go @@ -222,6 +222,36 @@ var _ = framework.KubeDescribe("Container", func() { } verifyLogContents(podConfig, logPath, expectedLogMessage) }) + + It("runtime should support reopening container log [Conformance]", func() { + By("create container with log") + logPath, containerID := createKeepLoggingContainer(rc, ic, "container-reopen-log-test-", podID, podConfig) + + By("start container with log") + startContainer(rc, containerID) + + Eventually(func() []logMessage { + return parseLogLine(podConfig, logPath) + }, time.Minute, time.Second).ShouldNot(BeEmpty(), "container log should be generated") + + By("rename container log") + newLogPath := logPath + ".new" + Expect(os.Rename(filepath.Join(podConfig.LogDirectory, logPath), + filepath.Join(podConfig.LogDirectory, newLogPath))).To(Succeed()) + + By("reopen container log") + Expect(rc.ReopenContainerLog(containerID)).To(Succeed()) + + Expect(pathExists(filepath.Join(podConfig.LogDirectory, logPath))).To( + BeTrue(), "new container log file should be created") + Eventually(func() []logMessage { + return parseLogLine(podConfig, logPath) + }, time.Minute, time.Second).ShouldNot(BeEmpty(), "new container log should be generated") + oldLength := len(parseLogLine(podConfig, newLogPath)) + Consistently(func() int { + return len(parseLogLine(podConfig, newLogPath)) + }, 5*time.Second, time.Second).Should(Equal(oldLength), "old container log should not change") + }) }) }) @@ -397,6 +427,20 @@ func createLogContainer(rc internalapi.RuntimeService, ic internalapi.ImageManag return containerConfig.LogPath, framework.CreateContainer(rc, ic, containerConfig, podID, podConfig) } +// createKeepLoggingContainer creates a container keeps logging defaultLog to output. +func createKeepLoggingContainer(rc internalapi.RuntimeService, ic internalapi.ImageManagerService, prefix string, podID string, podConfig *runtimeapi.PodSandboxConfig) (string, string) { + By("create a container with log and name") + containerName := prefix + framework.NewUUID() + path := fmt.Sprintf("%s.log", containerName) + containerConfig := &runtimeapi.ContainerConfig{ + Metadata: framework.BuildContainerMetadata(containerName, framework.DefaultAttempt), + Image: &runtimeapi.ImageSpec{Image: framework.DefaultContainerImage}, + Command: []string{"sh", "-c", "while true; do echo " + defaultLog + "; sleep 1; done"}, + LogPath: path, + } + return containerConfig.LogPath, framework.CreateContainer(rc, ic, containerConfig, podID, podConfig) +} + // pathExists check whether 'path' does exist or not func pathExists(path string) bool { _, err := os.Stat(path)