diff options
author | Paul Holzinger <paul.holzinger@web.de> | 2020-11-18 11:23:30 +0100 |
---|---|---|
committer | Paul Holzinger <paul.holzinger@web.de> | 2020-11-18 19:31:25 +0100 |
commit | e7fd9234cd0e6a23e32dd31c912ac47883b59738 (patch) | |
tree | 7befe4ca3c1e47c52aec7eaaec26204d729ae849 | |
parent | 6ece1d97c428f1641cb35972357cd037562fd06e (diff) | |
download | podman-e7fd9234cd0e6a23e32dd31c912ac47883b59738.tar.gz podman-e7fd9234cd0e6a23e32dd31c912ac47883b59738.tar.bz2 podman-e7fd9234cd0e6a23e32dd31c912ac47883b59738.zip |
Align the podman pod ps --filter behavior with podman ps
Filters with the same key work inclusive with the only exception being
`label` which is exclusive. Filters with different keys always work exclusive.
Also update the documentation with the new behavior.
Signed-off-by: Paul Holzinger <paul.holzinger@web.de>
-rw-r--r-- | docs/source/markdown/podman-pod-ps.1.md | 24 | ||||
-rw-r--r-- | docs/source/markdown/podman-ps.1.md | 8 | ||||
-rw-r--r-- | libpod/filters/pods.go | 97 | ||||
-rw-r--r-- | pkg/api/handlers/utils/pods.go | 14 | ||||
-rw-r--r-- | pkg/domain/infra/abi/pods.go | 17 | ||||
-rw-r--r-- | test/e2e/pod_ps_test.go | 26 |
6 files changed, 114 insertions, 72 deletions
diff --git a/docs/source/markdown/podman-pod-ps.1.md b/docs/source/markdown/podman-pod-ps.1.md index 94747cd10..e1d60d765 100644 --- a/docs/source/markdown/podman-pod-ps.1.md +++ b/docs/source/markdown/podman-pod-ps.1.md @@ -80,19 +80,23 @@ Default: created #### **--filter**, **-f**=*filter* -Filter output based on conditions given +Filter output based on conditions given. +Multiple filters can be given with multiple uses of the --filter flag. +Filters with the same key work inclusive with the only exception being +`label` which is exclusive. Filters with different keys always work exclusive. Valid filters are listed below: -| **Filter** | **Description** | -| --------------- | ------------------------------------------------------------------- | -| id | [ID] Pod's ID | -| name | [Name] Pod's name | -| label | [Key] or [Key=Value] Label assigned to a container | -| ctr-names | Container name within the pod | -| ctr-ids | Container ID within the pod | -| ctr-status | Container status within the pod | -| ctr-number | Number of containers in the pod | +| **Filter** | **Description** | +| ---------- | ------------------------------------------------------------------------------------- | +| id | [ID] Pod's ID (accepts regex) | +| name | [Name] Pod's name (accepts regex) | +| label | [Key] or [Key=Value] Label assigned to a container | +| status | Pod's status: `stopped`, `running`, `paused`, `exited`, `dead`, `created`, `degraded` | +| ctr-names | Container name within the pod (accepts regex) | +| ctr-ids | Container ID within the pod (accepts regex) | +| ctr-status | Container status within the pod | +| ctr-number | Number of containers in the pod | #### **--help**, **-h** diff --git a/docs/source/markdown/podman-ps.1.md b/docs/source/markdown/podman-ps.1.md index 5869f2307..f542daf4c 100644 --- a/docs/source/markdown/podman-ps.1.md +++ b/docs/source/markdown/podman-ps.1.md @@ -44,15 +44,15 @@ Display external containers that are not controlled by Podman but are stored in Filter what containers are shown in the output. Multiple filters can be given with multiple uses of the --filter flag. -If multiple filters are given, only containers which match all of the given filters will be shown. -Results will be drawn from all containers, regardless of whether --all was given. +Filters with the same key work inclusive with the only exception being +`label` which is exclusive. Filters with different keys always work exclusive. Valid filters are listed below: | **Filter** | **Description** | | --------------- | -------------------------------------------------------------------------------- | -| id | [ID] Container's ID | -| name | [Name] Container's name | +| id | [ID] Container's ID (accepts regex) | +| name | [Name] Container's name (accepts regex) | | label | [Key] or [Key=Value] Label assigned to a container | | exited | [Int] Container's exit code | | status | [Status] Container's status: 'created', 'exited', 'paused', 'running', 'unknown' | diff --git a/libpod/filters/pods.go b/libpod/filters/pods.go index 3cd97728f..17b3f3ca9 100644 --- a/libpod/filters/pods.go +++ b/libpod/filters/pods.go @@ -1,7 +1,6 @@ package lpfilters import ( - "regexp" "strconv" "strings" @@ -9,13 +8,12 @@ import ( "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/util" "github.com/pkg/errors" - "github.com/sirupsen/logrus" ) // GeneratePodFilterFunc takes a filter and filtervalue (key, value) // and generates a libpod function that can be used to filter // pods -func GeneratePodFilterFunc(filter, filterValue string) ( +func GeneratePodFilterFunc(filter string, filterValues []string) ( func(pod *libpod.Pod) bool, error) { switch filter { case "ctr-ids": @@ -24,7 +22,10 @@ func GeneratePodFilterFunc(filter, filterValue string) ( if err != nil { return false } - return util.StringInSlice(filterValue, ctrIds) + for _, id := range ctrIds { + return util.StringMatchRegexSlice(id, filterValues) + } + return false }, nil case "ctr-names": return func(p *libpod.Pod) bool { @@ -33,9 +34,7 @@ func GeneratePodFilterFunc(filter, filterValue string) ( return false } for _, ctr := range ctrs { - if filterValue == ctr.Name() { - return true - } + return util.StringMatchRegexSlice(ctr.Name(), filterValues) } return false }, nil @@ -45,18 +44,22 @@ func GeneratePodFilterFunc(filter, filterValue string) ( if err != nil { return false } - - fVint, err2 := strconv.Atoi(filterValue) - if err2 != nil { - return false + for _, filterValue := range filterValues { + fVint, err2 := strconv.Atoi(filterValue) + if err2 != nil { + return false + } + if len(ctrIds) == fVint { + return true + } } - return len(ctrIds) == fVint + return false }, nil case "ctr-status": - if !util.StringInSlice(filterValue, - []string{"created", "restarting", "running", "paused", - "exited", "unknown"}) { - return nil, errors.Errorf("%s is not a valid status", filterValue) + for _, filterValue := range filterValues { + if !util.StringInSlice(filterValue, []string{"created", "running", "paused", "stopped", "exited", "unknown"}) { + return nil, errors.Errorf("%s is not a valid status", filterValue) + } } return func(p *libpod.Pod) bool { ctrStatuses, err := p.Status() @@ -67,55 +70,69 @@ func GeneratePodFilterFunc(filter, filterValue string) ( state := ctrStatus.String() if ctrStatus == define.ContainerStateConfigured { state = "created" + } else if ctrStatus == define.ContainerStateStopped { + state = "exited" } - if state == filterValue { - return true + for _, filterValue := range filterValues { + if filterValue == "stopped" { + filterValue = "exited" + } + if state == filterValue { + return true + } } } return false }, nil case "id": return func(p *libpod.Pod) bool { - return strings.Contains(p.ID(), filterValue) + return util.StringMatchRegexSlice(p.ID(), filterValues) }, nil case "name": return func(p *libpod.Pod) bool { - match, err := regexp.MatchString(filterValue, p.Name()) - if err != nil { - logrus.Errorf("Failed to compile regex for 'name' filter: %v", err) - return false - } - return match + return util.StringMatchRegexSlice(p.Name(), filterValues) }, nil case "status": - if !util.StringInSlice(filterValue, []string{"stopped", "running", "paused", "exited", "dead", "created", "degraded"}) { - return nil, errors.Errorf("%s is not a valid pod status", filterValue) + for _, filterValue := range filterValues { + if !util.StringInSlice(filterValue, []string{"stopped", "running", "paused", "exited", "dead", "created", "degraded"}) { + return nil, errors.Errorf("%s is not a valid pod status", filterValue) + } } return func(p *libpod.Pod) bool { status, err := p.GetPodStatus() if err != nil { return false } - if strings.ToLower(status) == filterValue { - return true + for _, filterValue := range filterValues { + if strings.ToLower(status) == filterValue { + return true + } } return false }, nil case "label": - var filterArray = strings.SplitN(filterValue, "=", 2) - var filterKey = filterArray[0] - if len(filterArray) > 1 { - filterValue = filterArray[1] - } else { - filterValue = "" - } return func(p *libpod.Pod) bool { - for labelKey, labelValue := range p.Labels() { - if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) { - return true + labels := p.Labels() + for _, filterValue := range filterValues { + matched := false + filterArray := strings.SplitN(filterValue, "=", 2) + filterKey := filterArray[0] + if len(filterArray) > 1 { + filterValue = filterArray[1] + } else { + filterValue = "" + } + for labelKey, labelValue := range labels { + if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) { + matched = true + break + } + } + if !matched { + return false } } - return false + return true }, nil } return nil, errors.Errorf("%s is an invalid filter", filter) diff --git a/pkg/api/handlers/utils/pods.go b/pkg/api/handlers/utils/pods.go index 54ebe2d29..7506dbfd1 100644 --- a/pkg/api/handlers/utils/pods.go +++ b/pkg/api/handlers/utils/pods.go @@ -11,8 +11,7 @@ import ( func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport, error) { var ( - pods []*libpod.Pod - filters []libpod.PodFilter + pods []*libpod.Pod ) runtime := r.Context().Value("runtime").(*libpod.Runtime) decoder := r.Context().Value("decoder").(*schema.Decoder) @@ -30,14 +29,13 @@ func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport UnSupportedParameter("digests") } + filters := make([]libpod.PodFilter, 0, len(query.Filters)) for k, v := range query.Filters { - for _, filter := range v { - f, err := lpfilters.GeneratePodFilterFunc(k, filter) - if err != nil { - return nil, err - } - filters = append(filters, f) + f, err := lpfilters.GeneratePodFilterFunc(k, v) + if err != nil { + return nil, err } + filters = append(filters, f) } pods, err := runtime.Pods(filters...) if err != nil { diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go index 258640a81..11374e513 100644 --- a/pkg/domain/infra/abi/pods.go +++ b/pkg/domain/infra/abi/pods.go @@ -282,20 +282,17 @@ func (ic *ContainerEngine) PodTop(ctx context.Context, options entities.PodTopOp func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOptions) ([]*entities.ListPodsReport, error) { var ( - err error - filters = []libpod.PodFilter{} - pds = []*libpod.Pod{} + err error + pds = []*libpod.Pod{} ) + filters := make([]libpod.PodFilter, 0, len(options.Filters)) for k, v := range options.Filters { - for _, filter := range v { - f, err := lpfilters.GeneratePodFilterFunc(k, filter) - if err != nil { - return nil, err - } - filters = append(filters, f) - + f, err := lpfilters.GeneratePodFilterFunc(k, v) + if err != nil { + return nil, err } + filters = append(filters, f) } if options.Latest { pod, err := ic.Libpod.GetLatestPod() diff --git a/test/e2e/pod_ps_test.go b/test/e2e/pod_ps_test.go index 5d63d5985..ea8d10e78 100644 --- a/test/e2e/pod_ps_test.go +++ b/test/e2e/pod_ps_test.go @@ -194,12 +194,24 @@ var _ = Describe("Podman ps", func() { Expect(session.OutputToString()).To(ContainSubstring(podid1)) Expect(session.OutputToString()).To(Not(ContainSubstring(podid2))) + session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-names=test", "--filter", "ctr-status=running"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring(podid1)) + Expect(session.OutputToString()).To(Not(ContainSubstring(podid2))) + session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", fmt.Sprintf("ctr-ids=%s", cid)}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring(podid2)) Expect(session.OutputToString()).To(Not(ContainSubstring(podid1))) + session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-ids=" + cid[:40], "--filter", "ctr-ids=" + cid + "$"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring(podid2)) + Expect(session.OutputToString()).To(Not(ContainSubstring(podid1))) + _, ec3, podid3 := podmanTest.CreatePod("") Expect(ec3).To(Equal(0)) @@ -210,6 +222,13 @@ var _ = Describe("Podman ps", func() { Expect(session.OutputToString()).To(ContainSubstring(podid2)) Expect(session.OutputToString()).To(Not(ContainSubstring(podid3))) + session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-number=1", "--filter", "ctr-number=0"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring(podid1)) + Expect(session.OutputToString()).To(ContainSubstring(podid2)) + Expect(session.OutputToString()).To(ContainSubstring(podid3)) + session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-status=running"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -224,6 +243,13 @@ var _ = Describe("Podman ps", func() { Expect(session.OutputToString()).To(Not(ContainSubstring(podid1))) Expect(session.OutputToString()).To(Not(ContainSubstring(podid3))) + session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-status=exited", "--filter", "ctr-status=running"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring(podid1)) + Expect(session.OutputToString()).To(ContainSubstring(podid2)) + Expect(session.OutputToString()).To(Not(ContainSubstring(podid3))) + session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-status=created"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) |