diff options
author | Matthew Heon <matthew.heon@gmail.com> | 2017-11-29 14:37:35 -0500 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2017-11-30 18:05:56 +0000 |
commit | 7eb5ce940c8145ef57920ef90b52857e9716ffc9 (patch) | |
tree | 0a9d90a27d87820f8c08c802ad6c0a1859e614fb /libpod/sql_state_internal.go | |
parent | ed5d686076b9b01ce5da7ed0bd37faeed216ae75 (diff) | |
download | podman-7eb5ce940c8145ef57920ef90b52857e9716ffc9.tar.gz podman-7eb5ce940c8145ef57920ef90b52857e9716ffc9.tar.bz2 podman-7eb5ce940c8145ef57920ef90b52857e9716ffc9.zip |
Add schema validation to DB
This ensures we don't open a DB with an earlier schema or a
config that differs from ours
Signed-off-by: Matthew Heon <matthew.heon@gmail.com>
Closes: #86
Approved by: rhatdan
Diffstat (limited to 'libpod/sql_state_internal.go')
-rw-r--r-- | libpod/sql_state_internal.go | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/libpod/sql_state_internal.go b/libpod/sql_state_internal.go index 58a6daa58..6e0142b9b 100644 --- a/libpod/sql_state_internal.go +++ b/libpod/sql_state_internal.go @@ -15,6 +15,137 @@ import ( _ "github.com/mattn/go-sqlite3" ) +// Checks that the DB configuration matches the runtime's configuration +func checkDB(db *sql.DB, r *Runtime) (err error) { + // Create a table to hold runtime information + // TODO: Include UID/GID mappings + const runtimeTable = ` + CREATE TABLE runtime( + Id INTEGER NOT NULL PRIMARY KEY, + SchemaVersion INTEGER NOT NULL, + StaticDir TEXT NOT NULL, + TmpDir TEXT NOT NULL, + RunRoot TEXT NOT NULL, + GraphRoot TEXT NOT NULL, + GraphDriverName TEXT NOT NULL, + CHECK (Id=0) + ); + ` + const fillRuntimeTable = `INSERT INTO runtime VALUES ( + ?, ?, ?, ?, ?, ?, ? + );` + + const selectRuntimeTable = `SELECT SchemaVersion, + StaticDir, + TmpDir, + RunRoot, + GraphRoot, + GraphDriverName + FROM runtime WHERE id=0;` + + const checkRuntimeExists = "SELECT name FROM sqlite_master WHERE type='table' AND name='runtime';" + + tx, err := db.Begin() + if err != nil { + return errors.Wrapf(err, "error beginning database transaction") + } + defer func() { + if err != nil { + if err2 := tx.Rollback(); err2 != nil { + logrus.Errorf("Error rolling back transaction to check runtime table: %v", err2) + } + } + + }() + + row := tx.QueryRow(checkRuntimeExists) + var table string + if err := row.Scan(&table); err != nil { + // There is no runtime table + // Create and populate the runtime table + if err == sql.ErrNoRows { + if _, err := tx.Exec(runtimeTable); err != nil { + return errors.Wrapf(err, "error creating runtime table in database") + } + + _, err := tx.Exec(fillRuntimeTable, + 0, + DBSchema, + r.config.StaticDir, + r.config.TmpDir, + r.config.StorageConfig.RunRoot, + r.config.StorageConfig.GraphRoot, + r.config.StorageConfig.GraphDriverName) + if err != nil { + return errors.Wrapf(err, "error populating runtime table in database") + } + + if err := tx.Commit(); err != nil { + return errors.Wrapf(err, "error committing runtime table transaction in database") + } + + return nil + } + + return errors.Wrapf(err, "error checking for presence of runtime table in database") + } + + // There is a runtime table + // Retrieve its contents + var ( + schemaVersion int + staticDir string + tmpDir string + runRoot string + graphRoot string + graphDriverName string + ) + + row = tx.QueryRow(selectRuntimeTable) + err = row.Scan( + &schemaVersion, + &staticDir, + &tmpDir, + &runRoot, + &graphRoot, + &graphDriverName) + if err != nil { + return errors.Wrapf(err, "error retrieving runtime information from database") + } + + // Compare the information in the database against our runtime config + if schemaVersion != DBSchema { + return errors.Wrapf(ErrDBBadConfig, "database schema version %d does not match our schema version %d", + schemaVersion, DBSchema) + } + if staticDir != r.config.StaticDir { + return errors.Wrapf(ErrDBBadConfig, "database static directory %s does not match our static directory %s", + staticDir, r.config.StaticDir) + } + if tmpDir != r.config.TmpDir { + return errors.Wrapf(ErrDBBadConfig, "database temp directory %s does not match our temp directory %s", + tmpDir, r.config.TmpDir) + } + if runRoot != r.config.StorageConfig.RunRoot { + return errors.Wrapf(ErrDBBadConfig, "database runroot directory %s does not match our runroot directory %s", + runRoot, r.config.StorageConfig.RunRoot) + } + if graphRoot != r.config.StorageConfig.GraphRoot { + return errors.Wrapf(ErrDBBadConfig, "database graph root directory %s does not match our graph root directory %s", + graphRoot, r.config.StorageConfig.GraphRoot) + } + if graphDriverName != r.config.StorageConfig.GraphDriverName { + return errors.Wrapf(ErrDBBadConfig, "database runroot directory %s does not match our runroot directory %s", + graphDriverName, r.config.StorageConfig.GraphDriverName) + } + + if err := tx.Commit(); err != nil { + return errors.Wrapf(err, "error committing runtime table transaction in database") + } + + return nil +} + // Performs database setup including by not limited to initializing tables in // the database func prepareDB(db *sql.DB) (err error) { |