github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/api/handlers/compat/events.go (about) 1 package compat 2 3 import ( 4 "net/http" 5 6 "github.com/hanks177/podman/v4/libpod" 7 "github.com/hanks177/podman/v4/libpod/events" 8 "github.com/hanks177/podman/v4/pkg/api/handlers/utils" 9 api "github.com/hanks177/podman/v4/pkg/api/types" 10 "github.com/hanks177/podman/v4/pkg/domain/entities" 11 "github.com/hanks177/podman/v4/pkg/util" 12 "github.com/gorilla/schema" 13 jsoniter "github.com/json-iterator/go" 14 "github.com/pkg/errors" 15 "github.com/sirupsen/logrus" 16 ) 17 18 // GetEvents endpoint serves both the docker-compatible one and the new libpod one 19 func GetEvents(w http.ResponseWriter, r *http.Request) { 20 var ( 21 fromStart bool 22 decoder = r.Context().Value(api.DecoderKey).(*schema.Decoder) 23 runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime) 24 json = jsoniter.ConfigCompatibleWithStandardLibrary // FIXME: this should happen on the package level 25 ) 26 27 // NOTE: the "filters" parameter is extracted separately for backwards 28 // compat via `filterFromRequest()`. 29 query := struct { 30 Since string `schema:"since"` 31 Until string `schema:"until"` 32 Stream bool `schema:"stream"` 33 }{ 34 Stream: true, 35 } 36 if err := decoder.Decode(&query, r.URL.Query()); err != nil { 37 utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) 38 return 39 } 40 41 if len(query.Since) > 0 || len(query.Until) > 0 { 42 fromStart = true 43 } 44 45 libpodFilters, err := util.FiltersFromRequest(r) 46 if err != nil { 47 utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) 48 return 49 } 50 eventChannel := make(chan *events.Event) 51 errorChannel := make(chan error) 52 53 // Start reading events. 54 go func() { 55 readOpts := events.ReadOptions{ 56 FromStart: fromStart, 57 Stream: query.Stream, 58 Filters: libpodFilters, 59 EventChannel: eventChannel, 60 Since: query.Since, 61 Until: query.Until, 62 } 63 errorChannel <- runtime.Events(r.Context(), readOpts) 64 }() 65 66 flush := func() {} 67 if flusher, ok := w.(http.Flusher); ok { 68 flush = flusher.Flush 69 } 70 71 w.Header().Set("Content-Type", "application/json") 72 w.WriteHeader(http.StatusOK) 73 flush() 74 75 coder := json.NewEncoder(w) 76 coder.SetEscapeHTML(true) 77 78 for { 79 select { 80 case err := <-errorChannel: 81 if err != nil { 82 // FIXME StatusOK already sent above cannot send 500 here 83 utils.InternalServerError(w, err) 84 } 85 return 86 case evt := <-eventChannel: 87 if evt == nil { 88 continue 89 } 90 91 e := entities.ConvertToEntitiesEvent(*evt) 92 if !utils.IsLibpodRequest(r) && e.Status == "died" { 93 e.Status = "die" 94 e.Action = "die" 95 e.Actor.Attributes["exitCode"] = e.Actor.Attributes["containerExitCode"] 96 } 97 98 if err := coder.Encode(e); err != nil { 99 logrus.Errorf("Unable to write json: %q", err) 100 } 101 flush() 102 case <-r.Context().Done(): 103 return 104 } 105 } 106 }