Containers prune endpoint should use only prune filters

Containers endpoints for HTTP compad and libpod APIs allowed usage of list HTTP
endpoint filter funcs. Documentation in case of libpod and compat API does not allow that.
This commit aligns code with the documentation.

Signed-off-by: Jakub Guzik <jakubmguzik@gmail.com>
This commit is contained in:
Jakub Guzik
2021-03-30 10:19:22 +02:00
parent 08eab3f8f7
commit f7d82a1f30
5 changed files with 57 additions and 17 deletions

View File

@ -23,7 +23,7 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) {
filterFuncs := make([]libpod.ContainerFilter, 0, len(*filtersMap)) filterFuncs := make([]libpod.ContainerFilter, 0, len(*filtersMap))
for k, v := range *filtersMap { for k, v := range *filtersMap {
generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime) generatedFunc, err := filters.GeneratePruneContainerFilterFuncs(k, v, runtime)
if err != nil { if err != nil {
utils.InternalServerError(w, err) utils.InternalServerError(w, err)
return return

View File

@ -550,21 +550,28 @@ var _ = Describe("Podman containers ", func() {
filtersIncorrect := map[string][]string{ filtersIncorrect := map[string][]string{
"status": {"dummy"}, "status": {"dummy"},
} }
pruneResponse, err := containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filtersIncorrect)) _, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filtersIncorrect))
Expect(err).ToNot(BeNil())
// List filter params should not work with prune.
filtersIncorrect = map[string][]string{
"name": {"top"},
}
_, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filtersIncorrect))
Expect(err).ToNot(BeNil()) Expect(err).ToNot(BeNil())
// Mismatched filter params no container should be pruned. // Mismatched filter params no container should be pruned.
filtersIncorrect = map[string][]string{ filtersIncorrect = map[string][]string{
"name": {"r"}, "label": {"xyz"},
} }
pruneResponse, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filtersIncorrect)) pruneResponse, err := containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filtersIncorrect))
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(0)) Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(0))
Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0)) Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0))
// Valid filter params container should be pruned now. // Valid filter params container should be pruned now.
filters := map[string][]string{ filters := map[string][]string{
"name": {"top"}, "until": {"0s"},
} }
pruneResponse, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filters)) pruneResponse, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filters))
Expect(err).To(BeNil()) Expect(err).To(BeNil())

View File

@ -165,16 +165,7 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
return false return false
}, nil }, nil
case "until": case "until":
until, err := util.ComputeUntilTimestamp(filterValues) return prepareUntilFilterFunc(filterValues)
if err != nil {
return nil, err
}
return func(c *libpod.Container) bool {
if !until.IsZero() && c.CreatedTime().After((until)) {
return true
}
return false
}, nil
case "pod": case "pod":
var pods []*libpod.Pod var pods []*libpod.Pod
for _, podNameOrID := range filterValues { for _, podNameOrID := range filterValues {
@ -226,3 +217,29 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
} }
return nil, errors.Errorf("%s is an invalid filter", filter) return nil, errors.Errorf("%s is an invalid filter", filter)
} }
// GeneratePruneContainerFilterFuncs return ContainerFilter functions based of filter for prune operation
func GeneratePruneContainerFilterFuncs(filter string, filterValues []string, r *libpod.Runtime) (func(container *libpod.Container) bool, error) {
switch filter {
case "label":
return func(c *libpod.Container) bool {
return util.MatchLabelFilters(filterValues, c.Labels())
}, nil
case "until":
return prepareUntilFilterFunc(filterValues)
}
return nil, errors.Errorf("%s is an invalid filter", filter)
}
func prepareUntilFilterFunc(filterValues []string) (func(container *libpod.Container) bool, error) {
until, err := util.ComputeUntilTimestamp(filterValues)
if err != nil {
return nil, err
}
return func(c *libpod.Container) bool {
if !until.IsZero() && c.CreatedTime().After((until)) {
return true
}
return false
}, nil
}

View File

@ -194,7 +194,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) ([]*reports.PruneReport, error) { func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) ([]*reports.PruneReport, error) {
filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters)) filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters))
for k, v := range options.Filters { for k, v := range options.Filters {
generatedFunc, err := dfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod) generatedFunc, err := dfilters.GeneratePruneContainerFilterFuncs(k, v, ic.Libpod)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -298,7 +298,7 @@ t POST containers/prune?filters='garb1age}' 500 \
t POST libpod/containers/prune?filters='garb1age}' 500 \ t POST libpod/containers/prune?filters='garb1age}' 500 \
.cause="invalid character 'g' looking for beginning of value" .cause="invalid character 'g' looking for beginning of value"
## Prune containers with illformed label # Prune containers with illformed label
t POST containers/prune?filters='{"label":["tes' 500 \ t POST containers/prune?filters='{"label":["tes' 500 \
.cause="unexpected end of JSON input" .cause="unexpected end of JSON input"
t POST libpod/containers/prune?filters='{"label":["tes' 500 \ t POST libpod/containers/prune?filters='{"label":["tes' 500 \
@ -306,6 +306,22 @@ t POST libpod/containers/prune?filters='{"label":["tes' 500 \
t GET libpod/containers/json?filters='{"label":["testlabel"]}' 200 length=0 t GET libpod/containers/json?filters='{"label":["testlabel"]}' 200 length=0
# libpod api: do not use list filters for prune
t POST libpod/containers/prune?filters='{"name":["anyname"]}' 500 \
.cause="name is an invalid filter"
t POST libpod/containers/prune?filters='{"id":["anyid"]}' 500 \
.cause="id is an invalid filter"
t POST libpod/containers/prune?filters='{"network":["anynetwork"]}' 500 \
.cause="network is an invalid filter"
# compat api: do not use list filters for prune
t POST containers/prune?filters='{"name":["anyname"]}' 500 \
.cause="name is an invalid filter"
t POST containers/prune?filters='{"id":["anyid"]}' 500 \
.cause="id is an invalid filter"
t POST containers/prune?filters='{"network":["anynetwork"]}' 500 \
.cause="network is an invalid filter"
# 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\\}