diff options
author | Baron Lenardson <lenardson.baron@gmail.com> | 2020-12-22 20:29:31 -0600 |
---|---|---|
committer | Baron Lenardson <baron.lenardson@target.com> | 2020-12-24 20:27:41 +0000 |
commit | 76afb50f3ae41a3cc43fca8cc41a2d2f1f1b6dcc (patch) | |
tree | 0adcdac5dc8a124db32a90a386d708fc01922bf7 /pkg | |
parent | 8f75ed958562f4deb47799259e22d4f195e0d426 (diff) | |
download | podman-76afb50f3ae41a3cc43fca8cc41a2d2f1f1b6dcc.tar.gz podman-76afb50f3ae41a3cc43fca8cc41a2d2f1f1b6dcc.tar.bz2 podman-76afb50f3ae41a3cc43fca8cc41a2d2f1f1b6dcc.zip |
Consolidate filter logic to pkg subdirectory
Per the conversation on pull/8724 I am consolidating filter logic
and helper functions under the pkg/domain/filters dir.
Signed-off-by: Baron Lenardson <lenardson.baron@gmail.com>
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/api/handlers/compat/containers_prune.go | 4 | ||||
-rw-r--r-- | pkg/api/handlers/utils/pods.go | 4 | ||||
-rw-r--r-- | pkg/domain/filters/containers.go | 239 | ||||
-rw-r--r-- | pkg/domain/filters/pods.go | 139 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 4 | ||||
-rw-r--r-- | pkg/domain/infra/abi/pods.go | 4 | ||||
-rw-r--r-- | pkg/ps/ps.go | 6 |
7 files changed, 389 insertions, 11 deletions
diff --git a/pkg/api/handlers/compat/containers_prune.go b/pkg/api/handlers/compat/containers_prune.go index 2cfeebcce..a1e35dd97 100644 --- a/pkg/api/handlers/compat/containers_prune.go +++ b/pkg/api/handlers/compat/containers_prune.go @@ -4,9 +4,9 @@ import ( "net/http" "github.com/containers/podman/v2/libpod" - lpfilters "github.com/containers/podman/v2/libpod/filters" "github.com/containers/podman/v2/pkg/api/handlers/utils" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/filters" "github.com/docker/docker/api/types" "github.com/gorilla/schema" "github.com/pkg/errors" @@ -29,7 +29,7 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) { } filterFuncs := make([]libpod.ContainerFilter, 0, len(query.Filters)) for k, v := range query.Filters { - generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, runtime) + generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime) if err != nil { utils.InternalServerError(w, err) return diff --git a/pkg/api/handlers/utils/pods.go b/pkg/api/handlers/utils/pods.go index 7506dbfd1..0fe3a308b 100644 --- a/pkg/api/handlers/utils/pods.go +++ b/pkg/api/handlers/utils/pods.go @@ -4,8 +4,8 @@ import ( "net/http" "github.com/containers/podman/v2/libpod" - lpfilters "github.com/containers/podman/v2/libpod/filters" "github.com/containers/podman/v2/pkg/domain/entities" + dfilters "github.com/containers/podman/v2/pkg/domain/filters" "github.com/gorilla/schema" ) @@ -31,7 +31,7 @@ func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport filters := make([]libpod.PodFilter, 0, len(query.Filters)) for k, v := range query.Filters { - f, err := lpfilters.GeneratePodFilterFunc(k, v) + f, err := dfilters.GeneratePodFilterFunc(k, v) if err != nil { return nil, err } diff --git a/pkg/domain/filters/containers.go b/pkg/domain/filters/containers.go new file mode 100644 index 000000000..6abdd6b57 --- /dev/null +++ b/pkg/domain/filters/containers.go @@ -0,0 +1,239 @@ +package filters + +import ( + "strconv" + "strings" + "time" + + "github.com/containers/podman/v2/libpod" + "github.com/containers/podman/v2/libpod/define" + "github.com/containers/podman/v2/pkg/timetype" + "github.com/containers/podman/v2/pkg/util" + "github.com/pkg/errors" +) + +// GenerateContainerFilterFuncs return ContainerFilter functions based of filter. +func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpod.Runtime) (func(container *libpod.Container) bool, error) { + switch filter { + case "id": + // we only have to match one ID + return func(c *libpod.Container) bool { + return util.StringMatchRegexSlice(c.ID(), filterValues) + }, nil + case "label": + // we have to match that all given labels exits on that container + return func(c *libpod.Container) bool { + labels := c.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 true + }, nil + case "name": + // we only have to match one name + return func(c *libpod.Container) bool { + return util.StringMatchRegexSlice(c.Name(), filterValues) + }, nil + case "exited": + var exitCodes []int32 + for _, exitCode := range filterValues { + ec, err := strconv.ParseInt(exitCode, 10, 32) + if err != nil { + return nil, errors.Wrapf(err, "exited code out of range %q", ec) + } + exitCodes = append(exitCodes, int32(ec)) + } + return func(c *libpod.Container) bool { + ec, exited, err := c.ExitCode() + if err == nil && exited { + for _, exitCode := range exitCodes { + if ec == exitCode { + return true + } + } + } + return false + }, nil + case "status": + 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(c *libpod.Container) bool { + status, err := c.State() + if err != nil { + return false + } + state := status.String() + if status == define.ContainerStateConfigured { + state = "created" + } else if status == define.ContainerStateStopped { + state = "exited" + } + for _, filterValue := range filterValues { + if filterValue == "stopped" { + filterValue = "exited" + } + if state == filterValue { + return true + } + } + return false + }, nil + case "ancestor": + // This needs to refine to match docker + // - ancestor=(<image-name>[:tag]|<image-id>| ⟨image@digest⟩) - containers created from an image or a descendant. + return func(c *libpod.Container) bool { + for _, filterValue := range filterValues { + containerConfig := c.Config() + if strings.Contains(containerConfig.RootfsImageID, filterValue) || strings.Contains(containerConfig.RootfsImageName, filterValue) { + return true + } + } + return false + }, nil + case "before": + var createTime time.Time + for _, filterValue := range filterValues { + ctr, err := r.LookupContainer(filterValue) + if err != nil { + return nil, err + } + containerConfig := ctr.Config() + if createTime.IsZero() || createTime.After(containerConfig.CreatedTime) { + createTime = containerConfig.CreatedTime + } + } + return func(c *libpod.Container) bool { + cc := c.Config() + return createTime.After(cc.CreatedTime) + }, nil + case "since": + var createTime time.Time + for _, filterValue := range filterValues { + ctr, err := r.LookupContainer(filterValue) + if err != nil { + return nil, err + } + containerConfig := ctr.Config() + if createTime.IsZero() || createTime.After(containerConfig.CreatedTime) { + createTime = containerConfig.CreatedTime + } + } + return func(c *libpod.Container) bool { + cc := c.Config() + return createTime.Before(cc.CreatedTime) + }, nil + case "volume": + //- volume=(<volume-name>|<mount-point-destination>) + return func(c *libpod.Container) bool { + containerConfig := c.Config() + var dest string + for _, filterValue := range filterValues { + arr := strings.SplitN(filterValue, ":", 2) + source := arr[0] + if len(arr) == 2 { + dest = arr[1] + } + for _, mount := range containerConfig.Spec.Mounts { + if dest != "" && (mount.Source == source && mount.Destination == dest) { + return true + } + if dest == "" && mount.Source == source { + return true + } + } + for _, vname := range containerConfig.NamedVolumes { + if dest != "" && (vname.Name == source && vname.Dest == dest) { + return true + } + if dest == "" && vname.Name == source { + return true + } + } + } + return false + }, nil + case "health": + return func(c *libpod.Container) bool { + hcStatus, err := c.HealthCheckStatus() + if err != nil { + return false + } + for _, filterValue := range filterValues { + if hcStatus == filterValue { + return true + } + } + return false + }, nil + case "until": + if len(filterValues) != 1 { + return nil, errors.Errorf("specify exactly one timestamp for %s", filter) + } + ts, err := timetype.GetTimestamp(filterValues[0], time.Now()) + if err != nil { + return nil, err + } + seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0) + if err != nil { + return nil, err + } + until := time.Unix(seconds, nanoseconds) + return func(c *libpod.Container) bool { + if !until.IsZero() && c.CreatedTime().After((until)) { + return true + } + return false + }, nil + case "pod": + var pods []*libpod.Pod + for _, podNameOrID := range filterValues { + p, err := r.LookupPod(podNameOrID) + if err != nil { + if errors.Cause(err) == define.ErrNoSuchPod { + continue + } + return nil, err + } + pods = append(pods, p) + } + return func(c *libpod.Container) bool { + // if no pods match, quick out + if len(pods) < 1 { + return false + } + // if the container has no pod id, quick out + if len(c.PodID()) < 1 { + return false + } + for _, p := range pods { + // we already looked up by name or id, so id match + // here is ok + if p.ID() == c.PodID() { + return true + } + } + return false + }, nil + + } + return nil, errors.Errorf("%s is an invalid filter", filter) +} diff --git a/pkg/domain/filters/pods.go b/pkg/domain/filters/pods.go new file mode 100644 index 000000000..7e6b7f2cc --- /dev/null +++ b/pkg/domain/filters/pods.go @@ -0,0 +1,139 @@ +package filters + +import ( + "strconv" + "strings" + + "github.com/containers/podman/v2/libpod" + "github.com/containers/podman/v2/libpod/define" + "github.com/containers/podman/v2/pkg/util" + "github.com/pkg/errors" +) + +// GeneratePodFilterFunc takes a filter and filtervalue (key, value) +// and generates a libpod function that can be used to filter +// pods +func GeneratePodFilterFunc(filter string, filterValues []string) ( + func(pod *libpod.Pod) bool, error) { + switch filter { + case "ctr-ids": + return func(p *libpod.Pod) bool { + ctrIds, err := p.AllContainersByID() + if err != nil { + return false + } + for _, id := range ctrIds { + return util.StringMatchRegexSlice(id, filterValues) + } + return false + }, nil + case "ctr-names": + return func(p *libpod.Pod) bool { + ctrs, err := p.AllContainers() + if err != nil { + return false + } + for _, ctr := range ctrs { + return util.StringMatchRegexSlice(ctr.Name(), filterValues) + } + return false + }, nil + case "ctr-number": + return func(p *libpod.Pod) bool { + ctrIds, err := p.AllContainersByID() + if err != nil { + return false + } + for _, filterValue := range filterValues { + fVint, err2 := strconv.Atoi(filterValue) + if err2 != nil { + return false + } + if len(ctrIds) == fVint { + return true + } + } + return false + }, nil + case "ctr-status": + 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() + if err != nil { + return false + } + for _, ctrStatus := range ctrStatuses { + state := ctrStatus.String() + if ctrStatus == define.ContainerStateConfigured { + state = "created" + } else if ctrStatus == define.ContainerStateStopped { + state = "exited" + } + 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 util.StringMatchRegexSlice(p.ID(), filterValues) + }, nil + case "name": + return func(p *libpod.Pod) bool { + return util.StringMatchRegexSlice(p.Name(), filterValues) + }, nil + case "status": + 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 + } + for _, filterValue := range filterValues { + if strings.ToLower(status) == filterValue { + return true + } + } + return false + }, nil + case "label": + return func(p *libpod.Pod) bool { + 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 true + }, nil + } + return nil, errors.Errorf("%s is an invalid filter", filter) +} diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index efb4f866f..cfb3421ba 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -16,12 +16,12 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/libpod/events" - lpfilters "github.com/containers/podman/v2/libpod/filters" "github.com/containers/podman/v2/libpod/image" "github.com/containers/podman/v2/libpod/logs" "github.com/containers/podman/v2/pkg/cgroups" "github.com/containers/podman/v2/pkg/checkpoint" "github.com/containers/podman/v2/pkg/domain/entities" + dfilters "github.com/containers/podman/v2/pkg/domain/filters" "github.com/containers/podman/v2/pkg/domain/infra/abi/terminal" parallelctr "github.com/containers/podman/v2/pkg/parallel/ctr" "github.com/containers/podman/v2/pkg/ps" @@ -207,7 +207,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) { filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters)) for k, v := range options.Filters { - generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod) + generatedFunc, err := dfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod) if err != nil { return nil, err } diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go index 11374e513..f108b770c 100644 --- a/pkg/domain/infra/abi/pods.go +++ b/pkg/domain/infra/abi/pods.go @@ -5,8 +5,8 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" - lpfilters "github.com/containers/podman/v2/libpod/filters" "github.com/containers/podman/v2/pkg/domain/entities" + dfilters "github.com/containers/podman/v2/pkg/domain/filters" "github.com/containers/podman/v2/pkg/signal" "github.com/containers/podman/v2/pkg/specgen" "github.com/containers/podman/v2/pkg/specgen/generate" @@ -288,7 +288,7 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti filters := make([]libpod.PodFilter, 0, len(options.Filters)) for k, v := range options.Filters { - f, err := lpfilters.GeneratePodFilterFunc(k, v) + f, err := dfilters.GeneratePodFilterFunc(k, v) if err != nil { return nil, err } diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go index 6c26e8708..9e0dcb728 100644 --- a/pkg/ps/ps.go +++ b/pkg/ps/ps.go @@ -11,8 +11,8 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" - lpfilters "github.com/containers/podman/v2/libpod/filters" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/filters" psdefine "github.com/containers/podman/v2/pkg/ps/define" "github.com/containers/storage" "github.com/pkg/errors" @@ -27,7 +27,7 @@ func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOp all := options.All || options.Last > 0 if len(options.Filters) > 0 { for k, v := range options.Filters { - generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, runtime) + generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime) if err != nil { return nil, err } @@ -41,7 +41,7 @@ func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOp all = true } if !all { - runningOnly, err := lpfilters.GenerateContainerFilterFuncs("status", []string{define.ContainerStateRunning.String()}, runtime) + runningOnly, err := filters.GenerateContainerFilterFuncs("status", []string{define.ContainerStateRunning.String()}, runtime) if err != nil { return nil, err } |