Skip to content

Commit

Permalink
events endpoint: backwards compat to old type
Browse files Browse the repository at this point in the history
The versions Docker that the compat endpoints currently support are
using another type for the `filters` parameter than later versions
of Docker, which the libpod/events endpoint is also using.

To prevent existing deplopyments from breaking while still achieving
backward compat, we now support both types for the filters parameter.

Tested manually.

Fixes: containers#6899
Signed-off-by: Valentin Rothberg <[email protected]>
  • Loading branch information
vrothberg committed Jul 21, 2020
1 parent 142db01 commit 3fcdd0d
Showing 1 changed file with 55 additions and 15 deletions.
70 changes: 55 additions & 15 deletions pkg/api/handlers/compat/events.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package compat

import (
"encoding/json"
"fmt"
"net/http"
"sync"
Expand All @@ -15,6 +16,49 @@ import (
"github.com/sirupsen/logrus"
)

// filtersFromRequests extracts the "filters" parameter from the specified
// http.Request. The paramater 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(r.Form.Get("filters"))

// 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
Expand All @@ -23,11 +67,12 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
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"`
Filters map[string][]string `schema:"filters"`
Stream bool `schema:"stream"`
Since string `schema:"since"`
Until string `schema:"until"`
Stream bool `schema:"stream"`
}{
Stream: true,
}
Expand All @@ -36,21 +81,16 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
return
}

var libpodFilters = []string{}
if _, found := r.URL.Query()["filters"]; found {
for k, v := range query.Filters {
if len(v) == 0 {
utils.Error(w, "Failed to parse parameters", http.StatusBadRequest, errors.Errorf("empty value for filter %q", k))
return
}
libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", k, v[0]))
}
}

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)

Expand Down

0 comments on commit 3fcdd0d

Please sign in to comment.