Add a metadata system
This commit is contained in:
parent
07409a01be
commit
8b3218ad00
16 changed files with 365 additions and 61 deletions
|
|
@ -21,8 +21,8 @@ import (
|
|||
// ========== low-level connection ==========
|
||||
//
|
||||
|
||||
// Query performs a database query, outside a database contect
|
||||
func (sql *SQL) Query(query string, args ...interface{}) error {
|
||||
// Exec executes a database-independent database query.
|
||||
func (sql *SQL) Exec(query string, args ...interface{}) error {
|
||||
// connect to the server
|
||||
conn, err := sql.connect("")
|
||||
if err != nil {
|
||||
|
|
@ -39,10 +39,10 @@ func (sql *SQL) Query(query string, args ...interface{}) error {
|
|||
}
|
||||
}
|
||||
|
||||
// WaitQuery waits for the query interface to be able to connect to the database
|
||||
func (sql *SQL) WaitQuery() error {
|
||||
// WaitExec waits for the query interface to be able to connect to the database
|
||||
func (sql *SQL) WaitExec() error {
|
||||
return wait.Wait(func() bool {
|
||||
err := sql.Query("select 1;")
|
||||
err := sql.Exec("select 1;")
|
||||
// log.Printf("[WaitQuery] %s\n", err) // debug
|
||||
return err == nil
|
||||
}, sql.PollInterval, sql.PollContext)
|
||||
|
|
@ -52,8 +52,8 @@ func (sql *SQL) WaitQuery() error {
|
|||
// ========== connection via gorm ==========
|
||||
//
|
||||
|
||||
// QueryTable returns a gorm.DB to connect to the provided gorm database table
|
||||
func (sql *SQL) QueryTable(silent bool, name string) (*gorm.DB, error) {
|
||||
// QueryTable returns a gorm.DB to connect to the provided distillery database table
|
||||
func (sql *SQL) QueryTable(silent bool, table string) (*gorm.DB, error) {
|
||||
conn, err := sql.connect(sql.Config.DistilleryDatabase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -79,7 +79,7 @@ func (sql *SQL) QueryTable(silent bool, name string) (*gorm.DB, error) {
|
|||
}
|
||||
|
||||
// set the table
|
||||
db = db.Table(name)
|
||||
db = db.Table(table)
|
||||
|
||||
// check that nothing went wrong
|
||||
if db.Error != nil {
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
package sql
|
||||
|
|
@ -9,7 +9,10 @@ import (
|
|||
var errProvisionInvalidDatabaseParams = errors.New("Provision: Invalid parameters")
|
||||
var errProvisionInvalidGrant = errors.New("Provision: Grant failed")
|
||||
|
||||
// Provision provisions a new sql database and user
|
||||
// Provision creates a new database with the given name.
|
||||
// It then generates a new user, with the name 'user' and the password 'password', that is then granted access to this database.
|
||||
//
|
||||
// Provision internally waits for the database to become available.
|
||||
func (sql *SQL) Provision(name, user, password string) error {
|
||||
|
||||
// NOTE(twiesing): We shouldn't use string concat to build sql queries.
|
||||
|
|
@ -41,6 +44,10 @@ func (sql *SQL) Provision(name, user, password string) error {
|
|||
|
||||
var errCreateSuperuserGrant = errors.New("CreateSuperUser: Grant failed")
|
||||
|
||||
// CreateSuperuser createsa new user, with the name 'user' and the password 'password'.
|
||||
// It then grants this user superuser status in the database.
|
||||
//
|
||||
// CreateSuperuser internally waits for the database to become available.
|
||||
func (sql *SQL) CreateSuperuser(user, password string, allowExisting bool) error {
|
||||
// NOTE(twiesing): This function unsafely uses the shell directly to create a superuser.
|
||||
// This is for two reasons:
|
||||
|
|
@ -70,9 +77,21 @@ func (sql *SQL) CreateSuperuser(user, password string, allowExisting bool) error
|
|||
return nil
|
||||
}
|
||||
|
||||
var errPurgeUser = errors.New("PurgeUser: Failed to drop user")
|
||||
|
||||
// SQLPurgeUser deletes the specified user from the database
|
||||
func (sql *SQL) PurgeUser(user string) error {
|
||||
return sql.Query("DROP USER IF EXISTS ?@`%`; FLUSH PRIVILEGES; ", user)
|
||||
if !sqle.IsSafeDatabaseSingleQuote(user) {
|
||||
return errPurgeUser
|
||||
}
|
||||
|
||||
query := "DROP USER IF EXISTS '" + user + "'@'%';" +
|
||||
"FLUSH PRIVILEGES;"
|
||||
if !sql.unsafeQueryShell(query) {
|
||||
return errPurgeUser
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var errSQLPurgeDB = errors.New("unable to drop database: unsafe database name")
|
||||
|
|
@ -82,5 +101,5 @@ func (sql *SQL) PurgeDatabase(db string) error {
|
|||
if !sqle.IsSafeDatabaseLiteral(db) {
|
||||
return errSQLPurgeDB
|
||||
}
|
||||
return sql.Query("DROP DATABASE IF EXISTS `" + db + "`")
|
||||
return sql.Exec("DROP DATABASE IF EXISTS `" + db + "`")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/FAU-CDI/wisski-distillery/pkg/logging"
|
||||
"github.com/FAU-CDI/wisski-distillery/pkg/sqle"
|
||||
"github.com/FAU-CDI/wisski-distillery/pkg/wait"
|
||||
"github.com/tkw1536/goprogram/exit"
|
||||
"github.com/tkw1536/goprogram/stream"
|
||||
)
|
||||
|
||||
|
|
@ -36,6 +37,10 @@ func (sql *SQL) unsafeQueryShell(query string) bool {
|
|||
|
||||
var errSQLUnableToCreateUser = errors.New("unable to create administrative user")
|
||||
var errSQLUnsafeDatabaseName = errors.New("distillery database has an unsafe name")
|
||||
var errSQLUnableToMigrate = exit.Error{
|
||||
Message: "unable to migrate %s table: %s",
|
||||
ExitCode: exit.ExitGeneric,
|
||||
}
|
||||
|
||||
// Update initializes or updates the SQL database.
|
||||
func (sql *SQL) Update(io stream.IOStream) error {
|
||||
|
|
@ -62,7 +67,7 @@ func (sql *SQL) Update(io stream.IOStream) error {
|
|||
return errSQLUnsafeDatabaseName
|
||||
}
|
||||
createDBSQL := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s`;", sql.Config.DistilleryDatabase)
|
||||
if err := sql.Query(createDBSQL); err != nil {
|
||||
if err := sql.Exec(createDBSQL); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -71,18 +76,36 @@ func (sql *SQL) Update(io stream.IOStream) error {
|
|||
logging.LogMessage(io, "Waiting for database update to be complete")
|
||||
sql.WaitQueryTable()
|
||||
|
||||
// open the database
|
||||
logging.LogMessage(io, "Migrating instances table")
|
||||
{
|
||||
db, err := sql.QueryTable(false, models.InstanceTable)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to access bookkeeping table: %s", err)
|
||||
}
|
||||
|
||||
if err := db.AutoMigrate(&models.Instance{}); err != nil {
|
||||
return fmt.Errorf("unable to migrate bookkeeping table: %s", err)
|
||||
}
|
||||
tables := []struct {
|
||||
name string
|
||||
model any
|
||||
table string
|
||||
}{
|
||||
{
|
||||
"instance",
|
||||
&models.Instance{},
|
||||
models.InstanceTable,
|
||||
},
|
||||
{
|
||||
"metadata",
|
||||
&models.Metadatum{},
|
||||
models.MetadataTable,
|
||||
},
|
||||
}
|
||||
|
||||
return nil
|
||||
// migrate all of the tables!
|
||||
return logging.LogOperation(func() error {
|
||||
for _, table := range tables {
|
||||
logging.LogMessage(io, "migrating %q table", table.name)
|
||||
db, err := sql.QueryTable(false, table.table)
|
||||
if err != nil {
|
||||
return errSQLUnableToMigrate.WithMessageF(table.name, "unable to access table")
|
||||
}
|
||||
|
||||
if err := db.AutoMigrate(table.model); err != nil {
|
||||
return errSQLUnableToMigrate.WithMessageF(table.name, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}, io, "migrating database tables")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue