From bf8274f6e2afb28a624b75859991cb164cb367ff Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Wed, 12 Oct 2022 17:02:43 +0200 Subject: [PATCH] feat: --reset flag on swarm limit command (#9310) * feat: --reset flag on swarm limit command This flag allows to the user to reset limits to default values. Signed-off-by: Antonio Navarro Perez * Use adjusted default limits and remove already fixed FIXME Signed-off-by: Antonio Navarro Perez * Apply suggestions from code review Co-authored-by: Gus Eggert * Return correct defaults * Remove resetting all values from a map. Signed-off-by: Antonio Navarro Perez Signed-off-by: Antonio Navarro Perez Co-authored-by: Gus Eggert --- core/commands/swarm.go | 29 ++++++--- core/node/libp2p/rcmgr.go | 98 ++++++++++++++++++++++++++++++ core/node/libp2p/rcmgr_defaults.go | 1 - test/sharness/t0139-swarm-rcmgr.sh | 16 +++++ 4 files changed, 135 insertions(+), 9 deletions(-) diff --git a/core/commands/swarm.go b/core/commands/swarm.go index eb648a3c2..4594f07bd 100644 --- a/core/commands/swarm.go +++ b/core/commands/swarm.go @@ -63,10 +63,11 @@ ipfs peers in the internet. } const ( - swarmVerboseOptionName = "verbose" - swarmStreamsOptionName = "streams" - swarmLatencyOptionName = "latency" - swarmDirectionOptionName = "direction" + swarmVerboseOptionName = "verbose" + swarmStreamsOptionName = "streams" + swarmLatencyOptionName = "latency" + swarmDirectionOptionName = "direction" + swarmResetLimitsOptionName = "reset" ) type peeringResult struct { @@ -387,6 +388,9 @@ Changes made via command line are persisted in the Swarm.ResourceMgr.Limits fiel cmds.StringArg("scope", true, false, "scope of the limit"), cmds.FileArg("limit.json", false, false, "limits to be set").EnableStdin(), }, + Options: []cmds.Option{ + cmds.BoolOption(swarmResetLimitsOptionName, "reset limit to default"), + }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { node, err := cmdenv.GetNode(env) if err != nil { @@ -418,10 +422,19 @@ Changes made via command line are persisted in the Swarm.ResourceMgr.Limits fiel } } - // get scope limit - result, err := libp2p.NetLimit(node.ResourceManager, scope) - if err != nil { - return err + var result rcmgr.BaseLimit + _, reset := req.Options[swarmResetLimitsOptionName] + if reset { + result, err = libp2p.NetResetLimit(node.ResourceManager, node.Repo, scope) + if err != nil { + return err + } + } else { + // get scope limit + result, err = libp2p.NetLimit(node.ResourceManager, scope) + if err != nil { + return err + } } b := new(bytes.Buffer) diff --git a/core/node/libp2p/rcmgr.go b/core/node/libp2p/rcmgr.go index c24d03108..c9a04338a 100644 --- a/core/node/libp2p/rcmgr.go +++ b/core/node/libp2p/rcmgr.go @@ -347,3 +347,101 @@ func NetSetLimit(mgr network.ResourceManager, repo repo.Repo, scope string, limi return nil } + +// NetResetLimit resets ResourceManager limits to defaults. The limits take effect immediately, and are also persisted to the repo config. +func NetResetLimit(mgr network.ResourceManager, repo repo.Repo, scope string) (rcmgr.BaseLimit, error) { + var result rcmgr.BaseLimit + + setLimit := func(s network.ResourceScope, l rcmgr.Limit) error { + limiter, ok := s.(rcmgr.ResourceScopeLimiter) + if !ok { + return ErrNoResourceMgr + } + + limiter.SetLimit(l) + return nil + } + + cfg, err := repo.Config() + if err != nil { + return result, fmt.Errorf("reading config to reset limit: %w", err) + } + + defaults := adjustedDefaultLimits(cfg.Swarm) + + if cfg.Swarm.ResourceMgr.Limits == nil { + cfg.Swarm.ResourceMgr.Limits = &rcmgr.LimitConfig{} + } + configLimits := cfg.Swarm.ResourceMgr.Limits + + var setConfigFunc func() rcmgr.BaseLimit + switch { + case scope == config.ResourceMgrSystemScope: + err = mgr.ViewSystem(func(s network.ResourceScope) error { return setLimit(s, &defaults.System) }) + setConfigFunc = func() rcmgr.BaseLimit { + configLimits.System = defaults.System + return defaults.System + } + case scope == config.ResourceMgrTransientScope: + err = mgr.ViewTransient(func(s network.ResourceScope) error { return setLimit(s, &defaults.Transient) }) + setConfigFunc = func() rcmgr.BaseLimit { + configLimits.Transient = defaults.Transient + return defaults.Transient + } + case strings.HasPrefix(scope, config.ResourceMgrServiceScopePrefix): + svc := strings.TrimPrefix(scope, config.ResourceMgrServiceScopePrefix) + + err = mgr.ViewService(svc, func(s network.ServiceScope) error { return setLimit(s, &defaults.ServiceDefault) }) + setConfigFunc = func() rcmgr.BaseLimit { + if configLimits.Service == nil { + configLimits.Service = map[string]rcmgr.BaseLimit{} + } + configLimits.Service[svc] = defaults.ServiceDefault + return defaults.ServiceDefault + } + case strings.HasPrefix(scope, config.ResourceMgrProtocolScopePrefix): + proto := strings.TrimPrefix(scope, config.ResourceMgrProtocolScopePrefix) + + err = mgr.ViewProtocol(protocol.ID(proto), func(s network.ProtocolScope) error { return setLimit(s, &defaults.ProtocolDefault) }) + setConfigFunc = func() rcmgr.BaseLimit { + if configLimits.Protocol == nil { + configLimits.Protocol = map[protocol.ID]rcmgr.BaseLimit{} + } + configLimits.Protocol[protocol.ID(proto)] = defaults.ProtocolDefault + + return defaults.ProtocolDefault + } + case strings.HasPrefix(scope, config.ResourceMgrPeerScopePrefix): + p := strings.TrimPrefix(scope, config.ResourceMgrPeerScopePrefix) + + var pid peer.ID + pid, err = peer.Decode(p) + if err != nil { + return result, fmt.Errorf("invalid peer ID: %q: %w", p, err) + } + + err = mgr.ViewPeer(pid, func(s network.PeerScope) error { return setLimit(s, &defaults.PeerDefault) }) + setConfigFunc = func() rcmgr.BaseLimit { + if configLimits.Peer == nil { + configLimits.Peer = map[peer.ID]rcmgr.BaseLimit{} + } + configLimits.Peer[pid] = defaults.PeerDefault + + return defaults.PeerDefault + } + default: + return result, fmt.Errorf("invalid scope %q", scope) + } + + if err != nil { + return result, fmt.Errorf("resetting new limits on resource manager: %w", err) + } + + result = setConfigFunc() + + if err := repo.SetConfig(cfg); err != nil { + return result, fmt.Errorf("writing new limits to repo config: %w", err) + } + + return result, nil +} diff --git a/core/node/libp2p/rcmgr_defaults.go b/core/node/libp2p/rcmgr_defaults.go index e09a59845..8d77e56aa 100644 --- a/core/node/libp2p/rcmgr_defaults.go +++ b/core/node/libp2p/rcmgr_defaults.go @@ -21,7 +21,6 @@ import ( func adjustedDefaultLimits(cfg config.SwarmConfig) rcmgr.LimitConfig { // Run checks to avoid introducing regressions if os.Getenv("IPFS_CHECK_RCMGR_DEFAULTS") != "" { - // FIXME: Broken. Being tracked in https://github.com/ipfs/go-ipfs/issues/8949. checkImplicitDefaults() } defaultLimits := rcmgr.DefaultLimits diff --git a/test/sharness/t0139-swarm-rcmgr.sh b/test/sharness/t0139-swarm-rcmgr.sh index 3844c99bb..15b9a0089 100755 --- a/test/sharness/t0139-swarm-rcmgr.sh +++ b/test/sharness/t0139-swarm-rcmgr.sh @@ -54,6 +54,22 @@ test_expect_success 'ResourceMgr enabled: swarm limit' ' jq -e .StreamsInbound < json && jq -e .StreamsOutbound < json ' +test_expect_success 'ResourceMgr enabled: swarm limit reset' ' + ipfs swarm limit system --reset --enc=json 2> reset && + ipfs swarm limit system --enc=json 2> actual && + test_cmp reset actual +' + +test_expect_success 'ResourceMgr enabled: swarm limit reset on map values' ' + ipfs swarm limit peer:12D3KooWL7i1T9VSPeF8AgQApbyM51GNKZsYPvNvL347aMDmvNzG --reset --enc=json 2> reset && + ipfs swarm limit peer:12D3KooWL7i1T9VSPeF8AgQApbyM51GNKZsYPvNvL347aMDmvNzG --enc=json 2> actual && + test_cmp reset actual +' + +test_expect_success 'ResourceMgr enabled: scope is required using reset flag' ' + test_expect_code 1 ipfs swarm limit --reset 2> actual && + test_should_contain "Error: argument \"scope\" is required" actual +' test_expect_success 'connected: swarm stats all working properly' ' test_expect_code 0 ipfs swarm stats all