From fbc50e5285e960e6533e64a768dd4fb5615c8f7e Mon Sep 17 00:00:00 2001 From: Ashley Cui Date: Mon, 15 Feb 2021 15:36:33 -0500 Subject: fix journald logs --tail 0 Signed-off-by: Ashley Cui --- libpod/container_log_linux.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libpod') diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go index d895171cf..c9620100e 100644 --- a/libpod/container_log_linux.go +++ b/libpod/container_log_linux.go @@ -34,6 +34,8 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption var config journal.JournalReaderConfig if options.Tail < 0 { config.NumFromTail = 0 + } else if options.Tail == 0 { + config.NumFromTail = math.MaxUint64 } else { config.NumFromTail = uint64(options.Tail) } -- cgit v1.2.3-54-g00ecf From f2d057c943957dce99b49d291c2e1b96af31a9e5 Mon Sep 17 00:00:00 2001 From: Ashley Cui Date: Mon, 15 Feb 2021 15:37:45 -0500 Subject: Fix journald logs --since Signed-off-by: Ashley Cui --- libpod/container_log_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libpod') diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go index c9620100e..af46191d0 100644 --- a/libpod/container_log_linux.go +++ b/libpod/container_log_linux.go @@ -47,7 +47,7 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption if time.Now().Before(options.Since) { return nil } - config.Since = time.Since(options.Since) + config.Since = -time.Since(options.Since) } config.Matches = append(config.Matches, journal.Match{ Field: "CONTAINER_ID_FULL", -- cgit v1.2.3-54-g00ecf From 9016387bba45bd681d64e6b01f9c94f7bbb0448a Mon Sep 17 00:00:00 2001 From: Ashley Cui Date: Wed, 17 Feb 2021 15:02:22 -0500 Subject: Fix journald logs --follow Previously, --follow with a podman logs using journald would not exit Signed-off-by: Ashley Cui --- libpod/container_log_linux.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'libpod') diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go index af46191d0..713db9c1e 100644 --- a/libpod/container_log_linux.go +++ b/libpod/container_log_linux.go @@ -11,8 +11,10 @@ import ( "strings" "time" + "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/libpod/logs" journal "github.com/coreos/go-systemd/v22/sdjournal" + "github.com/hpcloud/tail/watch" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -65,8 +67,12 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption if options.Tail == math.MaxInt64 { r.Rewind() } + state, err := c.State() + if err != nil { + return err + } - if options.Follow { + if options.Follow && state == define.ContainerStateRunning { go func() { done := make(chan bool) until := make(chan time.Time) @@ -78,6 +84,21 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption // nothing to do anymore } }() + go func() { + for { + state, err := c.State() + if err != nil { + until <- time.Time{} + logrus.Error(err) + break + } + time.Sleep(watch.POLL_DURATION) + if state != define.ContainerStateRunning && state != define.ContainerStatePaused { + until <- time.Time{} + break + } + } + }() follower := FollowBuffer{logChannel} err := r.Follow(until, follower) if err != nil { -- cgit v1.2.3-54-g00ecf From 612ba6aa828d3c19b43f8420d99e0f1416f15cbf Mon Sep 17 00:00:00 2001 From: Ashley Cui Date: Wed, 17 Feb 2021 15:35:04 -0500 Subject: Fix journald logs with more than 1 container A podman logs on multiple containers will correctly display the container ID next to the log line Signed-off-by: Ashley Cui --- libpod/container_log_linux.go | 52 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) (limited to 'libpod') diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go index 713db9c1e..91ca216ea 100644 --- a/libpod/container_log_linux.go +++ b/libpod/container_log_linux.go @@ -8,7 +8,6 @@ import ( "fmt" "io" "math" - "strings" "time" "github.com/containers/podman/v2/libpod/define" @@ -41,7 +40,11 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption } else { config.NumFromTail = uint64(options.Tail) } - config.Formatter = journalFormatter + if options.Multi { + config.Formatter = journalFormatterWithID + } else { + config.Formatter = journalFormatter + } defaultTime := time.Time{} if options.Since != defaultTime { // coreos/go-systemd/sdjournal doesn't correctly handle requests for data in the future @@ -137,7 +140,45 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption return nil } +func journalFormatterWithID(entry *journal.JournalEntry) (string, error) { + // get + output, err := formatterPrefix(entry) + if err != nil { + return "", err + } + + id, ok := entry.Fields["CONTAINER_ID_FULL"] + if !ok { + return "", fmt.Errorf("no CONTAINER_ID_FULL field present in journal entry") + } + if len(id) > 12 { + id = id[:12] + } + output += fmt.Sprintf("%s ", id) + // Append message + msg, err := formatterMessage(entry) + if err != nil { + return "", err + } + output += msg + return output, nil +} + func journalFormatter(entry *journal.JournalEntry) (string, error) { + output, err := formatterPrefix(entry) + if err != nil { + return "", err + } + // Append message + msg, err := formatterMessage(entry) + if err != nil { + return "", err + } + output += msg + return output, nil +} + +func formatterPrefix(entry *journal.JournalEntry) (string, error) { usec := entry.RealtimeTimestamp tsString := time.Unix(0, int64(usec)*int64(time.Microsecond)).Format(logs.LogTimeFormat) output := fmt.Sprintf("%s ", tsString) @@ -160,13 +201,16 @@ func journalFormatter(entry *journal.JournalEntry) (string, error) { output += fmt.Sprintf("%s ", logs.FullLogType) } + return output, nil +} + +func formatterMessage(entry *journal.JournalEntry) (string, error) { // Finally, append the message msg, ok := entry.Fields["MESSAGE"] if !ok { return "", fmt.Errorf("no MESSAGE field present in journal entry") } - output += strings.TrimSpace(msg) - return output, nil + return msg, nil } type FollowBuffer struct { -- cgit v1.2.3-54-g00ecf From 05eb06f5686be1a14f33cdc0c23785d6da0feccb Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Wed, 17 Feb 2021 23:06:43 -0500 Subject: Turn on journald and k8s file logging tests Signed-off-by: Ashley Cui --- libpod/container_log_linux.go | 1 - test/e2e/logs_test.go | 622 +++++++++++++++++++++--------------------- test/utils/utils.go | 10 + 3 files changed, 319 insertions(+), 314 deletions(-) (limited to 'libpod') diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go index 91ca216ea..b1f601a4c 100644 --- a/libpod/container_log_linux.go +++ b/libpod/container_log_linux.go @@ -141,7 +141,6 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption } func journalFormatterWithID(entry *journal.JournalEntry) (string, error) { - // get output, err := formatterPrefix(entry) if err != nil { return "", err diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go index b370aeec1..1b9d26c49 100644 --- a/test/e2e/logs_test.go +++ b/test/e2e/logs_test.go @@ -36,345 +36,341 @@ var _ = Describe("Podman logs", func() { }) - It("all lines", func() { - logc := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - - cid := logc.OutputToString() - results := podmanTest.Podman([]string{"logs", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(len(results.OutputToStringArray())).To(Equal(3)) - }) - - It("tail two lines", func() { - logc := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - - results := podmanTest.Podman([]string{"logs", "--tail", "2", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(len(results.OutputToStringArray())).To(Equal(2)) - }) - - It("tail zero lines", func() { - logc := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - - results := podmanTest.Podman([]string{"logs", "--tail", "0", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(len(results.OutputToStringArray())).To(Equal(0)) - }) - - It("tail 800 lines", func() { - logc := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "i=1; while [ \"$i\" -ne 1000 ]; do echo \"line $i\"; i=$((i + 1)); done"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - - results := podmanTest.Podman([]string{"logs", "--tail", "800", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(len(results.OutputToStringArray())).To(Equal(800)) - }) - - It("tail 2 lines with timestamps", func() { - logc := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - - results := podmanTest.Podman([]string{"logs", "--tail", "2", "-t", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(len(results.OutputToStringArray())).To(Equal(2)) - }) - - It("since time 2017-08-07", func() { - logc := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - - results := podmanTest.Podman([]string{"logs", "--since", "2017-08-07T10:10:09.056611202-04:00", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(len(results.OutputToStringArray())).To(Equal(3)) - }) - - It("since duration 10m", func() { - logc := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - - results := podmanTest.Podman([]string{"logs", "--since", "10m", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(len(results.OutputToStringArray())).To(Equal(3)) - }) - - It("latest and container name should fail", func() { - results := podmanTest.Podman([]string{"logs", "-l", "foobar"}) - results.WaitWithDefaultTimeout() - Expect(results).To(ExitWithError()) - }) - - It("two containers showing short container IDs", func() { - SkipIfRemote("FIXME: podman-remote logs does not support showing two containers at the same time") - log1 := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - log1.WaitWithDefaultTimeout() - Expect(log1.ExitCode()).To(Equal(0)) - cid1 := log1.OutputToString() - - log2 := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - log2.WaitWithDefaultTimeout() - Expect(log2.ExitCode()).To(Equal(0)) - cid2 := log2.OutputToString() - - results := podmanTest.Podman([]string{"logs", cid1, cid2}) - results.WaitWithDefaultTimeout() - Expect(results).Should(Exit(0)) - - output := results.OutputToStringArray() - Expect(len(output)).To(Equal(6)) - Expect(strings.Contains(output[0], cid1[:12]) || strings.Contains(output[0], cid2[:12])).To(BeTrue()) - }) - - It("podman logs on a created container should result in 0 exit code", func() { - session := podmanTest.Podman([]string{"create", "-t", "--name", "log", ALPINE}) - session.WaitWithDefaultTimeout() - Expect(session).To(Exit(0)) - - results := podmanTest.Podman([]string{"logs", "log"}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - }) + for _, log := range []string{"k8s-file", "journald", "json-file"} { + It("all lines: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + + cid := logc.OutputToString() + results := podmanTest.Podman([]string{"logs", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(len(results.OutputToStringArray())).To(Equal(3)) + }) + + It("tail two lines: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--tail", "2", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(len(results.OutputToStringArray())).To(Equal(2)) + }) + + It("tail zero lines: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--tail", "0", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(len(results.OutputToStringArray())).To(Equal(0)) + }) + + It("tail 800 lines: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "i=1; while [ \"$i\" -ne 1000 ]; do echo \"line $i\"; i=$((i + 1)); done"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--tail", "800", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(len(results.OutputToStringArray())).To(Equal(800)) + }) + + It("tail 2 lines with timestamps: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--tail", "2", "-t", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(len(results.OutputToStringArray())).To(Equal(2)) + }) + + It("since time 2017-08-07: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--since", "2017-08-07T10:10:09.056611202-04:00", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(len(results.OutputToStringArray())).To(Equal(3)) + }) + + It("since duration 10m: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--since", "10m", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(len(results.OutputToStringArray())).To(Equal(3)) + }) + + It("latest and container name should fail: "+log, func() { + results := podmanTest.Podman([]string{"logs", "-l", "foobar"}) + results.WaitWithDefaultTimeout() + Expect(results).To(ExitWithError()) + }) + + It("two containers showing short container IDs: "+log, func() { + SkipIfRemote("FIXME: podman-remote logs does not support showing two containers at the same time") + log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + log1.WaitWithDefaultTimeout() + Expect(log1.ExitCode()).To(Equal(0)) + cid1 := log1.OutputToString() + + log2 := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + log2.WaitWithDefaultTimeout() + Expect(log2.ExitCode()).To(Equal(0)) + cid2 := log2.OutputToString() + + results := podmanTest.Podman([]string{"logs", cid1, cid2}) + results.WaitWithDefaultTimeout() + Expect(results).Should(Exit(0)) + + output := results.OutputToStringArray() + Expect(len(output)).To(Equal(6)) + Expect(strings.Contains(output[0], cid1[:12]) || strings.Contains(output[0], cid2[:12])).To(BeTrue()) + }) + + It("podman logs on a created container should result in 0 exit code: "+log, func() { + session := podmanTest.Podman([]string{"create", "-t", "--name", "log", ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session).To(Exit(0)) + + results := podmanTest.Podman([]string{"logs", "log"}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + }) + + It("for container: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(len(results.OutputToStringArray())).To(Equal(3)) + Expect(results.OutputToString()).To(Equal("podman podman podman")) + }) + + It("tail two lines: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() + results := podmanTest.Podman([]string{"logs", "--tail", "2", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(len(results.OutputToStringArray())).To(Equal(2)) + }) + + It("tail 99 lines: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--tail", "99", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(len(results.OutputToStringArray())).To(Equal(3)) + }) + + It("tail 2 lines with timestamps: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--tail", "2", "-t", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(len(results.OutputToStringArray())).To(Equal(2)) + }) + + It("since time 2017-08-07: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--since", "2017-08-07T10:10:09.056611202-04:00", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(len(results.OutputToStringArray())).To(Equal(3)) + }) + + It("with duration 10m: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--since", "10m", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(len(results.OutputToStringArray())).To(Equal(3)) + }) + + It("streaming output: "+log, func() { + containerName := "logs-f-rm" + + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--rm", "--name", containerName, "-dt", ALPINE, "sh", "-c", "echo podman; sleep 1; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + + results := podmanTest.Podman([]string{"logs", "-f", containerName}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + + // TODO: we should actually check for two podman lines, + // but as of 2020-06-17 there's a race condition in which + // 'logs -f' may not catch all output from a container + Expect(results.OutputToString()).To(ContainSubstring("podman")) + + // Container should now be terminatING or terminatED, but we + // have no guarantee of which: 'logs -f' does not necessarily + // wait for cleanup. Run 'inspect' and accept either state. + inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.State.Status}}", containerName}) + inspect.WaitWithDefaultTimeout() + if inspect.ExitCode() == 0 { + Expect(inspect.OutputToString()).To(Equal("exited")) + // TODO: add 2-second wait loop to confirm cleanup + } else { + Expect(inspect.ErrorToString()).To(ContainSubstring("no such container")) + } + }) + + It("podman logs with log-driver=none errors: "+log, func() { + ctrName := "logsctr" + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", ctrName, "-d", "--log-driver", "none", ALPINE, "top"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + + logs := podmanTest.Podman([]string{"logs", "-f", ctrName}) + logs.WaitWithDefaultTimeout() + Expect(logs).To(Not(Exit(0))) + }) + + It("follow output stopped container: "+log, func() { + containerName := "logs-f" + + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName, "-d", ALPINE, "true"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + + results := podmanTest.Podman([]string{"logs", "-f", containerName}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + }) + + It("using container with container log-size: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--log-opt=max-size=10k", "-d", ALPINE, "sh", "-c", "echo podman podman podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() + + wait := podmanTest.Podman([]string{"wait", cid}) + wait.WaitWithDefaultTimeout() + Expect(wait).To(Exit(0)) + + inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.HostConfig.LogConfig.Size}}", cid}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).To(Exit(0)) + Expect(inspect.OutputToString()).To(Equal("10kB")) + + results := podmanTest.Podman([]string{"logs", cid}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(results.OutputToString()).To(Equal("podman podman podman")) + }) + + It("Make sure logs match expected length: "+log, func() { + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-t", "--name", "test", ALPINE, "sh", "-c", "echo 1; echo 2"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + + wait := podmanTest.Podman([]string{"wait", "test"}) + wait.WaitWithDefaultTimeout() + Expect(wait).To(Exit(0)) + + results := podmanTest.Podman([]string{"logs", "test"}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + outlines := results.OutputToStringArray() + Expect(len(outlines)).To(Equal(2)) + Expect(outlines[0]).To(Equal("1\r")) + Expect(outlines[1]).To(Equal("2\r")) + }) + + It("podman logs test stdout and stderr: "+log, func() { + cname := "log-test" + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", cname, ALPINE, "sh", "-c", "echo stdout; echo stderr >&2"}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + + wait := podmanTest.Podman([]string{"wait", cname}) + wait.WaitWithDefaultTimeout() + Expect(wait).To(Exit(0)) + + results := podmanTest.Podman([]string{"logs", cname}) + results.WaitWithDefaultTimeout() + Expect(results).To(Exit(0)) + Expect(results.OutputToString()).To(Equal("stdout")) + Expect(results.ErrorToString()).To(Equal("stderr")) + }) + } It("using journald for container with container tag", func() { - Skip("need to verify images have correct packages for journald") + SkipIfInContainer("journalctl inside a container doesn't work correctly") logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "--log-opt=tag={{.ImageName}}", "-d", ALPINE, "sh", "-c", "echo podman; sleep 0.1; echo podman; sleep 0.1; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) cid := logc.OutputToString() - wait := podmanTest.Podman([]string{"wait", "-l"}) + wait := podmanTest.Podman([]string{"wait", cid}) wait.WaitWithDefaultTimeout() Expect(wait).To(Exit(0)) - cmd := exec.Command("journalctl", "--no-pager", "-o", "json", "--output-fields=CONTAINER_TAG", "-u", fmt.Sprintf("libpod-conmon-%s.scope", cid)) + cmd := exec.Command("journalctl", "--no-pager", "-o", "json", "--output-fields=CONTAINER_TAG", fmt.Sprintf("CONTAINER_ID_FULL=%s", cid)) out, err := cmd.CombinedOutput() Expect(err).To(BeNil()) Expect(string(out)).To(ContainSubstring("alpine")) }) - It("using journald for container name", func() { - Skip("need to verify images have correct packages for journald") + It("using journald container name", func() { + SkipIfInContainer("journalctl inside a container doesn't work correctly") containerName := "inside-journal" logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-d", "--name", containerName, ALPINE, "sh", "-c", "echo podman; sleep 0.1; echo podman; sleep 0.1; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) cid := logc.OutputToString() - wait := podmanTest.Podman([]string{"wait", "-l"}) + wait := podmanTest.Podman([]string{"wait", cid}) wait.WaitWithDefaultTimeout() Expect(wait).To(Exit(0)) - cmd := exec.Command("journalctl", "--no-pager", "-o", "json", "--output-fields=CONTAINER_NAME", "-u", fmt.Sprintf("libpod-conmon-%s.scope", cid)) + cmd := exec.Command("journalctl", "--no-pager", "-o", "json", "--output-fields=CONTAINER_NAME", fmt.Sprintf("CONTAINER_ID_FULL=%s", cid)) out, err := cmd.CombinedOutput() Expect(err).To(BeNil()) Expect(string(out)).To(ContainSubstring(containerName)) }) - - It("using journald for container", func() { - Skip("need to verify images have correct packages for journald") - logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - - results := podmanTest.Podman([]string{"logs", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(len(results.OutputToStringArray())).To(Equal(3)) - Expect(results.OutputToString()).To(Equal("podman podman podman")) - }) - - It("using journald tail two lines", func() { - Skip("need to verify images have correct packages for journald") - logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - results := podmanTest.Podman([]string{"logs", "--tail", "2", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(len(results.OutputToStringArray())).To(Equal(2)) - }) - - It("using journald tail 99 lines", func() { - Skip("need to verify images have correct packages for journald") - logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - - results := podmanTest.Podman([]string{"logs", "--tail", "99", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(len(results.OutputToStringArray())).To(Equal(3)) - }) - - It("using journald tail 2 lines with timestamps", func() { - Skip("need to verify images have correct packages for journald") - logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - - results := podmanTest.Podman([]string{"logs", "--tail", "2", "-t", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(len(results.OutputToStringArray())).To(Equal(2)) - }) - - It("using journald since time 2017-08-07", func() { - Skip("need to verify images have correct packages for journald") - logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - - results := podmanTest.Podman([]string{"logs", "--since", "2017-08-07T10:10:09.056611202-04:00", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(len(results.OutputToStringArray())).To(Equal(3)) - }) - - It("using journald with duration 10m", func() { - Skip("need to verify images have correct packages for journald") - logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - - results := podmanTest.Podman([]string{"logs", "--since", "10m", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(len(results.OutputToStringArray())).To(Equal(3)) - }) - - It("streaming output", func() { - containerName := "logs-f-rm" - - logc := podmanTest.Podman([]string{"run", "--rm", "--name", containerName, "-dt", ALPINE, "sh", "-c", "echo podman; sleep 1; echo podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - - results := podmanTest.Podman([]string{"logs", "-f", containerName}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - - // TODO: we should actually check for two podman lines, - // but as of 2020-06-17 there's a race condition in which - // 'logs -f' may not catch all output from a container - Expect(results.OutputToString()).To(ContainSubstring("podman")) - - // Container should now be terminatING or terminatED, but we - // have no guarantee of which: 'logs -f' does not necessarily - // wait for cleanup. Run 'inspect' and accept either state. - inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.State.Status}}", containerName}) - inspect.WaitWithDefaultTimeout() - if inspect.ExitCode() == 0 { - Expect(inspect.OutputToString()).To(Equal("exited")) - // TODO: add 2-second wait loop to confirm cleanup - } else { - Expect(inspect.ErrorToString()).To(ContainSubstring("no such container")) - } - }) - - It("podman logs with log-driver=none errors", func() { - ctrName := "logsctr" - logc := podmanTest.Podman([]string{"run", "--name", ctrName, "-d", "--log-driver", "none", ALPINE, "top"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - - logs := podmanTest.Podman([]string{"logs", "-f", ctrName}) - logs.WaitWithDefaultTimeout() - Expect(logs).To(Not(Exit(0))) - }) - - It("follow output stopped container", func() { - containerName := "logs-f" - - logc := podmanTest.Podman([]string{"run", "--name", containerName, "-d", ALPINE, "true"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - - results := podmanTest.Podman([]string{"logs", "-f", containerName}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - }) - - It("using container with container log-size", func() { - logc := podmanTest.Podman([]string{"run", "--log-opt=max-size=10k", "-d", ALPINE, "sh", "-c", "echo podman podman podman"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - - wait := podmanTest.Podman([]string{"wait", cid}) - wait.WaitWithDefaultTimeout() - Expect(wait).To(Exit(0)) - - inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.HostConfig.LogConfig.Size}}", cid}) - inspect.WaitWithDefaultTimeout() - Expect(inspect).To(Exit(0)) - Expect(inspect.OutputToString()).To(Equal("10kB")) - - results := podmanTest.Podman([]string{"logs", cid}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(results.OutputToString()).To(Equal("podman podman podman")) - }) - - It("Make sure logs match expected length", func() { - logc := podmanTest.Podman([]string{"run", "-t", "--name", "test", ALPINE, "sh", "-c", "echo 1; echo 2"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - - wait := podmanTest.Podman([]string{"wait", "test"}) - wait.WaitWithDefaultTimeout() - Expect(wait).To(Exit(0)) - - results := podmanTest.Podman([]string{"logs", "test"}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - outlines := results.OutputToStringArray() - Expect(len(outlines)).To(Equal(2)) - Expect(outlines[0]).To(Equal("1\r")) - Expect(outlines[1]).To(Equal("2\r")) - }) - - It("podman logs test stdout and stderr", func() { - cname := "log-test" - logc := podmanTest.Podman([]string{"run", "--name", cname, ALPINE, "sh", "-c", "echo stdout; echo stderr >&2"}) - logc.WaitWithDefaultTimeout() - Expect(logc).To(Exit(0)) - - wait := podmanTest.Podman([]string{"wait", cname}) - wait.WaitWithDefaultTimeout() - Expect(wait).To(Exit(0)) - - results := podmanTest.Podman([]string{"logs", cname}) - results.WaitWithDefaultTimeout() - Expect(results).To(Exit(0)) - Expect(results.OutputToString()).To(Equal("stdout")) - Expect(results.ErrorToString()).To(Equal("stderr")) - }) }) diff --git a/test/utils/utils.go b/test/utils/utils.go index 6790f31cd..80af7fb7c 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -482,3 +482,13 @@ func RandomString(n int) string { } return string(b) } + +//SkipIfInContainer skips a test if the test is run inside a container +func SkipIfInContainer(reason string) { + if len(reason) < 5 { + panic("SkipIfInContainer must specify a reason to skip") + } + if os.Getenv("TEST_ENVIRON") == "container" { + Skip("[container]: " + reason) + } +} -- cgit v1.2.3-54-g00ecf