Merge pull request #28455 from simonbrauner/fix-filtering-with-negated-labels

Fix filtering with negated labels
This commit is contained in:
Matt Heon
2026-04-30 12:08:31 -04:00
committed by GitHub
6 changed files with 23 additions and 8 deletions

View File

@@ -25,6 +25,8 @@ Supported filters:
The `label` *filter* accepts two formats. One is the `label`=*key* or `label`=*key*=*value*, which removes containers with the specified labels. The other format is the `label!`=*key* or `label!`=*key*=*value*, which removes containers without the specified labels.
**NOTE:** `label!` filters are combined with **AND**, so that the behavior is consistent with `label`, while in Docker, they are combined with **OR**.
The `until` *filter* can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machines time.
#### **--force**, **-f**

View File

@@ -43,6 +43,8 @@ Supported filters:
The `label` *filter* accepts two formats. One is the `label`=*key* or `label`=*key*=*value*, which removes volumes with the specified labels. The other format is the `label!`=*key* or `label!`=*key*=*value*, which removes volumes without the specified labels.
**NOTE:** `label!` filters are combined with **AND**, so that the behavior is consistent with `label`, while in Docker, they are combined with **OR**.
The `until` *filter* can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine's time.
#### **--force**, **-f**

View File

@@ -32,7 +32,7 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
}, nil
case "label!":
return func(c *libpod.Container) bool {
return !filters.MatchLabelFilters(filterValues, c.Labels())
return filters.MatchNegatedLabelFilters(filterValues, c.Labels())
}, nil
case "name":
// we only have to match one name
@@ -309,7 +309,7 @@ func GeneratePruneContainerFilterFuncs(filter string, filterValues []string, _ *
}, nil
case "label!":
return func(c *libpod.Container) bool {
return !filters.MatchLabelFilters(filterValues, c.Labels())
return filters.MatchNegatedLabelFilters(filterValues, c.Labels())
}, nil
case "until":
return prepareUntilFilterFunc(filterValues)
@@ -478,7 +478,11 @@ func GenerateExternalContainerFilterFuncs(filter string, filterValues []string,
}, nil
case "label":
return func(listContainer *types.ListContainer) bool {
return !filters.MatchLabelFilters(filterValues, listContainer.Labels)
return filters.MatchLabelFilters(filterValues, listContainer.Labels)
}, nil
case "label!":
return func(listContainer *types.ListContainer) bool {
return filters.MatchNegatedLabelFilters(filterValues, listContainer.Labels)
}, nil
case "pod":
var pods []*libpod.Pod

View File

@@ -122,7 +122,7 @@ func GeneratePodFilterFunc(filter string, filterValues []string, r *libpod.Runti
case "label!":
return func(p *libpod.Pod) bool {
labels := p.Labels()
return !filters.MatchLabelFilters(filterValues, labels)
return filters.MatchNegatedLabelFilters(filterValues, labels)
}, nil
case "until":
return func(p *libpod.Pod) bool {

View File

@@ -35,7 +35,7 @@ func GenerateVolumeFilters(filter string, filterValues []string, runtime *libpod
}, nil
case "label!":
return func(v *libpod.Volume) bool {
return !filters.MatchLabelFilters(filterValues, v.Labels())
return filters.MatchNegatedLabelFilters(filterValues, v.Labels())
}, nil
case "opt":
return func(v *libpod.Volume) bool {
@@ -101,7 +101,7 @@ func GeneratePruneVolumeFilters(filter string, filterValues []string, runtime *l
}, nil
case "label!":
return func(v *libpod.Volume) bool {
return !filters.MatchLabelFilters(filterValues, v.Labels())
return filters.MatchNegatedLabelFilters(filterValues, v.Labels())
}, nil
case "until":
return createUntilFilterVolumeFunction(filterValues)

View File

@@ -189,7 +189,7 @@ var _ = Describe("Podman volume ls", func() {
vol1Name := session.OutputToString()
session = podmanTest.Podman([]string{"volume", "create", "--label", "b=c", "--label", "a=b", "vol2"})
session = podmanTest.Podman([]string{"volume", "create", "--label", "a=b", "--label", "b=c", "--label", "d=e", "vol2"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
@@ -208,12 +208,19 @@ var _ = Describe("Podman volume ls", func() {
Expect(session.OutputToStringArray()[0]).To(Equal(vol1Name))
Expect(session.OutputToStringArray()[1]).To(Equal(vol2Name))
session = podmanTest.Podman([]string{"volume", "ls", "-q", "--filter", "label=c=d", "--filter", "label=b=c"})
session = podmanTest.Podman([]string{"volume", "ls", "-q", "--filter", "label=b=c", "--filter", "label=c=d"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToStringArray()).To(HaveLen(1))
Expect(session.OutputToStringArray()[0]).To(Equal(vol3Name))
// Filters with label! key
session = podmanTest.Podman([]string{"volume", "ls", "-q", "--filter", "label!=c=d", "--filter", "label!=d=e"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToStringArray()).To(HaveLen(1))
Expect(session.OutputToStringArray()[0]).To(Equal(vol1Name))
// Filters with different keys
session = podmanTest.Podman([]string{"volume", "ls", "-q", "--filter", "label=b=c", "--filter", "name=vol1"})
session.WaitWithDefaultTimeout()