summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaron Lenardson <lenardson.baron@gmail.com>2020-12-10 20:30:28 -0600
committerBaron Lenardson <lenardson.baron@gmail.com>2020-12-12 20:07:04 -0600
commita0204ada0974343cbf6eefe988ef35cdfe28fb52 (patch)
tree6271ae99e76ca81f38e3ea80136d7195a843b19c
parent9216be2008696bc9f0bc26686be8becae3d12bfc (diff)
downloadpodman-a0204ada0974343cbf6eefe988ef35cdfe28fb52.tar.gz
podman-a0204ada0974343cbf6eefe988ef35cdfe28fb52.tar.bz2
podman-a0204ada0974343cbf6eefe988ef35cdfe28fb52.zip
Add volume prune --filter support
This change adds support for the `--filter` / `?filters` arguments on the `podman volume prune` subcommand. * Adds ParseFilterArgumentsIntoFilters helper for consistent Filter string slice handling * Adds `--filter` support to podman volume prune cli * Adds `?filters...` support to podman volume prune api * Updates apiv2 / e2e tests Closes #8672 Signed-off-by: Baron Lenardson <lenardson.baron@gmail.com>
-rw-r--r--cmd/podman/volumes/prune.go16
-rw-r--r--docs/source/markdown/podman-volume-prune.1.md16
-rw-r--r--libpod/runtime_volume.go4
-rw-r--r--pkg/api/handlers/compat/volumes.go12
-rw-r--r--pkg/api/handlers/libpod/volumes.go20
-rw-r--r--pkg/bindings/test/volumes_test.go41
-rw-r--r--pkg/bindings/volumes/volumes.go12
-rw-r--r--pkg/domain/entities/engine_container.go2
-rw-r--r--pkg/domain/entities/volumes.go7
-rw-r--r--pkg/domain/filters/helpers.go20
-rw-r--r--pkg/domain/filters/volumes.go3
-rw-r--r--pkg/domain/infra/abi/system.go2
-rw-r--r--pkg/domain/infra/abi/volumes.go12
-rw-r--r--pkg/domain/infra/tunnel/volumes.go4
-rw-r--r--test/apiv2/30-volumes.at30
-rw-r--r--test/e2e/volume_prune_test.go60
16 files changed, 236 insertions, 25 deletions
diff --git a/cmd/podman/volumes/prune.go b/cmd/podman/volumes/prune.go
index d1370120b..0f3ba9ef6 100644
--- a/cmd/podman/volumes/prune.go
+++ b/cmd/podman/volumes/prune.go
@@ -8,10 +8,12 @@ import (
"strings"
"github.com/containers/common/pkg/completion"
+ "github.com/containers/podman/v2/cmd/podman/common"
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/utils"
"github.com/containers/podman/v2/cmd/podman/validate"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/filters"
"github.com/spf13/cobra"
)
@@ -28,6 +30,7 @@ var (
RunE: prune,
ValidArgsFunction: completion.AutocompleteNone,
}
+ filter = []string{}
)
func init() {
@@ -37,10 +40,17 @@ func init() {
Parent: volumeCmd,
})
flags := pruneCommand.Flags()
+
+ filterFlagName := "filter"
+ flags.StringArrayVar(&filter, filterFlagName, []string{}, "Provide filter values (e.g. 'label=<key>=<value>')")
+ _ = pruneCommand.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteVolumeFilters)
flags.BoolP("force", "f", false, "Do not prompt for confirmation")
}
func prune(cmd *cobra.Command, args []string) error {
+ var (
+ pruneOptions = entities.VolumePruneOptions{}
+ )
// Prompt for confirmation if --force is not set
force, err := cmd.Flags().GetBool("force")
if err != nil {
@@ -58,7 +68,11 @@ func prune(cmd *cobra.Command, args []string) error {
return nil
}
}
- responses, err := registry.ContainerEngine().VolumePrune(context.Background())
+ pruneOptions.Filters, err = filters.ParseFilterArgumentsIntoFilters(filter)
+ if err != nil {
+ return err
+ }
+ responses, err := registry.ContainerEngine().VolumePrune(context.Background(), pruneOptions)
if err != nil {
return err
}
diff --git a/docs/source/markdown/podman-volume-prune.1.md b/docs/source/markdown/podman-volume-prune.1.md
index b5f1b7e94..9477cb5d5 100644
--- a/docs/source/markdown/podman-volume-prune.1.md
+++ b/docs/source/markdown/podman-volume-prune.1.md
@@ -8,7 +8,8 @@ podman\-volume\-prune - Remove all unused volumes
## DESCRIPTION
-Removes all unused volumes. You will be prompted to confirm the removal of all the
+Removes unused volumes. By default all unused volumes will be removed, the **--filter** flag can
+be used to filter specific volumes. You will be prompted to confirm the removal of all the
unused volumes. To bypass the confirmation, use the **--force** flag.
@@ -18,6 +19,17 @@ unused volumes. To bypass the confirmation, use the **--force** flag.
Do not prompt for confirmation.
+#### **--filter**
+
+Filter volumes to be pruned. Volumes can be filtered by the following attributes:
+
+- dangling
+- driver
+- label
+- name
+- opt
+- scope
+
#### **--help**
Print usage statement
@@ -29,6 +41,8 @@ Print usage statement
$ podman volume prune
$ podman volume prune --force
+
+$ podman volume prune --filter label=mylabel=mylabelvalue
```
## SEE ALSO
diff --git a/libpod/runtime_volume.go b/libpod/runtime_volume.go
index 055a243c0..10c32a119 100644
--- a/libpod/runtime_volume.go
+++ b/libpod/runtime_volume.go
@@ -133,9 +133,9 @@ func (r *Runtime) GetAllVolumes() ([]*Volume, error) {
}
// PruneVolumes removes unused volumes from the system
-func (r *Runtime) PruneVolumes(ctx context.Context) (map[string]error, error) {
+func (r *Runtime) PruneVolumes(ctx context.Context, filterFuncs []VolumeFilter) (map[string]error, error) {
reports := make(map[string]error)
- vols, err := r.GetAllVolumes()
+ vols, err := r.Volumes(filterFuncs...)
if err != nil {
return nil, err
}
diff --git a/pkg/api/handlers/compat/volumes.go b/pkg/api/handlers/compat/volumes.go
index 71b848932..f76e18ee3 100644
--- a/pkg/api/handlers/compat/volumes.go
+++ b/pkg/api/handlers/compat/volumes.go
@@ -3,6 +3,7 @@ package compat
import (
"encoding/json"
"net/http"
+ "net/url"
"time"
"github.com/containers/podman/v2/libpod"
@@ -254,14 +255,15 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
- // TODO: We have no ability to pass pruning filters to `PruneVolumes()` so
- // we'll explicitly reject the request if we see any
- if len(query.Filters) > 0 {
- utils.InternalServerError(w, errors.New("filters for pruning volumes is not implemented"))
+
+ f := (url.Values)(query.Filters)
+ filterFuncs, err := filters.GenerateVolumeFilters(f)
+ if err != nil {
+ utils.Error(w, "Something when wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse filters for %s", f.Encode()))
return
}
- pruned, err := runtime.PruneVolumes(r.Context())
+ pruned, err := runtime.PruneVolumes(r.Context(), filterFuncs)
if err != nil {
utils.InternalServerError(w, err)
return
diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go
index b0d40fd8b..b02a6a8ce 100644
--- a/pkg/api/handlers/libpod/volumes.go
+++ b/pkg/api/handlers/libpod/volumes.go
@@ -3,6 +3,7 @@ package libpod
import (
"encoding/json"
"net/http"
+ "net/url"
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
@@ -180,8 +181,25 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
func pruneVolumesHelper(r *http.Request) ([]*entities.VolumePruneReport, error) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
+ decoder = r.Context().Value("decoder").(*schema.Decoder)
)
- pruned, err := runtime.PruneVolumes(r.Context())
+ query := struct {
+ Filters map[string][]string `schema:"filters"`
+ }{
+ // override any golang type defaults
+ }
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ return nil, err
+ }
+
+ f := (url.Values)(query.Filters)
+ filterFuncs, err := filters.GenerateVolumeFilters(f)
+ if err != nil {
+ return nil, err
+ }
+
+ pruned, err := runtime.PruneVolumes(r.Context(), filterFuncs)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/test/volumes_test.go b/pkg/bindings/test/volumes_test.go
index dc90d4d00..861a02441 100644
--- a/pkg/bindings/test/volumes_test.go
+++ b/pkg/bindings/test/volumes_test.go
@@ -144,16 +144,15 @@ var _ = Describe("Podman volumes", func() {
Expect(vols[0].Name).To(Equal("homer"))
})
- // TODO we need to add filtering to tests
It("prune unused volume", func() {
// Pruning when no volumes present should be ok
- _, err := volumes.Prune(connText)
+ _, err := volumes.Prune(connText, nil)
Expect(err).To(BeNil())
// Removing an unused volume should work
_, err = volumes.Create(connText, entities.VolumeCreateOptions{})
Expect(err).To(BeNil())
- vols, err := volumes.Prune(connText)
+ vols, err := volumes.Prune(connText, nil)
Expect(err).To(BeNil())
Expect(len(vols)).To(BeNumerically("==", 1))
@@ -163,11 +162,45 @@ var _ = Describe("Podman volumes", func() {
Expect(err).To(BeNil())
session := bt.runPodman([]string{"run", "-dt", "-v", fmt.Sprintf("%s:/homer", "homer"), "--name", "vtest", alpine.name, "top"})
session.Wait(45)
- vols, err = volumes.Prune(connText)
+ vols, err = volumes.Prune(connText, nil)
Expect(err).To(BeNil())
Expect(len(vols)).To(BeNumerically("==", 1))
_, err = volumes.Inspect(connText, "homer")
Expect(err).To(BeNil())
+
+ // Removing volume with non matching filter shouldn't prune any volumes
+ filters := make(map[string][]string)
+ filters["label"] = []string{"label1=idontmatch"}
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{Label: map[string]string{
+ "label1": "value1",
+ }})
+ Expect(err).To(BeNil())
+ vols, err = volumes.Prune(connText, filters)
+ Expect(err).To(BeNil())
+ Expect(len(vols)).To(BeNumerically("==", 0))
+ vol2, err := volumes.Create(connText, entities.VolumeCreateOptions{Label: map[string]string{
+ "label1": "value2",
+ }})
+ Expect(err).To(BeNil())
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{Label: map[string]string{
+ "label1": "value3",
+ }})
+ Expect(err).To(BeNil())
+
+ // Removing volume with matching filter label and value should remove specific entry
+ filters = make(map[string][]string)
+ filters["label"] = []string{"label1=value2"}
+ vols, err = volumes.Prune(connText, filters)
+ Expect(err).To(BeNil())
+ Expect(len(vols)).To(BeNumerically("==", 1))
+ Expect(vols[0].Id).To(Equal(vol2.Name))
+
+ // Removing volumes with matching filter label should remove all matching volumes
+ filters = make(map[string][]string)
+ filters["label"] = []string{"label1"}
+ vols, err = volumes.Prune(connText, filters)
+ Expect(err).To(BeNil())
+ Expect(len(vols)).To(BeNumerically("==", 2))
})
})
diff --git a/pkg/bindings/volumes/volumes.go b/pkg/bindings/volumes/volumes.go
index 00f1e5720..b1be257b8 100644
--- a/pkg/bindings/volumes/volumes.go
+++ b/pkg/bindings/volumes/volumes.go
@@ -75,7 +75,7 @@ func List(ctx context.Context, filters map[string][]string) ([]*entities.VolumeL
}
// Prune removes unused volumes from the local filesystem.
-func Prune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
+func Prune(ctx context.Context, filters map[string][]string) ([]*entities.VolumePruneReport, error) {
var (
pruned []*entities.VolumePruneReport
)
@@ -83,7 +83,15 @@ func Prune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/volumes/prune", nil, nil)
+ params := url.Values{}
+ if len(filters) > 0 {
+ strFilters, err := bindings.FiltersToString(filters)
+ if err != nil {
+ return nil, err
+ }
+ params.Set("filters", strFilters)
+ }
+ response, err := conn.DoRequest(nil, http.MethodPost, "/volumes/prune", params, nil)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 5ad475133..ac9073402 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -80,6 +80,6 @@ type ContainerEngine interface {
VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IDOrNameResponse, error)
VolumeInspect(ctx context.Context, namesOrIds []string, opts InspectOptions) ([]*VolumeInspectReport, []error, error)
VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error)
- VolumePrune(ctx context.Context) ([]*VolumePruneReport, error)
+ VolumePrune(ctx context.Context, options VolumePruneOptions) ([]*VolumePruneReport, error)
VolumeRm(ctx context.Context, namesOrIds []string, opts VolumeRmOptions) ([]*VolumeRmReport, error)
}
diff --git a/pkg/domain/entities/volumes.go b/pkg/domain/entities/volumes.go
index 1bc1e4301..e6b29e374 100644
--- a/pkg/domain/entities/volumes.go
+++ b/pkg/domain/entities/volumes.go
@@ -1,6 +1,7 @@
package entities
import (
+ "net/url"
"time"
docker_api_types "github.com/docker/docker/api/types"
@@ -109,6 +110,12 @@ type VolumeInspectReport struct {
*VolumeConfigResponse
}
+// VolumePruneOptions describes the options needed
+// to prune a volume from the CLI
+type VolumePruneOptions struct {
+ Filters url.Values `json:"filters" schema:"filters"`
+}
+
type VolumePruneReport struct {
Err error
Id string //nolint
diff --git a/pkg/domain/filters/helpers.go b/pkg/domain/filters/helpers.go
new file mode 100644
index 000000000..6a5fb68b1
--- /dev/null
+++ b/pkg/domain/filters/helpers.go
@@ -0,0 +1,20 @@
+package filters
+
+import (
+ "net/url"
+ "strings"
+
+ "github.com/pkg/errors"
+)
+
+func ParseFilterArgumentsIntoFilters(filters []string) (url.Values, error) {
+ parsedFilters := make(url.Values)
+ for _, f := range filters {
+ t := strings.SplitN(f, "=", 2)
+ if len(t) < 2 {
+ return parsedFilters, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
+ }
+ parsedFilters.Add(t[0], t[1])
+ }
+ return parsedFilters, nil
+}
diff --git a/pkg/domain/filters/volumes.go b/pkg/domain/filters/volumes.go
index 7819d3cdf..69bef4961 100644
--- a/pkg/domain/filters/volumes.go
+++ b/pkg/domain/filters/volumes.go
@@ -1,13 +1,14 @@
package filters
import (
+ "net/url"
"strings"
"github.com/containers/podman/v2/libpod"
"github.com/pkg/errors"
)
-func GenerateVolumeFilters(filters map[string][]string) ([]libpod.VolumeFilter, error) {
+func GenerateVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, error) {
var vf []libpod.VolumeFilter
for filter, v := range filters {
for _, val := range v {
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 7ed58092b..e4ed0a6be 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -214,7 +214,7 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
systemPruneReport.ImagePruneReport.Report.Id = append(systemPruneReport.ImagePruneReport.Report.Id, results...)
}
if options.Volume {
- volumePruneReport, err := ic.pruneVolumesHelper(ctx)
+ volumePruneReport, err := ic.pruneVolumesHelper(ctx, nil)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go
index a7262f61b..515e52754 100644
--- a/pkg/domain/infra/abi/volumes.go
+++ b/pkg/domain/infra/abi/volumes.go
@@ -127,12 +127,16 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
return reports, errs, nil
}
-func (ic *ContainerEngine) VolumePrune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
- return ic.pruneVolumesHelper(ctx)
+func (ic *ContainerEngine) VolumePrune(ctx context.Context, options entities.VolumePruneOptions) ([]*entities.VolumePruneReport, error) {
+ filterFuncs, err := filters.GenerateVolumeFilters(options.Filters)
+ if err != nil {
+ return nil, err
+ }
+ return ic.pruneVolumesHelper(ctx, filterFuncs)
}
-func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context) ([]*entities.VolumePruneReport, error) {
- pruned, err := ic.Libpod.PruneVolumes(ctx)
+func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context, filterFuncs []libpod.VolumeFilter) ([]*entities.VolumePruneReport, error) {
+ pruned, err := ic.Libpod.PruneVolumes(ctx, filterFuncs)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/tunnel/volumes.go b/pkg/domain/infra/tunnel/volumes.go
index c0df2bb7b..b431fc8bd 100644
--- a/pkg/domain/infra/tunnel/volumes.go
+++ b/pkg/domain/infra/tunnel/volumes.go
@@ -68,8 +68,8 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
return reports, errs, nil
}
-func (ic *ContainerEngine) VolumePrune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
- return volumes.Prune(ic.ClientCxt)
+func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*entities.VolumePruneReport, error) {
+ return volumes.Prune(ic.ClientCxt, (map[string][]string)(opts.Filters))
}
func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) {
diff --git a/test/apiv2/30-volumes.at b/test/apiv2/30-volumes.at
index aa167a97a..2cfca9d08 100644
--- a/test/apiv2/30-volumes.at
+++ b/test/apiv2/30-volumes.at
@@ -20,6 +20,18 @@ t POST libpod/volumes/create \
.Labels.testlabel=testonly \
.Options.type=tmpfs \
.Options.o=nodev,noexec
+t POST libpod/volumes/create \
+ '"Name":"foo3","Label":{"testlabel":""},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \
+ .Name=foo3 \
+ .Labels.testlabel="" \
+ .Options.type=tmpfs \
+ .Options.o=nodev,noexec
+t POST libpod/volumes/create \
+ '"Name":"foo4","Label":{"testlabel1":"testonly"},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \
+ .Name=foo4 \
+ .Labels.testlabel1=testonly \
+ .Options.type=tmpfs \
+ .Options.o=nodev,noexec
# Negative test
# We have created a volume named "foo1"
@@ -39,6 +51,12 @@ t GET libpod/volumes/json?filters=%7B%22name%22%3A%5B%22foo1%22%5D%7D 200 length
t GET libpod/volumes/json?filters=%7B%22name%22%3A%20%5B%22foo1%22%2C%20%22foo2%22%5D%7D 200 length=2 .[0].Name=foo1 .[1].Name=foo2
# -G --data-urlencode 'filters={"name":["notexist"]}'
t GET libpod/volumes/json?filters=%7B%22name%22%3A%5B%22notexists%22%5D%7D 200 length=0
+# -G --data-urlencode 'filters={"label":["testlabel"]}'
+t GET libpod/volumes/json?filters=%7B%22label%22:%5B%22testlabel%22%5D%7D 200 length=2
+# -G --data-urlencode 'filters={"label":["testlabel=testonly"]}'
+t GET libpod/volumes/json?filters=%7B%22label%22:%5B%22testlabel=testonly%22%5D%7D 200 length=1
+# -G --data-urlencode 'filters={"label":["testlabel1=testonly"]}'
+t GET libpod/volumes/json?filters=%7B%22label%22:%5B%22testlabel1=testonly%22%5D%7D 200 length=1
## inspect volume
t GET libpod/volumes/foo1/json 200 \
@@ -60,6 +78,18 @@ t DELETE libpod/volumes/foo1 404 \
.message~.* \
.response=404
+## Prune volumes with label matching 'testlabel1=testonly'
+# -G --data-urlencode 'filters={"label":["testlabel1=testonly"]}'
+t POST libpod/volumes/prune?filters=%7B%22label%22:%5B%22testlabel1=testonly%22%5D%7D "" 200
+# -G --data-urlencode 'filters={"label":["testlabel1=testonly"]}'
+t GET libpod/volumes/json?filters=%7B%22label%22:%5B%22testlabel1=testonly%22%5D%7D 200 length=0
+
+## Prune volumes with label matching 'testlabel'
+# -G --data-urlencode 'filters={"label":["testlabel"]}'
+t POST libpod/volumes/prune?filters=%7B%22label%22:%5B%22testlabel%22%5D%7D "" 200
+# -G --data-urlencode 'filters={"label":["testlabel"]}'
+t GET libpod/volumes/json?filters=%7B%22label%22:%5B%22testlabel%22%5D%7D 200 length=0
+
## Prune volumes
t POST libpod/volumes/prune "" 200
#After prune volumes, there should be no volume existing
diff --git a/test/e2e/volume_prune_test.go b/test/e2e/volume_prune_test.go
index c8521ebe7..a910c47a7 100644
--- a/test/e2e/volume_prune_test.go
+++ b/test/e2e/volume_prune_test.go
@@ -62,6 +62,66 @@ var _ = Describe("Podman volume prune", func() {
podmanTest.Cleanup()
})
+ It("podman prune volume --filter", func() {
+ session := podmanTest.Podman([]string{"volume", "create", "--label", "label1=value1", "myvol1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1=slv1", "myvol2"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1=slv2", "myvol3"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1", "myvol4"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"create", "-v", "myvol5:/myvol5", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"create", "-v", "myvol6:/myvol6", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(7))
+
+ session = podmanTest.Podman([]string{"volume", "prune", "--force", "--filter", "label=label1=value1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(6))
+
+ session = podmanTest.Podman([]string{"volume", "prune", "--force", "--filter", "label=sharedlabel1=slv1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(5))
+
+ session = podmanTest.Podman([]string{"volume", "prune", "--force", "--filter", "label=sharedlabel1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(3))
+
+ podmanTest.Cleanup()
+ })
+
It("podman system prune --volume", func() {
session := podmanTest.Podman([]string{"volume", "create"})
session.WaitWithDefaultTimeout()