Fix filtering with negated labels

Signed-off-by: Šimon Brauner <sbrauner@redhat.com>
This commit is contained in:
Šimon Brauner 2026-03-31 15:40:52 +02:00
parent 991cde5167
commit fdd8cc17fa
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()