From c31c46ee44c25bda82fc1b919576493991bac1a7 Mon Sep 17 00:00:00 2001 From: Tom Wiesing Date: Thu, 9 Mar 2023 11:13:19 +0100 Subject: [PATCH] Rework error messages This commit reworks error messages for all commands and makes sure they pass liniting. --- cmd/blind_update.go | 6 +++-- cmd/bootstrap.go | 22 +++++++-------- cmd/config.go | 13 +++++++-- cmd/cron.go | 10 ++++++- cmd/dis_grant.go | 9 ++++++- cmd/dis_ssh.go | 21 +++++++++++---- cmd/dis_user.go | 11 ++++++-- cmd/drupal_setting.go | 7 ++++- cmd/drupal_user.go | 14 +++++----- cmd/info.go | 10 ++++++- cmd/instance_lock.go | 7 ++++- cmd/instance_pause.go | 8 +++++- cmd/ls.go | 8 +++++- cmd/make_mysql_account.go | 15 +++++++---- cmd/pathbuilders.go | 11 +++++--- cmd/prefixes.go | 7 ++++- cmd/provision.go | 4 +-- cmd/purge.go | 11 +++++++- cmd/rebuild.go | 6 +++-- cmd/reserve.go | 6 +++-- cmd/server.go | 27 ++++++++++++------- cmd/shell.go | 6 ++--- cmd/snapshot.go | 7 ++++- cmd/ssh.go | 9 +++++-- cmd/status.go | 8 +++++- cmd/system_pause.go | 11 ++++++-- cmd/system_update.go | 25 ++++++++++------- cmd/update_prefix_config.go | 8 +++--- go.mod | 4 +-- go.sum | 8 +++--- internal/cli/meta.go | 2 +- internal/dis/component/auth/permission.go | 2 +- internal/dis/component/auth/session.go | 7 +---- internal/dis/component/sql/backup.go | 2 +- internal/dis/component/sql/provision.go | 8 +++--- internal/models/instances.go | 2 +- internal/phpx/types.go | 6 ++--- .../wisski/ingredient/php/extras/prefixes.go | 3 ++- .../wisski/ingredient/php/users/password.go | 4 +-- internal/wisski/ingredient/php/users/users.go | 4 +-- 40 files changed, 249 insertions(+), 110 deletions(-) diff --git a/cmd/blind_update.go b/cmd/blind_update.go index 752d0fe..cd755c5 100644 --- a/cmd/blind_update.go +++ b/cmd/blind_update.go @@ -34,11 +34,13 @@ func (blindUpdate) Description() wisski_distillery.Description { } var errBlindUpdateFailed = exit.Error{ - Message: "failed to run blind update script for instance %q: exited with code %s", + Message: "failed to run blind update", ExitCode: exit.ExitGeneric, } -func (bu blindUpdate) Run(context wisski_distillery.Context) error { +func (bu blindUpdate) Run(context wisski_distillery.Context) (err error) { + defer errBlindUpdateFailed.DeferWrap(&err) + // find all the instances! wissKIs, err := context.Environment.Instances().Load(context.Context, bu.Positionals.Slug...) if err != nil { diff --git a/cmd/bootstrap.go b/cmd/bootstrap.go index 6d509d9..b5333c1 100644 --- a/cmd/bootstrap.go +++ b/cmd/bootstrap.go @@ -34,7 +34,7 @@ func (cBootstrap) Description() wisski_distillery.Description { } var errBootstrapDifferent = exit.Error{ - Message: "refusing to bootstrap: base directory is already set to %s.", + Message: "refusing to bootstrap: base directory is already set to %s", ExitCode: exit.ExitGeneric, } @@ -54,17 +54,17 @@ var errBoostrapFailedToCopyExe = exit.Error{ } var errBootstrapWriteConfig = exit.Error{ - Message: "failed to write configuration file: %s", + Message: "failed to write configuration file", ExitCode: exit.ExitGeneric, } var errBootstrapOpenConfig = exit.Error{ - Message: "failed to open configuration file: %s", + Message: "failed to open configuration file", ExitCode: exit.ExitGeneric, } var errBootstrapCreateFile = exit.Error{ - Message: "failed to touch configuration file: %s", + Message: "failed to touch configuration file", ExitCode: exit.ExitGeneric, } @@ -82,10 +82,10 @@ func (bs cBootstrap) Run(context wisski_distillery.Context) error { { logging.LogMessage(context.Stderr, context.Context, "Creating root deployment directory") if err := fsx.MkdirAll(root, fsx.DefaultDirPerm); err != nil { - return errBootstrapFailedToCreateDirectory.WithMessageF(root) + return errBootstrapFailedToCreateDirectory.WithMessageF(root).Wrap(err) } if err := cli.WriteBaseDirectory(root); err != nil { - return errBootstrapFailedToSaveDirectory.WithMessageF(root) + return errBootstrapFailedToSaveDirectory.WithMessageF(root).Wrap(err) } context.Println(root) } @@ -101,7 +101,7 @@ func (bs cBootstrap) Run(context wisski_distillery.Context) error { // and use thge defaults if err := tpl.SetDefaults(); err != nil { - return errBootstrapWriteConfig.WithMessageF(err) + return errBootstrapWriteConfig.Wrap(err) } { @@ -145,7 +145,7 @@ func (bs cBootstrap) Run(context wisski_distillery.Context) error { return nil }, context.Stderr, context.Context, "Creating custom config files"); err != nil { - return errBootstrapCreateFile.WithMessageF(err) + return errBootstrapCreateFile.Wrap(err) } // Validate configuration file! @@ -171,7 +171,7 @@ func (bs cBootstrap) Run(context wisski_distillery.Context) error { return err } }, context.Stderr, context.Context, "Installing primary configuration file"); err != nil { - return errBootstrapWriteConfig.WithMessageF(err) + return errBootstrapWriteConfig.Wrap(err) } } @@ -181,13 +181,13 @@ func (bs cBootstrap) Run(context wisski_distillery.Context) error { logging.LogMessage(context.Stderr, context.Context, "Configuration is now complete") f, err := os.Open(cfgPath) if err != nil { - return errBootstrapOpenConfig.WithMessageF(err) + return errBootstrapOpenConfig.Wrap(err) } defer f.Close() var cfg config.Config if err := cfg.Unmarshal(f); err != nil { - return errBootstrapOpenConfig.WithMessageF(err) + return errBootstrapOpenConfig.Wrap(err) } context.Println(cfg) diff --git a/cmd/config.go b/cmd/config.go index 726a359..1094643 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -3,6 +3,7 @@ package cmd import ( wisski_distillery "github.com/FAU-CDI/wisski-distillery" "github.com/FAU-CDI/wisski-distillery/internal/cli" + "github.com/tkw1536/goprogram/exit" ) // Config is the configuration command @@ -20,6 +21,14 @@ func (c cfg) Description() wisski_distillery.Description { } } -func (cfg) Run(context wisski_distillery.Context) error { - return context.Environment.Config.Marshal(context.Stdout) +var errMarshalConfig = exit.Error{ + Message: "unable to marshal config", + ExitCode: exit.ExitGeneric, +} + +func (cfg) Run(context wisski_distillery.Context) error { + if err := context.Environment.Config.Marshal(context.Stdout); err != nil { + return errMarshalConfig.Wrap(err) + } + return nil } diff --git a/cmd/cron.go b/cmd/cron.go index de70881..6a18650 100644 --- a/cmd/cron.go +++ b/cmd/cron.go @@ -7,6 +7,7 @@ import ( wisski_distillery "github.com/FAU-CDI/wisski-distillery" "github.com/FAU-CDI/wisski-distillery/internal/cli" "github.com/FAU-CDI/wisski-distillery/internal/wisski" + "github.com/tkw1536/goprogram/exit" "github.com/tkw1536/goprogram/status" ) @@ -31,7 +32,14 @@ func (cron) Description() wisski_distillery.Description { } } -func (cr cron) Run(context wisski_distillery.Context) error { +var errCronFailed = exit.Error{ + Message: "failed to run cron", + ExitCode: exit.ExitGeneric, +} + +func (cr cron) Run(context wisski_distillery.Context) (err error) { + defer errCronFailed.DeferWrap(&err) + // find all the instances! wissKIs, err := context.Environment.Instances().Load(context.Context, cr.Positionals.Slug...) if err != nil { diff --git a/cmd/dis_grant.go b/cmd/dis_grant.go index c2159cf..f4a66d9 100644 --- a/cmd/dis_grant.go +++ b/cmd/dis_grant.go @@ -63,7 +63,14 @@ func (dg disGrant) AfterParse() error { return nil } -func (dg disGrant) Run(context wisski_distillery.Context) error { +var errFailedGrant = exit.Error{ + Message: "unable to manage grants", + ExitCode: exit.ExitGeneric, +} + +func (dg disGrant) Run(context wisski_distillery.Context) (err error) { + defer errFailedGrant.DeferWrap(&err) + switch { case dg.AddUser: return dg.runAddUser(context) diff --git a/cmd/dis_ssh.go b/cmd/dis_ssh.go index b0ff60e..84f1bc9 100644 --- a/cmd/dis_ssh.go +++ b/cmd/dis_ssh.go @@ -21,7 +21,7 @@ type disSSH struct { Positionals struct { User string `positional-arg-name:"USER" required:"1-1" description:"distillery username"` - Path string `positional-arg-name:"PATH" required:"1-1" description:"Path of key to add"` + Path string `positional-arg-name:"PATH" required:"1-1" description:"path of key to add"` } `positional-args:"true"` } @@ -53,6 +53,11 @@ func (ds disSSH) AfterParse() error { return nil } +var errSSHManageFailed = exit.Error{ + Message: "unable to manage ssh keys", + ExitCode: exit.ExitCommandArguments, +} + func (ds disSSH) Run(context wisski_distillery.Context) error { switch { case ds.Add: @@ -71,12 +76,12 @@ var errNoKey = exit.Error{ func (ds disSSH) parseOpts(context wisski_distillery.Context) (user *auth.AuthUser, key gossh.PublicKey, err error) { user, err = context.Environment.Auth().User(context.Context, ds.Positionals.User) if err != nil { - return nil, nil, err + return nil, nil, errSSHManageFailed.Wrap(err) } content, err := os.ReadFile(ds.Positionals.Path) if err != nil { - return nil, nil, err + return nil, nil, errSSHManageFailed.Wrap(err) } pk, _, _, _, err := gossh.ParseAuthorizedKey(content) @@ -93,7 +98,10 @@ func (ds disSSH) runAdd(context wisski_distillery.Context) error { return err } - return context.Environment.Keys().Add(context.Context, user.User.User, ds.Comment, key) + if err := context.Environment.Keys().Add(context.Context, user.User.User, ds.Comment, key); err != nil { + return errSSHManageFailed.Wrap(err) + } + return nil } func (ds disSSH) runRemove(context wisski_distillery.Context) error { @@ -102,5 +110,8 @@ func (ds disSSH) runRemove(context wisski_distillery.Context) error { return err } - return context.Environment.Keys().Remove(context.Context, user.User.User, key) + if err := context.Environment.Keys().Remove(context.Context, user.User.User, key); err != nil { + return errSSHManageFailed.Wrap(err) + } + return nil } diff --git a/cmd/dis_user.go b/cmd/dis_user.go index d1927d6..ab886c3 100644 --- a/cmd/dis_user.go +++ b/cmd/dis_user.go @@ -28,7 +28,7 @@ type disUser struct { DisableTOTP bool `short:"v" long:"disable-totp" description:"disable totp for a user"` Positionals struct { - User string `positional-arg-name:"USER" description:"username to manage. May be omitted for some actions"` + User string `positional-arg-name:"USER" description:"username to manage. may be omitted for some actions"` } `positional-args:"true"` } @@ -78,7 +78,14 @@ func (du disUser) AfterParse() error { return nil } -func (du disUser) Run(context wisski_distillery.Context) error { +var errDisUserActionFailed = exit.Error{ + Message: "action failed", + ExitCode: exit.ExitGeneric, +} + +func (du disUser) Run(context wisski_distillery.Context) (err error) { + defer errDisUserActionFailed.DeferWrap(&err) + switch { case du.InfoUser: return du.runInfo(context) diff --git a/cmd/drupal_setting.go b/cmd/drupal_setting.go index b924237..9b8709f 100644 --- a/cmd/drupal_setting.go +++ b/cmd/drupal_setting.go @@ -39,10 +39,15 @@ var errSettingSet = exit.Error{ Message: "unable to set setting", } +var errSettingWissKI = exit.Error{ + Message: "unable to get WissKI", + ExitCode: exit.ExitGeneric, +} + func (ds setting) Run(context wisski_distillery.Context) error { instance, err := context.Environment.Instances().WissKI(context.Context, ds.Positionals.Slug) if err != nil { - return err + return errSettingWissKI.Wrap(err) } if ds.Positionals.Value == "" { diff --git a/cmd/drupal_user.go b/cmd/drupal_user.go index f54dc67..a039d00 100644 --- a/cmd/drupal_user.go +++ b/cmd/drupal_user.go @@ -74,7 +74,14 @@ var errPasswordsNotIdentical = exit.Error{ ExitCode: exit.ExitGeneric, } -func (du drupalUser) Run(context wisski_distillery.Context) error { +var errDrupalUserActionFailed = exit.Error{ + Message: "action failed", + ExitCode: exit.ExitGeneric, +} + +func (du drupalUser) Run(context wisski_distillery.Context) (err error) { + defer errDrupalUserActionFailed.DeferWrap(&err) + instance, err := context.Environment.Instances().WissKI(context.Context, du.Positionals.Slug) if err != nil { return err @@ -102,11 +109,6 @@ func (du drupalUser) login(context wisski_distillery.Context, instance *wisski.W return nil } -var errPasswordFound = exit.Error{ - Message: "user had a dictionary password", - ExitCode: 5, -} - func (du drupalUser) checkCommonPassword(context wisski_distillery.Context, instance *wisski.WissKI) error { users := instance.Users() diff --git a/cmd/info.go b/cmd/info.go index 9ab6769..cacbd8f 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -5,6 +5,7 @@ import ( wisski_distillery "github.com/FAU-CDI/wisski-distillery" "github.com/FAU-CDI/wisski-distillery/internal/cli" + "github.com/tkw1536/goprogram/exit" "github.com/tkw1536/pkglib/collection" ) @@ -28,7 +29,14 @@ func (info) Description() wisski_distillery.Description { } } -func (i info) Run(context wisski_distillery.Context) error { +var errInfoFailed = exit.Error{ + Message: "failed to get info", + ExitCode: exit.ExitGeneric, +} + +func (i info) Run(context wisski_distillery.Context) (err error) { + defer errInfoFailed.DeferWrap(&err) + instance, err := context.Environment.Instances().WissKI(context.Context, i.Positionals.Slug) if err != nil { return err diff --git a/cmd/instance_lock.go b/cmd/instance_lock.go index 55bca66..1ecf1e8 100644 --- a/cmd/instance_lock.go +++ b/cmd/instance_lock.go @@ -45,10 +45,15 @@ var errNotUnlock = exit.Error{ ExitCode: exit.ExitCommandArguments, } +var errInstanceLockWissKI = exit.Error{ + Message: "unable to get WissKI", + ExitCode: exit.ExitGeneric, +} + func (l instanceLock) Run(context wisski_distillery.Context) error { instance, err := context.Environment.Instances().WissKI(context.Context, l.Positionals.Slug) if err != nil { - return err + return errInstanceLockWissKI.Wrap(err) } if l.Unlock { diff --git a/cmd/instance_pause.go b/cmd/instance_pause.go index 28a9e01..8db826e 100644 --- a/cmd/instance_pause.go +++ b/cmd/instance_pause.go @@ -3,6 +3,7 @@ package cmd import ( wisski_distillery "github.com/FAU-CDI/wisski-distillery" "github.com/FAU-CDI/wisski-distillery/internal/cli" + "github.com/tkw1536/goprogram/exit" ) // InstancePause is the 'instance_pause' command @@ -33,10 +34,15 @@ func (i instancepause) AfterParse() error { return nil } +var errInstancePauseWissKI = exit.Error{ + Message: "unable to get WissKI", + ExitCode: exit.ExitGeneric, +} + func (i instancepause) Run(context wisski_distillery.Context) error { instance, err := context.Environment.Instances().WissKI(context.Context, i.Positionals.Slug) if err != nil { - return err + return errInstancePauseWissKI.Wrap(err) } if i.Stop { diff --git a/cmd/ls.go b/cmd/ls.go index 50e29c0..bf40e30 100644 --- a/cmd/ls.go +++ b/cmd/ls.go @@ -3,6 +3,7 @@ package cmd import ( wisski_distillery "github.com/FAU-CDI/wisski-distillery" "github.com/FAU-CDI/wisski-distillery/internal/cli" + "github.com/tkw1536/goprogram/exit" ) // Ls is the 'ls' command @@ -24,10 +25,15 @@ func (ls) Description() wisski_distillery.Description { } } +var errLsWissKI = exit.Error{ + Message: "unable to get WissKIs", + ExitCode: exit.ExitGeneric, +} + func (l ls) Run(context wisski_distillery.Context) error { instances, err := context.Environment.Instances().Load(context.Context, l.Positionals.Slug...) if err != nil { - return err + return errLsWissKI.Wrap(err) } for _, instance := range instances { diff --git a/cmd/make_mysql_account.go b/cmd/make_mysql_account.go index 7fa9678..f2bf7d3 100644 --- a/cmd/make_mysql_account.go +++ b/cmd/make_mysql_account.go @@ -27,12 +27,17 @@ func (makeMysqlAccount) Description() wisski_distillery.Description { var errUnableToReadUsername = exit.Error{ ExitCode: exit.ExitGeneric, - Message: "unable to read username: %s", + Message: "unable to read username", } var errUnableToReadPassword = exit.Error{ ExitCode: exit.ExitGeneric, - Message: "unable to read password: %s", + Message: "unable to read password", +} + +var errUnableToMakeAccount = exit.Error{ + ExitCode: exit.ExitGeneric, + Message: "unable to create account", } func (mma makeMysqlAccount) Run(context wisski_distillery.Context) error { @@ -41,17 +46,17 @@ func (mma makeMysqlAccount) Run(context wisski_distillery.Context) error { context.Printf("Username>") username, err := context.ReadLine() if err != nil { - return errUnableToReadUsername.WithMessageF(err) + return errUnableToReadUsername.Wrap(err) } context.Printf("Password>") password, err := context.ReadPassword() if err != nil { - return errUnableToReadPassword.WithMessageF(err) + return errUnableToReadPassword.Wrap(err) } if err := dis.SQL().CreateSuperuser(context.Context, username, password, false); err != nil { - return err + return errUnableToMakeAccount.Wrap(err) } return nil diff --git a/cmd/pathbuilders.go b/cmd/pathbuilders.go index 9fc4dec..bffe794 100644 --- a/cmd/pathbuilders.go +++ b/cmd/pathbuilders.go @@ -27,7 +27,7 @@ func (pathbuilders) Description() wisski_distillery.Description { } var errPathbuilders = exit.Error{ - Message: "unable to export pathbuilder: %s", + Message: "unable to export pathbuilder", ExitCode: exit.ExitGeneric, } @@ -36,19 +36,24 @@ var errNoPathbuilder = exit.Error{ ExitCode: exit.ExitGeneric, } +var errPathbuilderWissKI = exit.Error{ + Message: "unable to find WissKI", + ExitCode: exit.ExitGeneric, +} + func (pb pathbuilders) Run(context wisski_distillery.Context) error { // get the wisski instance, err := context.Environment.Instances().WissKI(context.Context, pb.Positionals.Slug) if err != nil { - return err + return errPathbuilderWissKI.Wrap(err) } // get all of the pathbuilders if pb.Positionals.Name == "" { names, err := instance.Pathbuilder().All(context.Context, nil) if err != nil { - return errPathbuilders.WithMessageF(err) + return errPathbuilders.Wrap(err) } for _, name := range names { context.Println(name) diff --git a/cmd/prefixes.go b/cmd/prefixes.go index 2bfc150..a34ea3d 100644 --- a/cmd/prefixes.go +++ b/cmd/prefixes.go @@ -30,10 +30,15 @@ var errPrefixesGeneric = exit.Error{ Message: "unable to load prefixes", } +var errPrefixesWissKI = exit.Error{ + Message: "unable to find WissKI", + ExitCode: exit.ExitGeneric, +} + func (p prefixes) Run(context wisski_distillery.Context) error { instance, err := context.Environment.Instances().WissKI(context.Context, p.Positionals.Slug) if err != nil { - return err + return errPrefixesWissKI.Wrap(err) } prefixes, err := instance.Prefixes().All(context.Context, nil) diff --git a/cmd/provision.go b/cmd/provision.go index 2f6515c..cb39d00 100644 --- a/cmd/provision.go +++ b/cmd/provision.go @@ -28,7 +28,7 @@ func (pv) Description() wisski_distillery.Description { } var errProvisionGeneric = exit.Error{ - Message: "unable to provision instance %s: %s", + Message: "unable to provision instance %s", ExitCode: exit.ExitGeneric, } @@ -39,7 +39,7 @@ func (p pv) Run(context wisski_distillery.Context) error { Slug: p.Positionals.Slug, }) if err != nil { - return errProvisionGeneric.WithMessageF(p.Positionals.Slug, err) + return errProvisionGeneric.WithMessageF(p.Positionals.Slug).Wrap(err) } // and we're done! diff --git a/cmd/purge.go b/cmd/purge.go index f575381..4b9dd8d 100644 --- a/cmd/purge.go +++ b/cmd/purge.go @@ -31,6 +31,11 @@ var errPurgeNoConfirmation = exit.Error{ ExitCode: exit.ExitGeneric, } +var errPurgeFailed = exit.Error{ + Message: "failed to run purge", + ExitCode: exit.ExitGeneric, +} + func (p purge) Run(context wisski_distillery.Context) error { dis := context.Environment slug := p.Positionals.Slug @@ -45,5 +50,9 @@ func (p purge) Run(context wisski_distillery.Context) error { } } - return dis.Purger().Purge(context.Context, context.Stdout, slug) + // do the purge! + if err := dis.Purger().Purge(context.Context, context.Stdout, slug); err != nil { + return errPurgeFailed.Wrap(err) + } + return nil } diff --git a/cmd/rebuild.go b/cmd/rebuild.go index 58a1e8e..8e05127 100644 --- a/cmd/rebuild.go +++ b/cmd/rebuild.go @@ -32,11 +32,13 @@ func (rebuild) Description() wisski_distillery.Description { } var errRebuildFailed = exit.Error{ - Message: "failed to run rebuild script for instance %q: exited with code %s", + Message: "failed to run rebuild", ExitCode: exit.ExitGeneric, } -func (rb rebuild) Run(context wisski_distillery.Context) error { +func (rb rebuild) Run(context wisski_distillery.Context) (err error) { + defer errRebuildFailed.DeferWrap(&err) + dis := context.Environment // find the instances diff --git a/cmd/reserve.go b/cmd/reserve.go index f9aca0f..303f405 100644 --- a/cmd/reserve.go +++ b/cmd/reserve.go @@ -36,11 +36,13 @@ var errReserveAlreadyExists = exit.Error{ } var errReserveGeneric = exit.Error{ - Message: "unable to provision instance %s: %s", + Message: "unable to provision instance", ExitCode: exit.ExitGeneric, } -func (r reserve) Run(context wisski_distillery.Context) error { +func (r reserve) Run(context wisski_distillery.Context) (err error) { + defer errReserveGeneric.DeferWrap(&err) + dis := context.Environment slug := r.Positionals.Slug diff --git a/cmd/server.go b/cmd/server.go index 436d4f4..67b6841 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -8,6 +8,7 @@ import ( "github.com/FAU-CDI/wisski-distillery/internal/cli" "github.com/rs/zerolog" "github.com/tkw1536/goprogram/exit" + "github.com/tkw1536/pkglib/errorx" ) // Server is the 'server' command @@ -34,12 +35,24 @@ var errServerListen = exit.Error{ Message: "unable to listen", } +var errServerTrigger = exit.Error{ + Message: "failed to trigger", + ExitCode: exit.ExitGeneric, +} + +var errServerGeneric = exit.Error{ + ExitCode: exit.ExitGeneric, + Message: "unable to instantiate server", +} + func (s server) Run(context wisski_distillery.Context) error { dis := context.Environment // if the caller requested a trigger, just trigger the cron tasks if s.Trigger { - return dis.Control().Trigger(context.Context) + if err := dis.Control().Trigger(context.Context); err != nil { + return errServerTrigger.Wrap(err) + } } { @@ -57,7 +70,7 @@ func (s server) Run(context wisski_distillery.Context) error { // and start the server public, internal, err := dis.Control().Server(context.Context, context.Stderr) if err != nil { - return err + return errServerGeneric.Wrap(err) } // start the public listener @@ -92,17 +105,11 @@ func (s server) Run(context wisski_distillery.Context) error { go func() { <-context.Context.Done() + zerolog.Ctx(context.Context).Info().Msg("shutting down server") publicS.Shutdown(context.Context) internalS.Shutdown(context.Context) }() - if err2 := <-internalC; err2 != nil { - err = err2 - } - if err1 := <-publicC; err1 != nil { - err = err1 - } - - return errServerListen.Wrap(err) + return errServerListen.Wrap(errorx.First(<-internalC, <-publicC, err)) } diff --git a/cmd/shell.go b/cmd/shell.go index d1a01c9..f1b54c5 100644 --- a/cmd/shell.go +++ b/cmd/shell.go @@ -32,15 +32,15 @@ func (shell) Description() wisski_distillery.Description { } } -var errShell = exit.Error{ - Message: "unable to start shell: %s", +var errShellWissKI = exit.Error{ + Message: "unable to find WissKI", ExitCode: exit.ExitGeneric, } func (sh shell) Run(context wisski_distillery.Context) error { instance, err := context.Environment.Instances().WissKI(context.Context, sh.Positionals.Slug) if err != nil { - return err + return errShellWissKI.Wrap(err) } code := instance.Barrel().Shell(context.Context, context.IOStream, sh.Positionals.Args...)() diff --git a/cmd/snapshot.go b/cmd/snapshot.go index 0e3b864..0300f53 100644 --- a/cmd/snapshot.go +++ b/cmd/snapshot.go @@ -35,13 +35,18 @@ var errSnapshotFailed = exit.Error{ ExitCode: exit.ExitGeneric, } +var errSnapshotWissKI = exit.Error{ + Message: "unable to find WissKI", + ExitCode: exit.ExitGeneric, +} + func (sn snapshot) Run(context wisski_distillery.Context) error { dis := context.Environment // find the instance! instance, err := dis.Instances().WissKI(context.Context, sn.Positionals.Slug) if err != nil { - return err + return errSnapshotWissKI.Wrap(err) } // do a snapshot of it! diff --git a/cmd/ssh.go b/cmd/ssh.go index 168323e..abf037a 100644 --- a/cmd/ssh.go +++ b/cmd/ssh.go @@ -26,6 +26,11 @@ func (s ssh) Description() wisski_distillery.Description { } } +var errSSHServer = exit.Error{ + ExitCode: exit.ExitGeneric, + Message: "unable to listen server", +} + var errSSHListen = exit.Error{ ExitCode: exit.ExitGeneric, Message: "unable to listen", @@ -35,7 +40,7 @@ func (s ssh) Run(context wisski_distillery.Context) error { dis := context.Environment server, err := dis.SSH().Server(context.Context, s.PrivateKeyPath, context.Stderr) if err != nil { - return err + return errSSHServer.Wrap(err) } context.Printf("Listening on %s\n", s.Bind) @@ -43,7 +48,7 @@ func (s ssh) Run(context wisski_distillery.Context) error { // make a new listener listener, err := net.Listen("tcp", s.Bind) if err != nil { - return errServerListen.Wrap(err) + return errSSHListen.Wrap(err) } go func() { diff --git a/cmd/status.go b/cmd/status.go index af94fcb..dd315e6 100644 --- a/cmd/status.go +++ b/cmd/status.go @@ -5,6 +5,7 @@ import ( wisski_distillery "github.com/FAU-CDI/wisski-distillery" "github.com/FAU-CDI/wisski-distillery/internal/cli" + "github.com/tkw1536/goprogram/exit" ) // Info is then 'info' command @@ -24,10 +25,15 @@ func (cStatus) Description() wisski_distillery.Description { } } +var errStatusGeneric = exit.Error{ + ExitCode: exit.ExitGeneric, + Message: "unable to get status", +} + func (s cStatus) Run(context wisski_distillery.Context) error { status, _, err := context.Environment.Info().Status(context.Context, true) if err != nil { - return err + return errStatusGeneric.Wrap(err) } if s.JSON { diff --git a/cmd/system_pause.go b/cmd/system_pause.go index e3a0286..0fd76e7 100644 --- a/cmd/system_pause.go +++ b/cmd/system_pause.go @@ -33,7 +33,7 @@ func (systempause) Description() wisski_distillery.Description { } var errStopStartExcluded = exit.Error{ - Message: "exactly one of `--stop` and `--start` must be provied", + Message: "exactly one of `--stop` and `--start` must be provided", ExitCode: exit.ExitCommandArguments, } @@ -44,7 +44,14 @@ func (s systempause) AfterParse() error { return nil } -func (sp systempause) Run(context wisski_distillery.Context) error { +var errPauseGeneric = exit.Error{ + ExitCode: exit.ExitGeneric, + Message: "unable to pause or resume system", +} + +func (sp systempause) Run(context wisski_distillery.Context) (err error) { + defer errPauseGeneric.DeferWrap(&err) + if sp.Start { return sp.start(context, context.Environment) } else { diff --git a/cmd/system_update.go b/cmd/system_update.go index 0d6fcc6..774b733 100644 --- a/cmd/system_update.go +++ b/cmd/system_update.go @@ -53,26 +53,33 @@ func (s systemupdate) AfterParse() error { } var errBoostrapFailedToCreateDirectory = exit.Error{ - Message: "failed to create directory %s: %s", + Message: "failed to create directory %s", ExitCode: exit.ExitGeneric, } var errBootstrapComponent = exit.Error{ - Message: "unable to bootstrap %s: %s", + Message: "unable to bootstrap %s", ExitCode: exit.ExitGeneric, } var errDockerUnreachable = exit.Error{ - Message: "unable to reach docker api: %s", + Message: "unable to reach docker api", ExitCode: exit.ExitGeneric, } var errNetworkCreateFailed = exit.Error{ - Message: "unable to create docker network: %s", + Message: "unable to create docker network", ExitCode: exit.ExitGeneric, } -func (si systemupdate) Run(context wisski_distillery.Context) error { +var errSystemUpdateGeneric = exit.Error{ + Message: "generic system update error", + ExitCode: exit.ExitGeneric, +} + +func (si systemupdate) Run(context wisski_distillery.Context) (err error) { + defer errSystemUpdateGeneric.DeferWrap(&err) + dis := context.Environment // create all the other directories @@ -86,7 +93,7 @@ func (si systemupdate) Run(context wisski_distillery.Context) error { } { context.Println(d) if err := fsx.MkdirAll(d, fsx.DefaultDirPerm); err != nil { - return errBoostrapFailedToCreateDirectory.WithMessageF(d, err) + return errBoostrapFailedToCreateDirectory.WithMessageF(d).Wrap(err) } } @@ -116,7 +123,7 @@ func (si systemupdate) Run(context wisski_distillery.Context) error { logging.LogMessage(context.Stderr, context.Context, "Checking that the 'docker' api is reachable") ping, err := dis.Docker().Ping(context.Context) if err != nil { - return errDockerUnreachable.WithMessageF(err) + return errDockerUnreachable.Wrap(err) } context.Printf("API Version: %s (experimental: %t)\nBuilder Version: %s\n", ping.APIVersion, ping.Experimental, ping.BuilderVersion) } @@ -134,7 +141,7 @@ func (si systemupdate) Run(context wisski_distillery.Context) error { name := dis.Config.Docker.Network id, existed, err := dis.Docker().CreateNetwork(context.Context, name) if err != nil { - return errNetworkCreateFailed.WithMessageF(err) + return errNetworkCreateFailed.Wrap(err) } if existed { context.Printf("Network %s (id %s) already existed\n", name, id) @@ -198,7 +205,7 @@ func (si systemupdate) Run(context wisski_distillery.Context) error { } return item.Update(context.Context, context.Stderr) }, context.Stderr, context.Context, "Updating Component: %s", name); err != nil { - return errBootstrapComponent.WithMessageF(name, err) + return errBootstrapComponent.WithMessageF(name).Wrap(err) } } return nil diff --git a/cmd/update_prefix_config.go b/cmd/update_prefix_config.go index f7a571b..de5ae4d 100644 --- a/cmd/update_prefix_config.go +++ b/cmd/update_prefix_config.go @@ -35,19 +35,21 @@ var errPrefixUpdateFailed = exit.Error{ ExitCode: exit.ExitGeneric, } -func (upc updateprefixconfig) Run(context wisski_distillery.Context) error { +func (upc updateprefixconfig) Run(context wisski_distillery.Context) (err error) { + defer errPrefixUpdateFailed.DeferWrap(&err) + dis := context.Environment wissKIs, err := dis.Instances().All(context.Context) if err != nil { - return errPrefixUpdateFailed.Wrap(err) + return err } return status.WriterGroup(context.Stderr, upc.Parallel, func(instance *wisski.WissKI, writer io.Writer) error { logging.Progress(writer, context.Context, "reading prefixes") err := instance.Prefixes().Update(context.Context) if err != nil { - return errPrefixUpdateFailed.Wrap(err) + return err } return nil }, wissKIs, status.SmartMessage(func(item *wisski.WissKI) string { diff --git a/go.mod b/go.mod index 4857e7d..f7c0cba 100644 --- a/go.mod +++ b/go.mod @@ -15,8 +15,8 @@ require ( github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.4.0 github.com/rs/zerolog v1.29.0 - github.com/tkw1536/goprogram v0.3.0 - github.com/tkw1536/pkglib v0.0.0-20230308113336-6db7d9cd2d5a + github.com/tkw1536/goprogram v0.3.2 + github.com/tkw1536/pkglib v0.0.0-20230309100913-ec9fed77413a github.com/yuin/goldmark v1.5.4 github.com/yuin/goldmark-meta v1.1.0 golang.org/x/crypto v0.3.0 diff --git a/go.sum b/go.sum index 6fe6c06..eaa2c77 100644 --- a/go.sum +++ b/go.sum @@ -114,10 +114,10 @@ github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38= github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ= github.com/tdewolff/test v1.0.7 h1:8Vs0142DmPFW/bQeHRP3MV19m1gvndjUb1sn8yy74LM= -github.com/tkw1536/goprogram v0.3.0 h1:bMnr+PMZHRaaw3atIHz2I0/vCdwl2Bx8KaNutTD7psg= -github.com/tkw1536/goprogram v0.3.0/go.mod h1:lIWTpzLCbji7b9mSU+iPrQYTJOa0DgOE5is8UyW9/n0= -github.com/tkw1536/pkglib v0.0.0-20230308113336-6db7d9cd2d5a h1:IS5BHeyfagcrOuvPpubc65v/KmZbGhVk8oJ6hze/0nM= -github.com/tkw1536/pkglib v0.0.0-20230308113336-6db7d9cd2d5a/go.mod h1:R+8tKMAkSXC1+XGzxNUKx2DnPJqObycYeo4PKjWYkMg= +github.com/tkw1536/goprogram v0.3.2 h1:qEGPVD/x9nmGrCZLqCAJ67coz4UECbtnNXXHVMR+NOs= +github.com/tkw1536/goprogram v0.3.2/go.mod h1:/R+2nAG7l1nP3ty4axPwycksDg4eU4uBrZp0dsGq4Dw= +github.com/tkw1536/pkglib v0.0.0-20230309100913-ec9fed77413a h1:j6Z6uDiEyY8a0M+W3QJ0rv7KXoPqBjJ4yRS51RF3d44= +github.com/tkw1536/pkglib v0.0.0-20230309100913-ec9fed77413a/go.mod h1:R+8tKMAkSXC1+XGzxNUKx2DnPJqObycYeo4PKjWYkMg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= diff --git a/internal/cli/meta.go b/internal/cli/meta.go index b2effb5..dd5fbcf 100644 --- a/internal/cli/meta.go +++ b/internal/cli/meta.go @@ -28,7 +28,7 @@ func MetaConfigPath() (string, error) { return filepath.Join(usr.HomeDir, metaConfigFile), nil } -var errReadBaseDirectoryEmpty = errors.New("ReadBaseDirectory: Directory is empty") +var errReadBaseDirectoryEmpty = errors.New("`ReadBaseDirectory': directory is empty") // ReadBaseDirectory reads the base deployment directory from the environment. // Use [ParamsFromEnv] to initialize parameters completely. diff --git a/internal/dis/component/auth/permission.go b/internal/dis/component/auth/permission.go index d3ed9a7..31c504e 100644 --- a/internal/dis/component/auth/permission.go +++ b/internal/dis/component/auth/permission.go @@ -66,7 +66,7 @@ func AllPermissions(clauses ...Permission) Permission { } } -var errPermissionPanic = errors.New("permission: panic()") +var errPermissionPanic = errors.New("permission: `panic()'") // Permit checks if the given user has this permission. func (perm Permission) Permit(user *AuthUser, r *http.Request) (ok Grant, err error) { diff --git a/internal/dis/component/auth/session.go b/internal/dis/component/auth/session.go index 3c56308..8191e86 100644 --- a/internal/dis/component/auth/session.go +++ b/internal/dis/component/auth/session.go @@ -128,12 +128,7 @@ var loginTemplate = templating.ParseForm( templating.Assets(assets.AssetsUser), ) -var loginResponse = httpx.Response{ - ContentType: "text/plain", - Body: []byte("user is signed in"), -} - -var errLoginFailed = errors.New("Login failed") +var errLoginFailed = errors.New("login failed") // authLogin implements a view to login a user func (auth *Auth) authLogin(ctx context.Context) http.Handler { diff --git a/internal/dis/component/sql/backup.go b/internal/dis/component/sql/backup.go index c865c79..40b6678 100644 --- a/internal/dis/component/sql/backup.go +++ b/internal/dis/component/sql/backup.go @@ -9,7 +9,7 @@ import ( "github.com/tkw1536/goprogram/stream" ) -var errSQLBackup = errors.New("SQLBackup: Mysqldump returned non-zero exit code") +var errSQLBackup = errors.New("`SQLBackup': mysqldump returned non-zero exit code") func (*SQL) BackupName() string { return "sql.sql" diff --git a/internal/dis/component/sql/provision.go b/internal/dis/component/sql/provision.go index a20bd1b..88a1747 100644 --- a/internal/dis/component/sql/provision.go +++ b/internal/dis/component/sql/provision.go @@ -9,8 +9,8 @@ import ( "github.com/tkw1536/pkglib/sqlx" ) -var errProvisionInvalidDatabaseParams = errors.New("Provision: Invalid parameters") -var errProvisionInvalidGrant = errors.New("Provision: Grant failed") +var errProvisionInvalidDatabaseParams = errors.New("`Provision': invalid parameters") +var errProvisionInvalidGrant = errors.New("`Provision': grant failed") // Provision provisions sql-specific resource for the given instance func (sql *SQL) Provision(ctx context.Context, instance models.Instance, domain string) error { @@ -58,7 +58,7 @@ func (sql *SQL) CreateDatabase(ctx context.Context, name, user, password string) return nil } -var errCreateSuperuserGrant = errors.New("CreateSuperUser: Grant failed") +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. @@ -93,7 +93,7 @@ func (sql *SQL) CreateSuperuser(ctx context.Context, user, password string, allo return nil } -var errPurgeUser = errors.New("PurgeUser: Failed to drop user") +var errPurgeUser = errors.New("`PurgeUser': failed to drop user") // SQLPurgeUser deletes the specified user from the database func (sql *SQL) PurgeUser(ctx context.Context, user string) error { diff --git a/internal/models/instances.go b/internal/models/instances.go index 3b88908..fd0ce34 100644 --- a/internal/models/instances.go +++ b/internal/models/instances.go @@ -60,7 +60,7 @@ func (sb SQLBit1) Value() (driver.Value, error) { } } -var errBadBool = errors.New("SQLBit1: Database does not contain Bit(1)") +var errBadBool = errors.New("`SQLBit1': database does not contain `Bit(1)'") func (sb *SQLBit1) Scan(src interface{}) error { if bytes, ok := src.([]byte); ok && len(bytes) == 1 { diff --git a/internal/phpx/types.go b/internal/phpx/types.go index ac4b1cc..e5f8bc3 100644 --- a/internal/phpx/types.go +++ b/internal/phpx/types.go @@ -46,7 +46,7 @@ func (b Boolean) MarshalJSON() ([]byte, error) { return []byte("false"), nil } -var errNotABoolean = errors.New("Boolean.UnmarshalJSON: Not an integer") +var errNotABoolean = errors.New("`Boolean': not an integer") func (b *Boolean) UnmarshalJSON(data []byte) (err error) { return UnmarshalIntermediate(b, func(a any) (Boolean, error) { @@ -100,7 +100,7 @@ func (s String) MarshalJSON() ([]byte, error) { return json.Marshal(string(s)) } -var errNotAString = errors.New("String.UnmarshalJSON: Not a string") +var errNotAString = errors.New("`String': not a string") func (s *String) UnmarshalJSON(data []byte) (err error) { return UnmarshalIntermediate(s, func(a any) (String, error) { @@ -148,7 +148,7 @@ func (i Integer) MarshalJSON() ([]byte, error) { return json.Marshal(int64(i)) } -var errNotAnInteger = errors.New("Integer.UnmarshalJSON: Not an integer") +var errNotAnInteger = errors.New("`Integer': not an integer") func (i *Integer) UnmarshalJSON(data []byte) (err error) { return UnmarshalIntermediate(i, func(a any) (Integer, error) { diff --git a/internal/wisski/ingredient/php/extras/prefixes.go b/internal/wisski/ingredient/php/extras/prefixes.go index bf81e78..8bb451c 100644 --- a/internal/wisski/ingredient/php/extras/prefixes.go +++ b/internal/wisski/ingredient/php/extras/prefixes.go @@ -14,6 +14,7 @@ import ( "github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient/php" "github.com/FAU-CDI/wisski-distillery/pkg/fsx" "github.com/tkw1536/pkglib/collection" + "golang.org/x/exp/slices" _ "embed" ) @@ -110,7 +111,7 @@ func (prefixes *Prefixes) blocked() ([]string, error) { } func hasAnyPrefix(candidate string, prefixes []string) bool { - return collection.Any( + return slices.ContainsFunc( prefixes, func(prefix string) bool { return strings.HasPrefix(candidate, prefix) diff --git a/internal/wisski/ingredient/php/users/password.go b/internal/wisski/ingredient/php/users/password.go index 7c7e95e..633886d 100644 --- a/internal/wisski/ingredient/php/users/password.go +++ b/internal/wisski/ingredient/php/users/password.go @@ -11,7 +11,7 @@ import ( "github.com/tkw1536/pkglib/password" ) -var errGetValidator = errors.New("GetPasswordValidator: Unknown Error") +var errGetValidator = errors.New("`GetPasswordValidator': unknown error") func (u *Users) GetPasswordValidator(ctx context.Context, username string) (pv PasswordValidator, err error) { server := u.Dependencies.PHP.NewServer() @@ -53,7 +53,7 @@ func (pv PasswordValidator) Check(ctx context.Context, password string) bool { return bool(result) } -var errPasswordUsername = errors.New("username === password") +var errPasswordUsername = errors.New("username equals password") func (pv PasswordValidator) CheckDictionary(ctx context.Context, writer io.Writer) error { var counter int diff --git a/internal/wisski/ingredient/php/users/users.go b/internal/wisski/ingredient/php/users/users.go index e68b13b..4af2bdf 100644 --- a/internal/wisski/ingredient/php/users/users.go +++ b/internal/wisski/ingredient/php/users/users.go @@ -32,7 +32,7 @@ func (u *Users) All(ctx context.Context, server *phpx.Server) (users []status.Dr return } -var errLoginUnknownError = errors.New("Login: Unknown Error") +var errLoginUnknownError = errors.New("`Login': unknown error") // Login generates a login link for the user with the given username func (u *Users) Login(ctx context.Context, server *phpx.Server, username string) (dest *url.URL, err error) { @@ -75,7 +75,7 @@ func (u *Users) LoginWithOpt(ctx context.Context, server *phpx.Server, username return } -var errSetPassword = errors.New("SetPassword: Unknown Error") +var errSetPassword = errors.New("`SetPassword': unknown error") // SetPassword sets the password for a given user func (u *Users) SetPassword(ctx context.Context, server *phpx.Server, username, password string) error {