From f51e0d0597757da72fd7a10085998052684e396b Mon Sep 17 00:00:00 2001 From: Jhon Honce Date: Wed, 20 May 2020 14:24:18 -0700 Subject: V2 enable remote logs and testing * wire up bindings and handler for obtaining logs remotely * enable debug logging from podman in e2e test using DEBUG and DEBUG_SERVICE env variables * Fix error in streaming log frames * enable remote logs test Signed-off-by: Jhon Honce --- cmd/podman/containers/logs.go | 24 ++++--- pkg/api/handlers/compat/containers.go | 27 ++++---- pkg/bindings/containers/containers.go | 7 +- pkg/bindings/containers/logs.go | 77 +++++++--------------- pkg/bindings/test/containers_test.go | 4 +- pkg/domain/infra/tunnel/containers.go | 35 +++++++++- test/e2e/libpod_suite_remote_test.go | 9 ++- test/e2e/logs_test.go | 117 +++++++++++++++++----------------- 8 files changed, 156 insertions(+), 144 deletions(-) diff --git a/cmd/podman/containers/logs.go b/cmd/podman/containers/logs.go index 2b8c3ed5f..de5234044 100644 --- a/cmd/podman/containers/logs.go +++ b/cmd/podman/containers/logs.go @@ -29,7 +29,18 @@ var ( Use: "logs [flags] CONTAINER [CONTAINER...]", Short: "Fetch the logs of one or more containers", Long: logsDescription, - RunE: logs, + Args: func(cmd *cobra.Command, args []string) error { + switch { + case registry.IsRemote() && len(args) > 1: + return errors.New(cmd.Name() + " does not support multiple containers when run remotely") + case logsOptions.Latest && len(args) > 0: + return errors.New("no containers can be specified when using 'latest'") + case !logsOptions.Latest && len(args) < 1: + return errors.New("specify at least one container name or ID to log") + } + return nil + }, + RunE: logs, Example: `podman logs ctrID podman logs --names ctrID1 ctrID2 podman logs --tail 2 mywebserver @@ -41,6 +52,7 @@ var ( Use: logsCommand.Use, Short: logsCommand.Short, Long: logsCommand.Long, + Args: logsCommand.Args, RunE: logsCommand.RunE, Example: `podman container logs ctrID podman container logs --names ctrID1 ctrID2 @@ -53,7 +65,7 @@ var ( func init() { // logs registry.Commands = append(registry.Commands, registry.CliCommand{ - Mode: []entities.EngineMode{entities.ABIMode}, + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: logsCommand, }) @@ -62,7 +74,7 @@ func init() { // container logs registry.Commands = append(registry.Commands, registry.CliCommand{ - Mode: []entities.EngineMode{entities.ABIMode}, + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: containerLogsCommand, Parent: containerCmd, }) @@ -84,12 +96,6 @@ func logsFlags(flags *pflag.FlagSet) { } func logs(cmd *cobra.Command, args []string) error { - if len(args) > 0 && logsOptions.Latest { - return errors.New("no containers can be specified when using 'latest'") - } - if !logsOptions.Latest && len(args) < 1 { - return errors.New("specify at least one container name or ID to log") - } if logsOptions.SinceRaw != "" { // parse time, error out if something is wrong since, err := util.ParseInputTime(logsOptions.SinceRaw) diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index 239e41af4..cea4bd0f6 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "encoding/json" "fmt" + "io" "net/http" "strconv" "strings" @@ -295,7 +296,9 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) { }() w.WriteHeader(http.StatusOK) - var builder strings.Builder + + var frame strings.Builder + header := make([]byte, 8) for ok := true; ok; ok = query.Follow { for line := range logChannel { if _, found := r.URL.Query()["until"]; found { @@ -304,10 +307,8 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) { } } - // Reset variables we're ready to loop again - builder.Reset() - header := [8]byte{} - + // Reset buffer we're ready to loop again + frame.Reset() switch line.Device { case "stdout": if !query.Stdout { @@ -327,17 +328,17 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) { } if query.Timestamps { - builder.WriteString(line.Time.Format(time.RFC3339)) - builder.WriteRune(' ') + frame.WriteString(line.Time.Format(time.RFC3339)) + frame.WriteString(" ") } - builder.WriteString(line.Msg) - // Build header and output entry - binary.BigEndian.PutUint32(header[4:], uint32(len(header)+builder.Len())) - if _, err := w.Write(header[:]); err != nil { + frame.WriteString(line.Msg) + + binary.BigEndian.PutUint32(header[4:], uint32(frame.Len())) + if _, err := w.Write(header[0:8]); err != nil { log.Errorf("unable to write log output header: %q", err) } - if _, err := fmt.Fprint(w, builder.String()); err != nil { - log.Errorf("unable to write builder string: %q", err) + if _, err := io.WriteString(w, frame.String()); err != nil { + log.Errorf("unable to write frame string: %q", err) } if flusher, ok := w.(http.Flusher); ok { flusher.Flush() diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go index 1ed4919e0..39a077f36 100644 --- a/pkg/bindings/containers/containers.go +++ b/pkg/bindings/containers/containers.go @@ -23,7 +23,7 @@ import ( ) var ( - ErrLostSync = errors.New("lost synchronization with attach multiplexed result") + ErrLostSync = errors.New("lost synchronization with multiplexed stream") ) // List obtains a list of containers in local storage. All parameters to this method are optional. @@ -485,7 +485,7 @@ func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stre return err } case fd == 3: - return fmt.Errorf("error from daemon in stream: %s", frame) + return errors.New("error from service in stream: " + string(frame)) default: return fmt.Errorf("unrecognized input header: %d", fd) } @@ -507,7 +507,7 @@ func DemuxHeader(r io.Reader, buffer []byte) (fd, sz int, err error) { fd = int(buffer[0]) if fd < 0 || fd > 3 { - err = ErrLostSync + err = errors.Wrapf(ErrLostSync, fmt.Sprintf(`channel "%d" found, 0-3 supported`, fd)) return } @@ -528,7 +528,6 @@ func DemuxFrame(r io.Reader, buffer []byte, length int) (frame []byte, err error err = io.ErrUnexpectedEOF return } - return buffer[0:length], nil } diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go index b7ecb3c7e..20c8b4292 100644 --- a/pkg/bindings/containers/logs.go +++ b/pkg/bindings/containers/logs.go @@ -1,8 +1,9 @@ package containers import ( + "bytes" "context" - "encoding/binary" + "fmt" "io" "net/http" "net/url" @@ -49,68 +50,34 @@ func Logs(ctx context.Context, nameOrID string, opts LogOptions, stdoutChan, std if err != nil { return err } + defer response.Body.Close() - // read 8 bytes - // first byte determines stderr=2|stdout=1 - // bytes 4-7 len(msg) in uint32 + buffer := make([]byte, 1024) for { - stream, msgSize, err := readHeader(response.Body) + fd, l, err := DemuxHeader(response.Body, buffer) if err != nil { - // In case the server side closes up shop because !follow - if err == io.EOF { - break + if errors.Is(err, io.EOF) { + return nil } - return errors.Wrap(err, "unable to read log header") + return err } - msg, err := readMsg(response.Body, msgSize) + frame, err := DemuxFrame(response.Body, buffer, l) if err != nil { - return errors.Wrap(err, "unable to read log message") + return err } - if stream == 1 { - stdoutChan <- msg - } else { - stderrChan <- msg - } - } - return nil -} + frame = bytes.Replace(frame[0:l], []byte{13}, []byte{10}, -1) -func readMsg(r io.Reader, msgSize int) (string, error) { - var msg []byte - size := msgSize - for { - b := make([]byte, size) - _, err := r.Read(b) - if err != nil { - return "", err - } - msg = append(msg, b...) - if len(msg) == msgSize { - break - } - size = msgSize - len(msg) - } - return string(msg), nil -} - -func readHeader(r io.Reader) (byte, int, error) { - var ( - header []byte - size = 8 - ) - for { - b := make([]byte, size) - _, err := r.Read(b) - if err != nil { - return 0, 0, err - } - header = append(header, b...) - if len(header) == 8 { - break + switch fd { + case 0: + stdoutChan <- string(frame) + case 1: + stdoutChan <- string(frame) + case 2: + stderrChan <- string(frame) + case 3: + return errors.New("error from service in stream: " + string(frame)) + default: + return fmt.Errorf("unrecognized input header: %d", fd) } - size = 8 - len(header) } - stream := header[0] - msgSize := int(binary.BigEndian.Uint32(header[4:]) - 8) - return stream, msgSize, nil } diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go index f725d1cf2..3b94b10eb 100644 --- a/pkg/bindings/test/containers_test.go +++ b/pkg/bindings/test/containers_test.go @@ -378,9 +378,9 @@ var _ = Describe("Podman containers ", func() { containers.Logs(bt.conn, r.ID, opts, stdoutChan, nil) }() o := <-stdoutChan - o = strings.ReplaceAll(o, "\r", "") + o = strings.TrimSpace(o) _, err = time.Parse(time.RFC1123Z, o) - Expect(err).To(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) }) It("podman top", func() { diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 30c4a8359..beba55c2b 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -4,7 +4,9 @@ import ( "context" "io" "os" + "strconv" "strings" + "time" "github.com/containers/common/pkg/config" "github.com/containers/image/v5/docker/reference" @@ -336,9 +338,36 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG return &entities.ContainerCreateReport{Id: response.ID}, nil } -func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error { - // The endpoint is not ready yet and requires some more work. - return errors.New("not implemented yet") +func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIds []string, options entities.ContainerLogsOptions) error { + since := options.Since.Format(time.RFC3339) + tail := strconv.FormatInt(options.Tail, 10) + stdout := options.Writer != nil + opts := containers.LogOptions{ + Follow: &options.Follow, + Since: &since, + Stderr: &stdout, + Stdout: &stdout, + Tail: &tail, + Timestamps: &options.Timestamps, + Until: nil, + } + + var err error + outCh := make(chan string) + ctx, cancel := context.WithCancel(context.Background()) + go func() { + err = containers.Logs(ic.ClientCxt, nameOrIds[0], opts, outCh, outCh) + cancel() + }() + + for { + select { + case <-ctx.Done(): + return err + case line := <-outCh: + _, _ = io.WriteString(options.Writer, line) + } + } } func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string, options entities.AttachOptions) error { diff --git a/test/e2e/libpod_suite_remote_test.go b/test/e2e/libpod_suite_remote_test.go index 79d18115c..e8cdf91ee 100644 --- a/test/e2e/libpod_suite_remote_test.go +++ b/test/e2e/libpod_suite_remote_test.go @@ -89,10 +89,17 @@ func (p *PodmanTestIntegration) StartRemoteService() { if os.Geteuid() == 0 { os.MkdirAll("/run/podman", 0755) } + + args := []string{} + if _, found := os.LookupEnv("DEBUG_SERVICE"); found { + args = append(args, "--log-level", "debug") + } remoteSocket := p.RemoteSocket - args := []string{"system", "service", "--timeout", "0", remoteSocket} + args = append(args, "system", "service", "--timeout", "0", remoteSocket) podmanOptions := getRemoteOptions(p, args) command := exec.Command(p.PodmanBinary, podmanOptions...) + command.Stdout = os.Stdout + command.Stderr = os.Stderr fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " ")) command.Start() command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go index 8924db670..f36163ccc 100644 --- a/test/e2e/logs_test.go +++ b/test/e2e/logs_test.go @@ -9,6 +9,7 @@ import ( . "github.com/containers/libpod/test/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gexec" ) var _ = Describe("Podman logs", func() { @@ -19,7 +20,6 @@ var _ = Describe("Podman logs", func() { ) BeforeEach(func() { - SkipIfRemote() // v2remotefail tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) @@ -36,97 +36,99 @@ var _ = Describe("Podman logs", func() { }) - It("podman logs for container", func() { + It("all lines", func() { logc := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() - Expect(logc.ExitCode()).To(Equal(0)) - cid := logc.OutputToString() + Expect(logc).To(Exit(0)) + cid := logc.OutputToString() results := podmanTest.Podman([]string{"logs", cid}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) Expect(len(results.OutputToStringArray())).To(Equal(3)) }) - It("podman logs tail two lines", func() { + It("tail two lines", func() { logc := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() - Expect(logc.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) cid := logc.OutputToString() results := podmanTest.Podman([]string{"logs", "--tail", "2", cid}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) Expect(len(results.OutputToStringArray())).To(Equal(2)) }) - It("podman logs tail zero lines", func() { + It("tail zero lines", func() { logc := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() - Expect(logc.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) cid := logc.OutputToString() results := podmanTest.Podman([]string{"logs", "--tail", "0", cid}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) Expect(len(results.OutputToStringArray())).To(Equal(0)) }) - It("podman logs tail 99 lines", func() { + It("tail 99 lines", func() { logc := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() - Expect(logc.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) cid := logc.OutputToString() results := podmanTest.Podman([]string{"logs", "--tail", "99", cid}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) Expect(len(results.OutputToStringArray())).To(Equal(3)) }) - It("podman logs tail 2 lines with timestamps", func() { + 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.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) cid := logc.OutputToString() results := podmanTest.Podman([]string{"logs", "--tail", "2", "-t", cid}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) Expect(len(results.OutputToStringArray())).To(Equal(2)) }) - It("podman logs latest with since time", func() { + 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.ExitCode()).To(Equal(0)) + 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.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) Expect(len(results.OutputToStringArray())).To(Equal(3)) }) - It("podman logs latest with since duration", func() { + It("since duration 10m", func() { logc := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() - Expect(logc.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) cid := logc.OutputToString() results := podmanTest.Podman([]string{"logs", "--since", "10m", cid}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) Expect(len(results.OutputToStringArray())).To(Equal(3)) }) - It("podman logs latest and container name should fail", func() { + It("latest and container name should fail", func() { + SkipIfRemote() // -l not supported results := podmanTest.Podman([]string{"logs", "-l", "foobar"}) results.WaitWithDefaultTimeout() Expect(results).To(ExitWithError()) }) - It("podman logs two containers and should display short container IDs", func() { + It("two containers showing short container IDs", func() { + SkipIfRemote() // remote does not support multiple containers log1 := podmanTest.Podman([]string{"run", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) log1.WaitWithDefaultTimeout() Expect(log1.ExitCode()).To(Equal(0)) @@ -139,7 +141,7 @@ var _ = Describe("Podman logs", func() { results := podmanTest.Podman([]string{"logs", cid1, cid2}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) + Expect(results).Should(Exit(0)) output := results.OutputToStringArray() Expect(len(output)).To(Equal(6)) @@ -149,23 +151,24 @@ var _ = Describe("Podman logs", func() { It("podman logs on a created container should result in 0 exit code", func() { session := podmanTest.Podman([]string{"create", "-dt", "--name", "log", ALPINE}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) + Expect(session).To(Exit(0)) results := podmanTest.Podman([]string{"logs", "log"}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(BeZero()) + Expect(results).To(Exit(0)) }) - It("podman journald logs for container with container tag", func() { + It("using journald for container with container tag", func() { + SkipIfRemote() Skip("need to verify images have correct packages for journald") 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.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) cid := logc.OutputToString() wait := podmanTest.Podman([]string{"wait", "-l"}) wait.WaitWithDefaultTimeout() - Expect(wait.ExitCode()).To(BeZero()) + 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)) out, err := cmd.CombinedOutput() @@ -173,17 +176,18 @@ var _ = Describe("Podman logs", func() { Expect(string(out)).To(ContainSubstring("alpine")) }) - It("podman journald logs for container name", func() { + It("using journald for container name", func() { Skip("need to verify images have correct packages for journald") + SkipIfRemote() 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.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) cid := logc.OutputToString() wait := podmanTest.Podman([]string{"wait", "-l"}) wait.WaitWithDefaultTimeout() - Expect(wait.ExitCode()).To(BeZero()) + 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)) out, err := cmd.CombinedOutput() @@ -191,98 +195,97 @@ var _ = Describe("Podman logs", func() { Expect(string(out)).To(ContainSubstring(containerName)) }) - It("podman journald logs for container", func() { + 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.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) cid := logc.OutputToString() results := podmanTest.Podman([]string{"logs", cid}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) Expect(len(results.OutputToStringArray())).To(Equal(3)) }) - It("podman journald logs tail two lines", func() { + 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.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) cid := logc.OutputToString() - results := podmanTest.Podman([]string{"logs", "--tail", "2", cid}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) Expect(len(results.OutputToStringArray())).To(Equal(2)) }) - It("podman journald logs tail 99 lines", func() { + 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.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) cid := logc.OutputToString() results := podmanTest.Podman([]string{"logs", "--tail", "99", cid}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) Expect(len(results.OutputToStringArray())).To(Equal(3)) }) - It("podman journald logs tail 2 lines with timestamps", func() { + 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.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) cid := logc.OutputToString() results := podmanTest.Podman([]string{"logs", "--tail", "2", "-t", cid}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) Expect(len(results.OutputToStringArray())).To(Equal(2)) }) - It("podman journald logs latest with since time", func() { + 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.ExitCode()).To(Equal(0)) + 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.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) Expect(len(results.OutputToStringArray())).To(Equal(3)) }) - It("podman journald logs latest with since duration", func() { + 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.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) cid := logc.OutputToString() results := podmanTest.Podman([]string{"logs", "--since", "10m", cid}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) Expect(len(results.OutputToStringArray())).To(Equal(3)) }) - It("podman logs -f two lines", func() { + 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.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) results := podmanTest.Podman([]string{"logs", "-f", containerName}) results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) + Expect(results).To(Exit(0)) // Verify that the cleanup process worked correctly and we can recreate a container with the same name logc = podmanTest.Podman([]string{"run", "--rm", "--name", containerName, "-dt", ALPINE, "true"}) logc.WaitWithDefaultTimeout() - Expect(logc.ExitCode()).To(Equal(0)) + Expect(logc).To(Exit(0)) }) }) -- cgit v1.2.3-54-g00ecf