mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
prune filter handling
network and container prune could not handle the label!=... filter. vendor in c/common to fix this and add some podman level handling to make everything run smoothly resolves #14182 Signed-off-by: Charlie Doern <cdoern@redhat.com>
This commit is contained in:
@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/containers/common/pkg/filters"
|
||||||
cutil "github.com/containers/common/pkg/util"
|
cutil "github.com/containers/common/pkg/util"
|
||||||
"github.com/containers/podman/v4/libpod"
|
"github.com/containers/podman/v4/libpod"
|
||||||
"github.com/containers/podman/v4/libpod/define"
|
"github.com/containers/podman/v4/libpod/define"
|
||||||
@ -24,7 +25,7 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
|
|||||||
case "label":
|
case "label":
|
||||||
// we have to match that all given labels exits on that container
|
// we have to match that all given labels exits on that container
|
||||||
return func(c *libpod.Container) bool {
|
return func(c *libpod.Container) bool {
|
||||||
return util.MatchLabelFilters(filterValues, c.Labels())
|
return filters.MatchLabelFilters(filterValues, c.Labels())
|
||||||
}, nil
|
}, nil
|
||||||
case "name":
|
case "name":
|
||||||
// we only have to match one name
|
// we only have to match one name
|
||||||
@ -299,7 +300,11 @@ func GeneratePruneContainerFilterFuncs(filter string, filterValues []string, r *
|
|||||||
switch filter {
|
switch filter {
|
||||||
case "label":
|
case "label":
|
||||||
return func(c *libpod.Container) bool {
|
return func(c *libpod.Container) bool {
|
||||||
return util.MatchLabelFilters(filterValues, c.Labels())
|
return filters.MatchLabelFilters(filterValues, c.Labels())
|
||||||
|
}, nil
|
||||||
|
case "label!":
|
||||||
|
return func(c *libpod.Container) bool {
|
||||||
|
return !filters.MatchLabelFilters(filterValues, c.Labels())
|
||||||
}, nil
|
}, nil
|
||||||
case "until":
|
case "until":
|
||||||
return prepareUntilFilterFunc(filterValues)
|
return prepareUntilFilterFunc(filterValues)
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/common/pkg/filters"
|
||||||
cutil "github.com/containers/common/pkg/util"
|
cutil "github.com/containers/common/pkg/util"
|
||||||
"github.com/containers/podman/v4/libpod"
|
"github.com/containers/podman/v4/libpod"
|
||||||
"github.com/containers/podman/v4/libpod/define"
|
"github.com/containers/podman/v4/libpod/define"
|
||||||
@ -115,7 +116,7 @@ func GeneratePodFilterFunc(filter string, filterValues []string, r *libpod.Runti
|
|||||||
case "label":
|
case "label":
|
||||||
return func(p *libpod.Pod) bool {
|
return func(p *libpod.Pod) bool {
|
||||||
labels := p.Labels()
|
labels := p.Labels()
|
||||||
return util.MatchLabelFilters(filterValues, labels)
|
return filters.MatchLabelFilters(filterValues, labels)
|
||||||
}, nil
|
}, nil
|
||||||
case "until":
|
case "until":
|
||||||
return func(p *libpod.Pod) bool {
|
return func(p *libpod.Pod) bool {
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
pruneFilters "github.com/containers/common/pkg/filters"
|
||||||
"github.com/containers/podman/v4/libpod"
|
"github.com/containers/podman/v4/libpod"
|
||||||
"github.com/containers/podman/v4/pkg/util"
|
"github.com/containers/podman/v4/pkg/util"
|
||||||
)
|
)
|
||||||
@ -36,7 +37,7 @@ func GenerateVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, error) {
|
|||||||
case "label":
|
case "label":
|
||||||
filter := val
|
filter := val
|
||||||
vf = append(vf, func(v *libpod.Volume) bool {
|
vf = append(vf, func(v *libpod.Volume) bool {
|
||||||
return util.MatchLabelFilters([]string{filter}, v.Labels())
|
return pruneFilters.MatchLabelFilters([]string{filter}, v.Labels())
|
||||||
})
|
})
|
||||||
case "opt":
|
case "opt":
|
||||||
filterArray := strings.SplitN(val, "=", 2)
|
filterArray := strings.SplitN(val, "=", 2)
|
||||||
@ -100,7 +101,7 @@ func GeneratePruneVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, erro
|
|||||||
switch filter {
|
switch filter {
|
||||||
case "label":
|
case "label":
|
||||||
vf = append(vf, func(v *libpod.Volume) bool {
|
vf = append(vf, func(v *libpod.Volume) bool {
|
||||||
return util.MatchLabelFilters([]string{filterVal}, v.Labels())
|
return pruneFilters.MatchLabelFilters([]string{filterVal}, v.Labels())
|
||||||
})
|
})
|
||||||
case "until":
|
case "until":
|
||||||
f, err := createUntilFilterVolumeFunction(filterVal)
|
f, err := createUntilFilterVolumeFunction(filterVal)
|
||||||
|
@ -260,6 +260,7 @@ func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
filterFuncs = append(filterFuncs, generatedFunc)
|
filterFuncs = append(filterFuncs, generatedFunc)
|
||||||
}
|
}
|
||||||
return ic.Libpod.PruneContainers(filterFuncs)
|
return ic.Libpod.PruneContainers(filterFuncs)
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -94,35 +93,3 @@ func PrepareFilters(r *http.Request) (*map[string][]string, error) {
|
|||||||
}
|
}
|
||||||
return &filterMap, nil
|
return &filterMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchPattern(pattern string, value string) bool {
|
|
||||||
if strings.Contains(pattern, "*") {
|
|
||||||
filter := fmt.Sprintf("*%s*", pattern)
|
|
||||||
filter = strings.ReplaceAll(filter, string(filepath.Separator), "|")
|
|
||||||
newName := strings.ReplaceAll(value, string(filepath.Separator), "|")
|
|
||||||
match, _ := filepath.Match(filter, newName)
|
|
||||||
return match
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchLabelFilters matches labels and returns 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) || matchPattern(filterKey, labelKey)) && (filterValue == "" || labelValue == filterValue) {
|
|
||||||
continue outer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
@ -2,6 +2,8 @@ package util
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/containers/common/pkg/filters"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMatchLabelFilters(t *testing.T) {
|
func TestMatchLabelFilters(t *testing.T) {
|
||||||
@ -71,7 +73,7 @@ func TestMatchLabelFilters(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
tt := tt
|
tt := tt
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := MatchLabelFilters(tt.args.filterValues, tt.args.labels); got != tt.want {
|
if got := filters.MatchLabelFilters(tt.args.filterValues, tt.args.labels); got != tt.want {
|
||||||
t.Errorf("MatchLabelFilters() = %v, want %v", got, tt.want)
|
t.Errorf("MatchLabelFilters() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -280,6 +280,24 @@ var _ = Describe("Podman prune", func() {
|
|||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session).Should(Exit(0))
|
Expect(session).Should(Exit(0))
|
||||||
Expect(session.OutputToStringArray()).To(HaveLen(0))
|
Expect(session.OutputToStringArray()).To(HaveLen(0))
|
||||||
|
|
||||||
|
// Create new network.
|
||||||
|
session = podmanTest.Podman([]string{"network", "create", "test1", "--label", "foo"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(Exit(0))
|
||||||
|
|
||||||
|
// Remove all unused networks.
|
||||||
|
session = podmanTest.Podman([]string{"system", "prune", "-f", "--filter", "label!=foo"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(Exit(0))
|
||||||
|
Expect(session.OutputToString()).Should(Equal("Total reclaimed space: 0B"))
|
||||||
|
|
||||||
|
// Unused networks removed.
|
||||||
|
session = podmanTest.Podman([]string{"network", "ls", "-q", "--filter", "name=^test1$"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(Exit(0))
|
||||||
|
// label should make sure we do not remove this network
|
||||||
|
Expect(session.OutputToStringArray()).To(HaveLen(1))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman system prune - pod,container stopped", func() {
|
It("podman system prune - pod,container stopped", func() {
|
||||||
|
Reference in New Issue
Block a user