diff options
author | Matthew Heon <matthew.heon@pm.me> | 2019-08-30 16:09:17 -0400 |
---|---|---|
committer | Matthew Heon <matthew.heon@pm.me> | 2019-09-05 12:29:36 -0400 |
commit | 5a8a71ed817a4fa50fd9444846a50b76f25228d1 (patch) | |
tree | dee3a3bc42d410ff184acfa38d49ac1e5ad5bbed /libpod/boltdb_state.go | |
parent | c8193633cd82228b01e789becead410c2a940227 (diff) | |
download | podman-5a8a71ed817a4fa50fd9444846a50b76f25228d1.tar.gz podman-5a8a71ed817a4fa50fd9444846a50b76f25228d1.tar.bz2 podman-5a8a71ed817a4fa50fd9444846a50b76f25228d1.zip |
Add volume state
We need to be able to track the number of times a volume has been
mounted for tmpfs/nfs/etc volumes. As such, we need a mutable
state for volumes. Add one, with the expected update/save methods
in both states.
There is backwards compat here, in that older volumes without a
state will still be accepted.
Signed-off-by: Matthew Heon <matthew.heon@pm.me>
Diffstat (limited to 'libpod/boltdb_state.go')
-rw-r--r-- | libpod/boltdb_state.go | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index 1de8d80c9..ff5e62ce2 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -1352,6 +1352,16 @@ func (s *BoltState) AddVolume(volume *Volume) error { return errors.Wrapf(err, "error marshalling volume %s config to JSON", volume.Name()) } + // Volume state is allowed to not exist + var volStateJSON []byte + if volume.state != nil { + stateJSON, err := json.Marshal(volume.state) + if err != nil { + return errors.Wrapf(err, "error marshalling volume %s state to JSON", volume.Name()) + } + volStateJSON = stateJSON + } + db, err := s.getDBCon() if err != nil { return err @@ -1392,6 +1402,12 @@ func (s *BoltState) AddVolume(volume *Volume) error { return errors.Wrapf(err, "error storing volume %s configuration in DB", volume.Name()) } + if volStateJSON != nil { + if err := newVol.Put(stateKey, volStateJSON); err != nil { + return errors.Wrapf(err, "error storing volume %s state in DB", volume.Name()) + } + } + if err := allVolsBkt.Put(volName, volName); err != nil { return errors.Wrapf(err, "error storing volume %s in all volumes bucket in DB", volume.Name()) } @@ -1483,6 +1499,103 @@ func (s *BoltState) RemoveVolume(volume *Volume) error { return err } +// UpdateVolume updates the volume's state from the database. +func (s *BoltState) UpdateVolume(volume *Volume) error { + if !s.valid { + return define.ErrDBClosed + } + + if !volume.valid { + return define.ErrVolumeRemoved + } + + newState := new(VolumeState) + volumeName := []byte(volume.Name()) + + db, err := s.getDBCon() + if err != nil { + return err + } + defer s.deferredCloseDBCon(db) + + err = db.View(func(tx *bolt.Tx) error { + volBucket, err := getVolBucket(tx) + if err != nil { + return err + } + + volToUpdate := volBucket.Bucket(volumeName) + if volToUpdate == nil { + volume.valid = false + return errors.Wrapf(define.ErrNoSuchVolume, "no volume with name %s found in database", volume.Name()) + } + + stateBytes := volToUpdate.Get(stateKey) + if stateBytes == nil { + // Having no state is valid. + // Return nil, use the empty state. + return nil + } + + if err := json.Unmarshal(stateBytes, newState); err != nil { + return errors.Wrapf(err, "error unmarshalling volume %s state", volume.Name()) + } + + return nil + }) + if err != nil { + return err + } + + volume.state = newState + + return nil +} + +// SaveVolume saves the volume's state to the database. +func (s *BoltState) SaveVolume(volume *Volume) error { + if !s.valid { + return define.ErrDBClosed + } + + if !volume.valid { + return define.ErrVolumeRemoved + } + + volumeName := []byte(volume.Name()) + + var newStateJSON []byte + if volume.state != nil { + stateJSON, err := json.Marshal(volume.state) + if err != nil { + return errors.Wrapf(err, "error marshalling volume %s state to JSON", volume.Name()) + } + newStateJSON = stateJSON + } + + db, err := s.getDBCon() + if err != nil { + return err + } + defer s.deferredCloseDBCon(db) + + err = db.Update(func(tx *bolt.Tx) error { + volBucket, err := getVolBucket(tx) + if err != nil { + return err + } + + volToUpdate := volBucket.Bucket(volumeName) + if volToUpdate == nil { + volume.valid = false + return errors.Wrapf(define.ErrNoSuchVolume, "no volume with name %s found in database", volume.Name()) + } + + return volToUpdate.Put(stateKey, newStateJSON) + }) + return err +} + // AllVolumes returns all volumes present in the state func (s *BoltState) AllVolumes() ([]*Volume, error) { if !s.valid { @@ -1551,6 +1664,7 @@ func (s *BoltState) Volume(name string) (*Volume, error) { volume := new(Volume) volume.config = new(VolumeConfig) + volume.state = new(VolumeState) db, err := s.getDBCon() if err != nil { |