From 8cda197ea0c5b01425b390beb9d5e21393d56dfa Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 9 Jun 2023 08:16:05 +0400 Subject: [PATCH 1/9] cli: Rephrase error message about timeout waiting for the async op Specify in the message that a timeout has occurred to distinguish a potential delay from a failure. Signed-off-by: Leonard Lyubich --- cmd/neofs-cli/modules/container/util.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/neofs-cli/modules/container/util.go b/cmd/neofs-cli/modules/container/util.go index 97d5bb5f3b..19a2015ea9 100644 --- a/cmd/neofs-cli/modules/container/util.go +++ b/cmd/neofs-cli/modules/container/util.go @@ -17,9 +17,9 @@ const ( ) var ( - errCreateTimeout = errors.New("timeout: container has not been persisted on sidechain") - errDeleteTimeout = errors.New("timeout: container has not been removed from sidechain") - errSetEACLTimeout = errors.New("timeout: EACL has not been persisted on sidechain") + 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 { From 06e98d55bc84eaa86d30163cd89d1551d5fbafcf Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Tue, 13 Jun 2023 16:03:59 +0400 Subject: [PATCH 2/9] cli: Accept context parameter in all client operations Previously, internal client ops provided background context to underlying API client. Since background context is infinite, this could cause execution hang. To prevent this, client ops should be based on external context. Make all context-based functions of `internal/client` package to accept `context.Context` parameter explicitly. Adopt all intermediate client functions declared in `modules` to accept context and pass it into client ops. Add `GetCommandContext` function which constructs `context.Context` with timeout specified in `--timeout` flag and use the function in all commands with this flag. Signed-off-by: Leonard Lyubich --- cmd/neofs-cli/internal/client/client.go | 80 +++++++++---------- cmd/neofs-cli/internal/client/sdk.go | 8 +- cmd/neofs-cli/internal/commonflags/flags.go | 20 +++++ cmd/neofs-cli/modules/accounting/balance.go | 7 +- cmd/neofs-cli/modules/container/create.go | 13 +-- cmd/neofs-cli/modules/container/delete.go | 13 +-- cmd/neofs-cli/modules/container/get.go | 12 ++- cmd/neofs-cli/modules/container/get_eacl.go | 7 +- cmd/neofs-cli/modules/container/list.go | 9 ++- .../modules/container/list_objects.go | 9 ++- cmd/neofs-cli/modules/container/nodes.go | 9 ++- cmd/neofs-cli/modules/container/set_eacl.go | 11 ++- cmd/neofs-cli/modules/control/drop_objects.go | 6 +- .../modules/control/evacuate_shard.go | 6 +- cmd/neofs-cli/modules/control/flush_cache.go | 6 +- cmd/neofs-cli/modules/control/healthcheck.go | 6 +- .../modules/control/set_netmap_status.go | 5 +- cmd/neofs-cli/modules/control/shards_dump.go | 6 +- cmd/neofs-cli/modules/control/shards_list.go | 5 +- .../modules/control/shards_restore.go | 6 +- .../modules/control/shards_set_mode.go | 6 +- .../modules/control/synchronize_tree.go | 5 +- cmd/neofs-cli/modules/control/util.go | 5 +- cmd/neofs-cli/modules/netmap/get_epoch.go | 7 +- cmd/neofs-cli/modules/netmap/netinfo.go | 7 +- cmd/neofs-cli/modules/netmap/nodeinfo.go | 7 +- cmd/neofs-cli/modules/netmap/snapshot.go | 7 +- cmd/neofs-cli/modules/object/delete.go | 7 +- cmd/neofs-cli/modules/object/get.go | 9 ++- cmd/neofs-cli/modules/object/hash.go | 9 ++- cmd/neofs-cli/modules/object/head.go | 7 +- cmd/neofs-cli/modules/object/lock.go | 7 +- cmd/neofs-cli/modules/object/put.go | 7 +- cmd/neofs-cli/modules/object/range.go | 7 +- cmd/neofs-cli/modules/object/search.go | 7 +- cmd/neofs-cli/modules/object/util.go | 37 ++++----- cmd/neofs-cli/modules/session/create.go | 12 +-- cmd/neofs-cli/modules/storagegroup/delete.go | 7 +- cmd/neofs-cli/modules/storagegroup/get.go | 7 +- cmd/neofs-cli/modules/storagegroup/list.go | 7 +- cmd/neofs-cli/modules/storagegroup/put.go | 17 ++-- cmd/neofs-cli/modules/tree/add.go | 5 +- cmd/neofs-cli/modules/tree/add_by_path.go | 4 +- cmd/neofs-cli/modules/tree/get_by_path.go | 4 +- cmd/neofs-cli/modules/tree/list.go | 5 +- 45 files changed, 299 insertions(+), 154 deletions(-) diff --git a/cmd/neofs-cli/internal/client/client.go b/cmd/neofs-cli/internal/client/client.go index 5daf72a710..ad48d300c0 100644 --- a/cmd/neofs-cli/internal/client/client.go +++ b/cmd/neofs-cli/internal/client/client.go @@ -37,8 +37,8 @@ func (x BalanceOfRes) Balance() accounting.Decimal { // BalanceOf requests the current balance of a NeoFS user. // // Returns any error which prevented the operation from completing correctly in error return. -func BalanceOf(prm BalanceOfPrm) (res BalanceOfRes, err error) { - res.cliRes, err = prm.cli.BalanceGet(context.Background(), prm.PrmBalanceGet) +func BalanceOf(ctx context.Context, prm BalanceOfPrm) (res BalanceOfRes, err error) { + res.cliRes, err = prm.cli.BalanceGet(ctx, prm.PrmBalanceGet) return } @@ -62,8 +62,8 @@ func (x ListContainersRes) IDList() []cid.ID { // ListContainers requests a list of NeoFS user's containers. // // Returns any error which prevented the operation from completing correctly in error return. -func ListContainers(prm ListContainersPrm) (res ListContainersRes, err error) { - res.cliRes, err = prm.cli.ContainerList(context.Background(), prm.PrmContainerList) +func ListContainers(ctx context.Context, prm ListContainersPrm) (res ListContainersRes, err error) { + res.cliRes, err = prm.cli.ContainerList(ctx, prm.PrmContainerList) return } @@ -92,8 +92,8 @@ func (x PutContainerRes) ID() cid.ID { // Success can be verified by reading by identifier. // // Returns any error which prevented the operation from completing correctly in error return. -func PutContainer(prm PutContainerPrm) (res PutContainerRes, err error) { - cliRes, err := prm.cli.ContainerPut(context.Background(), prm.PrmContainerPut) +func PutContainer(ctx context.Context, prm PutContainerPrm) (res PutContainerRes, err error) { + cliRes, err := prm.cli.ContainerPut(ctx, prm.PrmContainerPut) if err == nil { res.cnr = cliRes.ID() } @@ -125,20 +125,20 @@ func (x GetContainerRes) Container() containerSDK.Container { // GetContainer reads a container from NeoFS by ID. // // Returns any error which prevented the operation from completing correctly in error return. -func GetContainer(prm GetContainerPrm) (res GetContainerRes, err error) { - res.cliRes, err = prm.cli.ContainerGet(context.Background(), prm.cliPrm) +func GetContainer(ctx context.Context, prm GetContainerPrm) (res GetContainerRes, err error) { + res.cliRes, err = prm.cli.ContainerGet(ctx, prm.cliPrm) return } // IsACLExtendable checks if ACL of the container referenced by the given identifier // can be extended. Client connection MUST BE correctly established in advance. -func IsACLExtendable(c *client.Client, cnr cid.ID) (bool, error) { +func IsACLExtendable(ctx context.Context, c *client.Client, cnr cid.ID) (bool, error) { var prm GetContainerPrm prm.SetClient(c) prm.SetContainer(cnr) - res, err := GetContainer(prm) + res, err := GetContainer(ctx, prm) if err != nil { return false, fmt.Errorf("get container from the NeoFS: %w", err) } @@ -163,8 +163,8 @@ type DeleteContainerRes struct{} // Success can be verified by reading by identifier. // // Returns any error which prevented the operation from completing correctly in error return. -func DeleteContainer(prm DeleteContainerPrm) (res DeleteContainerRes, err error) { - _, err = prm.cli.ContainerDelete(context.Background(), prm.PrmContainerDelete) +func DeleteContainer(ctx context.Context, prm DeleteContainerPrm) (res DeleteContainerRes, err error) { + _, err = prm.cli.ContainerDelete(ctx, prm.PrmContainerDelete) return } @@ -188,8 +188,8 @@ func (x EACLRes) EACL() eacl.Table { // EACL reads eACL table from NeoFS by container ID. // // Returns any error which prevented the operation from completing correctly in error return. -func EACL(prm EACLPrm) (res EACLRes, err error) { - res.cliRes, err = prm.cli.ContainerEACL(context.Background(), prm.PrmContainerEACL) +func EACL(ctx context.Context, prm EACLPrm) (res EACLRes, err error) { + res.cliRes, err = prm.cli.ContainerEACL(ctx, prm.PrmContainerEACL) return } @@ -211,8 +211,8 @@ type SetEACLRes struct{} // Success can be verified by reading by container identifier. // // Returns any error which prevented the operation from completing correctly in error return. -func SetEACL(prm SetEACLPrm) (res SetEACLRes, err error) { - _, err = prm.cli.ContainerSetEACL(context.Background(), prm.PrmContainerSetEACL) +func SetEACL(ctx context.Context, prm SetEACLPrm) (res SetEACLRes, err error) { + _, err = prm.cli.ContainerSetEACL(ctx, prm.PrmContainerSetEACL) return } @@ -236,8 +236,8 @@ func (x NetworkInfoRes) NetworkInfo() netmap.NetworkInfo { // NetworkInfo reads information about the NeoFS network. // // Returns any error which prevented the operation from completing correctly in error return. -func NetworkInfo(prm NetworkInfoPrm) (res NetworkInfoRes, err error) { - res.cliRes, err = prm.cli.NetworkInfo(context.Background(), prm.PrmNetworkInfo) +func NetworkInfo(ctx context.Context, prm NetworkInfoPrm) (res NetworkInfoRes, err error) { + res.cliRes, err = prm.cli.NetworkInfo(ctx, prm.PrmNetworkInfo) return } @@ -266,8 +266,8 @@ func (x NodeInfoRes) LatestVersion() version.Version { // NodeInfo requests information about the remote server from NeoFS netmap. // // Returns any error which prevented the operation from completing correctly in error return. -func NodeInfo(prm NodeInfoPrm) (res NodeInfoRes, err error) { - res.cliRes, err = prm.cli.EndpointInfo(context.Background(), prm.PrmEndpointInfo) +func NodeInfo(ctx context.Context, prm NodeInfoPrm) (res NodeInfoRes, err error) { + res.cliRes, err = prm.cli.EndpointInfo(ctx, prm.PrmEndpointInfo) return } @@ -290,8 +290,8 @@ func (x NetMapSnapshotRes) NetMap() netmap.NetMap { // NetMapSnapshot requests current network view of the remote server. // // Returns any error which prevented the operation from completing correctly in error return. -func NetMapSnapshot(prm NetMapSnapshotPrm) (res NetMapSnapshotRes, err error) { - res.cliRes, err = prm.cli.NetMapSnapshot(context.Background(), client.PrmNetMapSnapshot{}) +func NetMapSnapshot(ctx context.Context, prm NetMapSnapshotPrm) (res NetMapSnapshotRes, err error) { + res.cliRes, err = prm.cli.NetMapSnapshot(ctx, client.PrmNetMapSnapshot{}) return } @@ -319,8 +319,8 @@ func (x CreateSessionRes) SessionKey() []byte { // CreateSession opens a new unlimited session with the remote node. // // Returns any error which prevented the operation from completing correctly in error return. -func CreateSession(prm CreateSessionPrm) (res CreateSessionRes, err error) { - res.cliRes, err = prm.cli.SessionCreate(context.Background(), prm.PrmSessionCreate) +func CreateSession(ctx context.Context, prm CreateSessionPrm) (res CreateSessionRes, err error) { + res.cliRes, err = prm.cli.SessionCreate(ctx, prm.PrmSessionCreate) return } @@ -365,7 +365,7 @@ func (x PutObjectRes) ID() oid.ID { // PutObject saves the object in NeoFS network. // // Returns any error which prevented the operation from completing correctly in error return. -func PutObject(prm PutObjectPrm) (*PutObjectRes, error) { +func PutObject(ctx context.Context, prm PutObjectPrm) (*PutObjectRes, error) { var putPrm client.PrmObjectPutInit if prm.sessionToken != nil { @@ -382,7 +382,7 @@ func PutObject(prm PutObjectPrm) (*PutObjectRes, error) { putPrm.WithXHeaders(prm.xHeaders...) - wrt, err := prm.cli.ObjectPutInit(context.Background(), putPrm) + wrt, err := prm.cli.ObjectPutInit(ctx, putPrm) if err != nil { return nil, fmt.Errorf("init object writing: %w", err) } @@ -462,7 +462,7 @@ func (x DeleteObjectRes) Tombstone() oid.ID { // DeleteObject marks an object to be removed from NeoFS through tombstone placement. // // Returns any error which prevented the operation from completing correctly in error return. -func DeleteObject(prm DeleteObjectPrm) (*DeleteObjectRes, error) { +func DeleteObject(ctx context.Context, prm DeleteObjectPrm) (*DeleteObjectRes, error) { var delPrm client.PrmObjectDelete delPrm.FromContainer(prm.objAddr.Container()) delPrm.ByID(prm.objAddr.Object()) @@ -477,7 +477,7 @@ func DeleteObject(prm DeleteObjectPrm) (*DeleteObjectRes, error) { delPrm.WithXHeaders(prm.xHeaders...) - cliRes, err := prm.cli.ObjectDelete(context.Background(), delPrm) + cliRes, err := prm.cli.ObjectDelete(ctx, delPrm) if err != nil { return nil, fmt.Errorf("remove object via client: %w", err) } @@ -518,7 +518,7 @@ func (x GetObjectRes) Header() *object.Object { // // Returns any error which prevented the operation from completing correctly in error return. // For raw reading, returns *object.SplitInfoError error if object is virtual. -func GetObject(prm GetObjectPrm) (*GetObjectRes, error) { +func GetObject(ctx context.Context, prm GetObjectPrm) (*GetObjectRes, error) { var getPrm client.PrmObjectGet getPrm.FromContainer(prm.objAddr.Container()) getPrm.ByID(prm.objAddr.Object()) @@ -541,7 +541,7 @@ func GetObject(prm GetObjectPrm) (*GetObjectRes, error) { getPrm.WithXHeaders(prm.xHeaders...) - rdr, err := prm.cli.ObjectGetInit(context.Background(), getPrm) + rdr, err := prm.cli.ObjectGetInit(ctx, getPrm) if err != nil { return nil, fmt.Errorf("init object reading on client: %w", err) } @@ -594,7 +594,7 @@ func (x HeadObjectRes) Header() *object.Object { // // Returns any error which prevented the operation from completing correctly in error return. // For raw reading, returns *object.SplitInfoError error if object is virtual. -func HeadObject(prm HeadObjectPrm) (*HeadObjectRes, error) { +func HeadObject(ctx context.Context, prm HeadObjectPrm) (*HeadObjectRes, error) { var cliPrm client.PrmObjectHead cliPrm.FromContainer(prm.objAddr.Container()) cliPrm.ByID(prm.objAddr.Object()) @@ -617,7 +617,7 @@ func HeadObject(prm HeadObjectPrm) (*HeadObjectRes, error) { cliPrm.WithXHeaders(prm.xHeaders...) - res, err := prm.cli.ObjectHead(context.Background(), cliPrm) + res, err := prm.cli.ObjectHead(ctx, cliPrm) if err != nil { return nil, fmt.Errorf("read object header via client: %w", err) } @@ -659,7 +659,7 @@ func (x SearchObjectsRes) IDList() []oid.ID { // SearchObjects selects objects from the container which match the filters. // // Returns any error which prevented the operation from completing correctly in error return. -func SearchObjects(prm SearchObjectsPrm) (*SearchObjectsRes, error) { +func SearchObjects(ctx context.Context, prm SearchObjectsPrm) (*SearchObjectsRes, error) { var cliPrm client.PrmObjectSearch cliPrm.InContainer(prm.cnrID) cliPrm.SetFilters(prm.filters) @@ -678,7 +678,7 @@ func SearchObjects(prm SearchObjectsPrm) (*SearchObjectsRes, error) { cliPrm.WithXHeaders(prm.xHeaders...) - rdr, err := prm.cli.ObjectSearchInit(context.Background(), cliPrm) + rdr, err := prm.cli.ObjectSearchInit(ctx, cliPrm) if err != nil { return nil, fmt.Errorf("init object search: %w", err) } @@ -749,7 +749,7 @@ func (x HashPayloadRangesRes) HashList() [][]byte { // // Returns any error which prevented the operation from completing correctly in error return. // Returns an error if number of received hashes differs with the number of requested ranges. -func HashPayloadRanges(prm HashPayloadRangesPrm) (*HashPayloadRangesRes, error) { +func HashPayloadRanges(ctx context.Context, prm HashPayloadRangesPrm) (*HashPayloadRangesRes, error) { var cliPrm client.PrmObjectHash cliPrm.FromContainer(prm.objAddr.Container()) cliPrm.ByID(prm.objAddr.Object()) @@ -783,7 +783,7 @@ func HashPayloadRanges(prm HashPayloadRangesPrm) (*HashPayloadRangesRes, error) cliPrm.WithXHeaders(prm.xHeaders...) - res, err := prm.cli.ObjectHash(context.Background(), cliPrm) + res, err := prm.cli.ObjectHash(ctx, cliPrm) if err != nil { return nil, fmt.Errorf("read payload hashes via client: %w", err) } @@ -817,7 +817,7 @@ type PayloadRangeRes struct{} // // Returns any error which prevented the operation from completing correctly in error return. // For raw reading, returns *object.SplitInfoError error if object is virtual. -func PayloadRange(prm PayloadRangePrm) (*PayloadRangeRes, error) { +func PayloadRange(ctx context.Context, prm PayloadRangePrm) (*PayloadRangeRes, error) { var cliPrm client.PrmObjectRange cliPrm.FromContainer(prm.objAddr.Container()) cliPrm.ByID(prm.objAddr.Object()) @@ -843,7 +843,7 @@ func PayloadRange(prm PayloadRangePrm) (*PayloadRangeRes, error) { cliPrm.WithXHeaders(prm.xHeaders...) - rdr, err := prm.cli.ObjectRangeInit(context.Background(), cliPrm) + rdr, err := prm.cli.ObjectRangeInit(ctx, cliPrm) if err != nil { return nil, fmt.Errorf("init payload reading: %w", err) } @@ -877,12 +877,12 @@ type SyncContainerRes struct{} // Interrupts on any writer error. // // Panics if a container passed as a parameter is nil. -func SyncContainerSettings(prm SyncContainerPrm) (*SyncContainerRes, error) { +func SyncContainerSettings(ctx context.Context, prm SyncContainerPrm) (*SyncContainerRes, error) { if prm.c == nil { panic("sync container settings with the network: nil container") } - err := client.SyncContainerWithNetwork(context.Background(), prm.c, prm.cli) + err := client.SyncContainerWithNetwork(ctx, prm.c, prm.cli) if err != nil { return nil, err } diff --git a/cmd/neofs-cli/internal/client/sdk.go b/cmd/neofs-cli/internal/client/sdk.go index a2399fd27a..5562949ee0 100644 --- a/cmd/neofs-cli/internal/client/sdk.go +++ b/cmd/neofs-cli/internal/client/sdk.go @@ -21,22 +21,22 @@ var errInvalidEndpoint = errors.New("provided RPC endpoint is incorrect") // GetSDKClientByFlag returns default neofs-sdk-go client using the specified flag for the address. // On error, outputs to stderr of cmd and exits with non-zero code. -func GetSDKClientByFlag(cmd *cobra.Command, key *ecdsa.PrivateKey, endpointFlag string) *client.Client { - cli, err := getSDKClientByFlag(cmd, key, endpointFlag) +func GetSDKClientByFlag(ctx context.Context, cmd *cobra.Command, key *ecdsa.PrivateKey, endpointFlag string) *client.Client { + cli, err := getSDKClientByFlag(ctx, cmd, key, endpointFlag) if err != nil { common.ExitOnErr(cmd, "can't create API client: %w", err) } return cli } -func getSDKClientByFlag(cmd *cobra.Command, key *ecdsa.PrivateKey, endpointFlag string) (*client.Client, error) { +func getSDKClientByFlag(ctx context.Context, cmd *cobra.Command, key *ecdsa.PrivateKey, endpointFlag string) (*client.Client, error) { var addr network.Address err := addr.FromString(viper.GetString(endpointFlag)) if err != nil { return nil, fmt.Errorf("%v: %w", errInvalidEndpoint, err) } - return GetSDKClient(context.TODO(), cmd, key, addr) + return GetSDKClient(ctx, cmd, key, addr) } // GetSDKClient returns default neofs-sdk-go client. diff --git a/cmd/neofs-cli/internal/commonflags/flags.go b/cmd/neofs-cli/internal/commonflags/flags.go index 7ed0e7d28e..932696cfb5 100644 --- a/cmd/neofs-cli/internal/commonflags/flags.go +++ b/cmd/neofs-cli/internal/commonflags/flags.go @@ -1,6 +1,7 @@ package commonflags import ( + "context" "time" "github.com/spf13/cobra" @@ -82,3 +83,22 @@ func Bind(cmd *cobra.Command) { _ = viper.BindPFlag(RPC, ff.Lookup(RPC)) _ = viper.BindPFlag(Timeout, ff.Lookup(Timeout)) } + +// GetCommandContext returns cmd context with timeout specified in 'timeout' flag +// if the flag is set. +func GetCommandContext(cmd *cobra.Command) (context.Context, context.CancelFunc) { + return getCommandContext(cmd, viper.GetDuration(Timeout)) +} + +func getCommandContext(cmd *cobra.Command, timeout time.Duration) (context.Context, context.CancelFunc) { + parentCtx := cmd.Context() + if parentCtx == nil { + parentCtx = context.Background() + } + + if timeout <= 0 { + return parentCtx, func() {} + } + + return context.WithTimeout(parentCtx, timeout) +} diff --git a/cmd/neofs-cli/modules/accounting/balance.go b/cmd/neofs-cli/modules/accounting/balance.go index ffccafc6a7..20bd6b0d61 100644 --- a/cmd/neofs-cli/modules/accounting/balance.go +++ b/cmd/neofs-cli/modules/accounting/balance.go @@ -1,6 +1,7 @@ package accounting import ( + "context" "math/big" "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" @@ -25,6 +26,8 @@ var accountingBalanceCmd = &cobra.Command{ Short: "Get internal balance of NeoFS account", Long: `Get internal balance of NeoFS account`, Run: func(cmd *cobra.Command, args []string) { + ctx := context.Background() + var idUser user.ID pk := key.GetOrGenerate(cmd) @@ -37,13 +40,13 @@ var accountingBalanceCmd = &cobra.Command{ common.ExitOnErr(cmd, "can't decode owner ID wallet address: %w", idUser.DecodeString(balanceOwner)) } - cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pk, commonflags.RPC) var prm internalclient.BalanceOfPrm prm.SetClient(cli) prm.SetAccount(idUser) - res, err := internalclient.BalanceOf(prm) + res, err := internalclient.BalanceOf(ctx, prm) common.ExitOnErr(cmd, "rpc error: %w", err) // print to stdout diff --git a/cmd/neofs-cli/modules/container/create.go b/cmd/neofs-cli/modules/container/create.go index feb17a2ff0..62a38ddb42 100644 --- a/cmd/neofs-cli/modules/container/create.go +++ b/cmd/neofs-cli/modules/container/create.go @@ -38,17 +38,20 @@ var createContainerCmd = &cobra.Command{ Long: `Create new container and register it in the NeoFS. It will be stored in sidechain when inner ring will accepts it.`, Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + placementPolicy, err := parseContainerPolicy(cmd, containerPolicy) common.ExitOnErr(cmd, "", err) key := key.Get(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, key, commonflags.RPC) if !force { var prm internalclient.NetMapSnapshotPrm prm.SetClient(cli) - resmap, err := internalclient.NetMapSnapshot(prm) + resmap, err := internalclient.NetMapSnapshot(ctx, prm) common.ExitOnErr(cmd, "unable to get netmap snapshot to validate container placement, "+ "use --force option to skip this check: %w", err) @@ -106,7 +109,7 @@ It will be stored in sidechain when inner ring will accepts it.`, syncContainerPrm.SetClient(cli) syncContainerPrm.SetContainer(&cnr) - _, err = internalclient.SyncContainerSettings(syncContainerPrm) + _, err = internalclient.SyncContainerSettings(ctx, syncContainerPrm) common.ExitOnErr(cmd, "syncing container's settings rpc error: %w", err) var putPrm internalclient.PutContainerPrm @@ -117,7 +120,7 @@ It will be stored in sidechain when inner ring will accepts it.`, putPrm.WithinSession(*tok) } - res, err := internalclient.PutContainer(putPrm) + res, err := internalclient.PutContainer(ctx, putPrm) common.ExitOnErr(cmd, "put container rpc error: %w", err) id := res.ID() @@ -134,7 +137,7 @@ It will be stored in sidechain when inner ring will accepts it.`, for i := 0; i < awaitTimeout; i++ { time.Sleep(1 * time.Second) - _, err := internalclient.GetContainer(getPrm) + _, err := internalclient.GetContainer(ctx, getPrm) if err == nil { cmd.Println("container has been persisted on sidechain") return diff --git a/cmd/neofs-cli/modules/container/delete.go b/cmd/neofs-cli/modules/container/delete.go index 4096ede503..925df66c84 100644 --- a/cmd/neofs-cli/modules/container/delete.go +++ b/cmd/neofs-cli/modules/container/delete.go @@ -20,12 +20,15 @@ var deleteContainerCmd = &cobra.Command{ Long: `Delete existing container. Only owner of the container has a permission to remove container.`, Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + id := parseContainerID(cmd) tok := getSession(cmd) pk := key.Get(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pk, commonflags.RPC) if force, _ := cmd.Flags().GetBool(commonflags.ForceFlag); !force { common.PrintVerbose(cmd, "Reading the container to check ownership...") @@ -34,7 +37,7 @@ Only owner of the container has a permission to remove container.`, getPrm.SetClient(cli) getPrm.SetContainer(id) - resGet, err := internalclient.GetContainer(getPrm) + resGet, err := internalclient.GetContainer(ctx, getPrm) common.ExitOnErr(cmd, "can't get the container: %w", err) owner := resGet.Container().Owner() @@ -73,7 +76,7 @@ Only owner of the container has a permission to remove container.`, common.PrintVerbose(cmd, "Searching for LOCK objects...") - res, err := internalclient.SearchObjects(searchPrm) + res, err := internalclient.SearchObjects(ctx, searchPrm) common.ExitOnErr(cmd, "can't search for LOCK objects: %w", err) if len(res.IDList()) != 0 { @@ -92,7 +95,7 @@ Only owner of the container has a permission to remove container.`, delPrm.WithinSession(*tok) } - _, err := internalclient.DeleteContainer(delPrm) + _, err := internalclient.DeleteContainer(ctx, delPrm) common.ExitOnErr(cmd, "rpc error: %w", err) cmd.Println("container delete method invoked") @@ -107,7 +110,7 @@ Only owner of the container has a permission to remove container.`, for i := 0; i < awaitTimeout; i++ { time.Sleep(1 * time.Second) - _, err := internalclient.GetContainer(getPrm) + _, err := internalclient.GetContainer(ctx, getPrm) if err != nil { cmd.Println("container has been removed:", containerID) return diff --git a/cmd/neofs-cli/modules/container/get.go b/cmd/neofs-cli/modules/container/get.go index 1085dc4145..9ea081844c 100644 --- a/cmd/neofs-cli/modules/container/get.go +++ b/cmd/neofs-cli/modules/container/get.go @@ -1,6 +1,7 @@ package container import ( + "context" "crypto/ecdsa" "os" @@ -32,7 +33,10 @@ var getContainerInfoCmd = &cobra.Command{ Short: "Get container field info", Long: `Get container field info`, Run: func(cmd *cobra.Command, args []string) { - cnr, _ := getContainer(cmd) + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + + cnr, _ := getContainer(ctx, cmd) prettyPrintContainer(cmd, cnr, containerJSON) @@ -132,7 +136,7 @@ func prettyPrintBasicACL(cmd *cobra.Command, basicACL acl.Basic) { util.PrettyPrintTableBACL(cmd, &basicACL) } -func getContainer(cmd *cobra.Command) (container.Container, *ecdsa.PrivateKey) { +func getContainer(ctx context.Context, cmd *cobra.Command) (container.Container, *ecdsa.PrivateKey) { var cnr container.Container var pk *ecdsa.PrivateKey if containerPathFrom != "" { @@ -144,13 +148,13 @@ func getContainer(cmd *cobra.Command) (container.Container, *ecdsa.PrivateKey) { } else { id := parseContainerID(cmd) pk = key.GetOrGenerate(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pk, commonflags.RPC) var prm internalclient.GetContainerPrm prm.SetClient(cli) prm.SetContainer(id) - res, err := internalclient.GetContainer(prm) + res, err := internalclient.GetContainer(ctx, prm) common.ExitOnErr(cmd, "rpc error: %w", err) cnr = res.Container() diff --git a/cmd/neofs-cli/modules/container/get_eacl.go b/cmd/neofs-cli/modules/container/get_eacl.go index 482977b17f..e3c4d19473 100644 --- a/cmd/neofs-cli/modules/container/get_eacl.go +++ b/cmd/neofs-cli/modules/container/get_eacl.go @@ -15,15 +15,18 @@ var getExtendedACLCmd = &cobra.Command{ Short: "Get extended ACL table of container", Long: `Get extended ACL table of container`, Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + id := parseContainerID(cmd) pk := key.GetOrGenerate(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pk, commonflags.RPC) var eaclPrm internalclient.EACLPrm eaclPrm.SetClient(cli) eaclPrm.SetContainer(id) - res, err := internalclient.EACL(eaclPrm) + res, err := internalclient.EACL(ctx, eaclPrm) common.ExitOnErr(cmd, "rpc error: %w", err) eaclTable := res.EACL() diff --git a/cmd/neofs-cli/modules/container/list.go b/cmd/neofs-cli/modules/container/list.go index d3d4d61e72..5cd55c081e 100644 --- a/cmd/neofs-cli/modules/container/list.go +++ b/cmd/neofs-cli/modules/container/list.go @@ -30,6 +30,9 @@ var listContainersCmd = &cobra.Command{ Short: "List all created containers", Long: "List all created containers", Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + var idUser user.ID key := key.GetOrGenerate(cmd) @@ -42,13 +45,13 @@ var listContainersCmd = &cobra.Command{ common.ExitOnErr(cmd, "invalid user ID: %w", err) } - cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, key, commonflags.RPC) var prm internalclient.ListContainersPrm prm.SetClient(cli) prm.SetAccount(idUser) - res, err := internalclient.ListContainers(prm) + res, err := internalclient.ListContainers(ctx, prm) common.ExitOnErr(cmd, "rpc error: %w", err) var prmGet internalclient.GetContainerPrm @@ -61,7 +64,7 @@ var listContainersCmd = &cobra.Command{ if flagVarListPrintAttr { prmGet.SetContainer(list[i]) - res, err := internalclient.GetContainer(prmGet) + res, err := internalclient.GetContainer(ctx, prmGet) if err == nil { res.Container().IterateAttributes(func(key, val string) { if !strings.HasPrefix(key, container.SysAttributePrefix) { diff --git a/cmd/neofs-cli/modules/container/list_objects.go b/cmd/neofs-cli/modules/container/list_objects.go index 74c1f955f8..7dd0683208 100644 --- a/cmd/neofs-cli/modules/container/list_objects.go +++ b/cmd/neofs-cli/modules/container/list_objects.go @@ -29,12 +29,15 @@ var listContainerObjectsCmd = &cobra.Command{ Short: "List existing objects in container", Long: `List existing objects in container`, Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + id := parseContainerID(cmd) filters := new(object.SearchFilters) filters.AddRootFilter() // search only user created objects - cli := internalclient.GetSDKClientByFlag(cmd, key.GetOrGenerate(cmd), commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, key.GetOrGenerate(cmd), commonflags.RPC) var prmSearch internalclient.SearchObjectsPrm var prmHead internalclient.HeadObjectPrm @@ -51,7 +54,7 @@ var listContainerObjectsCmd = &cobra.Command{ prmSearch.SetContainerID(id) prmSearch.SetFilters(*filters) - res, err := internalclient.SearchObjects(prmSearch) + res, err := internalclient.SearchObjects(ctx, prmSearch) common.ExitOnErr(cmd, "rpc error: %w", err) objectIDs := res.IDList() @@ -65,7 +68,7 @@ var listContainerObjectsCmd = &cobra.Command{ addr.SetObject(objectIDs[i]) prmHead.SetAddress(addr) - resHead, err := internalclient.HeadObject(prmHead) + resHead, err := internalclient.HeadObject(ctx, prmHead) if err == nil { attrs := resHead.Header().Attributes() for i := range attrs { diff --git a/cmd/neofs-cli/modules/container/nodes.go b/cmd/neofs-cli/modules/container/nodes.go index 5df5e934cd..08c3b4232b 100644 --- a/cmd/neofs-cli/modules/container/nodes.go +++ b/cmd/neofs-cli/modules/container/nodes.go @@ -18,18 +18,21 @@ var containerNodesCmd = &cobra.Command{ Short: "Show nodes for container", Long: "Show nodes taking part in a container at the current epoch.", Run: func(cmd *cobra.Command, args []string) { - var cnr, pkey = getContainer(cmd) + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + + var cnr, pkey = getContainer(ctx, cmd) if pkey == nil { pkey = key.GetOrGenerate(cmd) } - cli := internalclient.GetSDKClientByFlag(cmd, pkey, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pkey, commonflags.RPC) var prm internalclient.NetMapSnapshotPrm prm.SetClient(cli) - resmap, err := internalclient.NetMapSnapshot(prm) + resmap, err := internalclient.NetMapSnapshot(ctx, prm) common.ExitOnErr(cmd, "unable to get netmap snapshot", err) var id cid.ID diff --git a/cmd/neofs-cli/modules/container/set_eacl.go b/cmd/neofs-cli/modules/container/set_eacl.go index fb5f39e695..c627aaf29f 100644 --- a/cmd/neofs-cli/modules/container/set_eacl.go +++ b/cmd/neofs-cli/modules/container/set_eacl.go @@ -24,6 +24,9 @@ var setExtendedACLCmd = &cobra.Command{ Long: `Set new extended ACL table for container. Container ID in EACL table will be substituted with ID from the CLI.`, Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + id := parseContainerID(cmd) eaclTable := common.ReadEACL(cmd, flagVarsSetEACL.srcPath) @@ -32,12 +35,12 @@ Container ID in EACL table will be substituted with ID from the CLI.`, eaclTable.SetCID(id) pk := key.GetOrGenerate(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pk, commonflags.RPC) if !flagVarsSetEACL.noPreCheck { cmd.Println("Checking the ability to modify access rights in the container...") - extendable, err := internalclient.IsACLExtendable(cli, id) + extendable, err := internalclient.IsACLExtendable(ctx, cli, id) common.ExitOnErr(cmd, "Extensibility check failure: %w", err) if !extendable { @@ -55,7 +58,7 @@ Container ID in EACL table will be substituted with ID from the CLI.`, setEACLPrm.WithinSession(*tok) } - _, err := internalclient.SetEACL(setEACLPrm) + _, err := internalclient.SetEACL(ctx, setEACLPrm) common.ExitOnErr(cmd, "rpc error: %w", err) if containerAwait { @@ -71,7 +74,7 @@ Container ID in EACL table will be substituted with ID from the CLI.`, for i := 0; i < awaitTimeout; i++ { time.Sleep(1 * time.Second) - res, err := internalclient.EACL(getEACLPrm) + res, err := internalclient.EACL(ctx, getEACLPrm) if err == nil { // compare binary values because EACL could have been set already table := res.EACL() diff --git a/cmd/neofs-cli/modules/control/drop_objects.go b/cmd/neofs-cli/modules/control/drop_objects.go index 61d58d50b4..b91c56d3bd 100644 --- a/cmd/neofs-cli/modules/control/drop_objects.go +++ b/cmd/neofs-cli/modules/control/drop_objects.go @@ -3,6 +3,7 @@ package control import ( rawclient "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common" + "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/pkg/services/control" "github.com/spf13/cobra" @@ -15,6 +16,9 @@ var dropObjectsCmd = &cobra.Command{ Short: "Drop objects from the node's local storage", Long: "Drop objects from the node's local storage", Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.Get(cmd) dropObjectsList, _ := cmd.Flags().GetStringSlice(dropObjectsFlag) @@ -32,7 +36,7 @@ var dropObjectsCmd = &cobra.Command{ signRequest(cmd, pk, req) - cli := getClient(cmd, pk) + cli := getClient(ctx, cmd, pk) var resp *control.DropObjectsResponse var err error diff --git a/cmd/neofs-cli/modules/control/evacuate_shard.go b/cmd/neofs-cli/modules/control/evacuate_shard.go index dd82cefd42..974f961421 100644 --- a/cmd/neofs-cli/modules/control/evacuate_shard.go +++ b/cmd/neofs-cli/modules/control/evacuate_shard.go @@ -3,6 +3,7 @@ package control import ( "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common" + "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/pkg/services/control" "github.com/spf13/cobra" @@ -16,6 +17,9 @@ var evacuateShardCmd = &cobra.Command{ } func evacuateShard(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.Get(cmd) req := &control.EvacuateShardRequest{Body: new(control.EvacuateShardRequest_Body)} @@ -24,7 +28,7 @@ func evacuateShard(cmd *cobra.Command, _ []string) { signRequest(cmd, pk, req) - cli := getClient(cmd, pk) + cli := getClient(ctx, cmd, pk) var resp *control.EvacuateShardResponse var err error diff --git a/cmd/neofs-cli/modules/control/flush_cache.go b/cmd/neofs-cli/modules/control/flush_cache.go index 31ef9c9783..73aeeb6f1a 100644 --- a/cmd/neofs-cli/modules/control/flush_cache.go +++ b/cmd/neofs-cli/modules/control/flush_cache.go @@ -3,6 +3,7 @@ package control import ( "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common" + "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/pkg/services/control" "github.com/spf13/cobra" @@ -16,6 +17,9 @@ var flushCacheCmd = &cobra.Command{ } func flushCache(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.Get(cmd) req := &control.FlushCacheRequest{Body: new(control.FlushCacheRequest_Body)} @@ -23,7 +27,7 @@ func flushCache(cmd *cobra.Command, _ []string) { signRequest(cmd, pk, req) - cli := getClient(cmd, pk) + cli := getClient(ctx, cmd, pk) var resp *control.FlushCacheResponse var err error diff --git a/cmd/neofs-cli/modules/control/healthcheck.go b/cmd/neofs-cli/modules/control/healthcheck.go index 7d5f50b8fa..be2fa8f2bc 100644 --- a/cmd/neofs-cli/modules/control/healthcheck.go +++ b/cmd/neofs-cli/modules/control/healthcheck.go @@ -5,6 +5,7 @@ import ( rawclient "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common" + "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/pkg/services/control" ircontrol "github.com/nspcc-dev/neofs-node/pkg/services/control/ir" @@ -32,9 +33,12 @@ func initControlHealthCheckCmd() { } func healthCheck(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.Get(cmd) - cli := getClient(cmd, pk) + cli := getClient(ctx, cmd, pk) if isIR, _ := cmd.Flags().GetBool(healthcheckIRFlag); isIR { healthCheckIR(cmd, pk, cli) diff --git a/cmd/neofs-cli/modules/control/set_netmap_status.go b/cmd/neofs-cli/modules/control/set_netmap_status.go index 2781543223..61eba58ef2 100644 --- a/cmd/neofs-cli/modules/control/set_netmap_status.go +++ b/cmd/neofs-cli/modules/control/set_netmap_status.go @@ -45,6 +45,9 @@ func initControlSetNetmapStatusCmd() { } func setNetmapStatus(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.Get(cmd) body := new(control.SetNetmapStatusRequest_Body) force, _ := cmd.Flags().GetBool(commonflags.ForceFlag) @@ -78,7 +81,7 @@ func setNetmapStatus(cmd *cobra.Command, _ []string) { signRequest(cmd, pk, req) - cli := getClient(cmd, pk) + cli := getClient(ctx, cmd, pk) var resp *control.SetNetmapStatusResponse var err error diff --git a/cmd/neofs-cli/modules/control/shards_dump.go b/cmd/neofs-cli/modules/control/shards_dump.go index 4b04a323da..4c32a1fff9 100644 --- a/cmd/neofs-cli/modules/control/shards_dump.go +++ b/cmd/neofs-cli/modules/control/shards_dump.go @@ -3,6 +3,7 @@ package control import ( "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common" + "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/pkg/services/control" "github.com/spf13/cobra" @@ -21,6 +22,9 @@ var dumpShardCmd = &cobra.Command{ } func dumpShard(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.Get(cmd) body := new(control.DumpShardRequest_Body) @@ -37,7 +41,7 @@ func dumpShard(cmd *cobra.Command, _ []string) { signRequest(cmd, pk, req) - cli := getClient(cmd, pk) + cli := getClient(ctx, cmd, pk) var resp *control.DumpShardResponse var err error diff --git a/cmd/neofs-cli/modules/control/shards_list.go b/cmd/neofs-cli/modules/control/shards_list.go index d8711d69a2..af5473fa94 100644 --- a/cmd/neofs-cli/modules/control/shards_list.go +++ b/cmd/neofs-cli/modules/control/shards_list.go @@ -30,6 +30,9 @@ func initControlShardsListCmd() { } func listShards(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.Get(cmd) req := new(control.ListShardsRequest) @@ -37,7 +40,7 @@ func listShards(cmd *cobra.Command, _ []string) { signRequest(cmd, pk, req) - cli := getClient(cmd, pk) + cli := getClient(ctx, cmd, pk) var resp *control.ListShardsResponse var err error diff --git a/cmd/neofs-cli/modules/control/shards_restore.go b/cmd/neofs-cli/modules/control/shards_restore.go index b61ccee97a..ff2870f706 100644 --- a/cmd/neofs-cli/modules/control/shards_restore.go +++ b/cmd/neofs-cli/modules/control/shards_restore.go @@ -3,6 +3,7 @@ package control import ( "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common" + "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/pkg/services/control" "github.com/spf13/cobra" @@ -21,6 +22,9 @@ var restoreShardCmd = &cobra.Command{ } func restoreShard(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.Get(cmd) body := new(control.RestoreShardRequest_Body) @@ -37,7 +41,7 @@ func restoreShard(cmd *cobra.Command, _ []string) { signRequest(cmd, pk, req) - cli := getClient(cmd, pk) + cli := getClient(ctx, cmd, pk) var resp *control.RestoreShardResponse var err error diff --git a/cmd/neofs-cli/modules/control/shards_set_mode.go b/cmd/neofs-cli/modules/control/shards_set_mode.go index 0b63ca30ba..951bfc6249 100644 --- a/cmd/neofs-cli/modules/control/shards_set_mode.go +++ b/cmd/neofs-cli/modules/control/shards_set_mode.go @@ -7,6 +7,7 @@ import ( "github.com/mr-tron/base58" rawclient "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common" + "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" "github.com/nspcc-dev/neofs-node/pkg/services/control" "github.com/spf13/cobra" @@ -99,6 +100,9 @@ func initControlSetShardModeCmd() { } func setShardMode(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.Get(cmd) strMode, _ := cmd.Flags().GetString(shardModeFlag) @@ -121,7 +125,7 @@ func setShardMode(cmd *cobra.Command, _ []string) { signRequest(cmd, pk, req) - cli := getClient(cmd, pk) + cli := getClient(ctx, cmd, pk) var resp *control.SetShardModeResponse var err error diff --git a/cmd/neofs-cli/modules/control/synchronize_tree.go b/cmd/neofs-cli/modules/control/synchronize_tree.go index 2bf4515196..a83525cb61 100644 --- a/cmd/neofs-cli/modules/control/synchronize_tree.go +++ b/cmd/neofs-cli/modules/control/synchronize_tree.go @@ -36,6 +36,9 @@ func initControlSynchronizeTreeCmd() { } func synchronizeTree(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.Get(cmd) var cnr cid.ID @@ -63,7 +66,7 @@ func synchronizeTree(cmd *cobra.Command, _ []string) { err := controlSvc.SignMessage(pk, req) common.ExitOnErr(cmd, "could not sign request: %w", err) - cli := getClient(cmd, pk) + cli := getClient(ctx, cmd, pk) var resp *control.SynchronizeTreeResponse err = cli.ExecRaw(func(client *rawclient.Client) error { diff --git a/cmd/neofs-cli/modules/control/util.go b/cmd/neofs-cli/modules/control/util.go index 59bae90e6f..b1c29daf9f 100644 --- a/cmd/neofs-cli/modules/control/util.go +++ b/cmd/neofs-cli/modules/control/util.go @@ -1,6 +1,7 @@ package control import ( + "context" "crypto/ecdsa" "errors" @@ -54,6 +55,6 @@ func verifyResponse(cmd *cobra.Command, } } -func getClient(cmd *cobra.Command, pk *ecdsa.PrivateKey) *client.Client { - return internalclient.GetSDKClientByFlag(cmd, pk, controlRPC) +func getClient(ctx context.Context, cmd *cobra.Command, pk *ecdsa.PrivateKey) *client.Client { + return internalclient.GetSDKClientByFlag(ctx, cmd, pk, controlRPC) } diff --git a/cmd/neofs-cli/modules/netmap/get_epoch.go b/cmd/neofs-cli/modules/netmap/get_epoch.go index 9ac6e64d3b..eaf0091634 100644 --- a/cmd/neofs-cli/modules/netmap/get_epoch.go +++ b/cmd/neofs-cli/modules/netmap/get_epoch.go @@ -13,13 +13,16 @@ var getEpochCmd = &cobra.Command{ Short: "Get current epoch number", Long: "Get current epoch number", Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + p := key.GetOrGenerate(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, p, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, p, commonflags.RPC) var prm internalclient.NetworkInfoPrm prm.SetClient(cli) - res, err := internalclient.NetworkInfo(prm) + res, err := internalclient.NetworkInfo(ctx, prm) common.ExitOnErr(cmd, "rpc error: %w", err) netInfo := res.NetworkInfo() diff --git a/cmd/neofs-cli/modules/netmap/netinfo.go b/cmd/neofs-cli/modules/netmap/netinfo.go index 6999aa3dfb..aea9077ed3 100644 --- a/cmd/neofs-cli/modules/netmap/netinfo.go +++ b/cmd/neofs-cli/modules/netmap/netinfo.go @@ -17,13 +17,16 @@ var netInfoCmd = &cobra.Command{ Short: "Get information about NeoFS network", Long: "Get information about NeoFS network", Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + p := key.GetOrGenerate(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, p, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, p, commonflags.RPC) var prm internalclient.NetworkInfoPrm prm.SetClient(cli) - res, err := internalclient.NetworkInfo(prm) + res, err := internalclient.NetworkInfo(ctx, prm) common.ExitOnErr(cmd, "rpc error: %w", err) netInfo := res.NetworkInfo() diff --git a/cmd/neofs-cli/modules/netmap/nodeinfo.go b/cmd/neofs-cli/modules/netmap/nodeinfo.go index 9c14a1b73c..d2233e9862 100644 --- a/cmd/neofs-cli/modules/netmap/nodeinfo.go +++ b/cmd/neofs-cli/modules/netmap/nodeinfo.go @@ -18,13 +18,16 @@ var nodeInfoCmd = &cobra.Command{ Short: "Get target node info", Long: `Get target node info`, Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + p := key.GetOrGenerate(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, p, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, p, commonflags.RPC) var prm internalclient.NodeInfoPrm prm.SetClient(cli) - res, err := internalclient.NodeInfo(prm) + res, err := internalclient.NodeInfo(ctx, prm) common.ExitOnErr(cmd, "rpc error: %w", err) prettyPrintNodeInfo(cmd, res.NodeInfo()) diff --git a/cmd/neofs-cli/modules/netmap/snapshot.go b/cmd/neofs-cli/modules/netmap/snapshot.go index 0e9bf2b7bf..92b26b8f4f 100644 --- a/cmd/neofs-cli/modules/netmap/snapshot.go +++ b/cmd/neofs-cli/modules/netmap/snapshot.go @@ -13,13 +13,16 @@ var snapshotCmd = &cobra.Command{ Short: "Request current local snapshot of the network map", Long: `Request current local snapshot of the network map`, Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + p := key.GetOrGenerate(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, p, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, p, commonflags.RPC) var prm internalclient.NetMapSnapshotPrm prm.SetClient(cli) - res, err := internalclient.NetMapSnapshot(prm) + res, err := internalclient.NetMapSnapshot(ctx, prm) common.ExitOnErr(cmd, "rpc error: %w", err) common.PrettyPrintNetMap(cmd, res.NetMap()) diff --git a/cmd/neofs-cli/modules/object/delete.go b/cmd/neofs-cli/modules/object/delete.go index 6bf06c662b..f5b8128d0e 100644 --- a/cmd/neofs-cli/modules/object/delete.go +++ b/cmd/neofs-cli/modules/object/delete.go @@ -33,6 +33,9 @@ func initObjectDeleteCmd() { } func deleteObject(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + var cnr cid.ID var obj oid.ID var objAddr oid.Address @@ -61,11 +64,11 @@ func deleteObject(cmd *cobra.Command, _ []string) { pk := key.GetOrGenerate(cmd) var prm internalclient.DeleteObjectPrm - ReadOrOpenSession(cmd, &prm, pk, cnr, &obj) + ReadOrOpenSession(ctx, cmd, &prm, pk, cnr, &obj) Prepare(cmd, &prm) prm.SetAddress(objAddr) - res, err := internalclient.DeleteObject(prm) + res, err := internalclient.DeleteObject(ctx, prm) common.ExitOnErr(cmd, "rpc error: %w", err) tomb := res.Tombstone() diff --git a/cmd/neofs-cli/modules/object/get.go b/cmd/neofs-cli/modules/object/get.go index 69bbd644aa..97a97de334 100644 --- a/cmd/neofs-cli/modules/object/get.go +++ b/cmd/neofs-cli/modules/object/get.go @@ -43,6 +43,9 @@ func initObjectGetCmd() { } func getObject(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + var cnr cid.ID var obj oid.ID @@ -65,7 +68,7 @@ func getObject(cmd *cobra.Command, _ []string) { pk := key.GetOrGenerate(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pk, commonflags.RPC) var prm internalclient.GetObjectPrm prm.SetClient(cli) @@ -101,7 +104,7 @@ func getObject(cmd *cobra.Command, _ []string) { }) } - res, err := internalclient.GetObject(prm) + res, err := internalclient.GetObject(ctx, prm) if p != nil { p.Finish() } @@ -115,7 +118,7 @@ func getObject(cmd *cobra.Command, _ []string) { if binary { objToStore := res.Header() - //TODO(@acid-ant): #1932 Use streams to marshal/unmarshal payload + // TODO(@acid-ant): #1932 Use streams to marshal/unmarshal payload objToStore.SetPayload(payloadBuffer.Bytes()) objBytes, err := objToStore.Marshal() common.ExitOnErr(cmd, "", err) diff --git a/cmd/neofs-cli/modules/object/hash.go b/cmd/neofs-cli/modules/object/hash.go index 2430443c70..f45a79bc44 100644 --- a/cmd/neofs-cli/modules/object/hash.go +++ b/cmd/neofs-cli/modules/object/hash.go @@ -48,6 +48,9 @@ func initObjectHashCmd() { } func getObjectHash(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + var cnr cid.ID var obj oid.ID @@ -64,7 +67,7 @@ func getObjectHash(cmd *cobra.Command, _ []string) { common.ExitOnErr(cmd, "could not decode salt: %w", err) pk := key.GetOrGenerate(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pk, commonflags.RPC) tz := typ == hashTz fullHash := len(ranges) == 0 @@ -75,7 +78,7 @@ func getObjectHash(cmd *cobra.Command, _ []string) { headPrm.SetAddress(objAddr) // get hash of full payload through HEAD (may be user can do it through dedicated command?) - res, err := internalclient.HeadObject(headPrm) + res, err := internalclient.HeadObject(ctx, headPrm) common.ExitOnErr(cmd, "rpc error: %w", err) var cs checksum.Checksum @@ -108,7 +111,7 @@ func getObjectHash(cmd *cobra.Command, _ []string) { hashPrm.TZ() } - res, err := internalclient.HashPayloadRanges(hashPrm) + res, err := internalclient.HashPayloadRanges(ctx, hashPrm) common.ExitOnErr(cmd, "rpc error: %w", err) hs := res.HashList() diff --git a/cmd/neofs-cli/modules/object/head.go b/cmd/neofs-cli/modules/object/head.go index 81ac42cdce..f4bc607fd0 100644 --- a/cmd/neofs-cli/modules/object/head.go +++ b/cmd/neofs-cli/modules/object/head.go @@ -45,6 +45,9 @@ func initObjectHeadCmd() { } func getObjectHeader(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + var cnr cid.ID var obj oid.ID @@ -52,7 +55,7 @@ func getObjectHeader(cmd *cobra.Command, _ []string) { mainOnly, _ := cmd.Flags().GetBool("main-only") pk := key.GetOrGenerate(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pk, commonflags.RPC) var prm internalclient.HeadObjectPrm prm.SetClient(cli) @@ -64,7 +67,7 @@ func getObjectHeader(cmd *cobra.Command, _ []string) { prm.SetAddress(objAddr) prm.SetMainOnlyFlag(mainOnly) - res, err := internalclient.HeadObject(prm) + res, err := internalclient.HeadObject(ctx, prm) if err != nil { if ok := printSplitInfoErr(cmd, err); ok { return diff --git a/cmd/neofs-cli/modules/object/lock.go b/cmd/neofs-cli/modules/object/lock.go index dd639784b3..34652af7d1 100644 --- a/cmd/neofs-cli/modules/object/lock.go +++ b/cmd/neofs-cli/modules/object/lock.go @@ -26,6 +26,9 @@ var objectLockCmd = &cobra.Command{ Short: "Lock object in container", Long: "Lock object in container", Run: func(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + cidRaw, _ := cmd.Flags().GetString(commonflags.CIDFlag) var cnr cid.ID @@ -82,11 +85,11 @@ var objectLockCmd = &cobra.Command{ obj.SetPayload(lock.Marshal()) var prm internalclient.PutObjectPrm - ReadOrOpenSession(cmd, &prm, key, cnr, nil) + ReadOrOpenSession(ctx, cmd, &prm, key, cnr, nil) Prepare(cmd, &prm) prm.SetHeader(obj) - res, err := internalclient.PutObject(prm) + res, err := internalclient.PutObject(ctx, prm) common.ExitOnErr(cmd, "Store lock object in NeoFS: %w", err) cmd.Printf("Lock object ID: %s\n", res.ID()) diff --git a/cmd/neofs-cli/modules/object/put.go b/cmd/neofs-cli/modules/object/put.go index ca28d31c2f..29ed6dc48e 100644 --- a/cmd/neofs-cli/modules/object/put.go +++ b/cmd/neofs-cli/modules/object/put.go @@ -60,6 +60,9 @@ func initObjectPutCmd() { } func putObject(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + binary, _ := cmd.Flags().GetBool(binaryFlag) cidVal, _ := cmd.Flags().GetString(commonflags.CIDFlag) @@ -130,7 +133,7 @@ func putObject(cmd *cobra.Command, _ []string) { } var prm internalclient.PutObjectPrm - ReadOrOpenSession(cmd, &prm, pk, cnr, nil) + ReadOrOpenSession(ctx, cmd, &prm, pk, cnr, nil) Prepare(cmd, &prm) prm.SetHeader(obj) @@ -161,7 +164,7 @@ func putObject(cmd *cobra.Command, _ []string) { } } - res, err := internalclient.PutObject(prm) + res, err := internalclient.PutObject(ctx, prm) if p != nil { p.Finish() } diff --git a/cmd/neofs-cli/modules/object/range.go b/cmd/neofs-cli/modules/object/range.go index bf85f75a34..e51f35f45b 100644 --- a/cmd/neofs-cli/modules/object/range.go +++ b/cmd/neofs-cli/modules/object/range.go @@ -44,6 +44,9 @@ func initObjectRangeCmd() { } func getObjectRange(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + var cnr cid.ID var obj oid.ID @@ -74,7 +77,7 @@ func getObjectRange(cmd *cobra.Command, _ []string) { pk := key.GetOrGenerate(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pk, commonflags.RPC) var prm internalclient.PayloadRangePrm prm.SetClient(cli) @@ -87,7 +90,7 @@ func getObjectRange(cmd *cobra.Command, _ []string) { prm.SetRange(ranges[0]) prm.SetPayloadWriter(out) - _, err = internalclient.PayloadRange(prm) + _, err = internalclient.PayloadRange(ctx, prm) if err != nil { if ok := printSplitInfoErr(cmd, err); ok { return diff --git a/cmd/neofs-cli/modules/object/search.go b/cmd/neofs-cli/modules/object/search.go index a6c0990573..30cfb93de4 100644 --- a/cmd/neofs-cli/modules/object/search.go +++ b/cmd/neofs-cli/modules/object/search.go @@ -44,6 +44,9 @@ func initObjectSearchCmd() { } func searchObject(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + var cnr cid.ID readCID(cmd, &cnr) @@ -52,7 +55,7 @@ func searchObject(cmd *cobra.Command, _ []string) { pk := key.GetOrGenerate(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pk, commonflags.RPC) var prm internalclient.SearchObjectsPrm prm.SetClient(cli) @@ -61,7 +64,7 @@ func searchObject(cmd *cobra.Command, _ []string) { prm.SetContainerID(cnr) prm.SetFilters(sf) - res, err := internalclient.SearchObjects(prm) + res, err := internalclient.SearchObjects(ctx, prm) common.ExitOnErr(cmd, "rpc error: %w", err) ids := res.IDList() diff --git a/cmd/neofs-cli/modules/object/util.go b/cmd/neofs-cli/modules/object/util.go index 3366485f59..96a9475b26 100644 --- a/cmd/neofs-cli/modules/object/util.go +++ b/cmd/neofs-cli/modules/object/util.go @@ -1,6 +1,7 @@ package object import ( + "context" "crypto/ecdsa" "errors" "fmt" @@ -206,19 +207,19 @@ func _readVerifiedSession(cmd *cobra.Command, dst SessionPrm, key *ecdsa.Private } // ReadOrOpenSession opens client connection and calls ReadOrOpenSessionViaClient with it. -func ReadOrOpenSession(cmd *cobra.Command, dst SessionPrm, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) { - cli := internal.GetSDKClientByFlag(cmd, key, commonflags.RPC) - ReadOrOpenSessionViaClient(cmd, dst, cli, key, cnr, obj) +func ReadOrOpenSession(ctx context.Context, cmd *cobra.Command, dst SessionPrm, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) { + cli := internal.GetSDKClientByFlag(ctx, cmd, key, commonflags.RPC) + ReadOrOpenSessionViaClient(ctx, cmd, dst, cli, key, cnr, obj) } // ReadOrOpenSessionViaClient tries to read session from the file specified in // commonflags.SessionToken flag, finalizes structures of the decoded token // and write the result into provided SessionPrm. If file is missing, // ReadOrOpenSessionViaClient calls OpenSessionViaClient. -func ReadOrOpenSessionViaClient(cmd *cobra.Command, dst SessionPrm, cli *client.Client, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) { +func ReadOrOpenSessionViaClient(ctx context.Context, cmd *cobra.Command, dst SessionPrm, cli *client.Client, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) { tok := getSession(cmd) if tok == nil { - OpenSessionViaClient(cmd, dst, cli, key, cnr, obj) + OpenSessionViaClient(ctx, cmd, dst, cli, key, cnr, obj) return } @@ -229,7 +230,7 @@ func ReadOrOpenSessionViaClient(cmd *cobra.Command, dst SessionPrm, cli *client. if _, ok := dst.(*internal.DeleteObjectPrm); ok { common.PrintVerbose(cmd, "Collecting relatives of the removal object...") - objs = append(objs, collectObjectRelatives(cmd, cli, cnr, *obj)...) + objs = append(objs, collectObjectRelatives(ctx, cmd, cli, cnr, *obj)...) } } @@ -238,9 +239,9 @@ func ReadOrOpenSessionViaClient(cmd *cobra.Command, dst SessionPrm, cli *client. } // OpenSession opens client connection and calls OpenSessionViaClient with it. -func OpenSession(cmd *cobra.Command, dst SessionPrm, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) { - cli := internal.GetSDKClientByFlag(cmd, key, commonflags.RPC) - OpenSessionViaClient(cmd, dst, cli, key, cnr, obj) +func OpenSession(ctx context.Context, cmd *cobra.Command, dst SessionPrm, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) { + cli := internal.GetSDKClientByFlag(ctx, cmd, key, commonflags.RPC) + OpenSessionViaClient(ctx, cmd, dst, cli, key, cnr, obj) } // OpenSessionViaClient opens object session with the remote node, finalizes @@ -254,14 +255,14 @@ func OpenSession(cmd *cobra.Command, dst SessionPrm, key *ecdsa.PrivateKey, cnr // // If provided SessionPrm is of type internal.DeleteObjectPrm, OpenSessionViaClient // spreads the session to all object's relatives. -func OpenSessionViaClient(cmd *cobra.Command, dst SessionPrm, cli *client.Client, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) { +func OpenSessionViaClient(ctx context.Context, cmd *cobra.Command, dst SessionPrm, cli *client.Client, key *ecdsa.PrivateKey, cnr cid.ID, obj *oid.ID) { var objs []oid.ID if obj != nil { if _, ok := dst.(*internal.DeleteObjectPrm); ok { common.PrintVerbose(cmd, "Collecting relatives of the removal object...") - rels := collectObjectRelatives(cmd, cli, cnr, *obj) + rels := collectObjectRelatives(ctx, cmd, cli, cnr, *obj) if len(rels) == 0 { objs = []oid.ID{*obj} @@ -277,7 +278,7 @@ func OpenSessionViaClient(cmd *cobra.Command, dst SessionPrm, cli *client.Client common.PrintVerbose(cmd, "Opening remote session with the node...") - err := sessionCli.CreateSession(&tok, cli, neofsecdsa.SignerRFC6979(*key), sessionLifetime) + err := sessionCli.CreateSession(ctx, &tok, cli, neofsecdsa.SignerRFC6979(*key), sessionLifetime) common.ExitOnErr(cmd, "open remote session: %w", err) common.PrintVerbose(cmd, "Session successfully opened.") @@ -338,7 +339,7 @@ func initFlagSession(cmd *cobra.Command, verb string) { // container. // // The object itself is not included in the result. -func collectObjectRelatives(cmd *cobra.Command, cli *client.Client, cnr cid.ID, obj oid.ID) []oid.ID { +func collectObjectRelatives(ctx context.Context, cmd *cobra.Command, cli *client.Client, cnr cid.ID, obj oid.ID) []oid.ID { common.PrintVerbose(cmd, "Fetching raw object header...") // request raw header first @@ -353,7 +354,7 @@ func collectObjectRelatives(cmd *cobra.Command, cli *client.Client, cnr cid.ID, Prepare(cmd, &prmHead) - _, err := internal.HeadObject(prmHead) + _, err := internal.HeadObject(ctx, prmHead) var errSplit *object.SplitInfoError @@ -380,7 +381,7 @@ func collectObjectRelatives(cmd *cobra.Command, cli *client.Client, cnr cid.ID, prmHead.SetRawFlag(false) // client is already set - res, err := internal.HeadObject(prmHead) + res, err := internal.HeadObject(ctx, prmHead) if err == nil { children := res.Header().Children() @@ -406,7 +407,7 @@ func collectObjectRelatives(cmd *cobra.Command, cli *client.Client, cnr cid.ID, prm.SetClient(cli) prm.SetFilters(query) - res, err := internal.SearchObjects(prm) + res, err := internal.SearchObjects(ctx, prm) common.ExitOnErr(cmd, "failed to search objects by split ID: %w", err) members := res.IDList() @@ -435,7 +436,7 @@ func collectObjectRelatives(cmd *cobra.Command, cli *client.Client, cnr cid.ID, addrObj.SetObject(idMember) - res, err = internal.HeadObject(prmHead) + res, err = internal.HeadObject(ctx, prmHead) common.ExitOnErr(cmd, "failed to read split chain member's header: %w", err) idMember, ok = res.Header().PreviousID() @@ -462,7 +463,7 @@ func collectObjectRelatives(cmd *cobra.Command, cli *client.Client, cnr cid.ID, prmSearch.SetContainerID(cnr) prmSearch.SetFilters(query) - resSearch, err := internal.SearchObjects(prmSearch) + resSearch, err := internal.SearchObjects(ctx, prmSearch) common.ExitOnErr(cmd, "failed to find object children: %w", err) list := resSearch.IDList() diff --git a/cmd/neofs-cli/modules/session/create.go b/cmd/neofs-cli/modules/session/create.go index ee604ff839..f4414fd5be 100644 --- a/cmd/neofs-cli/modules/session/create.go +++ b/cmd/neofs-cli/modules/session/create.go @@ -50,13 +50,15 @@ func init() { } func createSession(cmd *cobra.Command, _ []string) { + ctx := context.Background() + privKey := key.Get(cmd) var netAddr network.Address addrStr, _ := cmd.Flags().GetString(commonflags.RPC) common.ExitOnErr(cmd, "can't parse endpoint: %w", netAddr.FromString(addrStr)) - c, err := internalclient.GetSDKClient(context.TODO(), cmd, privKey, netAddr) + c, err := internalclient.GetSDKClient(ctx, cmd, privKey, netAddr) common.ExitOnErr(cmd, "can't create client: %w", err) lifetime := uint64(defaultLifetime) @@ -66,7 +68,7 @@ func createSession(cmd *cobra.Command, _ []string) { var tok session.Object - err = CreateSession(&tok, c, neofsecdsa.SignerRFC6979(*privKey), lifetime) + err = CreateSession(ctx, &tok, c, neofsecdsa.SignerRFC6979(*privKey), lifetime) common.ExitOnErr(cmd, "can't create session: %w", err) var data []byte @@ -88,11 +90,11 @@ func createSession(cmd *cobra.Command, _ []string) { // number of epochs. // // Fills ID, lifetime and session key. -func CreateSession(dst *session.Object, c *client.Client, _signer neofscrypto.Signer, lifetime uint64) error { +func CreateSession(ctx context.Context, dst *session.Object, c *client.Client, _signer neofscrypto.Signer, lifetime uint64) error { var netInfoPrm internalclient.NetworkInfoPrm netInfoPrm.SetClient(c) - ni, err := internalclient.NetworkInfo(netInfoPrm) + ni, err := internalclient.NetworkInfo(ctx, netInfoPrm) if err != nil { return fmt.Errorf("can't fetch network info: %w", err) } @@ -105,7 +107,7 @@ func CreateSession(dst *session.Object, c *client.Client, _signer neofscrypto.Si sessionPrm.SetExp(exp) sessionPrm.UseSigner(_signer) - sessionRes, err := internalclient.CreateSession(sessionPrm) + sessionRes, err := internalclient.CreateSession(ctx, sessionPrm) if err != nil { return fmt.Errorf("can't open session: %w", err) } diff --git a/cmd/neofs-cli/modules/storagegroup/delete.go b/cmd/neofs-cli/modules/storagegroup/delete.go index 10f7bde7b9..6c971ddfd9 100644 --- a/cmd/neofs-cli/modules/storagegroup/delete.go +++ b/cmd/neofs-cli/modules/storagegroup/delete.go @@ -31,6 +31,9 @@ func initSGDeleteCmd() { } func delSG(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.GetOrGenerate(cmd) var cnr cid.ID @@ -39,11 +42,11 @@ func delSG(cmd *cobra.Command, _ []string) { addr := readObjectAddress(cmd, &cnr, &obj) var prm internalclient.DeleteObjectPrm - objectCli.OpenSession(cmd, &prm, pk, cnr, &obj) + objectCli.OpenSession(ctx, cmd, &prm, pk, cnr, &obj) objectCli.Prepare(cmd, &prm) prm.SetAddress(addr) - res, err := internalclient.DeleteObject(prm) + res, err := internalclient.DeleteObject(ctx, prm) common.ExitOnErr(cmd, "rpc error: %w", err) tombstone := res.Tombstone() diff --git a/cmd/neofs-cli/modules/storagegroup/get.go b/cmd/neofs-cli/modules/storagegroup/get.go index f7511b3575..5bc02e4125 100644 --- a/cmd/neofs-cli/modules/storagegroup/get.go +++ b/cmd/neofs-cli/modules/storagegroup/get.go @@ -38,6 +38,9 @@ func initSGGetCmd() { } func getSG(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + var cnr cid.ID var obj oid.ID @@ -45,7 +48,7 @@ func getSG(cmd *cobra.Command, _ []string) { pk := key.GetOrGenerate(cmd) buf := bytes.NewBuffer(nil) - cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pk, commonflags.RPC) var prm internalclient.GetObjectPrm objectCli.Prepare(cmd, &prm) @@ -56,7 +59,7 @@ func getSG(cmd *cobra.Command, _ []string) { prm.SetAddress(addr) prm.SetPayloadWriter(buf) - res, err := internalclient.GetObject(prm) + res, err := internalclient.GetObject(ctx, prm) common.ExitOnErr(cmd, "rpc error: %w", err) rawObj := res.Header() diff --git a/cmd/neofs-cli/modules/storagegroup/list.go b/cmd/neofs-cli/modules/storagegroup/list.go index 0d5be94d66..c1a71a47bb 100644 --- a/cmd/neofs-cli/modules/storagegroup/list.go +++ b/cmd/neofs-cli/modules/storagegroup/list.go @@ -26,12 +26,15 @@ func initSGListCmd() { } func listSG(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + var cnr cid.ID readCID(cmd, &cnr) pk := key.GetOrGenerate(cmd) - cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pk, commonflags.RPC) var prm internalclient.SearchObjectsPrm objectCli.Prepare(cmd, &prm) @@ -39,7 +42,7 @@ func listSG(cmd *cobra.Command, _ []string) { prm.SetContainerID(cnr) prm.SetFilters(storagegroup.SearchQuery()) - res, err := internalclient.SearchObjects(prm) + res, err := internalclient.SearchObjects(ctx, prm) common.ExitOnErr(cmd, "rpc error: %w", err) ids := res.IDList() diff --git a/cmd/neofs-cli/modules/storagegroup/put.go b/cmd/neofs-cli/modules/storagegroup/put.go index 13a81f8728..57a91afd1e 100644 --- a/cmd/neofs-cli/modules/storagegroup/put.go +++ b/cmd/neofs-cli/modules/storagegroup/put.go @@ -1,6 +1,7 @@ package storagegroup import ( + "context" "crypto/ecdsa" "errors" "fmt" @@ -48,6 +49,9 @@ func initSGPutCmd() { } func putSG(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.GetOrGenerate(cmd) var ownerID user.ID @@ -77,14 +81,14 @@ func putSG(cmd *cobra.Command, _ []string) { getCnrPrm internalclient.GetContainerPrm ) - cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + cli := internalclient.GetSDKClientByFlag(ctx, cmd, pk, commonflags.RPC) getCnrPrm.SetClient(cli) getCnrPrm.SetContainer(cnr) - resGetCnr, err := internalclient.GetContainer(getCnrPrm) + resGetCnr, err := internalclient.GetContainer(ctx, getCnrPrm) common.ExitOnErr(cmd, "get container RPC call: %w", err) - objectCli.OpenSessionViaClient(cmd, &putPrm, cli, pk, cnr, nil) + objectCli.OpenSessionViaClient(ctx, cmd, &putPrm, cli, pk, cnr, nil) objectCli.Prepare(cmd, &headPrm, &putPrm) headPrm.SetRawFlag(true) @@ -101,7 +105,7 @@ func putSG(cmd *cobra.Command, _ []string) { var netInfoPrm internalclient.NetworkInfoPrm netInfoPrm.SetClient(cli) - ni, err := internalclient.NetworkInfo(netInfoPrm) + ni, err := internalclient.NetworkInfo(ctx, netInfoPrm) common.ExitOnErr(cmd, "can't fetch network info: %w", err) lifetime, _ := cmd.Flags().GetUint64(commonflags.Lifetime) @@ -115,7 +119,7 @@ func putSG(cmd *cobra.Command, _ []string) { putPrm.SetHeader(obj) - res, err := internalclient.PutObject(putPrm) + res, err := internalclient.PutObject(ctx, putPrm) common.ExitOnErr(cmd, "rpc error: %w", err) cmd.Println("Storage group successfully stored") @@ -123,6 +127,7 @@ func putSG(cmd *cobra.Command, _ []string) { } type sgHeadReceiver struct { + ctx context.Context cmd *cobra.Command key *ecdsa.PrivateKey ownerID *user.ID @@ -132,7 +137,7 @@ type sgHeadReceiver struct { func (c sgHeadReceiver) Head(addr oid.Address) (interface{}, error) { c.prm.SetAddress(addr) - res, err := internalclient.HeadObject(c.prm) + res, err := internalclient.HeadObject(c.ctx, c.prm) var errSplitInfo *object.SplitInfoError diff --git a/cmd/neofs-cli/modules/tree/add.go b/cmd/neofs-cli/modules/tree/add.go index 2230733346..79b873631c 100644 --- a/cmd/neofs-cli/modules/tree/add.go +++ b/cmd/neofs-cli/modules/tree/add.go @@ -34,6 +34,9 @@ func initAddCmd() { } func add(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.GetOrGenerate(cmd) var cnr cid.ID @@ -46,8 +49,6 @@ func add(cmd *cobra.Command, _ []string) { meta, err := parseMeta(cmd) common.ExitOnErr(cmd, "meta data parsing: %w", err) - ctx := cmd.Context() - cli, err := _client(ctx) common.ExitOnErr(cmd, "client: %w", err) diff --git a/cmd/neofs-cli/modules/tree/add_by_path.go b/cmd/neofs-cli/modules/tree/add_by_path.go index 17e413194a..2e7578b98f 100644 --- a/cmd/neofs-cli/modules/tree/add_by_path.go +++ b/cmd/neofs-cli/modules/tree/add_by_path.go @@ -40,6 +40,9 @@ func initAddByPathCmd() { } func addByPath(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.GetOrGenerate(cmd) cidRaw, _ := cmd.Flags().GetString(commonflags.CIDFlag) @@ -49,7 +52,6 @@ func addByPath(cmd *cobra.Command, _ []string) { common.ExitOnErr(cmd, "decode container ID string: %w", err) tid, _ := cmd.Flags().GetString(treeIDFlagKey) - ctx := cmd.Context() cli, err := _client(ctx) common.ExitOnErr(cmd, "client: %w", err) diff --git a/cmd/neofs-cli/modules/tree/get_by_path.go b/cmd/neofs-cli/modules/tree/get_by_path.go index eb7af4446f..074f16c289 100644 --- a/cmd/neofs-cli/modules/tree/get_by_path.go +++ b/cmd/neofs-cli/modules/tree/get_by_path.go @@ -40,6 +40,9 @@ func initGetByPathCmd() { } func getByPath(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.GetOrGenerate(cmd) cidRaw, _ := cmd.Flags().GetString(commonflags.CIDFlag) @@ -49,7 +52,6 @@ func getByPath(cmd *cobra.Command, _ []string) { common.ExitOnErr(cmd, "decode container ID string: %w", err) tid, _ := cmd.Flags().GetString(treeIDFlagKey) - ctx := cmd.Context() cli, err := _client(ctx) common.ExitOnErr(cmd, "client: %w", err) diff --git a/cmd/neofs-cli/modules/tree/list.go b/cmd/neofs-cli/modules/tree/list.go index 076cf1f1dd..bfef9c3e25 100644 --- a/cmd/neofs-cli/modules/tree/list.go +++ b/cmd/neofs-cli/modules/tree/list.go @@ -31,6 +31,9 @@ func initListCmd() { } func list(cmd *cobra.Command, _ []string) { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + pk := key.GetOrGenerate(cmd) cidString, _ := cmd.Flags().GetString(commonflags.CIDFlag) @@ -38,8 +41,6 @@ func list(cmd *cobra.Command, _ []string) { err := cnr.DecodeString(cidString) common.ExitOnErr(cmd, "decode container ID string: %w", err) - ctx := cmd.Context() - cli, err := _client(ctx) common.ExitOnErr(cmd, "client: %w", err) From 9900193e2699b1f741b59790ed9836d1da25b33f Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Tue, 13 Jun 2023 16:12:18 +0400 Subject: [PATCH 3/9] cli: Calculate API client timeouts from command context deadline Previously, function making API client dial used `--timeout` flag to set client timeouts. This could be at odds with provided context within which connection is expected to be opened. To reduce command timeout discrepancy, there is a need base the connection only on the context. Set context deadline as dial timeout of API client in `GetSDKClient` function. Signed-off-by: Leonard Lyubich --- cmd/neofs-cli/internal/client/sdk.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/cmd/neofs-cli/internal/client/sdk.go b/cmd/neofs-cli/internal/client/sdk.go index 5562949ee0..0258d48141 100644 --- a/cmd/neofs-cli/internal/client/sdk.go +++ b/cmd/neofs-cli/internal/client/sdk.go @@ -7,9 +7,9 @@ import ( "crypto/rand" "errors" "fmt" + "time" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common" - "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "github.com/nspcc-dev/neofs-node/pkg/network" "github.com/nspcc-dev/neofs-sdk-go/client" neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa" @@ -51,14 +51,16 @@ func GetSDKClient(ctx context.Context, cmd *cobra.Command, key *ecdsa.PrivateKey prmInit.ResolveNeoFSFailures() prmDial.SetServerURI(addr.URIAddr()) prmDial.SetContext(ctx) - if timeout := viper.GetDuration(commonflags.Timeout); timeout > 0 { - // In CLI we can only set a timeout for the whole operation. - // By also setting stream timeout we ensure that no operation hands - // for too long. - prmDial.SetTimeout(timeout) - prmDial.SetStreamTimeout(timeout) - - common.PrintVerbose(cmd, "Set request timeout to %s.", timeout) + + deadline, ok := ctx.Deadline() + if ok { + if timeout := time.Until(deadline); timeout > 0 { + // In CLI we can only set a timeout for the whole operation. + // By also setting stream timeout we ensure that no operation hands + // for too long. + prmDial.SetTimeout(timeout) + prmDial.SetStreamTimeout(timeout) + } } c.Init(prmInit) From 32fa5e6969c9dc01c904167310ba8db85ebb61e5 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Tue, 13 Jun 2023 16:41:57 +0400 Subject: [PATCH 4/9] cli: Increase default execution timeout in async-await commands Some CLI commands like `container create` are async-await. Previously, default execution timeout was 15s for such commands. Since more than one RPC is needed for theses commands (e.g. creation request and polling), there is a need to increase default timeout in waiting mode. Add `GetCommandContextWithAwait` and use it in `create`, `delete` and `set-eacl` commands of `container` section. Make command to time out after 1m if `--await` flag is set while `--timeout` one is omitted. Closes #2124. Signed-off-by: Leonard Lyubich --- CHANGELOG.md | 10 ++++++++++ cmd/neofs-cli/internal/commonflags/flags.go | 13 +++++++++++++ cmd/neofs-cli/modules/container/create.go | 12 ++++++++---- cmd/neofs-cli/modules/container/delete.go | 12 ++++++++---- cmd/neofs-cli/modules/container/set_eacl.go | 11 ++++++++--- cmd/neofs-cli/modules/container/util.go | 8 +++++++- 6 files changed, 54 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d0a26e8cd..2bcd98f60f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,19 @@ Changelog for NeoFS Node ### Removed +### Changed +- CLI `--timeout` flag configures whole execution timeout from now (#2124) +- CLI default timeout for commands with `--await` flag increased to 1m (#2124) + ### Updated ### Updating from v0.37.0 +CLI command timeouts (flag `--timeout`) now limit the total command execution +time and not single network operation. If any commands suddenly start to fail +on timeout, try increasing the value, for example, twice. Also note that the +execution of commands with the `--await` flag and without an explicitly +specified time period is now limited to 1 minute. This value can be changed with +`--timeout` flag. ## [0.37.0] - 2023-06-15 - Sogado diff --git a/cmd/neofs-cli/internal/commonflags/flags.go b/cmd/neofs-cli/internal/commonflags/flags.go index 932696cfb5..c1e7d75c7e 100644 --- a/cmd/neofs-cli/internal/commonflags/flags.go +++ b/cmd/neofs-cli/internal/commonflags/flags.go @@ -84,6 +84,19 @@ func Bind(cmd *cobra.Command) { _ = viper.BindPFlag(Timeout, ff.Lookup(Timeout)) } +// GetCommandContextWithAwait works like GetCommandContext but uses specified +// await timeout if 'timeout' flag is omitted and given boolean await flag is +// set. +func GetCommandContextWithAwait(cmd *cobra.Command, awaitFlag string, awaitTimeout time.Duration) (context.Context, context.CancelFunc) { + if !viper.IsSet(Timeout) { + if await, _ := cmd.Flags().GetBool(awaitFlag); await { + return getCommandContext(cmd, awaitTimeout) + } + } + + return GetCommandContext(cmd) +} + // GetCommandContext returns cmd context with timeout specified in 'timeout' flag // if the flag is set. func GetCommandContext(cmd *cobra.Command) (context.Context, context.CancelFunc) { diff --git a/cmd/neofs-cli/modules/container/create.go b/cmd/neofs-cli/modules/container/create.go index 62a38ddb42..e606466a83 100644 --- a/cmd/neofs-cli/modules/container/create.go +++ b/cmd/neofs-cli/modules/container/create.go @@ -38,7 +38,7 @@ var createContainerCmd = &cobra.Command{ Long: `Create new container and register it in the NeoFS. It will be stored in sidechain when inner ring will accepts it.`, Run: func(cmd *cobra.Command, args []string) { - ctx, cancel := commonflags.GetCommandContext(cmd) + ctx, cancel := getAwaitContext(cmd) defer cancel() placementPolicy, err := parseContainerPolicy(cmd, containerPolicy) @@ -134,17 +134,21 @@ It will be stored in sidechain when inner ring will accepts it.`, getPrm.SetClient(cli) getPrm.SetContainer(id) - for i := 0; i < awaitTimeout; i++ { + for { time.Sleep(1 * time.Second) + select { + case <-ctx.Done(): + common.ExitOnErr(cmd, "", errCreateTimeout) + default: + } + _, err := internalclient.GetContainer(ctx, getPrm) if err == nil { cmd.Println("container has been persisted on sidechain") return } } - - common.ExitOnErr(cmd, "", errCreateTimeout) } }, } diff --git a/cmd/neofs-cli/modules/container/delete.go b/cmd/neofs-cli/modules/container/delete.go index 925df66c84..ec2f5c763b 100644 --- a/cmd/neofs-cli/modules/container/delete.go +++ b/cmd/neofs-cli/modules/container/delete.go @@ -20,7 +20,7 @@ var deleteContainerCmd = &cobra.Command{ Long: `Delete existing container. Only owner of the container has a permission to remove container.`, Run: func(cmd *cobra.Command, args []string) { - ctx, cancel := commonflags.GetCommandContext(cmd) + ctx, cancel := getAwaitContext(cmd) defer cancel() id := parseContainerID(cmd) @@ -107,17 +107,21 @@ Only owner of the container has a permission to remove container.`, getPrm.SetClient(cli) getPrm.SetContainer(id) - for i := 0; i < awaitTimeout; i++ { + for { time.Sleep(1 * time.Second) + select { + case <-ctx.Done(): + common.ExitOnErr(cmd, "", errDeleteTimeout) + default: + } + _, err := internalclient.GetContainer(ctx, getPrm) if err != nil { cmd.Println("container has been removed:", containerID) return } } - - common.ExitOnErr(cmd, "", errDeleteTimeout) } }, } diff --git a/cmd/neofs-cli/modules/container/set_eacl.go b/cmd/neofs-cli/modules/container/set_eacl.go index c627aaf29f..0f7da4a1a6 100644 --- a/cmd/neofs-cli/modules/container/set_eacl.go +++ b/cmd/neofs-cli/modules/container/set_eacl.go @@ -24,7 +24,7 @@ var setExtendedACLCmd = &cobra.Command{ Long: `Set new extended ACL table for container. Container ID in EACL table will be substituted with ID from the CLI.`, Run: func(cmd *cobra.Command, args []string) { - ctx, cancel := commonflags.GetCommandContext(cmd) + ctx, cancel := getAwaitContext(cmd) defer cancel() id := parseContainerID(cmd) @@ -71,9 +71,15 @@ Container ID in EACL table will be substituted with ID from the CLI.`, getEACLPrm.SetClient(cli) getEACLPrm.SetContainer(id) - for i := 0; i < awaitTimeout; i++ { + for { time.Sleep(1 * time.Second) + select { + case <-ctx.Done(): + common.ExitOnErr(cmd, "", errSetEACLTimeout) + default: + } + res, err := internalclient.EACL(ctx, getEACLPrm) if err == nil { // compare binary values because EACL could have been set already @@ -90,7 +96,6 @@ Container ID in EACL table will be substituted with ID from the CLI.`, } } - common.ExitOnErr(cmd, "", errSetEACLTimeout) } }, } diff --git a/cmd/neofs-cli/modules/container/util.go b/cmd/neofs-cli/modules/container/util.go index 19a2015ea9..fcbb8d3849 100644 --- a/cmd/neofs-cli/modules/container/util.go +++ b/cmd/neofs-cli/modules/container/util.go @@ -1,7 +1,9 @@ package container import ( + "context" "errors" + "time" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" @@ -13,7 +15,7 @@ import ( const ( attributeDelimiter = "=" - awaitTimeout = 120 // in seconds + awaitTimeout = time.Minute ) var ( @@ -55,3 +57,7 @@ func getSession(cmd *cobra.Command) *session.Container { return &res } + +func getAwaitContext(cmd *cobra.Command) (context.Context, context.CancelFunc) { + return commonflags.GetCommandContextWithAwait(cmd, "await", awaitTimeout) +} From 9e9c5adea4bdeb669d681f29c5ece2351fe8daef Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Wed, 14 Jun 2023 15:23:58 +0400 Subject: [PATCH 5/9] cli: Write how `--await` flag affects default timeout in help Signed-off-by: Leonard Lyubich --- cmd/neofs-cli/modules/container/create.go | 3 ++- cmd/neofs-cli/modules/container/delete.go | 3 ++- cmd/neofs-cli/modules/container/set_eacl.go | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cmd/neofs-cli/modules/container/create.go b/cmd/neofs-cli/modules/container/create.go index e606466a83..4e493811f9 100644 --- a/cmd/neofs-cli/modules/container/create.go +++ b/cmd/neofs-cli/modules/container/create.go @@ -167,7 +167,8 @@ func initContainerCreateCmd() { )) flags.StringVarP(&containerPolicy, "policy", "p", "", "QL-encoded or JSON-encoded placement policy or path to file with it") flags.StringSliceVarP(&containerAttributes, "attributes", "a", nil, "Comma separated pairs of container attributes in form of Key1=Value1,Key2=Value2") - flags.BoolVar(&containerAwait, "await", false, "Block execution until container is persisted") + flags.BoolVar(&containerAwait, "await", false, fmt.Sprintf("Block execution until container is persisted. "+ + "Increases default execution timeout to %.0fs", awaitTimeout.Seconds())) // simple %s notation prints 1m0s https://github.com/golang/go/issues/39064 flags.StringVar(&containerName, "name", "", "Container name attribute") flags.BoolVar(&containerNoTimestamp, "disable-timestamp", false, "Disable timestamp container attribute") flags.StringVar(&containerSubnet, "subnet", "", "String representation of container subnetwork") diff --git a/cmd/neofs-cli/modules/container/delete.go b/cmd/neofs-cli/modules/container/delete.go index ec2f5c763b..4ffd6a9590 100644 --- a/cmd/neofs-cli/modules/container/delete.go +++ b/cmd/neofs-cli/modules/container/delete.go @@ -134,6 +134,7 @@ func initContainerDeleteCmd() { flags.StringP(commonflags.RPC, commonflags.RPCShorthand, commonflags.RPCDefault, commonflags.RPCUsage) flags.StringVar(&containerID, commonflags.CIDFlag, "", commonflags.CIDFlagUsage) - flags.BoolVar(&containerAwait, "await", false, "Block execution until container is removed") + flags.BoolVar(&containerAwait, "await", false, fmt.Sprintf("Block execution until container is removed. "+ + "Increases default execution timeout to %.0fs", awaitTimeout.Seconds())) // simple %s notation prints 1m0s https://github.com/golang/go/issues/39064 flags.BoolP(commonflags.ForceFlag, commonflags.ForceFlagShorthand, false, "Skip validation checks (ownership, presence of LOCK objects)") } diff --git a/cmd/neofs-cli/modules/container/set_eacl.go b/cmd/neofs-cli/modules/container/set_eacl.go index 0f7da4a1a6..938df114bb 100644 --- a/cmd/neofs-cli/modules/container/set_eacl.go +++ b/cmd/neofs-cli/modules/container/set_eacl.go @@ -3,6 +3,7 @@ package container import ( "bytes" "errors" + "fmt" "time" internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client" @@ -106,6 +107,7 @@ func initContainerSetEACLCmd() { flags := setExtendedACLCmd.Flags() flags.StringVar(&containerID, commonflags.CIDFlag, "", commonflags.CIDFlagUsage) flags.StringVar(&flagVarsSetEACL.srcPath, "table", "", "path to file with JSON or binary encoded EACL table") - flags.BoolVar(&containerAwait, "await", false, "block execution until EACL is persisted") + flags.BoolVar(&containerAwait, "await", false, fmt.Sprintf("block execution until EACL is persisted. "+ + "Increases default execution timeout to %.0fs", awaitTimeout.Seconds())) // simple %s notation prints 1m0s https://github.com/golang/go/issues/39064 flags.BoolVar(&flagVarsSetEACL.noPreCheck, "no-precheck", false, "do not pre-check the extensibility of the container ACL") } From 976e535b7384b891bf2df619bb67cff8b5b35908 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 16 Jun 2023 14:57:43 +0400 Subject: [PATCH 6/9] cli/container: Write message about accepted `set-eacl` request CLI `container set-eacl` command can be called without no expectation of success. In this case, if request is successfully sent, command prints nothing and exits with 0 code. On the one hand, the code implies the success of the action, on the other hand, the outcome can be perceived ambiguously. It's worth to write clear message about what's going on. Print message about accepted request to modify the container eACL speaking explicitly of potential incompleteness. Signed-off-by: Leonard Lyubich --- cmd/neofs-cli/modules/container/set_eacl.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/neofs-cli/modules/container/set_eacl.go b/cmd/neofs-cli/modules/container/set_eacl.go index 938df114bb..9cfef7e9cd 100644 --- a/cmd/neofs-cli/modules/container/set_eacl.go +++ b/cmd/neofs-cli/modules/container/set_eacl.go @@ -62,6 +62,8 @@ Container ID in EACL table will be substituted with ID from the CLI.`, _, err := internalclient.SetEACL(ctx, setEACLPrm) common.ExitOnErr(cmd, "rpc error: %w", err) + cmd.Println("eACL modification request accepted for processing (the operation may not be completed yet)") + if containerAwait { exp, err := eaclTable.Marshal() common.ExitOnErr(cmd, "broken EACL table: %w", err) From dc1a70b5d10fe77b1cfd7f534bdecfc17df6538a Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 16 Jun 2023 15:01:18 +0400 Subject: [PATCH 7/9] cli/container: Clarify message about accepted `create` request CLI `container create` command prints container ID if request was accepted (the ID can be received from the success response only), however, it does not say anything about the completion of the operation. Write clear message about accepted request to make operation to be approved. Signed-off-by: Leonard Lyubich --- cmd/neofs-cli/modules/container/create.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/neofs-cli/modules/container/create.go b/cmd/neofs-cli/modules/container/create.go index 4e493811f9..e1052f2776 100644 --- a/cmd/neofs-cli/modules/container/create.go +++ b/cmd/neofs-cli/modules/container/create.go @@ -125,6 +125,7 @@ It will be stored in sidechain when inner ring will accepts it.`, id := res.ID() + cmd.Println("container creation request accepted for processing (the operation may not be completed yet)") cmd.Println("container ID:", id) if containerAwait { From c3259a22b6f8976ec6d3893594f5cb6dffabb16a Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 16 Jun 2023 15:04:49 +0400 Subject: [PATCH 8/9] cli/container: Improve message about accepted `delete` request CLI `container delete` command output `container delete method invoked` can be difficult to interpret by the average user. Signed-off-by: Leonard Lyubich --- cmd/neofs-cli/modules/container/delete.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/neofs-cli/modules/container/delete.go b/cmd/neofs-cli/modules/container/delete.go index 4ffd6a9590..2f42edcef5 100644 --- a/cmd/neofs-cli/modules/container/delete.go +++ b/cmd/neofs-cli/modules/container/delete.go @@ -98,7 +98,7 @@ Only owner of the container has a permission to remove container.`, _, err := internalclient.DeleteContainer(ctx, delPrm) common.ExitOnErr(cmd, "rpc error: %w", err) - cmd.Println("container delete method invoked") + cmd.Println("container removal request accepted for processing (the operation may not be completed yet)") if containerAwait { cmd.Println("awaiting...") From 8cebfb4c9d9d8c216a8845eb0ad0b25b7deff28d Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 16 Jun 2023 15:15:49 +0400 Subject: [PATCH 9/9] cli: Replace looped `time.Sleep` with `time.Timer` Signed-off-by: Leonard Lyubich --- cmd/neofs-cli/modules/container/create.go | 9 ++++++--- cmd/neofs-cli/modules/container/delete.go | 9 ++++++--- cmd/neofs-cli/modules/container/set_eacl.go | 9 ++++++--- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/cmd/neofs-cli/modules/container/create.go b/cmd/neofs-cli/modules/container/create.go index e1052f2776..a3eea1d0b5 100644 --- a/cmd/neofs-cli/modules/container/create.go +++ b/cmd/neofs-cli/modules/container/create.go @@ -135,13 +135,16 @@ It will be stored in sidechain when inner ring will accepts it.`, getPrm.SetClient(cli) getPrm.SetContainer(id) - for { - time.Sleep(1 * time.Second) + const waitInterval = time.Second + t := time.NewTimer(waitInterval) + defer t.Stop() + + for ; ; t.Reset(waitInterval) { select { case <-ctx.Done(): common.ExitOnErr(cmd, "", errCreateTimeout) - default: + case <-t.C: } _, err := internalclient.GetContainer(ctx, getPrm) diff --git a/cmd/neofs-cli/modules/container/delete.go b/cmd/neofs-cli/modules/container/delete.go index 2f42edcef5..1e05737193 100644 --- a/cmd/neofs-cli/modules/container/delete.go +++ b/cmd/neofs-cli/modules/container/delete.go @@ -107,13 +107,16 @@ Only owner of the container has a permission to remove container.`, getPrm.SetClient(cli) getPrm.SetContainer(id) - for { - time.Sleep(1 * time.Second) + const waitInterval = time.Second + t := time.NewTimer(waitInterval) + defer t.Stop() + + for ; ; t.Reset(waitInterval) { select { case <-ctx.Done(): common.ExitOnErr(cmd, "", errDeleteTimeout) - default: + case <-t.C: } _, err := internalclient.GetContainer(ctx, getPrm) diff --git a/cmd/neofs-cli/modules/container/set_eacl.go b/cmd/neofs-cli/modules/container/set_eacl.go index 9cfef7e9cd..446ce39f97 100644 --- a/cmd/neofs-cli/modules/container/set_eacl.go +++ b/cmd/neofs-cli/modules/container/set_eacl.go @@ -74,13 +74,16 @@ Container ID in EACL table will be substituted with ID from the CLI.`, getEACLPrm.SetClient(cli) getEACLPrm.SetContainer(id) - for { - time.Sleep(1 * time.Second) + const waitInterval = time.Second + t := time.NewTimer(waitInterval) + defer t.Stop() + + for ; ; t.Reset(waitInterval) { select { case <-ctx.Done(): common.ExitOnErr(cmd, "", errSetEACLTimeout) - default: + case <-t.C: } res, err := internalclient.EACL(ctx, getEACLPrm)