diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f4c13b0a4c..b7b593635d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ minor release, the component will be purged, so be prepared (see `Updating` sect - New `blobovnicza-to-peapod` tool providing blobovnicza-to-peapod data migration (#2453) - SN's version and capacity is announced via the attributes automatically but can be overwritten explicitly (#2455, #602) - `peapod` command for `neofs-lens` (#2507) +- New CLI exit code for awaiting timeout (#2380) ### Fixed - `neo-go` RPC connection loss handling (#1337) diff --git a/README.md b/README.md index 97588f6b4ea..b43d774cd3e 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ for all of its commands and options internally, but some specific concepts have additional documents describing them: * [Sessions](docs/cli-sessions.md) * [Extended headers](docs/cli-xheaders.md) + * [Exit codes](docs/cli-exit-codes.md) `neofs-adm` is a network setup and management utility usually used by the network administrators. Refer to [docs/cli-adm.md](docs/cli-adm.md) for mode diff --git a/cmd/neofs-cli/internal/common/exit.go b/cmd/neofs-cli/internal/common/exit.go index a7d25e1e203..be16f6e2131 100644 --- a/cmd/neofs-cli/internal/common/exit.go +++ b/cmd/neofs-cli/internal/common/exit.go @@ -9,10 +9,16 @@ import ( "github.com/spf13/cobra" ) -// ExitOnErr prints error and exits with a code that matches -// one of the common errors from sdk library. If no errors -// found, exits with 1 code. -// Does nothing if passed error in nil. +// ErrAwaitTimeout represents the expiration of a polling interval +// while awaiting a certain condition. +var ErrAwaitTimeout = errors.New("await timeout expired") + +// ExitOnErr prints error and exits with a code depending on the error type +// +// 0 if nil +// 1 if [sdkstatus.ErrServerInternal] or untyped +// 2 if [sdkstatus.ErrObjectAccessDenied] +// 3 if [ErrAwaitTimeout] func ExitOnErr(cmd *cobra.Command, errFmt string, err error) { if err == nil { return @@ -26,6 +32,7 @@ func ExitOnErr(cmd *cobra.Command, errFmt string, err error) { _ = iota internal aclDenied + awaitTimeout ) var code int @@ -37,6 +44,8 @@ func ExitOnErr(cmd *cobra.Command, errFmt string, err error) { case errors.As(err, &accessErr): code = aclDenied err = fmt.Errorf("%w: %s", err, accessErr.Reason()) + case errors.Is(err, ErrAwaitTimeout): + code = awaitTimeout default: code = internal } diff --git a/cmd/neofs-cli/modules/container/create.go b/cmd/neofs-cli/modules/container/create.go index faeb67c88fb..3ab11348e73 100644 --- a/cmd/neofs-cli/modules/container/create.go +++ b/cmd/neofs-cli/modules/container/create.go @@ -128,7 +128,7 @@ It will be stored in sidechain when inner ring will accepts it.`, for ; ; t.Reset(waitInterval) { select { case <-ctx.Done(): - common.ExitOnErr(cmd, "", errCreateTimeout) + common.ExitOnErr(cmd, "container creation: %s", common.ErrAwaitTimeout) case <-t.C: } diff --git a/cmd/neofs-cli/modules/container/delete.go b/cmd/neofs-cli/modules/container/delete.go index 5ac6bd0bf7f..1ceda31e35b 100644 --- a/cmd/neofs-cli/modules/container/delete.go +++ b/cmd/neofs-cli/modules/container/delete.go @@ -114,7 +114,7 @@ Only owner of the container has a permission to remove container.`, for ; ; t.Reset(waitInterval) { select { case <-ctx.Done(): - common.ExitOnErr(cmd, "", errDeleteTimeout) + common.ExitOnErr(cmd, "container deletion: %s", common.ErrAwaitTimeout) case <-t.C: } diff --git a/cmd/neofs-cli/modules/container/set_eacl.go b/cmd/neofs-cli/modules/container/set_eacl.go index d373b4a8ce6..dc5a913bce3 100644 --- a/cmd/neofs-cli/modules/container/set_eacl.go +++ b/cmd/neofs-cli/modules/container/set_eacl.go @@ -112,7 +112,7 @@ Container ID in EACL table will be substituted with ID from the CLI.`, for ; ; t.Reset(waitInterval) { select { case <-ctx.Done(): - common.ExitOnErr(cmd, "", errSetEACLTimeout) + common.ExitOnErr(cmd, "eACL setting: %s", common.ErrAwaitTimeout) case <-t.C: } diff --git a/cmd/neofs-cli/modules/container/util.go b/cmd/neofs-cli/modules/container/util.go index fcbb8d3849e..a6c3685246a 100644 --- a/cmd/neofs-cli/modules/container/util.go +++ b/cmd/neofs-cli/modules/container/util.go @@ -18,12 +18,6 @@ const ( awaitTimeout = time.Minute ) -var ( - errCreateTimeout = errors.New("container creation was requested, but timeout has happened while waiting for the outcome") - errDeleteTimeout = errors.New("container removal was requested, but timeout has happened while waiting for the outcome") - errSetEACLTimeout = errors.New("eACL modification was requested, but timeout has happened while waiting for the outcome") -) - func parseContainerID(cmd *cobra.Command) cid.ID { if containerID == "" { common.ExitOnErr(cmd, "", errors.New("container ID is not set")) diff --git a/docs/cli-exit-codes.md b/docs/cli-exit-codes.md new file mode 100644 index 00000000000..89ec5f05282 --- /dev/null +++ b/docs/cli-exit-codes.md @@ -0,0 +1,17 @@ + +# Command Line Interface (CLI) Return Codes + +The NeoFS CLI returns specific exit codes to indicate the outcome of command execution. + +## Exit Codes + +| Exit Code | Meaning | +|-----------|------------------------------------------------| +| 0 | Command executed successfully. | +| 1 | Internal error or an unspecified failure. | +| 2 | Object access denied or unauthorized. | +| 3 | Await timeout expired for a certain condition. | + + + +These exit codes allow you to understand the outcome of the executed command and handle it accordingly in your scripts or automation workflows.