mirror of
				https://github.com/containers/podman.git
				synced 2025-11-01 02:42:11 +08:00 
			
		
		
		
	 74fcd9fef3
			
		
	
	74fcd9fef3
	
	
	
		
			
			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>
		
			
				
	
	
		
			151 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package compat
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"net/http"
 | |
| 
 | |
| 	"github.com/containers/podman/v2/libpod"
 | |
| 	"github.com/containers/podman/v2/libpod/events"
 | |
| 	"github.com/containers/podman/v2/pkg/api/handlers/utils"
 | |
| 	"github.com/containers/podman/v2/pkg/domain/entities"
 | |
| 	"github.com/gorilla/schema"
 | |
| 	jsoniter "github.com/json-iterator/go"
 | |
| 	"github.com/pkg/errors"
 | |
| 	"github.com/sirupsen/logrus"
 | |
| )
 | |
| 
 | |
| // filtersFromRequests extracts the "filters" parameter from the specified
 | |
| // http.Request.  The parameter can either be a `map[string][]string` as done
 | |
| // in new versions of Docker and libpod, or a `map[string]map[string]bool` as
 | |
| // done in older versions of Docker.  We have to do a bit of Yoga to support
 | |
| // both - just as Docker does as well.
 | |
| //
 | |
| // Please refer to https://github.com/containers/podman/issues/6899 for some
 | |
| // background.
 | |
| func filtersFromRequest(r *http.Request) ([]string, error) {
 | |
| 	var (
 | |
| 		compatFilters map[string]map[string]bool
 | |
| 		filters       map[string][]string
 | |
| 		libpodFilters []string
 | |
| 		raw           []byte
 | |
| 	)
 | |
| 
 | |
| 	if _, found := r.URL.Query()["filters"]; found {
 | |
| 		raw = []byte(r.Form.Get("filters"))
 | |
| 	} else {
 | |
| 		return []string{}, nil
 | |
| 	}
 | |
| 
 | |
| 	// Backwards compat with older versions of Docker.
 | |
| 	if err := json.Unmarshal(raw, &compatFilters); err == nil {
 | |
| 		for filterKey, filterMap := range compatFilters {
 | |
| 			for filterValue, toAdd := range filterMap {
 | |
| 				if toAdd {
 | |
| 					libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", filterKey, filterValue))
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		return libpodFilters, nil
 | |
| 	}
 | |
| 
 | |
| 	if err := json.Unmarshal(raw, &filters); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	for filterKey, filterSlice := range filters {
 | |
| 		for _, filterValue := range filterSlice {
 | |
| 			libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", filterKey, filterValue))
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return libpodFilters, nil
 | |
| }
 | |
| 
 | |
| // NOTE: this endpoint serves both the docker-compatible one and the new libpod
 | |
| // one.
 | |
| func GetEvents(w http.ResponseWriter, r *http.Request) {
 | |
| 	var (
 | |
| 		fromStart bool
 | |
| 		decoder   = r.Context().Value("decoder").(*schema.Decoder)
 | |
| 		runtime   = r.Context().Value("runtime").(*libpod.Runtime)
 | |
| 		json      = jsoniter.ConfigCompatibleWithStandardLibrary // FIXME: this should happen on the package level
 | |
| 	)
 | |
| 
 | |
| 	// NOTE: the "filters" parameter is extracted separately for backwards
 | |
| 	// compat via `fitlerFromRequest()`.
 | |
| 	query := struct {
 | |
| 		Since  string `schema:"since"`
 | |
| 		Until  string `schema:"until"`
 | |
| 		Stream bool   `schema:"stream"`
 | |
| 	}{
 | |
| 		Stream: true,
 | |
| 	}
 | |
| 	if err := decoder.Decode(&query, r.URL.Query()); err != nil {
 | |
| 		utils.Error(w, "failed to parse parameters", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if len(query.Since) > 0 || len(query.Until) > 0 {
 | |
| 		fromStart = true
 | |
| 	}
 | |
| 
 | |
| 	libpodFilters, err := filtersFromRequest(r)
 | |
| 	if err != nil {
 | |
| 		utils.Error(w, "failed to parse parameters", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	eventChannel := make(chan *events.Event)
 | |
| 	errorChannel := make(chan error)
 | |
| 
 | |
| 	// Start reading events.
 | |
| 	go func() {
 | |
| 		readOpts := events.ReadOptions{
 | |
| 			FromStart:    fromStart,
 | |
| 			Stream:       query.Stream,
 | |
| 			Filters:      libpodFilters,
 | |
| 			EventChannel: eventChannel,
 | |
| 			Since:        query.Since,
 | |
| 			Until:        query.Until,
 | |
| 		}
 | |
| 		errorChannel <- runtime.Events(r.Context(), readOpts)
 | |
| 
 | |
| 	}()
 | |
| 
 | |
| 	var flush = func() {}
 | |
| 	if flusher, ok := w.(http.Flusher); ok {
 | |
| 		flush = flusher.Flush
 | |
| 	}
 | |
| 
 | |
| 	w.Header().Set("Content-Type", "application/json")
 | |
| 	w.WriteHeader(http.StatusOK)
 | |
| 	flush()
 | |
| 
 | |
| 	coder := json.NewEncoder(w)
 | |
| 	coder.SetEscapeHTML(true)
 | |
| 
 | |
| 	for stream := true; stream; stream = query.Stream {
 | |
| 		select {
 | |
| 		case err := <-errorChannel:
 | |
| 			if err != nil {
 | |
| 				// FIXME StatusOK already sent above cannot send 500 here
 | |
| 				utils.InternalServerError(w, err)
 | |
| 			}
 | |
| 			return
 | |
| 		case evt := <-eventChannel:
 | |
| 			if evt == nil {
 | |
| 				continue
 | |
| 			}
 | |
| 
 | |
| 			e := entities.ConvertToEntitiesEvent(*evt)
 | |
| 			if err := coder.Encode(e); err != nil {
 | |
| 				logrus.Errorf("unable to write json: %q", err)
 | |
| 			}
 | |
| 			flush()
 | |
| 		case <-r.Context().Done():
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| }
 |