aboutsummaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@pm.me>2019-08-27 15:25:54 -0400
committerMatthew Heon <matthew.heon@pm.me>2019-09-09 12:06:10 -0400
commit046178e55f72ed9db7cf5898d3be91b0112ab94f (patch)
treead844579a48f043d1959233ca881307801f79a45 /libpod
parent16a70490852fdaf3ea5aeea6b2be19dd70fbf1c7 (diff)
downloadpodman-046178e55f72ed9db7cf5898d3be91b0112ab94f.tar.gz
podman-046178e55f72ed9db7cf5898d3be91b0112ab94f.tar.bz2
podman-046178e55f72ed9db7cf5898d3be91b0112ab94f.zip
Add function for looking up volumes by partial name
This isn't included in Docker, but seems handy enough. Use the new API for 'volume rm' and 'volume inspect'. Fixes #3891 Signed-off-by: Matthew Heon <matthew.heon@pm.me>
Diffstat (limited to 'libpod')
-rw-r--r--libpod/boltdb_state.go68
-rw-r--r--libpod/in_memory_state.go35
-rw-r--r--libpod/runtime_volume.go46
-rw-r--r--libpod/state.go3
4 files changed, 121 insertions, 31 deletions
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index 31b551b36..4e7f78f13 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -1735,6 +1735,74 @@ func (s *BoltState) Volume(name string) (*Volume, error) {
return volume, nil
}
+// LookupVolume locates a volume from a partial name.
+func (s *BoltState) LookupVolume(name string) (*Volume, error) {
+ if name == "" {
+ return nil, define.ErrEmptyID
+ }
+
+ if !s.valid {
+ return nil, define.ErrDBClosed
+ }
+
+ volName := []byte(name)
+
+ volume := new(Volume)
+ volume.config = new(VolumeConfig)
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return nil, err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ err = db.View(func(tx *bolt.Tx) error {
+ volBkt, err := getVolBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ allVolsBkt, err := getAllVolsBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ // Check for exact match on name
+ volDB := volBkt.Bucket(volName)
+ if volDB != nil {
+ return s.getVolumeFromDB(volName, volume, volBkt)
+ }
+
+ // No exact match. Search all names.
+ foundMatch := false
+ err = allVolsBkt.ForEach(func(checkName, checkName2 []byte) error {
+ if strings.HasPrefix(string(checkName), name) {
+ if foundMatch {
+ return errors.Wrapf(define.ErrVolumeExists, "more than one result for volume name %q", name)
+ }
+ foundMatch = true
+ volName = checkName
+ }
+ return nil
+ })
+ if err != nil {
+ return err
+ }
+
+ if !foundMatch {
+ return errors.Wrapf(define.ErrNoSuchVolume, "no volume with name %q found", name)
+ }
+
+ return s.getVolumeFromDB(volName, volume, volBkt)
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return volume, nil
+
+}
+
// HasVolume returns true if the given volume exists in the state, otherwise it returns false
func (s *BoltState) HasVolume(name string) (bool, error) {
if name == "" {
diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go
index 280ae5f5c..a008fcb39 100644
--- a/libpod/in_memory_state.go
+++ b/libpod/in_memory_state.go
@@ -459,6 +459,41 @@ func (s *InMemoryState) Volume(name string) (*Volume, error) {
return vol, nil
}
+// LookupVolume finds a volume from an unambiguous partial ID.
+func (s *InMemoryState) LookupVolume(name string) (*Volume, error) {
+ if name == "" {
+ return nil, define.ErrEmptyID
+ }
+
+ vol, ok := s.volumes[name]
+ if ok {
+ return vol, nil
+ }
+
+ // Alright, we've failed to find by full name. Now comes the expensive
+ // part.
+ // Loop through all volumes and look for matches.
+ var (
+ foundMatch bool
+ candidate *Volume
+ )
+ for volName, vol := range s.volumes {
+ if strings.HasPrefix(volName, name) {
+ if foundMatch {
+ return nil, errors.Wrapf(define.ErrVolumeExists, "more than one result for volume name %q", name)
+ }
+ candidate = vol
+ foundMatch = true
+ }
+ }
+
+ if !foundMatch {
+ return nil, errors.Wrapf(define.ErrNoSuchVolume, "no volume with name %q found", name)
+ }
+
+ return candidate, nil
+}
+
// HasVolume checks if a volume with the given name is present in the state
func (s *InMemoryState) HasVolume(name string) (bool, error) {
if name == "" {
diff --git a/libpod/runtime_volume.go b/libpod/runtime_volume.go
index 512e778a1..a6ab748e5 100644
--- a/libpod/runtime_volume.go
+++ b/libpod/runtime_volume.go
@@ -6,7 +6,6 @@ import (
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/events"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
// Contains the public Runtime API for volumes
@@ -43,40 +42,25 @@ func (r *Runtime) RemoveVolume(ctx context.Context, v *Volume, force bool) error
return r.removeVolume(ctx, v, force)
}
-// RemoveVolumes removes a slice of volumes or all with a force bool
-func (r *Runtime) RemoveVolumes(ctx context.Context, volumes []string, all, force bool) ([]string, error) {
- var (
- vols []*Volume
- err error
- deletedVols []string
- )
- if all {
- vols, err = r.Volumes()
- if err != nil {
- return nil, errors.Wrapf(err, "unable to get all volumes")
- }
- } else {
- for _, i := range volumes {
- vol, err := r.GetVolume(i)
- if err != nil {
- return nil, err
- }
- vols = append(vols, vol)
- }
+// GetVolume retrieves a volume given its full name.
+func (r *Runtime) GetVolume(name string) (*Volume, error) {
+ r.lock.RLock()
+ defer r.lock.RUnlock()
+
+ if !r.valid {
+ return nil, define.ErrRuntimeStopped
}
- for _, vol := range vols {
- if err := r.RemoveVolume(ctx, vol, force); err != nil {
- return deletedVols, err
- }
- logrus.Debugf("removed volume %s", vol.Name())
- deletedVols = append(deletedVols, vol.Name())
+ vol, err := r.state.Volume(name)
+ if err != nil {
+ return nil, err
}
- return deletedVols, nil
+
+ return vol, nil
}
-// GetVolume retrieves a volume given its full name.
-func (r *Runtime) GetVolume(name string) (*Volume, error) {
+// LookupVolume retrieves a volume by unambigious partial name.
+func (r *Runtime) LookupVolume(name string) (*Volume, error) {
r.lock.RLock()
defer r.lock.RUnlock()
@@ -84,7 +68,7 @@ func (r *Runtime) GetVolume(name string) (*Volume, error) {
return nil, define.ErrRuntimeStopped
}
- vol, err := r.state.Volume(name)
+ vol, err := r.state.LookupVolume(name)
if err != nil {
return nil, err
}
diff --git a/libpod/state.go b/libpod/state.go
index db4667ad6..40080d2cc 100644
--- a/libpod/state.go
+++ b/libpod/state.go
@@ -190,6 +190,9 @@ type State interface {
// Volume accepts full name of volume
// If the volume doesn't exist, an error will be returned
Volume(volName string) (*Volume, error)
+ // LookupVolume accepts an unambiguous partial name or full name of a
+ // volume. Ambiguous names will result in an error.
+ LookupVolume(name string) (*Volume, error)
// HasVolume returns true if volName exists in the state,
// otherwise it returns false
HasVolume(volName string) (bool, error)