Skip to content

Commit

Permalink
podman events: check for an error after we finish reading events
Browse files Browse the repository at this point in the history
The function that's handing us events will return an error after closing
the channel over which it's sending events, and its caller (in its own
goroutine) will then send that error over another channel.

The logic that started the goroutine is likely to notice that the events
channel is closed before noticing that the error channel has a result
for it to read, so any error that would have been communicated would be
lost.

When we finish reading events, check if the reader returned an error
before telling our caller that there was no error.

Signed-off-by: Nalin Dahyabhai <[email protected]>
  • Loading branch information
nalind committed May 14, 2024
1 parent ef66190 commit c46884a
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 6 deletions.
10 changes: 8 additions & 2 deletions cmd/podman/system/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,21 @@ func eventsCmd(cmd *cobra.Command, _ []string) error {
}

go func() {
err := registry.ContainerEngine().Events(context.Background(), eventOptions)
errChannel <- err
errChannel <- registry.ContainerEngine().Events(context.Background(), eventOptions)
}()

for {
select {
case event, ok := <-eventChannel:
if !ok {
// channel was closed we can exit
select {
case err := <-errChannel:
if err != nil {
return err
}
default:
}
return nil
}
switch {
Expand Down
14 changes: 10 additions & 4 deletions pkg/api/handlers/compat/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {

libpodFilters, err := util.FiltersFromRequest(r)
if err != nil {
utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err))
utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse filters for %s: %w", r.URL.String(), err))
return
}
eventChannel := make(chan *events.Event)
Expand All @@ -68,8 +68,13 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
}

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
flush()
wroteContent := false
defer func() {
if !wroteContent {
w.WriteHeader(http.StatusOK)
flush()
}
}()

coder := json.NewEncoder(w)
coder.SetEscapeHTML(true)
Expand All @@ -78,8 +83,8 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
select {
case err := <-errorChannel:
if err != nil {
// FIXME StatusOK already sent above cannot send 500 here
utils.InternalServerError(w, err)
wroteContent = true
}
return
case evt := <-eventChannel:
Expand All @@ -103,6 +108,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
if err := coder.Encode(e); err != nil {
logrus.Errorf("Unable to write json: %q", err)
}
wroteContent = true
flush()
case <-r.Context().Done():
return
Expand Down
4 changes: 4 additions & 0 deletions pkg/bindings/system/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ func Events(ctx context.Context, eventChan chan types.Event, cancelChan chan boo
}()
}

if response.StatusCode != http.StatusOK {
return response.Process(nil)
}

dec := json.NewDecoder(response.Body)
for err = (error)(nil); err == nil; {
var e = types.Event{}
Expand Down
5 changes: 5 additions & 0 deletions test/system/090-events.bats
Original file line number Diff line number Diff line change
Expand Up @@ -406,3 +406,8 @@ EOF
run_podman events --since=1m --stream=false --filter volume=${vname:0:5}
assert "$output" = "$notrunc_results"
}

@test "events - invalid filter" {
run_podman 125 events --since="the dawn of time...ish"
assert "$output" =~ "failed to parse event filters"
}

0 comments on commit c46884a

Please sign in to comment.