Skip to content

Commit

Permalink
Merge pull request containers#9758 from jmguzik/volumes-networks-http…
Browse files Browse the repository at this point in the history
…-fix

Fix volumes and networks list/prune filters in http api
  • Loading branch information
openshift-merge-robot authored Mar 19, 2021
2 parents 2c967c3 + aa2d6e6 commit 61e3b15
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 132 deletions.
54 changes: 2 additions & 52 deletions pkg/api/handlers/compat/events.go
Original file line number Diff line number Diff line change
@@ -1,69 +1,19 @@
package compat

import (
"encoding/json"
"fmt"
"net/http"

"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/events"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/util"
"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 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) {
Expand Down Expand Up @@ -92,7 +42,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
fromStart = true
}

libpodFilters, err := filtersFromRequest(r)
libpodFilters, err := util.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
Expand Down
26 changes: 7 additions & 19 deletions pkg/api/handlers/compat/networks.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
networkid "github.com/containers/podman/v3/pkg/network"
"github.com/containers/podman/v3/pkg/util"
"github.com/docker/docker/api/types"
dockerNetwork "github.com/docker/docker/api/types/network"
"github.com/gorilla/schema"
Expand Down Expand Up @@ -181,18 +182,12 @@ func findPluginByName(plugins []*libcni.NetworkConfig, pluginType string) ([]byt

func ListNetworks(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
filters, err := filtersFromRequest(r)
filterMap, err := util.PrepareFilters(r)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
filterMap := map[string][]string{}
for _, filter := range filters {
split := strings.SplitN(filter, "=", 2)
if len(split) > 1 {
filterMap[split[0]] = append(filterMap[split[0]], split[1])
}
}

config, err := runtime.GetConfig()
if err != nil {
utils.InternalServerError(w, err)
Expand All @@ -208,7 +203,7 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
reports := []*types.NetworkResource{}
logrus.Debugf("netNames: %q", strings.Join(netNames, ", "))
for _, name := range netNames {
report, err := getNetworkResourceByNameOrID(name, runtime, filterMap)
report, err := getNetworkResourceByNameOrID(name, runtime, *filterMap)
if err != nil {
utils.InternalServerError(w, err)
return
Expand Down Expand Up @@ -401,22 +396,15 @@ func Disconnect(w http.ResponseWriter, r *http.Request) {
// Prune removes unused networks
func Prune(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
filters, err := filtersFromRequest(r)
filterMap, err := util.PrepareFilters(r)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
filterMap := map[string][]string{}
for _, filter := range filters {
split := strings.SplitN(filter, "=", 2)
if len(split) > 1 {
filterMap[split[0]] = append(filterMap[split[0]], split[1])
}
}

ic := abi.ContainerEngine{Libpod: runtime}
pruneOptions := entities.NetworkPruneOptions{
Filters: filterMap,
Filters: *filterMap,
}
pruneReports, err := ic.NetworkPrune(r.Context(), pruneOptions)
if err != nil {
Expand Down
27 changes: 7 additions & 20 deletions pkg/api/handlers/compat/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/json"
"net/http"
"net/url"
"strings"
"time"

"github.com/containers/podman/v3/libpod"
Expand All @@ -14,6 +13,7 @@ import (
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/domain/filters"
"github.com/containers/podman/v3/pkg/domain/infra/abi/parse"
"github.com/containers/podman/v3/pkg/util"
docker_api_types "github.com/docker/docker/api/types"
docker_api_types_volume "github.com/docker/docker/api/types/volume"
"github.com/gorilla/schema"
Expand All @@ -22,31 +22,25 @@ import (

func ListVolumes(w http.ResponseWriter, r *http.Request) {
var (
decoder = r.Context().Value("decoder").(*schema.Decoder)
runtime = r.Context().Value("runtime").(*libpod.Runtime)
)
query := struct {
Filters map[string][]string `schema:"filters"`
}{
// override any golang type defaults
}

if err := decoder.Decode(&query, r.URL.Query()); err != nil {
filtersMap, err := util.PrepareFilters(r)
if err != nil {
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}

// Reject any libpod specific filters since `GenerateVolumeFilters()` will
// happily parse them for us.
for filter := range query.Filters {
for filter := range *filtersMap {
if filter == "opts" {
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
errors.Errorf("unsupported libpod filters passed to docker endpoint"))
return
}
}
volumeFilters, err := filters.GenerateVolumeFilters(query.Filters)
volumeFilters, err := filters.GenerateVolumeFilters(*filtersMap)
if err != nil {
utils.InternalServerError(w, err)
return
Expand Down Expand Up @@ -265,20 +259,13 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
)
filtersList, err := filtersFromRequest(r)
filterMap, err := util.PrepareFilters(r)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
filterMap := map[string][]string{}
for _, filter := range filtersList {
split := strings.SplitN(filter, "=", 2)
if len(split) > 1 {
filterMap[split[0]] = append(filterMap[split[0]], split[1])
}
}

f := (url.Values)(filterMap)
f := (url.Values)(*filterMap)
filterFuncs, err := filters.GenerateVolumeFilters(f)
if err != nil {
utils.Error(w, "Something when wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to parse filters for %s", f.Encode()))
Expand Down
29 changes: 10 additions & 19 deletions pkg/api/handlers/libpod/networks.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
"github.com/containers/podman/v3/pkg/util"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -45,20 +46,15 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) {
}
func ListNetworks(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
Filters map[string][]string `schema:"filters"`
}{
// override any golang type defaults
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
filterMap, err := util.PrepareFilters(r)
if err != nil {
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}

options := entities.NetworkListOptions{
Filters: query.Filters,
Filters: *filterMap,
}
ic := abi.ContainerEngine{Libpod: runtime}
reports, err := ic.NetworkList(r.Context(), options)
Expand All @@ -78,7 +74,7 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
// override any golang type defaults
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
Expand Down Expand Up @@ -111,7 +107,7 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
// override any golang type defaults
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
Expand Down Expand Up @@ -178,20 +174,15 @@ func ExistsNetwork(w http.ResponseWriter, r *http.Request) {
// Prune removes unused networks
func Prune(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
Filters map[string][]string `schema:"filters"`
}{
// override any golang type defaults
}

if err := decoder.Decode(&query, r.URL.Query()); err != nil {
filterMap, err := util.PrepareFilters(r)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}

pruneOptions := entities.NetworkPruneOptions{
Filters: query.Filters,
Filters: *filterMap,
}
ic := abi.ContainerEngine{Libpod: runtime}
pruneReports, err := ic.NetworkPrune(r.Context(), pruneOptions)
Expand Down
32 changes: 11 additions & 21 deletions pkg/api/handlers/libpod/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/containers/podman/v3/pkg/domain/filters"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
"github.com/containers/podman/v3/pkg/domain/infra/abi/parse"
"github.com/containers/podman/v3/pkg/util"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
Expand All @@ -29,7 +30,7 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) {
}
input := entities.VolumeCreateOptions{}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
Expand Down Expand Up @@ -95,22 +96,16 @@ func InspectVolume(w http.ResponseWriter, r *http.Request) {

func ListVolumes(w http.ResponseWriter, r *http.Request) {
var (
decoder = r.Context().Value("decoder").(*schema.Decoder)
runtime = r.Context().Value("runtime").(*libpod.Runtime)
)
query := struct {
Filters map[string][]string `schema:"filters"`
}{
// override any golang type defaults
}

if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
filterMap, err := util.PrepareFilters(r)
if err != nil {
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}

volumeFilters, err := filters.GenerateVolumeFilters(query.Filters)
volumeFilters, err := filters.GenerateVolumeFilters(*filterMap)
if err != nil {
utils.InternalServerError(w, err)
return
Expand Down Expand Up @@ -148,19 +143,13 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
func pruneVolumesHelper(r *http.Request) ([]*reports.PruneReport, error) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
decoder = r.Context().Value("decoder").(*schema.Decoder)
)
query := struct {
Filters map[string][]string `schema:"filters"`
}{
// override any golang type defaults
}

if err := decoder.Decode(&query, r.URL.Query()); err != nil {
filterMap, err := util.PrepareFilters(r)
if err != nil {
return nil, err
}

f := (url.Values)(query.Filters)
f := (url.Values)(*filterMap)
filterFuncs, err := filters.GenerateVolumeFilters(f)
if err != nil {
return nil, err
Expand All @@ -172,6 +161,7 @@ func pruneVolumesHelper(r *http.Request) ([]*reports.PruneReport, error) {
}
return reports, nil
}

func RemoveVolume(w http.ResponseWriter, r *http.Request) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
Expand All @@ -184,7 +174,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) {
}

if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
Expand Down
Loading

0 comments on commit 61e3b15

Please sign in to comment.