mirror of
https://github.com/containers/podman.git
synced 2025-06-23 02:18:13 +08:00
Fix containers list/prune http api filter behaviour
The problem described in #9711 and followed by #9758 affects containers as well. When user provides wrong filter input, error message should occur, not fallback to full list/prune command. This change fixes the issue. Additionally, there are error message fixes for docker http api compat. Signed-off-by: Jakub Guzik <jakubmguzik@gmail.com>
This commit is contained in:
@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
"github.com/containers/podman/v3/pkg/ps"
|
"github.com/containers/podman/v3/pkg/ps"
|
||||||
"github.com/containers/podman/v3/pkg/signal"
|
"github.com/containers/podman/v3/pkg/signal"
|
||||||
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
@ -95,20 +96,21 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
|
|||||||
All bool `schema:"all"`
|
All bool `schema:"all"`
|
||||||
Limit int `schema:"limit"`
|
Limit int `schema:"limit"`
|
||||||
Size bool `schema:"size"`
|
Size bool `schema:"size"`
|
||||||
Filters map[string][]string `schema:"filters"`
|
|
||||||
}{
|
}{
|
||||||
// override any golang type defaults
|
// override any golang type defaults
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
filterMap, err := util.PrepareFilters(r)
|
||||||
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
|
||||||
|
if dErr := decoder.Decode(&query, r.URL.Query()); dErr != nil || err != nil {
|
||||||
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
filterFuncs := make([]libpod.ContainerFilter, 0, len(query.Filters))
|
filterFuncs := make([]libpod.ContainerFilter, 0, len(*filterMap))
|
||||||
all := query.All || query.Limit > 0
|
all := query.All || query.Limit > 0
|
||||||
if len(query.Filters) > 0 {
|
if len((*filterMap)) > 0 {
|
||||||
for k, v := range query.Filters {
|
for k, v := range *filterMap {
|
||||||
generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime)
|
generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
@ -120,7 +122,7 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// Docker thinks that if status is given as an input, then we should override
|
// Docker thinks that if status is given as an input, then we should override
|
||||||
// the all setting and always deal with all containers.
|
// the all setting and always deal with all containers.
|
||||||
if len(query.Filters["status"]) > 0 {
|
if len((*filterMap)["status"]) > 0 {
|
||||||
all = true
|
all = true
|
||||||
}
|
}
|
||||||
if !all {
|
if !all {
|
||||||
|
@ -9,23 +9,20 @@ import (
|
|||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities/reports"
|
"github.com/containers/podman/v3/pkg/domain/entities/reports"
|
||||||
"github.com/containers/podman/v3/pkg/domain/filters"
|
"github.com/containers/podman/v3/pkg/domain/filters"
|
||||||
"github.com/gorilla/schema"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PruneContainers(w http.ResponseWriter, r *http.Request) {
|
func PruneContainers(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
filtersMap, err := util.PrepareFilters(r)
|
||||||
|
if err != nil {
|
||||||
query := struct {
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
Filters map[string][]string `schema:"filters"`
|
|
||||||
}{}
|
|
||||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
|
||||||
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
filterFuncs := make([]libpod.ContainerFilter, 0, len(query.Filters))
|
|
||||||
for k, v := range query.Filters {
|
filterFuncs := make([]libpod.ContainerFilter, 0, len(*filtersMap))
|
||||||
|
for k, v := range *filtersMap {
|
||||||
generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime)
|
generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -61,7 +62,6 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
|
|||||||
query := struct {
|
query := struct {
|
||||||
All bool `schema:"all"`
|
All bool `schema:"all"`
|
||||||
External bool `schema:"external"`
|
External bool `schema:"external"`
|
||||||
Filters map[string][]string `schema:"filters"`
|
|
||||||
Last int `schema:"last"` // alias for limit
|
Last int `schema:"last"` // alias for limit
|
||||||
Limit int `schema:"limit"`
|
Limit int `schema:"limit"`
|
||||||
Namespace bool `schema:"namespace"`
|
Namespace bool `schema:"namespace"`
|
||||||
@ -71,8 +71,10 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
|
|||||||
// override any golang type defaults
|
// override any golang type defaults
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
filterMap, err := util.PrepareFilters(r)
|
||||||
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
|
|
||||||
|
if dErr := decoder.Decode(&query, r.URL.Query()); dErr != nil || err != nil {
|
||||||
|
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
|
||||||
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -94,7 +96,7 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
|
|||||||
opts := entities.ContainerListOptions{
|
opts := entities.ContainerListOptions{
|
||||||
All: query.All,
|
All: query.All,
|
||||||
External: query.External,
|
External: query.External,
|
||||||
Filters: query.Filters,
|
Filters: *filterMap,
|
||||||
Last: limit,
|
Last: limit,
|
||||||
Namespace: query.Namespace,
|
Namespace: query.Namespace,
|
||||||
// Always return Pod, should not be part of the API.
|
// Always return Pod, should not be part of the API.
|
||||||
|
@ -280,6 +280,32 @@ t GET containers/json 200 \
|
|||||||
|
|
||||||
podman stop bar
|
podman stop bar
|
||||||
|
|
||||||
|
#compat api list containers sanity checks
|
||||||
|
t GET containers/json?filters='garb1age}' 500 \
|
||||||
|
.cause="invalid character 'g' looking for beginning of value"
|
||||||
|
t GET containers/json?filters='{"label":["testl' 500 \
|
||||||
|
.cause="unexpected end of JSON input"
|
||||||
|
|
||||||
|
#libpod api list containers sanity checks
|
||||||
|
t GET libpod/containers/json?filters='garb1age}' 500 \
|
||||||
|
.cause="invalid character 'g' looking for beginning of value"
|
||||||
|
t GET libpod/containers/json?filters='{"label":["testl' 500 \
|
||||||
|
.cause="unexpected end of JSON input"
|
||||||
|
|
||||||
|
# Prune containers - bad filter input
|
||||||
|
t POST containers/prune?filters='garb1age}' 500 \
|
||||||
|
.cause="invalid character 'g' looking for beginning of value"
|
||||||
|
t POST libpod/containers/prune?filters='garb1age}' 500 \
|
||||||
|
.cause="invalid character 'g' looking for beginning of value"
|
||||||
|
|
||||||
|
## Prune containers with illformed label
|
||||||
|
t POST containers/prune?filters='{"label":["tes' 500 \
|
||||||
|
.cause="unexpected end of JSON input"
|
||||||
|
t POST libpod/containers/prune?filters='{"label":["tes' 500 \
|
||||||
|
.cause="unexpected end of JSON input"
|
||||||
|
|
||||||
|
t GET libpod/containers/json?filters='{"label":["testlabel"]}' 200 length=0
|
||||||
|
|
||||||
# Test CPU limit (NanoCPUs)
|
# Test CPU limit (NanoCPUs)
|
||||||
t POST containers/create Image=$IMAGE HostConfig='{"NanoCpus":500000}' 201 \
|
t POST containers/create Image=$IMAGE HostConfig='{"NanoCpus":500000}' 201 \
|
||||||
.Id~[0-9a-f]\\{64\\}
|
.Id~[0-9a-f]\\{64\\}
|
||||||
|
Reference in New Issue
Block a user