Skip to content

Commit

Permalink
cli: Use --timeout flag as a command exec timeout (#2135)
Browse files Browse the repository at this point in the history
* closes #2124
  • Loading branch information
roman-khimov committed Jun 16, 2023
2 parents 04ce9e3 + 8cebfb4 commit 93733ff
Show file tree
Hide file tree
Showing 47 changed files with 387 additions and 182 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
80 changes: 40 additions & 40 deletions cmd/neofs-cli/internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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
}
Expand Down Expand Up @@ -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()
}
Expand Down Expand Up @@ -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)
}
Expand All @@ -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
}
Expand All @@ -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
}
Expand All @@ -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
}
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand All @@ -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
}

Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
}
Expand Down Expand Up @@ -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())
Expand All @@ -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)
}
Expand Down Expand Up @@ -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())
Expand All @@ -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)
}
Expand Down Expand Up @@ -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())
Expand All @@ -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)
}
Expand Down Expand Up @@ -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)
Expand All @@ -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)
}
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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())
Expand All @@ -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)
}
Expand Down Expand Up @@ -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
}
Expand Down
28 changes: 15 additions & 13 deletions cmd/neofs-cli/internal/client/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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.
Expand All @@ -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)
Expand Down
Loading

0 comments on commit 93733ff

Please sign in to comment.