[#152] authmate: Add basic error types and exit codes #204
8 changed files with 94 additions and 24 deletions
|
@ -17,6 +17,7 @@ This document outlines major changes between releases.
|
|||
- Use correct keys in `list-multipart-uploads` response (#185)
|
||||
|
||||
### Added
|
||||
- Add basic error types and exit codes to `frostfs-s3-authmate` (#152)
|
||||
- Add a metric with addresses of nodes of the same and highest priority that are currently healthy (#51)
|
||||
- Support dump metrics descriptions (#80)
|
||||
- Add `copies_numbers` section to `placement_policy` in config file and support vectors of copies numbers (#70, #101)
|
||||
|
|
|
@ -15,6 +15,6 @@ func main() {
|
|||
if cmd, err := modules.Execute(ctx); err != nil {
|
||||
cmd.PrintErrln("Error:", err.Error())
|
||||
cmd.PrintErrf("Run '%v --help' for usage.\n", cmd.CommandPath())
|
||||
os.Exit(1)
|
||||
os.Exit(modules.ExitCode(err))
|
||||
}
|
||||
}
|
||||
|
|
53
cmd/s3-authmate/modules/errors.go
Normal file
53
cmd/s3-authmate/modules/errors.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
package modules
|
||||
|
||||
type (
|
||||
preparationError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
frostFSInitError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
businessLogicError struct {
|
||||
err error
|
||||
}
|
||||
)
|
||||
|
||||
func wrapPreparationError(e error) error {
|
||||
return preparationError{e}
|
||||
}
|
||||
|
||||
func (e preparationError) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
func wrapFrostFSInitError(e error) error {
|
||||
return frostFSInitError{e}
|
||||
}
|
||||
|
||||
func (e frostFSInitError) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
func wrapBusinessLogicError(e error) error {
|
||||
return businessLogicError{e}
|
||||
}
|
||||
|
||||
func (e businessLogicError) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
// ExitCode picks corresponding error code depending on the type of error provided.
|
||||
// Returns 1 if error type is unknown.
|
||||
func ExitCode(e error) int {
|
||||
switch e.(type) {
|
||||
case preparationError:
|
||||
return 2
|
||||
case frostFSInitError:
|
||||
return 3
|
||||
case businessLogicError:
|
||||
return 4
|
||||
}
|
||||
return 1
|
||||
}
|
|
@ -76,7 +76,7 @@ func runGeneratePresignedURLCmd(*cobra.Command, []string) error {
|
|||
SharedConfigState: session.SharedConfigEnable,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't get aws credentials: %w", err)
|
||||
return wrapPreparationError(fmt.Errorf("couldn't get aws credentials: %w", err))
|
||||
}
|
||||
|
||||
reqData := auth.RequestData{
|
||||
|
@ -94,7 +94,7 @@ func runGeneratePresignedURLCmd(*cobra.Command, []string) error {
|
|||
|
||||
req, err := auth.PresignRequest(sess.Config.Credentials, reqData, presignData)
|
||||
if err != nil {
|
||||
return err
|
||||
return wrapBusinessLogicError(err)
|
||||
}
|
||||
|
||||
res := &struct{ URL string }{
|
||||
|
@ -104,5 +104,9 @@ func runGeneratePresignedURLCmd(*cobra.Command, []string) error {
|
|||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
enc.SetEscapeHTML(false)
|
||||
return enc.Encode(res)
|
||||
err = enc.Encode(res)
|
||||
if err != nil {
|
||||
return wrapBusinessLogicError(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -92,14 +92,14 @@ func runIssueSecretCmd(cmd *cobra.Command, _ []string) error {
|
|||
password := wallet.GetPassword(viper.GetViper(), walletPassphraseCfg)
|
||||
key, err := wallet.GetKeyFromPath(viper.GetString(walletFlag), viper.GetString(addressFlag), password)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load frostfs private key: %s", err)
|
||||
return wrapPreparationError(fmt.Errorf("failed to load frostfs private key: %s", err))
|
||||
}
|
||||
|
||||
var cnrID cid.ID
|
||||
containerID := viper.GetString(containerIDFlag)
|
||||
if len(containerID) > 0 {
|
||||
if err = cnrID.DecodeString(containerID); err != nil {
|
||||
return fmt.Errorf("failed to parse auth container id: %s", err)
|
||||
return wrapPreparationError(fmt.Errorf("failed to parse auth container id: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,35 +107,35 @@ func runIssueSecretCmd(cmd *cobra.Command, _ []string) error {
|
|||
for _, keyStr := range viper.GetStringSlice(gatePublicKeyFlag) {
|
||||
gpk, err := keys.NewPublicKeyFromString(keyStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load gate's public key: %s", err)
|
||||
return wrapPreparationError(fmt.Errorf("failed to load gate's public key: %s", err))
|
||||
}
|
||||
gatesPublicKeys = append(gatesPublicKeys, gpk)
|
||||
}
|
||||
|
||||
lifetime := viper.GetDuration(lifetimeFlag)
|
||||
if lifetime <= 0 {
|
||||
return fmt.Errorf("lifetime must be greater 0, current value: %d", lifetime)
|
||||
return wrapPreparationError(fmt.Errorf("lifetime must be greater 0, current value: %d", lifetime))
|
||||
}
|
||||
|
||||
policies, err := parsePolicies(viper.GetString(containerPolicyFlag))
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't parse container policy: %s", err.Error())
|
||||
return wrapPreparationError(fmt.Errorf("couldn't parse container policy: %s", err.Error()))
|
||||
}
|
||||
|
||||
disableImpersonate := viper.GetBool(disableImpersonateFlag)
|
||||
eaclRules := viper.GetString(bearerRulesFlag)
|
||||
if !disableImpersonate && eaclRules != "" {
|
||||
return errors.New("--bearer-rules flag can be used only with --disable-impersonate")
|
||||
return wrapPreparationError(errors.New("--bearer-rules flag can be used only with --disable-impersonate"))
|
||||
}
|
||||
|
||||
bearerRules, err := getJSONRules(eaclRules)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't parse 'bearer-rules' flag: %s", err.Error())
|
||||
return wrapPreparationError(fmt.Errorf("couldn't parse 'bearer-rules' flag: %s", err.Error()))
|
||||
}
|
||||
|
||||
sessionRules, skipSessionRules, err := getSessionRules(viper.GetString(sessionTokensFlag))
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't parse 'session-tokens' flag: %s", err.Error())
|
||||
return wrapPreparationError(fmt.Errorf("couldn't parse 'session-tokens' flag: %s", err.Error()))
|
||||
}
|
||||
|
||||
poolCfg := PoolConfig{
|
||||
|
@ -149,7 +149,7 @@ func runIssueSecretCmd(cmd *cobra.Command, _ []string) error {
|
|||
|
||||
frostFS, err := createFrostFS(ctx, log, poolCfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create FrostFS component: %s", err)
|
||||
return wrapFrostFSInitError(fmt.Errorf("failed to create FrostFS component: %s", err))
|
||||
}
|
||||
|
||||
issueSecretOptions := &authmate.IssueSecretOptions{
|
||||
|
@ -170,7 +170,7 @@ func runIssueSecretCmd(cmd *cobra.Command, _ []string) error {
|
|||
}
|
||||
|
||||
if err = authmate.New(log, frostFS).IssueSecret(ctx, os.Stdout, issueSecretOptions); err != nil {
|
||||
return fmt.Errorf("failed to issue secret: %s", err)
|
||||
return wrapBusinessLogicError(fmt.Errorf("failed to issue secret: %s", err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -58,13 +58,13 @@ func runObtainSecretCmd(cmd *cobra.Command, _ []string) error {
|
|||
password := wallet.GetPassword(viper.GetViper(), walletPassphraseCfg)
|
||||
key, err := wallet.GetKeyFromPath(viper.GetString(walletFlag), viper.GetString(addressFlag), password)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load frostfs private key: %s", err)
|
||||
return wrapPreparationError(fmt.Errorf("failed to load frostfs private key: %s", err))
|
||||
}
|
||||
|
||||
gatePassword := wallet.GetPassword(viper.GetViper(), walletGatePassphraseCfg)
|
||||
gateKey, err := wallet.GetKeyFromPath(viper.GetString(gateWalletFlag), viper.GetString(gateAddressFlag), gatePassword)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load s3 gate private key: %s", err)
|
||||
return wrapPreparationError(fmt.Errorf("failed to load s3 gate private key: %s", err))
|
||||
}
|
||||
|
||||
poolCfg := PoolConfig{
|
||||
|
@ -78,7 +78,7 @@ func runObtainSecretCmd(cmd *cobra.Command, _ []string) error {
|
|||
|
||||
frostFS, err := createFrostFS(ctx, log, poolCfg)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to create FrostFS component: %s", err), 2)
|
||||
return wrapFrostFSInitError(cli.Exit(fmt.Sprintf("failed to create FrostFS component: %s", err), 2))
|
||||
}
|
||||
|
||||
obtainSecretOptions := &authmate.ObtainSecretOptions{
|
||||
|
@ -87,7 +87,7 @@ func runObtainSecretCmd(cmd *cobra.Command, _ []string) error {
|
|||
}
|
||||
|
||||
if err = authmate.New(log, frostFS).ObtainSecret(ctx, os.Stdout, obtainSecretOptions); err != nil {
|
||||
return fmt.Errorf("failed to obtain secret: %s", err)
|
||||
return wrapBusinessLogicError(fmt.Errorf("failed to obtain secret: %s", err))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -56,26 +56,26 @@ func runUpdateSecretCmd(cmd *cobra.Command, _ []string) error {
|
|||
password := wallet.GetPassword(viper.GetViper(), walletPassphraseCfg)
|
||||
key, err := wallet.GetKeyFromPath(viper.GetString(walletFlag), viper.GetString(addressFlag), password)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load frostfs private key: %s", err)
|
||||
return wrapPreparationError(fmt.Errorf("failed to load frostfs private key: %s", err))
|
||||
}
|
||||
|
||||
gatePassword := wallet.GetPassword(viper.GetViper(), walletGatePassphraseCfg)
|
||||
gateKey, err := wallet.GetKeyFromPath(viper.GetString(gateWalletFlag), viper.GetString(gateAddressFlag), gatePassword)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load s3 gate private key: %s", err)
|
||||
return wrapPreparationError(fmt.Errorf("failed to load s3 gate private key: %s", err))
|
||||
}
|
||||
|
||||
var accessBoxAddress oid.Address
|
||||
credAddr := strings.Replace(viper.GetString(accessKeyIDFlag), "0", "/", 1)
|
||||
if err = accessBoxAddress.DecodeString(credAddr); err != nil {
|
||||
return fmt.Errorf("failed to parse creds address: %w", err)
|
||||
return wrapPreparationError(fmt.Errorf("failed to parse creds address: %w", err))
|
||||
}
|
||||
|
||||
var gatesPublicKeys []*keys.PublicKey
|
||||
for _, keyStr := range viper.GetStringSlice(gatePublicKeyFlag) {
|
||||
gpk, err := keys.NewPublicKeyFromString(keyStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load gate's public key: %s", err)
|
||||
return wrapPreparationError(fmt.Errorf("failed to load gate's public key: %s", err))
|
||||
}
|
||||
gatesPublicKeys = append(gatesPublicKeys, gpk)
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ func runUpdateSecretCmd(cmd *cobra.Command, _ []string) error {
|
|||
|
||||
frostFS, err := createFrostFS(ctx, log, poolCfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create FrostFS component: %s", err)
|
||||
return wrapFrostFSInitError(fmt.Errorf("failed to create FrostFS component: %s", err))
|
||||
}
|
||||
|
||||
updateSecretOptions := &authmate.UpdateSecretOptions{
|
||||
|
@ -102,7 +102,7 @@ func runUpdateSecretCmd(cmd *cobra.Command, _ []string) error {
|
|||
}
|
||||
|
||||
if err = authmate.New(log, frostFS).UpdateSecret(ctx, os.Stdout, updateSecretOptions); err != nil {
|
||||
return fmt.Errorf("failed to update secret: %s", err)
|
||||
return wrapBusinessLogicError(fmt.Errorf("failed to update secret: %s", err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ potentially).
|
|||
3. [Obtainment of a secret](#obtaining-credential-secrets)
|
||||
4. [Generate presigned url](#generate-presigned-url)
|
||||
5. [Update secrets](#update-secret)
|
||||
6. [Exit codes](#exit-codes)
|
||||
|
||||
## Generation of wallet
|
||||
|
||||
|
@ -371,3 +372,14 @@ Enter password for s3-wallet.json >
|
|||
"container_id": "HwrdXgetdGcEWAQwi68r1PMvw4iSm1Y5Z1fsFNSD6sQP"
|
||||
}
|
||||
```
|
||||
|
||||
## Exit codes
|
||||
|
||||
There are several non-zero exit codes added at the moment.
|
||||
|
||||
| Code | Description |
|
||||
|-------|--------------------------------------------------------------------------------------------|
|
||||
| 1 | Any unknown errors, or errors generated by the parser of command line parameters. |
|
||||
| 2 | Preparation errors: malformed configuration, issues with input data parsing. |
|
||||
| 3 | FrostFS errors: connectivity problems, misconfiguration. |
|
||||
| 4 | Business logic errors: `authmate` could not execute its task because of some restrictions. |
|
||||
|
|
Loading…
Reference in a new issue