From 6e167029478e29d24ff75d259123e7f7e093b6ff Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Wed, 28 Nov 2018 15:27:09 -0500 Subject: 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 --- libpod/boltdb_state.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'libpod/boltdb_state.go') diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index 42f029379..7191b184a 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -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 { -- cgit v1.2.3-54-g00ecf From 137e0948aed96c3fe6412512e0d138eedf71d499 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Sun, 2 Dec 2018 13:36:55 -0500 Subject: Make DB config validation an explicit step Previously, we implicitly validated runtime configuration against what was stored in the database as part of database init. Make this an explicit step, so we can call it after the database has been initialized. This will allow us to retrieve paths from the database and use them to overwrite our defaults if they differ. Signed-off-by: Matthew Heon --- libpod/boltdb_state.go | 29 ++++++++++++++++++++++++----- libpod/in_memory_state.go | 6 ++++++ libpod/runtime.go | 5 +++++ libpod/state.go | 9 +++++++++ 4 files changed, 44 insertions(+), 5 deletions(-) (limited to 'libpod/boltdb_state.go') diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index 7191b184a..37b309c0d 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -115,11 +115,6 @@ func NewBoltState(path, lockDir string, runtime *Runtime) (State, error) { return nil, errors.Wrapf(err, "error creating initial database layout") } - // Check runtime configuration - if err := checkRuntimeConfig(db, runtime); err != nil { - return nil, err - } - state.valid = true return state, nil @@ -243,6 +238,10 @@ func (s *BoltState) Refresh() error { // GetDBConfig retrieves runtime configuration fields that were created when // the database was first initialized func (s *BoltState) GetDBConfig() (*DBConfig, error) { + if !s.valid { + return nil, ErrDBClosed + } + cfg := new(DBConfig) db, err := s.getDBCon() @@ -282,6 +281,26 @@ func (s *BoltState) GetDBConfig() (*DBConfig, error) { return cfg, nil } +// ValidateDBConfig validates paths in the given runtime against the database +func (s *BoltState) ValidateDBConfig(runtime *Runtime) error { + if !s.valid { + return ErrDBClosed + } + + db, err := s.getDBCon() + if err != nil { + return err + } + defer s.closeDBCon(db) + + // Check runtime configuration + if err := checkRuntimeConfig(db, runtime); err != nil { + return err + } + + return nil +} + // SetNamespace sets the namespace that will be used for container and pod // retrieval func (s *BoltState) SetNamespace(ns string) error { diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go index 3a775eb43..8cd2f47b9 100644 --- a/libpod/in_memory_state.go +++ b/libpod/in_memory_state.go @@ -78,6 +78,12 @@ func (s *InMemoryState) GetDBConfig() (*DBConfig, error) { return nil, ErrNotImplemented } +// ValidateDBConfig is not implemented for the in-memory state. +// Since we do nothing just return no error. +func (s *InMemoryState) ValidateDBConfig(runtime *Runtime) error { + return nil +} + // SetNamespace sets the namespace for container and pod retrieval. func (s *InMemoryState) SetNamespace(ns string) error { s.namespace = ns diff --git a/libpod/runtime.go b/libpod/runtime.go index 8615e5e12..2e76f159b 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -448,6 +448,11 @@ func makeRuntime(runtime *Runtime) (err error) { return errors.Wrapf(ErrInvalidArg, "unrecognized state type passed") } + // Validate our config against the database + if err := runtime.state.ValidateDBConfig(runtime); err != nil { + return err + } + if err := runtime.state.SetNamespace(runtime.config.Namespace); err != nil { return errors.Wrapf(err, "error setting libpod namespace in state") } diff --git a/libpod/state.go b/libpod/state.go index 7f4efa21b..99e2435a2 100644 --- a/libpod/state.go +++ b/libpod/state.go @@ -38,6 +38,15 @@ type State interface { // validate runtime configuration. GetDBConfig() (*DBConfig, error) + // ValidateDBConfig ralidates the config in the given Runtime struct + // against paths stored in the configured database. + // Libpod root and tmp dirs and c/storage root and tmp dirs and graph + // driver are validated. + // This is not implemented by the in-memory state, as it has no need to + // validate runtime configuration that may change over multiple runs of + // the program. + ValidateDBConfig(runtime *Runtime) 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 -- cgit v1.2.3-54-g00ecf From 03229239b018b611b5f0307dc0d11bb0fb15c1ae Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Sun, 2 Dec 2018 15:32:06 -0500 Subject: Do not initialize locks dir in BoltDB We already create the locks directory as part of the libpod runtime's init - no need to do it again as part of BoltDB's init. Signed-off-by: Matthew Heon --- libpod/boltdb_state.go | 10 ---------- libpod/runtime.go | 7 +++++++ 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'libpod/boltdb_state.go') diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index 37b309c0d..8b9b77a54 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -3,7 +3,6 @@ package libpod import ( "bytes" "encoding/json" - "os" "strings" "sync" @@ -62,15 +61,6 @@ func NewBoltState(path, lockDir string, runtime *Runtime) (State, error) { logrus.Debugf("Initializing boltdb state at %s", path) - // Make the directory that will hold container lockfiles - if err := os.MkdirAll(lockDir, 0750); err != nil { - // The directory is allowed to exist - if !os.IsExist(err) { - return nil, errors.Wrapf(err, "error creating lockfiles dir %s", lockDir) - } - } - state.lockDir = lockDir - db, err := bolt.Open(path, 0600, nil) if err != nil { return nil, errors.Wrapf(err, "error opening database %s", path) diff --git a/libpod/runtime.go b/libpod/runtime.go index 6a5d2ad39..9afa1bc10 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -285,6 +285,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) { return nil, errors.Wrapf(err, "error retrieving rootless storage config") } runtime.config.StorageConfig = storageConf + runtime.config.StaticDir = filepath.Join(storageConf.GraphRoot, "libpod") } configPath := ConfigPath @@ -516,6 +517,12 @@ func makeRuntime(runtime *Runtime) (err error) { runtime.config.TmpDir = dbConfig.LibpodTmp } + logrus.Debugf("Using graph driver %s", runtime.config.StorageConfig.GraphDriverName) + logrus.Debugf("Using graph root %s", runtime.config.StorageConfig.GraphRoot) + logrus.Debugf("Using run root %s", runtime.config.StorageConfig.RunRoot) + logrus.Debugf("Using static dir %s", runtime.config.StaticDir) + logrus.Debugf("Using tmp dir %s", runtime.config.TmpDir) + // Validate our config against the database, now that we've set our // final storage configuration if err := runtime.state.ValidateDBConfig(runtime); err != nil { -- cgit v1.2.3-54-g00ecf From e3882cfa2d1329d44c8a580418ea1d56804b331d Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Tue, 4 Dec 2018 13:50:38 -0500 Subject: Use runtime lockDir in BoltDB state Instead of storing the runtime's file lock dir in the BoltDB state, refer to the runtime inside the Bolt state instead, and use the path stored in the runtime. This is necessary since we moved DB initialization very far up in runtime init, before the locks dir is properly initialized (and it must happen before the locks dir can be created, as we use the DB to retrieve the proper path for the locks dir now). Signed-off-by: Matthew Heon --- libpod/boltdb_state.go | 4 +--- libpod/boltdb_state_internal.go | 4 ++-- libpod/runtime.go | 2 +- libpod/state_test.go | 3 ++- 4 files changed, 6 insertions(+), 7 deletions(-) (limited to 'libpod/boltdb_state.go') diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index 8b9b77a54..cb661d4e9 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -18,7 +18,6 @@ type BoltState struct { dbLock sync.Mutex namespace string namespaceBytes []byte - lockDir string runtime *Runtime } @@ -51,10 +50,9 @@ type BoltState struct { // containers/storage do not occur. // NewBoltState creates a new bolt-backed state database -func NewBoltState(path, lockDir string, runtime *Runtime) (State, error) { +func NewBoltState(path string, runtime *Runtime) (State, error) { state := new(BoltState) state.dbPath = path - state.lockDir = lockDir state.runtime = runtime state.namespace = "" state.namespaceBytes = nil diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go index 05536e069..3f00657ea 100644 --- a/libpod/boltdb_state_internal.go +++ b/libpod/boltdb_state_internal.go @@ -266,7 +266,7 @@ func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt. } // Get the lock - lockPath := filepath.Join(s.lockDir, string(id)) + lockPath := filepath.Join(s.runtime.lockDir, string(id)) lock, err := storage.GetLockfile(lockPath) if err != nil { return errors.Wrapf(err, "error retrieving lockfile for container %s", string(id)) @@ -302,7 +302,7 @@ func (s *BoltState) getPodFromDB(id []byte, pod *Pod, podBkt *bolt.Bucket) error } // Get the lock - lockPath := filepath.Join(s.lockDir, string(id)) + lockPath := filepath.Join(s.runtime.lockDir, string(id)) lock, err := storage.GetLockfile(lockPath) if err != nil { return errors.Wrapf(err, "error retrieving lockfile for pod %s", string(id)) diff --git a/libpod/runtime.go b/libpod/runtime.go index e69b63a24..083ab1ec3 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -494,7 +494,7 @@ func makeRuntime(runtime *Runtime) (err error) { case BoltDBStateStore: dbPath := filepath.Join(runtime.config.StaticDir, "bolt_state.db") - state, err := NewBoltState(dbPath, runtime.lockDir, runtime) + state, err := NewBoltState(dbPath, runtime) if err != nil { return err } diff --git a/libpod/state_test.go b/libpod/state_test.go index 0f5da62e4..d93a371f3 100644 --- a/libpod/state_test.go +++ b/libpod/state_test.go @@ -52,8 +52,9 @@ func getEmptyBoltState() (s State, p string, p2 string, err error) { runtime := new(Runtime) runtime.config = new(RuntimeConfig) runtime.config.StorageConfig = storage.StoreOptions{} + runtime.lockDir = lockDir - state, err := NewBoltState(dbPath, lockDir, runtime) + state, err := NewBoltState(dbPath, runtime) if err != nil { return nil, "", "", err } -- cgit v1.2.3-54-g00ecf