Add support for dangling filter to volumes

The dangling filter determine whether a volume is dangling - IE,
it has no containers attached using it. Unlike our other filters,
this one is a boolean - must be true or false, not arbitrary
values.

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
This commit is contained in:
Matthew Heon
2020-06-24 14:10:29 -04:00
parent 4ee66598c1
commit d78e83f47d
4 changed files with 62 additions and 2 deletions

View File

@ -137,7 +137,7 @@ func (v *Volume) Config() (*VolumeConfig, error) {
// VolumeInUse goes through the container dependencies of a volume // VolumeInUse goes through the container dependencies of a volume
// and checks if the volume is being used by any container. // and checks if the volume is being used by any container.
func (v *Volume) VolumesInUse() ([]string, error) { func (v *Volume) VolumeInUse() ([]string, error) {
v.lock.Lock() v.lock.Lock()
defer v.lock.Unlock() defer v.lock.Unlock()
@ -146,3 +146,13 @@ func (v *Volume) VolumesInUse() ([]string, error) {
} }
return v.runtime.state.VolumeInUse(v) return v.runtime.state.VolumeInUse(v)
} }
// IsDangling returns whether this volume is dangling (unused by any
// containers).
func (v *Volume) IsDangling() (bool, error) {
ctrs, err := v.VolumeInUse()
if err != nil {
return false, err
}
return len(ctrs) == 0, nil
}

View File

@ -61,6 +61,29 @@ func GenerateVolumeFilters(filters map[string][]string) ([]libpod.VolumeFilter,
} }
return false return false
}) })
case "dangling":
danglingVal := val
invert := false
switch strings.ToLower(danglingVal) {
case "true", "1":
// Do nothing
case "false", "0":
// Dangling=false requires that we
// invert the result of IsDangling.
invert = true
default:
return nil, errors.Errorf("%q is not a valid value for the \"dangling\" filter - must be true or false", danglingVal)
}
vf = append(vf, func(v *libpod.Volume) bool {
dangling, err := v.IsDangling()
if err != nil {
return false
}
if invert {
return !dangling
}
return dangling
})
default: default:
return nil, errors.Errorf("%q is in an invalid volume filter", filter) return nil, errors.Errorf("%q is in an invalid volume filter", filter)
} }

View File

@ -330,7 +330,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
if err != nil { if err != nil {
return nil, err return nil, err
} }
inUse, err := v.VolumesInUse() inUse, err := v.VolumeInUse()
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,6 +1,7 @@
package integration package integration
import ( import (
"fmt"
"os" "os"
. "github.com/containers/libpod/test/utils" . "github.com/containers/libpod/test/utils"
@ -82,4 +83,30 @@ var _ = Describe("Podman volume ls", func() {
Expect(len(session.OutputToStringArray())).To(Equal(2)) Expect(len(session.OutputToStringArray())).To(Equal(2))
Expect(session.OutputToStringArray()[1]).To(ContainSubstring(volName)) Expect(session.OutputToStringArray()[1]).To(ContainSubstring(volName))
}) })
It("podman volume ls with --filter dangling", func() {
volName1 := "volume1"
session := podmanTest.Podman([]string{"volume", "create", volName1})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
volName2 := "volume2"
session2 := podmanTest.Podman([]string{"volume", "create", volName2})
session2.WaitWithDefaultTimeout()
Expect(session2.ExitCode()).To(Equal(0))
ctr := podmanTest.Podman([]string{"create", "-v", fmt.Sprintf("%s:/test", volName2), ALPINE, "sh"})
ctr.WaitWithDefaultTimeout()
Expect(ctr.ExitCode()).To(Equal(0))
lsNoDangling := podmanTest.Podman([]string{"volume", "ls", "--filter", "dangling=false", "--quiet"})
lsNoDangling.WaitWithDefaultTimeout()
Expect(lsNoDangling.ExitCode()).To(Equal(0))
Expect(lsNoDangling.OutputToString()).To(ContainSubstring(volName2))
lsDangling := podmanTest.Podman([]string{"volume", "ls", "--filter", "dangling=true", "--quiet"})
lsDangling.WaitWithDefaultTimeout()
Expect(lsDangling.ExitCode()).To(Equal(0))
Expect(lsDangling.OutputToString()).To(ContainSubstring(volName1))
})
}) })