podman events allow future time for --until

The podman events aren't read until the given timestamp if the
timestamp is in the future. It just reads all events until now
and exits afterwards.
This does not make sense and does not match docker. The correct
behavior is to read all events until the given time is reached.

This fixes a bug where the wrong event log file path was used
when running first time with a new storage location.
Fixes #8694

This also fixes the events api endpoint which only exited when
an error occurred. Otherwise it just hung after reading all events.

Signed-off-by: Paul Holzinger <paul.holzinger@web.de>
This commit is contained in:
Paul Holzinger committed 2020-12-11 23:15:09 +01:00
1 parent dd954781e6
commit 74fcd9fef3
6 files changed
+68 -10

No files matched your search

-3
View File
@@ -216,8 +216,5 @@ func (e EventLogFile) getTail(options ReadOptions) (*tail.Tail, error) {
reopen = false
}
stream := options.Stream
if len(options.Until) > 0 {
stream = false
}
return tail.TailFile(e.options.LogFilePath, tail.Config{ReOpen: reopen, Follow: stream, Location: &seek, Logger: tail.DiscardingLogger, Poll: true})
}
+14 -2
View File
@@ -8,6 +8,7 @@ import (
"strconv"
"time"
"github.com/containers/podman/v2/pkg/util"
"github.com/coreos/go-systemd/v22/journal"
"github.com/coreos/go-systemd/v22/sdjournal"
"github.com/pkg/errors"
@@ -72,6 +73,13 @@ func (e EventJournalD) Read(ctx context.Context, options ReadOptions) error {
if err != nil {
return errors.Wrapf(err, "failed to generate event options")
}
var untilTime time.Time
if len(options.Until) > 0 {
untilTime, err = util.ParseInputTime(options.Until)
if err != nil {
return err
}
}
j, err := sdjournal.NewJournal()
if err != nil {
return err
@@ -122,10 +130,14 @@ func (e EventJournalD) Read(ctx context.Context, options ReadOptions) error {
return errors.Wrap(err, "failed to get journal cursor")
}
if prevCursor == newCursor {
if len(options.Until) > 0 || !options.Stream {
if !options.Stream || (len(options.Until) > 0 && time.Now().After(untilTime)) {
break
}
_ = j.Wait(sdjournal.IndefiniteWait)
t := sdjournal.IndefiniteWait
if len(options.Until) > 0 {
t = time.Until(untilTime)
}
_ = j.Wait(t)
continue
}
prevCursor = newCursor
+12
View File
@@ -4,7 +4,9 @@ import (
"context"
"fmt"
"os"
"time"
"github.com/containers/podman/v2/pkg/util"
"github.com/containers/storage"
"github.com/pkg/errors"
)
@@ -51,6 +53,16 @@ func (e EventLogFile) Read(ctx context.Context, options ReadOptions) error {
if err != nil {
return err
}
if len(options.Until) > 0 {
untilTime, err := util.ParseInputTime(options.Until)
if err != nil {
return err
}
go func() {
time.Sleep(time.Until(untilTime))
t.Stop()
}()
}
funcDone := make(chan bool)
copy := true
go func() {
+1
View File
@@ -502,6 +502,7 @@ func WithEventsLogger(logger string) RuntimeOption {
}
rt.config.Engine.EventsLogger = logger
rt.config.Engine.EventsLogFilePath = filepath.Join(rt.config.Engine.TmpDir, "events", "events.log")
return nil
}
+2 -1
View File
@@ -110,6 +110,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
Until: query.Until,
}
errorChannel <- runtime.Events(r.Context(), readOpts)
}()
var flush = func() {}
@@ -130,8 +131,8 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
if err != nil {
// FIXME StatusOK already sent above cannot send 500 here
utils.InternalServerError(w, err)
return
}
return
case evt := <-eventChannel:
if evt == nil {
continue
+39 -4
View File
@@ -5,9 +5,11 @@ import (
"fmt"
"os"
"strings"
"sync"
"time"
. "github.com/containers/podman/v2/test/utils"
"github.com/containers/storage/pkg/stringid"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
@@ -115,10 +117,7 @@ var _ = Describe("Podman events", func() {
SkipIfNotFedora()
_, ec, _ := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
test := podmanTest.Podman([]string{"events", "--help"})
test.WaitWithDefaultTimeout()
fmt.Println(test.OutputToStringArray())
result := podmanTest.Podman([]string{"events", "--stream=false", "--since", "1h"})
result := podmanTest.Podman([]string{"events", "--stream=false", "--until", "1h"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(BeZero())
})
@@ -154,4 +153,40 @@ var _ = Describe("Podman events", func() {
Expect(eventsMap).To(HaveKey("Status"))
})
It("podman events --until future", func() {
name1 := stringid.GenerateNonCryptoID()
name2 := stringid.GenerateNonCryptoID()
name3 := stringid.GenerateNonCryptoID()
session := podmanTest.Podman([]string{"create", "--name", name1, ALPINE})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer GinkgoRecover()
defer wg.Done()
// wait 2 seconds to be sure events is running
time.Sleep(time.Second * 2)
session = podmanTest.Podman([]string{"create", "--name", name2, ALPINE})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"create", "--name", name3, ALPINE})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
}()
// unix timestamp in 10 seconds
until := time.Now().Add(time.Second * 10).Unix()
result := podmanTest.Podman([]string{"events", "--since", "30s", "--until", fmt.Sprint(until)})
result.Wait(11)
Expect(result.ExitCode()).To(BeZero())
Expect(result.OutputToString()).To(ContainSubstring(name1))
Expect(result.OutputToString()).To(ContainSubstring(name2))
Expect(result.OutputToString()).To(ContainSubstring(name3))
wg.Wait()
})
})