Add ability to retrieve runtime configuration from DB

When we create a Libpod database, we store a number of runtime
configuration fields in it. If we can retrieve those, we can use
them to configure the runtime to match the DB instead of inbuilt
defaults, helping to ensure that we don't error in cases where
our compiled-in defaults changed.

Signed-off-by: Matthew Heon <mheon@redhat.com>
This commit is contained in:
Matthew Heon 2018-11-28 15:27:09 -05:00
parent 41f250c486
commit 6e16702947
4 changed files with 88 additions and 19 deletions

View file

@ -240,6 +240,48 @@ func (s *BoltState) Refresh() error {
return err
}
// GetDBConfig retrieves runtime configuration fields that were created when
// the database was first initialized
func (s *BoltState) GetDBConfig() (*DBConfig, error) {
cfg := new(DBConfig)
db, err := s.getDBCon()
if err != nil {
return nil, err
}
defer s.closeDBCon(db)
err = db.View(func(tx *bolt.Tx) error {
configBucket, err := getRuntimeConfigBucket(tx)
if err != nil {
return nil
}
// Some of these may be nil
// When we convert to string, Go will coerce them to ""
// That's probably fine - we could raise an error if the key is
// missing, but just not including it is also OK.
libpodRoot := configBucket.Get(staticDirKey)
libpodTmp := configBucket.Get(tmpDirKey)
storageRoot := configBucket.Get(graphRootKey)
storageTmp := configBucket.Get(runRootKey)
graphDriver := configBucket.Get(graphDriverKey)
cfg.LibpodRoot = string(libpodRoot)
cfg.LibpodTmp = string(libpodTmp)
cfg.StorageRoot = string(storageRoot)
cfg.StorageTmp = string(storageTmp)
cfg.GraphDriver = string(graphDriver)
return nil
})
if err != nil {
return nil, err
}
return cfg, nil
}
// SetNamespace sets the namespace that will be used for container and pod
// retrieval
func (s *BoltState) SetNamespace(ns string) error {

View file

@ -30,6 +30,13 @@ const (
containersName = "containers"
podIDName = "pod-id"
namespaceName = "namespace"
staticDirName = "static-dir"
tmpDirName = "tmp-dir"
runRootName = "run-root"
graphRootName = "graph-root"
graphDriverName = "graph-driver-name"
osName = "os"
)
var (
@ -49,21 +56,19 @@ var (
containersBkt = []byte(containersName)
podIDKey = []byte(podIDName)
namespaceKey = []byte(namespaceName)
staticDirKey = []byte(staticDirName)
tmpDirKey = []byte(tmpDirName)
runRootKey = []byte(runRootName)
graphRootKey = []byte(graphRootName)
graphDriverKey = []byte(graphDriverName)
osKey = []byte(osName)
)
// 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, rt *Runtime) error {
var (
staticDir = []byte("static-dir")
tmpDir = []byte("tmp-dir")
runRoot = []byte("run-root")
graphRoot = []byte("graph-root")
graphDriverName = []byte("graph-driver-name")
osKey = []byte("os")
)
err := db.Update(func(tx *bolt.Tx) error {
configBkt, err := getRuntimeConfigBucket(tx)
if err != nil {
@ -74,31 +79,31 @@ func checkRuntimeConfig(db *bolt.DB, rt *Runtime) error {
return err
}
if err := validateDBAgainstConfig(configBkt, "static dir",
rt.config.StaticDir, staticDir, ""); err != nil {
if err := validateDBAgainstConfig(configBkt, "libpod root directory",
rt.config.StaticDir, staticDirKey, ""); err != nil {
return err
}
if err := validateDBAgainstConfig(configBkt, "tmp dir",
rt.config.TmpDir, tmpDir, ""); err != nil {
if err := validateDBAgainstConfig(configBkt, "libpod temporary files directory",
rt.config.TmpDir, tmpDirKey, ""); err != nil {
return err
}
if err := validateDBAgainstConfig(configBkt, "run root",
rt.config.StorageConfig.RunRoot, runRoot,
if err := validateDBAgainstConfig(configBkt, "storage temporary directory",
rt.config.StorageConfig.RunRoot, runRootKey,
storage.DefaultStoreOptions.RunRoot); err != nil {
return err
}
if err := validateDBAgainstConfig(configBkt, "graph root",
rt.config.StorageConfig.GraphRoot, graphRoot,
if err := validateDBAgainstConfig(configBkt, "storage graph root directory",
rt.config.StorageConfig.GraphRoot, graphRootKey,
storage.DefaultStoreOptions.GraphRoot); err != nil {
return err
}
return validateDBAgainstConfig(configBkt, "graph driver name",
return validateDBAgainstConfig(configBkt, "storage graph driver",
rt.config.StorageConfig.GraphDriverName,
graphDriverName,
graphDriverKey,
storage.DefaultStoreOptions.GraphDriverName)
})

View file

@ -73,6 +73,11 @@ func (s *InMemoryState) Refresh() error {
return nil
}
// GetDBConfig is not implemented for the in-memory state
func (s *InMemoryState) GetDBConfig() (*DBConfig, error) {
return nil, ErrNotImplemented
}
// SetNamespace sets the namespace for container and pod retrieval.
func (s *InMemoryState) SetNamespace(ns string) error {
s.namespace = ns

View file

@ -1,5 +1,15 @@
package libpod
// DBConfig is a set of Libpod runtime configuration settings that are saved
// in a State when it is first created, and can subsequently be retrieved.
type DBConfig struct {
LibpodRoot string
LibpodTmp string
StorageRoot string
StorageTmp string
GraphDriver string
}
// State is a storage backend for libpod's current state.
// A State is only initialized once per instance of libpod.
// As such, initialization methods for State implementations may safely assume
@ -21,6 +31,13 @@ type State interface {
// Refresh clears container and pod states after a reboot
Refresh() error
// GetDBConfig retrieves several paths configured within the database
// when it was created - namely, Libpod root and tmp dirs, c/storage
// root and tmp dirs, and c/storage graph driver.
// This is not implemented by the in-memory state, as it has no need to
// validate runtime configuration.
GetDBConfig() (*DBConfig, error)
// SetNamespace() sets the namespace for the store, and will determine
// what containers are retrieved with container and pod retrieval calls.
// A namespace of "", the empty string, acts as no namespace, and