From 4995c511e581723ee9d441d500eda2e6d2e8a839 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Wed, 1 Jul 2020 16:21:57 -0400 Subject: Fix `system service` panic from early hangup in events We weren't actually halting the goroutine that sent events, so it would continue sending even when the channel closed (the most notable cause being early hangup - e.g. Control-c on a curl session). Use a context to cancel the events goroutine and stop sending events. Fixes #6805 Signed-off-by: Matthew Heon --- pkg/api/handlers/compat/events.go | 6 +++++- pkg/domain/infra/abi/containers.go | 4 ++-- pkg/domain/infra/abi/events.go | 2 +- pkg/varlinkapi/attach.go | 3 ++- pkg/varlinkapi/events.go | 3 ++- 5 files changed, 12 insertions(+), 6 deletions(-) (limited to 'pkg') diff --git a/pkg/api/handlers/compat/events.go b/pkg/api/handlers/compat/events.go index 215d7c972..5acc94153 100644 --- a/pkg/api/handlers/compat/events.go +++ b/pkg/api/handlers/compat/events.go @@ -1,6 +1,7 @@ package compat import ( + "context" "fmt" "net/http" @@ -45,13 +46,15 @@ func GetEvents(w http.ResponseWriter, r *http.Request) { fromStart = true } + eventCtx, eventCancel := context.WithCancel(r.Context()) eventChannel := make(chan *events.Event) go func() { readOpts := events.ReadOptions{FromStart: fromStart, Stream: query.Stream, Filters: libpodFilters, EventChannel: eventChannel, Since: query.Since, Until: query.Until} - eventsError = runtime.Events(readOpts) + eventsError = runtime.Events(eventCtx, readOpts) }() if eventsError != nil { utils.InternalServerError(w, eventsError) + eventCancel() close(eventChannel) return } @@ -59,6 +62,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) { // If client disappears we need to stop listening for events go func(done <-chan struct{}) { <-done + eventCancel() if _, ok := <-eventChannel; ok { close(eventChannel) } diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index d5dce0b0f..596fc2cc1 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -741,7 +741,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri if ecode, err := ctr.Wait(); err != nil { if errors.Cause(err) == define.ErrNoSuchCtr { // Check events - event, err := ic.Libpod.GetLastContainerEvent(ctr.ID(), events.Exited) + event, err := ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited) if err != nil { logrus.Errorf("Cannot get exit code: %v", err) exitCode = define.ExecErrorCodeNotFound @@ -871,7 +871,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta if ecode, err := ctr.Wait(); err != nil { if errors.Cause(err) == define.ErrNoSuchCtr { // Check events - event, err := ic.Libpod.GetLastContainerEvent(ctr.ID(), events.Exited) + event, err := ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited) if err != nil { logrus.Errorf("Cannot get exit code: %v", err) report.ExitCode = define.ExecErrorCodeNotFound diff --git a/pkg/domain/infra/abi/events.go b/pkg/domain/infra/abi/events.go index 50d7727ce..7a8185445 100644 --- a/pkg/domain/infra/abi/events.go +++ b/pkg/domain/infra/abi/events.go @@ -9,5 +9,5 @@ import ( func (ic *ContainerEngine) Events(ctx context.Context, opts entities.EventsOptions) error { readOpts := events.ReadOptions{FromStart: opts.FromStart, Stream: opts.Stream, Filters: opts.Filter, EventChannel: opts.EventChan, Since: opts.Since, Until: opts.Until} - return ic.Libpod.Events(readOpts) + return ic.Libpod.Events(ctx, readOpts) } diff --git a/pkg/varlinkapi/attach.go b/pkg/varlinkapi/attach.go index 731d89b8f..8acf2a1b6 100644 --- a/pkg/varlinkapi/attach.go +++ b/pkg/varlinkapi/attach.go @@ -4,6 +4,7 @@ package varlinkapi import ( "bufio" + "context" "io" "github.com/containers/libpod/v2/libpod" @@ -89,7 +90,7 @@ func (i *VarlinkAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys s if ecode, err := ctr.Wait(); err != nil { if errors.Cause(err) == define.ErrNoSuchCtr { // Check events - event, err := i.Runtime.GetLastContainerEvent(ctr.ID(), events.Exited) + event, err := i.Runtime.GetLastContainerEvent(context.Background(), ctr.ID(), events.Exited) if err != nil { logrus.Errorf("Cannot get exit code: %v", err) exitCode = define.ExecErrorCodeNotFound diff --git a/pkg/varlinkapi/events.go b/pkg/varlinkapi/events.go index 2e468b706..910b64a57 100644 --- a/pkg/varlinkapi/events.go +++ b/pkg/varlinkapi/events.go @@ -3,6 +3,7 @@ package varlinkapi import ( + "context" "time" "github.com/containers/libpod/v2/libpod/events" @@ -27,7 +28,7 @@ func (i *VarlinkAPI) GetEvents(call iopodman.VarlinkCall, filter []string, since eventChannel := make(chan *events.Event) go func() { readOpts := events.ReadOptions{FromStart: fromStart, Stream: stream, Filters: filter, EventChannel: eventChannel} - eventsError = i.Runtime.Events(readOpts) + eventsError = i.Runtime.Events(context.Background(), readOpts) }() if eventsError != nil { return call.ReplyErrorOccurred(eventsError.Error()) -- cgit v1.2.3-54-g00ecf