Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/source/markdown/podman-volume-prune.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ removal unless **--force** is used.

Remove all unused volumes (anonymous and named). Without this option, only anonymous unused volumes are removed.

**--all** can be combined with **--filter**: **--all** widens the set of candidate volumes to all unused ones, and the filters then restrict which of those are removed. For example, **--all --filter label!=keep** removes every unused volume that does not have the *keep* label.

#### **--dry-run**

Show which volumes would be pruned without removing them.
Expand Down Expand Up @@ -77,6 +79,11 @@ Prune all unused volumes (anonymous and named).
$ podman volume prune --all --force
```

Prune all unused volumes except those with a specific label (combine **--all** with a filter).
```
$ podman volume prune --all --force --filter label!=keep
```

Prune all unused volumes using the filter (equivalent to **--all**).
```
$ podman volume prune --filter all=true --force
Expand Down
9 changes: 6 additions & 3 deletions pkg/util/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,12 @@ func NormalizeVolumePruneFilters(f url.Values) url.Values {
}
allValue := f.Get("all")
if strings.EqualFold(allValue, "true") || allValue == "1" {
for key := range f {
f.Del(key)
}
// "all" only widens the scope from anonymous-only to every unused
// volume; it is orthogonal to the other filters. Drop just the "all"
// key and keep the rest (e.g. label/label!, until) so they continue to
// constrain which volumes are pruned, matching Docker, which ANDs the
// "all" scope together with the label filters.
f.Del("all")
return f
}
f.Del("all")
Expand Down
13 changes: 13 additions & 0 deletions pkg/util/filters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,19 @@ func TestNormalizeVolumePruneFilters(t *testing.T) {
t.Fatalf("got %#v, want no all/anonymous keys", got)
}
})
t.Run("all true keeps label filters", func(t *testing.T) {
t.Parallel()
got := NormalizeVolumePruneFilters(url.Values{"all": {"true"}, "label": {"k=v"}, "label!": {"x"}})
if got.Has("all") || got.Has("anonymous") {
t.Fatalf("got %#v, want no all/anonymous keys", got)
}
if got.Get("label") != "k=v" {
t.Fatalf("label dropped alongside all: got %#v", got)
}
if got.Get("label!") != "x" {
t.Fatalf("label! dropped alongside all: got %#v", got)
}
})
t.Run("label without anonymous key does not inject anonymous", func(t *testing.T) {
t.Parallel()
in := url.Values{"label": {"k=v"}}
Expand Down
18 changes: 18 additions & 0 deletions test/e2e/volume_prune_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,24 @@ var _ = Describe("Podman volume prune", func() {
podmanTest.PodmanExitCleanly("volume", "prune", "--force", "--filter", "label!=testlabel")
})

It("podman volume prune --all keeps the label filter", func() {
// Regression: the "all" flag must not discard a label/label! filter.
// With "--all --filter label!=keep" only unlabeled unused volumes are
// pruned; the labeled one survives. Before the fix, "all" cleared the
// filter and both volumes were removed.
podmanTest.PodmanExitCleanly("volume", "create", "--label", "keep=yes", "keepvol")
podmanTest.PodmanExitCleanly("volume", "create", "dropvol")

session := podmanTest.PodmanExitCleanly("volume", "ls", "-q")
Expect(session.OutputToStringArray()).To(HaveLen(2))

podmanTest.PodmanExitCleanly("volume", "prune", "--all", "--force", "--filter", "label!=keep")

session = podmanTest.PodmanExitCleanly("volume", "ls", "-q")
Expect(session.OutputToStringArray()).To(HaveLen(1))
Expect(session.OutputToString()).To(Equal("keepvol"))
})

It("podman system prune --volume", func() {
useCustomNetworkDir(podmanTest, tempdir)
podmanTest.PodmanExitCleanly("volume", "create")
Expand Down