internal: Improve error message consistency
This commit is contained in:
parent
5d906169f4
commit
a64c02cd78
7 changed files with 72 additions and 71 deletions
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"github.com/tkw1536/goprogram/exit"
|
"github.com/tkw1536/goprogram/exit"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BlindUpdate is the 'blind-update' command
|
// BlindUpdate is the 'blind_update' command
|
||||||
var BlindUpdate wisski_distillery.Command = blindUpdate{}
|
var BlindUpdate wisski_distillery.Command = blindUpdate{}
|
||||||
|
|
||||||
type blindUpdate struct {
|
type blindUpdate struct {
|
||||||
|
|
|
||||||
|
|
@ -53,16 +53,26 @@ func (s systemupdate) AfterParse() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var errFailedToCreateDirectory = exit.Error{
|
var errBoostrapFailedToCreateDirectory = exit.Error{
|
||||||
Message: "failed to create directory %s: %s",
|
Message: "failed to create directory %s: %s",
|
||||||
ExitCode: exit.ExitGeneric,
|
ExitCode: exit.ExitGeneric,
|
||||||
}
|
}
|
||||||
|
|
||||||
var errFailedRuntime = exit.Error{
|
var errBootstrapFailedRuntime = exit.Error{
|
||||||
Message: "failed to update runtime: %s",
|
Message: "failed to update runtime: %s",
|
||||||
ExitCode: exit.ExitGeneric,
|
ExitCode: exit.ExitGeneric,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errBootstrapTriplestore = exit.Error{
|
||||||
|
Message: "Unable to bootstrap Triplestore: %s",
|
||||||
|
ExitCode: exit.ExitGeneric,
|
||||||
|
}
|
||||||
|
|
||||||
|
var errBootstrapSQL = exit.Error{
|
||||||
|
Message: "Unable to bootstrap SQL: %s",
|
||||||
|
ExitCode: exit.ExitGeneric,
|
||||||
|
}
|
||||||
|
|
||||||
func (si systemupdate) Run(context wisski_distillery.Context) error {
|
func (si systemupdate) Run(context wisski_distillery.Context) error {
|
||||||
dis := context.Environment
|
dis := context.Environment
|
||||||
|
|
||||||
|
|
@ -76,7 +86,7 @@ func (si systemupdate) Run(context wisski_distillery.Context) error {
|
||||||
} {
|
} {
|
||||||
context.Println(d)
|
context.Println(d)
|
||||||
if err := os.MkdirAll(d, os.ModeDir); err != nil {
|
if err := os.MkdirAll(d, os.ModeDir); err != nil {
|
||||||
return errFailedToCreateDirectory.WithMessageF(d, err)
|
return errBoostrapFailedToCreateDirectory.WithMessageF(d, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,6 +105,7 @@ func (si systemupdate) Run(context wisski_distillery.Context) error {
|
||||||
if err := si.mustExec(context, "", "apt-get", "install", "curl"); err != nil {
|
if err := si.mustExec(context, "", "apt-get", "install", "curl"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// TODO: Download directly
|
||||||
if err := si.mustExec(context, "", "/bin/sh", "-c", "curl -fsSL https://get.docker.com -o - | /bin/sh"); err != nil {
|
if err := si.mustExec(context, "", "/bin/sh", "-c", "curl -fsSL https://get.docker.com -o - | /bin/sh"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -130,32 +141,23 @@ func (si systemupdate) Run(context wisski_distillery.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := logging.LogOperation(func() error {
|
if err := logging.LogOperation(func() error {
|
||||||
if err := distillery.InstallResource(dis.RuntimeDir(), filepath.Join("resources", "runtime"), func(dst, src string) {
|
return distillery.InstallResource(dis.RuntimeDir(), filepath.Join("resources", "runtime"), func(dst, src string) {
|
||||||
context.Printf("[copy] %s\n", dst)
|
context.Printf("[copy] %s\n", dst)
|
||||||
}); err != nil {
|
})
|
||||||
return errFailedRuntime.WithMessageF(err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}, context.IOStream, "Unpacking Runtime Components"); err != nil {
|
}, context.IOStream, "Unpacking Runtime Components"); err != nil {
|
||||||
return err
|
return errBootstrapFailedRuntime.WithMessageF(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := logging.LogOperation(func() error {
|
if err := logging.LogOperation(func() error {
|
||||||
if err := dis.SQLBootstrap(context.IOStream); err != nil {
|
return dis.SQLBootstrap(context.IOStream)
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}, context.IOStream, "Bootstraping SQL database"); err != nil {
|
}, context.IOStream, "Bootstraping SQL database"); err != nil {
|
||||||
return err
|
return errBootstrapSQL.WithMessageF(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := logging.LogOperation(func() error {
|
if err := logging.LogOperation(func() error {
|
||||||
if err := dis.TriplestoreBootstrap(context.IOStream); err != nil {
|
return dis.TriplestoreBootstrap(context.IOStream)
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}, context.IOStream, "Bootstraping Triplestore"); err != nil {
|
}, context.IOStream, "Bootstraping Triplestore"); err != nil {
|
||||||
return err
|
return errBootstrapTriplestore.WithMessageF(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logging.LogMessage(context.IOStream, "System has been updated")
|
logging.LogMessage(context.IOStream, "System has been updated")
|
||||||
|
|
|
||||||
41
env/stack_sql.go
vendored
41
env/stack_sql.go
vendored
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/stack"
|
"github.com/FAU-CDI/wisski-distillery/internal/stack"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/wait"
|
"github.com/FAU-CDI/wisski-distillery/internal/wait"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/tkw1536/goprogram/exit"
|
|
||||||
"github.com/tkw1536/goprogram/stream"
|
"github.com/tkw1536/goprogram/stream"
|
||||||
"gorm.io/driver/mysql"
|
"gorm.io/driver/mysql"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
@ -54,11 +53,6 @@ func (env Distillery) sqlOpen(database string, config *gorm.Config) (*gorm.DB, e
|
||||||
return db, nil
|
return db, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var errSQL = exit.Error{
|
|
||||||
Message: "error querying sql database: %s",
|
|
||||||
ExitCode: exit.ExitGeneric,
|
|
||||||
}
|
|
||||||
|
|
||||||
// sqlBkTable returns a gorm connection to the bookkeeping database.
|
// sqlBkTable returns a gorm connection to the bookkeeping database.
|
||||||
func (dis *Distillery) sqlBkTable(silent bool) (*gorm.DB, error) {
|
func (dis *Distillery) sqlBkTable(silent bool) (*gorm.DB, error) {
|
||||||
|
|
||||||
|
|
@ -70,13 +64,13 @@ func (dis *Distillery) sqlBkTable(silent bool) (*gorm.DB, error) {
|
||||||
// open the database
|
// open the database
|
||||||
db, err := dis.sqlOpen(dis.Config.DistilleryBookkeepingDatabase, config)
|
db, err := dis.sqlOpen(dis.Config.DistilleryBookkeepingDatabase, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errSQL.WithMessageF(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the table
|
// load the table
|
||||||
table := db.Table(dis.Config.DistilleryBookkeepingTable)
|
table := db.Table(dis.Config.DistilleryBookkeepingTable)
|
||||||
if table.Error != nil {
|
if table.Error != nil {
|
||||||
return nil, errSQL.WithMessageF(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return table, nil
|
return table, nil
|
||||||
|
|
@ -87,11 +81,6 @@ func (dis *Distillery) SQLShell(io stream.IOStream, argv ...string) (int, error)
|
||||||
return dis.SQLStack().Exec(io, "sql", "mysql", argv...)
|
return dis.SQLStack().Exec(io, "sql", "mysql", argv...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var errSQLBootstrap = exit.Error{
|
|
||||||
Message: "Unable to boostrap SQL: %s",
|
|
||||||
ExitCode: exit.ExitGeneric,
|
|
||||||
}
|
|
||||||
|
|
||||||
const waitSQLInterval = 1 * time.Second
|
const waitSQLInterval = 1 * time.Second
|
||||||
|
|
||||||
// SQLWaitForShell waits for the sql database to be reachable via a docker-compose shell
|
// SQLWaitForShell waits for the sql database to be reachable via a docker-compose shell
|
||||||
|
|
@ -140,10 +129,7 @@ func (dis *Distillery) SQLProvision(name, user, password string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var errSQLPurgeUser = exit.Error{
|
var errSQLPurgeUser = errors.New("unable to delete user")
|
||||||
Message: "Unable to delete user",
|
|
||||||
ExitCode: exit.ExitGeneric,
|
|
||||||
}
|
|
||||||
|
|
||||||
// SQLPurgeUser deletes the specified user from the database
|
// SQLPurgeUser deletes the specified user from the database
|
||||||
func (dis *Distillery) SQLPurgeUser(user string) error {
|
func (dis *Distillery) SQLPurgeUser(user string) error {
|
||||||
|
|
@ -154,10 +140,7 @@ func (dis *Distillery) SQLPurgeUser(user string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var errSQLPurgeDB = exit.Error{
|
var errSQLPurgeDB = errors.New("unable to drop database")
|
||||||
Message: "Unable to delete database",
|
|
||||||
ExitCode: exit.ExitGeneric,
|
|
||||||
}
|
|
||||||
|
|
||||||
// SQLPurgeDatabase deletes the specified db from the database
|
// SQLPurgeDatabase deletes the specified db from the database
|
||||||
func (dis *Distillery) SQLPurgeDatabase(db string) error {
|
func (dis *Distillery) SQLPurgeDatabase(db string) error {
|
||||||
|
|
@ -170,10 +153,14 @@ func (dis *Distillery) SQLPurgeDatabase(db string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errSQLUnableToCreateUser = errors.New("unable to create administrative user")
|
||||||
|
var errSQLUnsafeDatabaseName = errors.New("Bookkeeping database has an unsafe name")
|
||||||
|
var errSQLUnableToCreate = errors.New("unable to create bookkeeping database")
|
||||||
|
|
||||||
// SQLBootstrap bootstraps the SQL database, and makes sure that the bookkeeping table is up-to-date
|
// SQLBootstrap bootstraps the SQL database, and makes sure that the bookkeeping table is up-to-date
|
||||||
func (dis *Distillery) SQLBootstrap(io stream.IOStream) error {
|
func (dis *Distillery) SQLBootstrap(io stream.IOStream) error {
|
||||||
if err := dis.SQLWaitForShell(); err != nil {
|
if err := dis.SQLWaitForShell(); err != nil {
|
||||||
return errSQLBootstrap.WithMessageF(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the admin user
|
// create the admin user
|
||||||
|
|
@ -182,7 +169,7 @@ func (dis *Distillery) SQLBootstrap(io stream.IOStream) error {
|
||||||
username := dis.Config.MysqlAdminUser
|
username := dis.Config.MysqlAdminUser
|
||||||
password := dis.Config.MysqlAdminPassword
|
password := dis.Config.MysqlAdminPassword
|
||||||
if !dis.sqlRaw("CREATE USER IF NOT EXISTS ?@'%' IDENTIFIED BY ?; GRANT ALL PRIVILEGES ON *.* TO ?@`%` WITH GRANT OPTION; FLUSH PRIVILEGES;", username, password, username) {
|
if !dis.sqlRaw("CREATE USER IF NOT EXISTS ?@'%' IDENTIFIED BY ?; GRANT ALL PRIVILEGES ON *.* TO ?@`%` WITH GRANT OPTION; FLUSH PRIVILEGES;", username, password, username) {
|
||||||
return errSQLBootstrap.WithMessageF("Unable to create administrative user")
|
return errSQLUnableToCreateUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,11 +177,11 @@ func (dis *Distillery) SQLBootstrap(io stream.IOStream) error {
|
||||||
logging.LogMessage(io, "Creating sql database")
|
logging.LogMessage(io, "Creating sql database")
|
||||||
{
|
{
|
||||||
if !sqle.IsSafeDatabaseName(dis.Config.DistilleryBookkeepingDatabase) {
|
if !sqle.IsSafeDatabaseName(dis.Config.DistilleryBookkeepingDatabase) {
|
||||||
return errSQLBootstrap.WithMessageF("Unsafe database name")
|
return errSQLUnsafeDatabaseName
|
||||||
}
|
}
|
||||||
createDBSQL := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s`;", dis.Config.DistilleryBookkeepingDatabase)
|
createDBSQL := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s`;", dis.Config.DistilleryBookkeepingDatabase)
|
||||||
if !dis.sqlRaw(createDBSQL) {
|
if !dis.sqlRaw(createDBSQL) {
|
||||||
return errSQLBootstrap.WithMessageF(createDBSQL)
|
return errSQLUnableToCreate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,11 +194,11 @@ func (dis *Distillery) SQLBootstrap(io stream.IOStream) error {
|
||||||
{
|
{
|
||||||
db, err := dis.sqlBkTable(false)
|
db, err := dis.sqlBkTable(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errSQLBootstrap.WithMessageF(err)
|
return fmt.Errorf("unable to access bookkeeping table: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := db.AutoMigrate(&bookkeeping.Instance{}); err != nil {
|
if err := db.AutoMigrate(&bookkeeping.Instance{}); err != nil {
|
||||||
return errSQLBootstrap.WithMessageF(err)
|
return fmt.Errorf("unable to migrate bookkeeping table: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
16
env/stack_triplestore.go
vendored
16
env/stack_triplestore.go
vendored
|
|
@ -3,6 +3,7 @@ package env
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
|
|
@ -49,11 +50,6 @@ type TriplestoreUserAppSettings struct {
|
||||||
ExecuteCount bool `json:"EXECUTE_COUNT"`
|
ExecuteCount bool `json:"EXECUTE_COUNT"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var errTriplestoreBootstrap = exit.Error{
|
|
||||||
Message: "Unable to bootstrap Triplestore: %s",
|
|
||||||
ExitCode: exit.ExitGeneric,
|
|
||||||
}
|
|
||||||
|
|
||||||
const triplestoreBaseURL = "http://127.0.0.1:7200"
|
const triplestoreBaseURL = "http://127.0.0.1:7200"
|
||||||
const waitTSInterval = 1 * time.Second
|
const waitTSInterval = 1 * time.Second
|
||||||
|
|
||||||
|
|
@ -204,6 +200,8 @@ func (dis *Distillery) TriplestorePurgeRepo(repo string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errTriplestoreFailedSecurity = errors.New("failed to enable triplestore security: request did not succeed with HTTP 200 OK")
|
||||||
|
|
||||||
func (dis *Distillery) TriplestoreBootstrap(io stream.IOStream) error {
|
func (dis *Distillery) TriplestoreBootstrap(io stream.IOStream) error {
|
||||||
logging.LogMessage(io, "Waiting for Triplestore")
|
logging.LogMessage(io, "Waiting for Triplestore")
|
||||||
if err := dis.TriplestoreWaitForConnection(); err != nil {
|
if err := dis.TriplestoreWaitForConnection(); err != nil {
|
||||||
|
|
@ -224,7 +222,7 @@ func (dis *Distillery) TriplestoreBootstrap(io stream.IOStream) error {
|
||||||
GrantedAuthorities: []string{"ROLE_ADMIN"},
|
GrantedAuthorities: []string{"ROLE_ADMIN"},
|
||||||
}, "", "")
|
}, "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errTriplestoreBootstrap.WithMessageF(err)
|
return fmt.Errorf("failed to create triplestore user: %s", err)
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
|
@ -238,7 +236,7 @@ func (dis *Distillery) TriplestoreBootstrap(io stream.IOStream) error {
|
||||||
logging.LogMessage(io, "Security is already enabled")
|
logging.LogMessage(io, "Security is already enabled")
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return errTriplestoreBootstrap.WithMessageF("Unable to set administrative password")
|
return fmt.Errorf("failed to create triplestore user: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,12 +244,12 @@ func (dis *Distillery) TriplestoreBootstrap(io stream.IOStream) error {
|
||||||
{
|
{
|
||||||
res, err := dis.triplestoreRequest("POST", "/rest/security", true, "", "")
|
res, err := dis.triplestoreRequest("POST", "/rest/security", true, "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errTriplestoreBootstrap.WithMessageF(err)
|
return fmt.Errorf("failed to enable triplestore security: %s", err)
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
return errTriplestoreBootstrap.WithMessageF("Unable to enable security")
|
return errTriplestoreFailedSecurity
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
package execx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/tkw1536/goprogram/stream"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Compose runs a docker-compose command in a specific directory, with the provided arguments and streams.
|
|
||||||
// It then waits for the process to exit, and returns the exit code.
|
|
||||||
func Compose(io stream.IOStream, workdir string, args ...string) int {
|
|
||||||
return Exec(io, workdir, "docker", append([]string{"compose"}, args...)...)
|
|
||||||
}
|
|
||||||
15
internal/execx/look.go
Normal file
15
internal/execx/look.go
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package execx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LookPathAbs is like [exec.LookPath], but always returns an absolute path
|
||||||
|
func LookPathAbs(file string) (string, error) {
|
||||||
|
path, err := exec.LookPath(file)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return filepath.Abs(path)
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,8 @@ import (
|
||||||
// In the future the idea is to replace this with a native docker compose client.
|
// In the future the idea is to replace this with a native docker compose client.
|
||||||
type Stack struct {
|
type Stack struct {
|
||||||
Dir string // Directory this Stack is located in
|
Dir string // Directory this Stack is located in
|
||||||
|
|
||||||
|
DockerExecutable string // Path to the native docker executable to use
|
||||||
}
|
}
|
||||||
|
|
||||||
var errStackUpdatePull = errors.New("Stack.Update: Pull returned non-zero exit code")
|
var errStackUpdatePull = errors.New("Stack.Update: Pull returned non-zero exit code")
|
||||||
|
|
@ -131,9 +133,17 @@ func (ds Stack) Down(io stream.IOStream) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compose executes a 'docker compose' command on this stack.
|
// compose executes a 'docker compose' command on this stack.
|
||||||
// TODO: This should be removed and replaced by an internal call directly to libcompose.
|
//
|
||||||
|
// NOTE(twiesing): Check if this can be replaced by an internal call to libcompose.
|
||||||
|
// But probably not.
|
||||||
func (ds Stack) compose(io stream.IOStream, args ...string) (int, error) {
|
func (ds Stack) compose(io stream.IOStream, args ...string) (int, error) {
|
||||||
// TODO: can we migrate to a built-in version of this?
|
if ds.DockerExecutable == "" {
|
||||||
return execx.Compose(io, ds.Dir, args...), nil
|
var err error
|
||||||
|
ds.DockerExecutable, err = execx.LookPathAbs("docker")
|
||||||
|
if err != nil {
|
||||||
|
return execx.ExecCommandError, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return execx.Exec(io, ds.Dir, ds.DockerExecutable, append([]string{"compose"}, args...)...), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue