[#152] authmate: Add basic error types and exit codes
All checks were successful
/ DCO (pull_request) Successful in 1m9s
/ Vulncheck (pull_request) Successful in 5m17s
/ Builds (1.20) (pull_request) Successful in 2m1s
/ Builds (1.21) (pull_request) Successful in 7m18s
/ Lint (pull_request) Successful in 15m19s
/ Tests (1.20) (pull_request) Successful in 1m14s
/ Tests (1.21) (pull_request) Successful in 11m45s
All checks were successful
/ DCO (pull_request) Successful in 1m9s
/ Vulncheck (pull_request) Successful in 5m17s
/ Builds (1.20) (pull_request) Successful in 2m1s
/ Builds (1.21) (pull_request) Successful in 7m18s
/ Lint (pull_request) Successful in 15m19s
/ Tests (1.20) (pull_request) Successful in 1m14s
/ Tests (1.21) (pull_request) Successful in 11m45s
Signed-off-by: Artem Tataurov <a.tataurov@yadro.com>
This commit is contained in:
parent
69227b4845
commit
54e1c333a1
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)
|
- Use correct keys in `list-multipart-uploads` response (#185)
|
||||||
|
|
||||||
### Added
|
### 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)
|
- Add a metric with addresses of nodes of the same and highest priority that are currently healthy (#51)
|
||||||
- Support dump metrics descriptions (#80)
|
- Support dump metrics descriptions (#80)
|
||||||
- Add `copies_numbers` section to `placement_policy` in config file and support vectors of copies numbers (#70, #101)
|
- 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 {
|
if cmd, err := modules.Execute(ctx); err != nil {
|
||||||
cmd.PrintErrln("Error:", err.Error())
|
cmd.PrintErrln("Error:", err.Error())
|
||||||
cmd.PrintErrf("Run '%v --help' for usage.\n", cmd.CommandPath())
|
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,
|
SharedConfigState: session.SharedConfigEnable,
|
||||||
})
|
})
|
||||||
if err != nil {
|
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{
|
reqData := auth.RequestData{
|
||||||
|
@ -94,7 +94,7 @@ func runGeneratePresignedURLCmd(*cobra.Command, []string) error {
|
||||||
|
|
||||||
req, err := auth.PresignRequest(sess.Config.Credentials, reqData, presignData)
|
req, err := auth.PresignRequest(sess.Config.Credentials, reqData, presignData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return wrapBusinessLogicError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res := &struct{ URL string }{
|
res := &struct{ URL string }{
|
||||||
|
@ -104,5 +104,9 @@ func runGeneratePresignedURLCmd(*cobra.Command, []string) error {
|
||||||
enc := json.NewEncoder(os.Stdout)
|
enc := json.NewEncoder(os.Stdout)
|
||||||
enc.SetIndent("", " ")
|
enc.SetIndent("", " ")
|
||||||
enc.SetEscapeHTML(false)
|
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)
|
password := wallet.GetPassword(viper.GetViper(), walletPassphraseCfg)
|
||||||
key, err := wallet.GetKeyFromPath(viper.GetString(walletFlag), viper.GetString(addressFlag), password)
|
key, err := wallet.GetKeyFromPath(viper.GetString(walletFlag), viper.GetString(addressFlag), password)
|
||||||
if err != nil {
|
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
|
var cnrID cid.ID
|
||||||
containerID := viper.GetString(containerIDFlag)
|
containerID := viper.GetString(containerIDFlag)
|
||||||
if len(containerID) > 0 {
|
if len(containerID) > 0 {
|
||||||
if err = cnrID.DecodeString(containerID); err != nil {
|
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) {
|
for _, keyStr := range viper.GetStringSlice(gatePublicKeyFlag) {
|
||||||
gpk, err := keys.NewPublicKeyFromString(keyStr)
|
gpk, err := keys.NewPublicKeyFromString(keyStr)
|
||||||
if err != nil {
|
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)
|
gatesPublicKeys = append(gatesPublicKeys, gpk)
|
||||||
}
|
}
|
||||||
|
|
||||||
lifetime := viper.GetDuration(lifetimeFlag)
|
lifetime := viper.GetDuration(lifetimeFlag)
|
||||||
if lifetime <= 0 {
|
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))
|
policies, err := parsePolicies(viper.GetString(containerPolicyFlag))
|
||||||
if err != nil {
|
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)
|
disableImpersonate := viper.GetBool(disableImpersonateFlag)
|
||||||
eaclRules := viper.GetString(bearerRulesFlag)
|
eaclRules := viper.GetString(bearerRulesFlag)
|
||||||
if !disableImpersonate && eaclRules != "" {
|
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)
|
bearerRules, err := getJSONRules(eaclRules)
|
||||||
if err != nil {
|
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))
|
sessionRules, skipSessionRules, err := getSessionRules(viper.GetString(sessionTokensFlag))
|
||||||
if err != nil {
|
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{
|
poolCfg := PoolConfig{
|
||||||
|
@ -149,7 +149,7 @@ func runIssueSecretCmd(cmd *cobra.Command, _ []string) error {
|
||||||
|
|
||||||
frostFS, err := createFrostFS(ctx, log, poolCfg)
|
frostFS, err := createFrostFS(ctx, log, poolCfg)
|
||||||
if err != nil {
|
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{
|
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 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,13 +58,13 @@ func runObtainSecretCmd(cmd *cobra.Command, _ []string) error {
|
||||||
password := wallet.GetPassword(viper.GetViper(), walletPassphraseCfg)
|
password := wallet.GetPassword(viper.GetViper(), walletPassphraseCfg)
|
||||||
key, err := wallet.GetKeyFromPath(viper.GetString(walletFlag), viper.GetString(addressFlag), password)
|
key, err := wallet.GetKeyFromPath(viper.GetString(walletFlag), viper.GetString(addressFlag), password)
|
||||||
if err != nil {
|
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)
|
gatePassword := wallet.GetPassword(viper.GetViper(), walletGatePassphraseCfg)
|
||||||
gateKey, err := wallet.GetKeyFromPath(viper.GetString(gateWalletFlag), viper.GetString(gateAddressFlag), gatePassword)
|
gateKey, err := wallet.GetKeyFromPath(viper.GetString(gateWalletFlag), viper.GetString(gateAddressFlag), gatePassword)
|
||||||
if err != nil {
|
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{
|
poolCfg := PoolConfig{
|
||||||
|
@ -78,7 +78,7 @@ func runObtainSecretCmd(cmd *cobra.Command, _ []string) error {
|
||||||
|
|
||||||
frostFS, err := createFrostFS(ctx, log, poolCfg)
|
frostFS, err := createFrostFS(ctx, log, poolCfg)
|
||||||
if err != nil {
|
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{
|
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 {
|
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
|
return nil
|
||||||
|
|
|
@ -56,26 +56,26 @@ func runUpdateSecretCmd(cmd *cobra.Command, _ []string) error {
|
||||||
password := wallet.GetPassword(viper.GetViper(), walletPassphraseCfg)
|
password := wallet.GetPassword(viper.GetViper(), walletPassphraseCfg)
|
||||||
key, err := wallet.GetKeyFromPath(viper.GetString(walletFlag), viper.GetString(addressFlag), password)
|
key, err := wallet.GetKeyFromPath(viper.GetString(walletFlag), viper.GetString(addressFlag), password)
|
||||||
if err != nil {
|
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)
|
gatePassword := wallet.GetPassword(viper.GetViper(), walletGatePassphraseCfg)
|
||||||
gateKey, err := wallet.GetKeyFromPath(viper.GetString(gateWalletFlag), viper.GetString(gateAddressFlag), gatePassword)
|
gateKey, err := wallet.GetKeyFromPath(viper.GetString(gateWalletFlag), viper.GetString(gateAddressFlag), gatePassword)
|
||||||
if err != nil {
|
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
|
var accessBoxAddress oid.Address
|
||||||
credAddr := strings.Replace(viper.GetString(accessKeyIDFlag), "0", "/", 1)
|
credAddr := strings.Replace(viper.GetString(accessKeyIDFlag), "0", "/", 1)
|
||||||
if err = accessBoxAddress.DecodeString(credAddr); err != nil {
|
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
|
var gatesPublicKeys []*keys.PublicKey
|
||||||
for _, keyStr := range viper.GetStringSlice(gatePublicKeyFlag) {
|
for _, keyStr := range viper.GetStringSlice(gatePublicKeyFlag) {
|
||||||
gpk, err := keys.NewPublicKeyFromString(keyStr)
|
gpk, err := keys.NewPublicKeyFromString(keyStr)
|
||||||
if err != nil {
|
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)
|
gatesPublicKeys = append(gatesPublicKeys, gpk)
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ func runUpdateSecretCmd(cmd *cobra.Command, _ []string) error {
|
||||||
|
|
||||||
frostFS, err := createFrostFS(ctx, log, poolCfg)
|
frostFS, err := createFrostFS(ctx, log, poolCfg)
|
||||||
if err != nil {
|
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{
|
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 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ potentially).
|
||||||
3. [Obtainment of a secret](#obtaining-credential-secrets)
|
3. [Obtainment of a secret](#obtaining-credential-secrets)
|
||||||
4. [Generate presigned url](#generate-presigned-url)
|
4. [Generate presigned url](#generate-presigned-url)
|
||||||
5. [Update secrets](#update-secret)
|
5. [Update secrets](#update-secret)
|
||||||
|
6. [Exit codes](#exit-codes)
|
||||||
|
|
||||||
## Generation of wallet
|
## Generation of wallet
|
||||||
|
|
||||||
|
@ -371,3 +372,14 @@ Enter password for s3-wallet.json >
|
||||||
"container_id": "HwrdXgetdGcEWAQwi68r1PMvw4iSm1Y5Z1fsFNSD6sQP"
|
"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