diff options
author | Matthew Heon <matthew.heon@gmail.com> | 2017-12-13 22:02:15 -0500 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2018-02-12 14:28:07 +0000 |
commit | b4cdc27b31a638322fb83b64aea869ce8600ea01 (patch) | |
tree | 5d248aeafa1f54a2c169d1d51deaaeb5de1e0e23 /libpod/boltdb_state_internal.go | |
parent | 2e96acf3007cbd05a37a8af7156f0abda073cb5a (diff) | |
download | podman-b4cdc27b31a638322fb83b64aea869ce8600ea01.tar.gz podman-b4cdc27b31a638322fb83b64aea869ce8600ea01.tar.bz2 podman-b4cdc27b31a638322fb83b64aea869ce8600ea01.zip |
Add implementation for BoltDB-backed state
Signed-off-by: Matthew Heon <matthew.heon@gmail.com>
Closes: #184
Approved by: baude
Diffstat (limited to 'libpod/boltdb_state_internal.go')
-rw-r--r-- | libpod/boltdb_state_internal.go | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go new file mode 100644 index 000000000..8b4e8e28c --- /dev/null +++ b/libpod/boltdb_state_internal.go @@ -0,0 +1,204 @@ +package libpod + +import ( + "encoding/json" + "path/filepath" + + "github.com/boltdb/bolt" + "github.com/containers/storage" + "github.com/pkg/errors" +) + +const ( + idRegistryName = "id-registry" + nameRegistryName = "name-registry" + ctrConfigName = "container-config" + ctrStateName = "container-state" + netNSName = "net-ns" + runtimeConfigName = "runtime-config" + ctrDependsName = "container-depends" +) + +var ( + idRegistryBkt = []byte(idRegistryName) + nameRegistryBkt = []byte(nameRegistryName) + ctrConfigBkt = []byte(ctrConfigName) + ctrStateBkt = []byte(ctrStateName) + netNSBkt = []byte(netNSName) + runtimeConfigBkt = []byte(runtimeConfigName) + ctrDependsBkt = []byte(ctrDependsName) +) + +// Check if the configuration of the database is compatible with the +// configuration of the runtime opening it +// If there is no runtime configuration loaded, load our own +func checkRuntimeConfig(db *bolt.DB, runtime *Runtime) error { + var ( + staticDir = []byte("static-dir") + tmpDir = []byte("tmp-dir") + runRoot = []byte("run-root") + graphRoot = []byte("graph-root") + graphDriverName = []byte("graph-driver-name") + ) + + err := db.Update(func(tx *bolt.Tx) error { + configBkt, err := getRuntimeConfigBucket(tx) + if err != nil { + return err + } + + if err := validateDBAgainstConfig(configBkt, "static dir", + runtime.config.StaticDir, staticDir); err != nil { + return err + } + + if err := validateDBAgainstConfig(configBkt, "tmp dir", + runtime.config.TmpDir, tmpDir); err != nil { + return err + } + + if err := validateDBAgainstConfig(configBkt, "run root", + runtime.config.StorageConfig.RunRoot, runRoot); err != nil { + return err + } + + if err := validateDBAgainstConfig(configBkt, "graph root", + runtime.config.StorageConfig.GraphRoot, graphRoot); err != nil { + return err + } + + return validateDBAgainstConfig(configBkt, "graph driver name", + runtime.config.StorageConfig.GraphDriverName, + graphDriverName) + }) + + return err +} + +// Validate a configuration entry in the DB against current runtime config +// If the given configuration key does not exist it will be created +func validateDBAgainstConfig(bucket *bolt.Bucket, fieldName, runtimeValue string, keyName []byte) error { + keyBytes := bucket.Get(keyName) + if keyBytes == nil { + if err := bucket.Put(keyName, []byte(runtimeValue)); err != nil { + return errors.Wrapf(err, "error updating %s in DB runtime config", fieldName) + } + } else { + if runtimeValue != string(keyBytes) { + return errors.Wrapf(ErrDBBadConfig, "database %s %s does not match our %s %s", + fieldName, string(keyBytes), fieldName, runtimeValue) + } + } + + return nil +} + +func (s *BoltState) getDBCon() (*bolt.DB, error) { + db, err := bolt.Open(s.dbPath, 0600, nil) + if err != nil { + return nil, errors.Wrapf(err, "error opening database %s", s.dbPath) + } + + return db, nil +} + +func getIDBucket(tx *bolt.Tx) (*bolt.Bucket, error) { + bkt := tx.Bucket(idRegistryBkt) + if bkt == nil { + return nil, errors.Wrapf(ErrDBBadConfig, "id registry bucket not found in DB") + } + return bkt, nil +} + +func getNamesBucket(tx *bolt.Tx) (*bolt.Bucket, error) { + bkt := tx.Bucket(nameRegistryBkt) + if bkt == nil { + return nil, errors.Wrapf(ErrDBBadConfig, "name registry bucket not found in DB") + } + return bkt, nil +} + +func getCtrConfigBucket(tx *bolt.Tx) (*bolt.Bucket, error) { + bkt := tx.Bucket(ctrConfigBkt) + if bkt == nil { + return nil, errors.Wrapf(ErrDBBadConfig, "container config bucket not found in DB") + } + return bkt, nil +} + +func getCtrStateBucket(tx *bolt.Tx) (*bolt.Bucket, error) { + bkt := tx.Bucket(ctrStateBkt) + if bkt == nil { + return nil, errors.Wrapf(ErrDBBadConfig, "container state bucket not found in DB") + } + return bkt, nil +} + +func getNetNSBucket(tx *bolt.Tx) (*bolt.Bucket, error) { + bkt := tx.Bucket(netNSBkt) + if bkt == nil { + return nil, errors.Wrapf(ErrDBBadConfig, "network namespace bucket not found in DB") + } + return bkt, nil +} + +func getRuntimeConfigBucket(tx *bolt.Tx) (*bolt.Bucket, error) { + bkt := tx.Bucket(runtimeConfigBkt) + if bkt == nil { + return nil, errors.Wrapf(ErrDBBadConfig, "runtime configuration bucket not found in DB") + } + return bkt, nil +} + +func getCtrDependsBucket(tx *bolt.Tx) (*bolt.Bucket, error) { + bkt := tx.Bucket(ctrDependsBkt) + if bkt == nil { + return nil, errors.Wrapf(ErrDBBadConfig, "container dependencies bucket not found in DB") + } + return bkt, nil +} + +func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, config, state, netNS *bolt.Bucket) error { + configBytes := config.Get(id) + if configBytes == nil { + return errors.Wrapf(ErrNoSuchCtr, "error unmarshalling container %s config", string(id)) + } + + if err := json.Unmarshal(configBytes, ctr.config); err != nil { + return errors.Wrapf(err, "error unmarshalling container %s config", string(id)) + } + + stateBytes := state.Get(id) + if stateBytes == nil { + return errors.Wrapf(ErrInternal, "container %s has config but no state", string(id)) + } + + if err := json.Unmarshal(stateBytes, ctr.state); err != nil { + return errors.Wrapf(err, "error unmarshalling container %s state", string(id)) + } + + // The container may not have a network namespace, so it's OK if this is + // nil + netNSBytes := netNS.Get(id) + if netNSBytes != nil { + nsPath := string(netNSBytes) + netNS, err := joinNetNS(nsPath) + if err != nil { + return errors.Wrapf(err, "error joining network namespace for container %s", string(id)) + } + ctr.state.NetNS = netNS + } + + // Get the lock + lockPath := filepath.Join(s.lockDir, string(id)) + lock, err := storage.GetLockfile(lockPath) + if err != nil { + return errors.Wrapf(err, "error retrieving lockfile for container %s", string(id)) + } + ctr.lock = lock + + ctr.runtime = s.runtime + ctr.valid = true + + return nil +} |