From 4624142c2db039343efc8c9b8070cf1e0d3a7262 Mon Sep 17 00:00:00 2001 From: cdoern Date: Tue, 6 Jul 2021 14:53:56 -0400 Subject: Implemented Until Query Parameter for Containers/logs compat containers/logs was missing actual usage of until query param. fixes #10859 Signed-off-by: cdoern --- libpod/container_log.go | 4 ++-- libpod/container_log_linux.go | 8 ++++++++ libpod/logs/log.go | 8 +++++++- pkg/api/handlers/compat/containers_logs.go | 14 ++++++++------ test/apiv2/python/rest_api/test_v2_0_0_container.py | 13 +++++++++++++ 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/libpod/container_log.go b/libpod/container_log.go index 43b3f7736..743c9c61b 100644 --- a/libpod/container_log.go +++ b/libpod/container_log.go @@ -56,7 +56,7 @@ func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOption for _, nll := range tailLog { nll.CID = c.ID() nll.CName = c.Name() - if nll.Since(options.Since) { + if nll.Since(options.Since) && nll.Until(options.Until) { logChannel <- nll } } @@ -88,7 +88,7 @@ func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOption } nll.CID = c.ID() nll.CName = c.Name() - if nll.Since(options.Since) { + if nll.Since(options.Since) && nll.Until(options.Until) { logChannel <- nll } } diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go index 892ee34e3..9f9dd3b0d 100644 --- a/libpod/container_log_linux.go +++ b/libpod/container_log_linux.go @@ -97,6 +97,7 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption } }() + beforeTimeStamp := true afterTimeStamp := false // needed for options.Since tailQueue := []*logs.LogLine{} // needed for options.Tail doTail := options.Tail > 0 @@ -156,6 +157,13 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption } afterTimeStamp = true } + if beforeTimeStamp { + entryTime := time.Unix(0, int64(entry.RealtimeTimestamp)*int64(time.Microsecond)) + if entryTime.Before(options.Until) || !options.Until.IsZero() { + continue + } + beforeTimeStamp = false + } // If we're reading an event and the container exited/died, // then we're done and can return. diff --git a/libpod/logs/log.go b/libpod/logs/log.go index 308053b47..1a0223edc 100644 --- a/libpod/logs/log.go +++ b/libpod/logs/log.go @@ -34,6 +34,7 @@ type LogOptions struct { Details bool Follow bool Since time.Time + Until time.Time Tail int64 Timestamps bool Multi bool @@ -184,7 +185,12 @@ func (l *LogLine) String(options *LogOptions) string { // Since returns a bool as to whether a log line occurred after a given time func (l *LogLine) Since(since time.Time) bool { - return l.Time.After(since) + return l.Time.After(since) || since.IsZero() +} + +// Until returns a bool as to whether a log line occurred before a given time +func (l *LogLine) Until(until time.Time) bool { + return l.Time.Before(until) || until.IsZero() } // NewLogLine creates a logLine struct from a container log string diff --git a/pkg/api/handlers/compat/containers_logs.go b/pkg/api/handlers/compat/containers_logs.go index cb4dee4d2..656e2c627 100644 --- a/pkg/api/handlers/compat/containers_logs.go +++ b/pkg/api/handlers/compat/containers_logs.go @@ -72,11 +72,12 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) { var until time.Time if _, found := r.URL.Query()["until"]; found { - // FIXME: until != since but the logs backend does not yet support until. - since, err = util.ParseInputTime(query.Until) - if err != nil { - utils.BadRequest(w, "until", query.Until, err) - return + if query.Until != "0" { + until, err = util.ParseInputTime(query.Until) + if err != nil { + utils.BadRequest(w, "until", query.Until, err) + return + } } } @@ -84,6 +85,7 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) { Details: true, Follow: query.Follow, Since: since, + Until: until, Tail: tail, Timestamps: query.Timestamps, } @@ -119,7 +121,7 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) { for line := range logChannel { if _, found := r.URL.Query()["until"]; found { - if line.Time.After(until) { + if line.Time.After(until) && !until.IsZero() { break } } diff --git a/test/apiv2/python/rest_api/test_v2_0_0_container.py b/test/apiv2/python/rest_api/test_v2_0_0_container.py index 2fab4aeb9..f252bd401 100644 --- a/test/apiv2/python/rest_api/test_v2_0_0_container.py +++ b/test/apiv2/python/rest_api/test_v2_0_0_container.py @@ -1,5 +1,6 @@ import random import unittest +import json import requests from dateutil.parser import parse @@ -97,6 +98,18 @@ class ContainerTestCase(APITestCase): def test_logs(self): r = requests.get(self.uri(self.resolve_container("/containers/{}/logs?stdout=true"))) self.assertEqual(r.status_code, 200, r.text) + r = requests.post( + self.podman_url + "/v1.40/containers/create?name=topcontainer", + json={"Cmd": ["top", "ls"], "Image": "alpine:latest"}, + ) + self.assertEqual(r.status_code, 201, r.text) + payload = r.json() + container_id = payload["Id"] + self.assertIsNotNone(container_id) + r = requests.get(self.podman_url + f"/v1.40/containers/{payload['Id']}/logs?follow=false&stdout=true&until=0") + self.assertEqual(r.status_code, 200, r.text) + r = requests.get(self.podman_url + f"/v1.40/containers/{payload['Id']}/logs?follow=false&stdout=true&until=1") + self.assertEqual(r.status_code, 200, r.text) def test_commit(self): r = requests.post(self.uri(self.resolve_container("/commit?container={}"))) -- cgit v1.2.3-54-g00ecf