summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2021-03-24 03:10:28 -0700
committerGitHub <noreply@github.com>2021-03-24 03:10:28 -0700
commit0cb306674af4a8740464e57767d6defb020efb8e (patch)
treecf047fc93a7f0183b6c3312736ed12b014189114
parent860de13d4fe530e585c82a87a81fb46f3d0275ef (diff)
parent914218c1e8fd0dc11c1caee807bbed0cf26fdaf8 (diff)
downloadpodman-0cb306674af4a8740464e57767d6defb020efb8e.tar.gz
podman-0cb306674af4a8740464e57767d6defb020efb8e.tar.bz2
podman-0cb306674af4a8740464e57767d6defb020efb8e.zip
Merge pull request #9785 from jmguzik/unification-of-label-filter
Unification of label and until filters across list/prune endpoints
-rw-r--r--libpod/image/filters.go14
-rw-r--r--libpod/image/prune.go24
-rw-r--r--libpod/network/netconflist.go29
-rw-r--r--pkg/domain/filters/containers.go24
-rw-r--r--pkg/domain/filters/pods.go21
-rw-r--r--pkg/domain/filters/volumes.go17
-rw-r--r--pkg/util/filters.go27
-rw-r--r--pkg/util/filters_test.go113
8 files changed, 152 insertions, 117 deletions
diff --git a/libpod/image/filters.go b/libpod/image/filters.go
index 37d3cb6a5..d316c6956 100644
--- a/libpod/image/filters.go
+++ b/libpod/image/filters.go
@@ -9,6 +9,7 @@ import (
"time"
"github.com/containers/podman/v3/pkg/inspect"
+ "github.com/containers/podman/v3/pkg/util"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -78,23 +79,14 @@ func ReadOnlyFilter(readOnly bool) ResultFilter {
}
// LabelFilter allows you to filter by images labels key and/or value
-func LabelFilter(ctx context.Context, labelfilter string) ResultFilter {
+func LabelFilter(ctx context.Context, filter string) ResultFilter {
// We need to handle both label=key and label=key=value
return func(i *Image) bool {
- var value string
- splitFilter := strings.SplitN(labelfilter, "=", 2)
- key := splitFilter[0]
- if len(splitFilter) > 1 {
- value = splitFilter[1]
- }
labels, err := i.Labels(ctx)
if err != nil {
return false
}
- if len(strings.TrimSpace(labels[key])) > 0 && len(strings.TrimSpace(value)) == 0 {
- return true
- }
- return labels[key] == value
+ return util.MatchLabelFilters([]string{filter}, labels)
}
}
diff --git a/libpod/image/prune.go b/libpod/image/prune.go
index d6ae5feaf..7ee3e077e 100644
--- a/libpod/image/prune.go
+++ b/libpod/image/prune.go
@@ -3,11 +3,10 @@ package image
import (
"context"
"strings"
- "time"
"github.com/containers/podman/v3/libpod/events"
"github.com/containers/podman/v3/pkg/domain/entities/reports"
- "github.com/containers/podman/v3/pkg/timetype"
+ "github.com/containers/podman/v3/pkg/util"
"github.com/containers/storage"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -16,36 +15,19 @@ import (
func generatePruneFilterFuncs(filter, filterValue string) (ImageFilter, error) {
switch filter {
case "label":
- var filterArray = strings.SplitN(filterValue, "=", 2)
- var filterKey = filterArray[0]
- if len(filterArray) > 1 {
- filterValue = filterArray[1]
- } else {
- filterValue = ""
- }
return func(i *Image) bool {
labels, err := i.Labels(context.Background())
if err != nil {
return false
}
- for labelKey, labelValue := range labels {
- if labelKey == filterKey && (filterValue == "" || labelValue == filterValue) {
- return true
- }
- }
- return false
+ return util.MatchLabelFilters([]string{filterValue}, labels)
}, nil
case "until":
- ts, err := timetype.GetTimestamp(filterValue, time.Now())
- if err != nil {
- return nil, err
- }
- seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0)
+ until, err := util.ComputeUntilTimestamp([]string{filterValue})
if err != nil {
return nil, err
}
- until := time.Unix(seconds, nanoseconds)
return func(i *Image) bool {
if !until.IsZero() && i.Created().After((until)) {
return true
diff --git a/libpod/network/netconflist.go b/libpod/network/netconflist.go
index b358bc530..08816f2bd 100644
--- a/libpod/network/netconflist.go
+++ b/libpod/network/netconflist.go
@@ -225,7 +225,7 @@ func IfPassesFilter(netconf *libcni.NetworkConfigList, filters map[string][]stri
case "label":
// matches all labels
- result = matchPruneLabelFilters(netconf, filterValues)
+ result = util.MatchLabelFilters(filterValues, GetNetworkLabels(netconf))
case "driver":
// matches only for the DefaultNetworkDriver
@@ -260,9 +260,9 @@ func IfPassesPruneFilter(config *config.Config, netconf *libcni.NetworkConfigLis
for key, filterValues := range f {
switch strings.ToLower(key) {
case "label":
- return matchPruneLabelFilters(netconf, filterValues), nil
+ return util.MatchLabelFilters(filterValues, GetNetworkLabels(netconf)), nil
case "until":
- until, err := util.ComputeUntilTimestamp(key, filterValues)
+ until, err := util.ComputeUntilTimestamp(filterValues)
if err != nil {
return false, err
}
@@ -280,29 +280,6 @@ func IfPassesPruneFilter(config *config.Config, netconf *libcni.NetworkConfigLis
return false, nil
}
-func matchPruneLabelFilters(netconf *libcni.NetworkConfigList, filterValues []string) bool {
- labels := GetNetworkLabels(netconf)
- result := true
-outer:
- for _, filterValue := range filterValues {
- 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) {
- result = true
- continue outer
- }
- }
- result = false
- }
- return result
-}
-
func getCreatedTimestamp(config *config.Config, netconf *libcni.NetworkConfigList) (*time.Time, error) {
networkConfigPath, err := GetCNIConfigPathByNameOrID(config, netconf.Name)
if err != nil {
diff --git a/pkg/domain/filters/containers.go b/pkg/domain/filters/containers.go
index 02727e841..84cf03764 100644
--- a/pkg/domain/filters/containers.go
+++ b/pkg/domain/filters/containers.go
@@ -23,27 +23,7 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
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
+ return util.MatchLabelFilters(filterValues, c.Labels())
}, nil
case "name":
// we only have to match one name
@@ -185,7 +165,7 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
return false
}, nil
case "until":
- until, err := util.ComputeUntilTimestamp(filter, filterValues)
+ until, err := util.ComputeUntilTimestamp(filterValues)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/filters/pods.go b/pkg/domain/filters/pods.go
index 0490a4848..9a1c7d19d 100644
--- a/pkg/domain/filters/pods.go
+++ b/pkg/domain/filters/pods.go
@@ -114,26 +114,7 @@ func GeneratePodFilterFunc(filter string, filterValues []string) (
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
+ return util.MatchLabelFilters(filterValues, labels)
}, nil
case "network":
return func(p *libpod.Pod) bool {
diff --git a/pkg/domain/filters/volumes.go b/pkg/domain/filters/volumes.go
index bc1756cf5..9b2fc5280 100644
--- a/pkg/domain/filters/volumes.go
+++ b/pkg/domain/filters/volumes.go
@@ -5,6 +5,7 @@ import (
"strings"
"github.com/containers/podman/v3/libpod"
+ "github.com/containers/podman/v3/pkg/util"
"github.com/pkg/errors"
)
@@ -29,21 +30,9 @@ func GenerateVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, error) {
return v.Scope() == scopeVal
})
case "label":
- filterArray := strings.SplitN(val, "=", 2)
- filterKey := filterArray[0]
- var filterVal string
- if len(filterArray) > 1 {
- filterVal = filterArray[1]
- } else {
- filterVal = ""
- }
+ filter := val
vf = append(vf, func(v *libpod.Volume) bool {
- for labelKey, labelValue := range v.Labels() {
- if labelKey == filterKey && (filterVal == "" || labelValue == filterVal) {
- return true
- }
- }
- return false
+ return util.MatchLabelFilters([]string{filter}, v.Labels())
})
case "opt":
filterArray := strings.SplitN(val, "=", 2)
diff --git a/pkg/util/filters.go b/pkg/util/filters.go
index 51b2c5331..43bf646f1 100644
--- a/pkg/util/filters.go
+++ b/pkg/util/filters.go
@@ -11,11 +11,11 @@ import (
"github.com/pkg/errors"
)
-// ComputeUntilTimestamp extracts unitil timestamp from filters
-func ComputeUntilTimestamp(filter string, filterValues []string) (time.Time, error) {
+// ComputeUntilTimestamp extracts until timestamp from filters
+func ComputeUntilTimestamp(filterValues []string) (time.Time, error) {
invalid := time.Time{}
if len(filterValues) != 1 {
- return invalid, errors.Errorf("specify exactly one timestamp for %s", filter)
+ return invalid, errors.Errorf("specify exactly one timestamp for until")
}
ts, err := timetype.GetTimestamp(filterValues[0], time.Now())
if err != nil {
@@ -93,3 +93,24 @@ func PrepareFilters(r *http.Request) (*map[string][]string, error) {
}
return &filterMap, nil
}
+
+// MatchLabelFilters matches labels and returs true if they are valid
+func MatchLabelFilters(filterValues []string, labels map[string]string) bool {
+outer:
+ for _, filterValue := range filterValues {
+ 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) {
+ continue outer
+ }
+ }
+ return false
+ }
+ return true
+}
diff --git a/pkg/util/filters_test.go b/pkg/util/filters_test.go
new file mode 100644
index 000000000..47259013e
--- /dev/null
+++ b/pkg/util/filters_test.go
@@ -0,0 +1,113 @@
+package util
+
+import (
+ "testing"
+)
+
+func TestMatchLabelFilters(t *testing.T) {
+ testLabels := map[string]string{
+ "label1": "",
+ "label2": "test",
+ "label3": "",
+ }
+ type args struct {
+ filterValues []string
+ labels map[string]string
+ }
+ tests := []struct {
+ name string
+ args args
+ want bool
+ }{
+ {
+ name: "Match when all filters the same as labels",
+ args: args{
+ filterValues: []string{"label1", "label3", "label2=test"},
+ labels: testLabels,
+ },
+ want: true,
+ },
+ {
+ name: "Match when filter value not provided in args",
+ args: args{
+ filterValues: []string{"label2"},
+ labels: testLabels,
+ },
+ want: true,
+ },
+ {
+ name: "Match when no filter value is given",
+ args: args{
+ filterValues: []string{"label2="},
+ labels: testLabels,
+ },
+ want: true,
+ },
+ {
+ name: "Do not match when filter value differs",
+ args: args{
+ filterValues: []string{"label2=differs"},
+ labels: testLabels,
+ },
+ want: false,
+ },
+ {
+ name: "Do not match when filter value not listed in labels",
+ args: args{
+ filterValues: []string{"label1=xyz"},
+ labels: testLabels,
+ },
+ want: false,
+ },
+ {
+ name: "Do not match when one from many not ok",
+ args: args{
+ filterValues: []string{"label1=xyz", "invalid=valid"},
+ labels: testLabels,
+ },
+ want: false,
+ },
+ }
+ for _, tt := range tests {
+ tt := tt
+ t.Run(tt.name, func(t *testing.T) {
+ if got := MatchLabelFilters(tt.args.filterValues, tt.args.labels); got != tt.want {
+ t.Errorf("MatchLabelFilters() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func TestComputeUntilTimestamp(t *testing.T) {
+ tests := []struct {
+ name string
+ args []string
+ wantErr bool
+ }{
+ {
+ name: "Return error when more values in list",
+ args: []string{"5h", "6s"},
+ wantErr: true,
+ },
+ {
+ name: "Return error when invalid time",
+ args: []string{"invalidTime"},
+ wantErr: true,
+ },
+ {
+ name: "Do not return error when correct time format supplied",
+ args: []string{"44m"},
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ tt := tt
+ t.Run(tt.name, func(t *testing.T) {
+ _, err := ComputeUntilTimestamp(tt.args)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("ComputeUntilTimestamp() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ })
+ }
+}