Skip to content

Commit 3316b0d

Browse files
committed
don't panic when rcmgr enabled but no config & add sharness tests
1 parent 281b3a5 commit 3316b0d

File tree

3 files changed

+116
-19
lines changed

3 files changed

+116
-19
lines changed

core/commands/swarm.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,7 @@ It is possible to use this command to inspect and tweak limits at runtime:
381381
$ vi limit.json
382382
$ ipfs swarm limit system limit.json
383383
384-
Changes made via command line are discarded on node shutdown.
385-
For permanent limits set Swarm.ResourceMgr.Limits in the $IPFS_PATH/config file.
384+
Changes made via command line are persisted in the Swarm.ResourceMgr.Limits field of the $IPFS_PATH/config file.
386385
`},
387386
Arguments: []cmds.Argument{
388387
cmds.StringArg("scope", true, false, "scope of the limit"),

core/node/libp2p/rcmgr.go

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,13 @@ func ResourceManager(cfg config.SwarmConfig) func(fx.Lifecycle, repo.Repo) (netw
4949
}
5050

5151
defaultLimits := adjustedDefaultLimits(cfg)
52-
limiter, err := rcmgr.NewLimiter(*cfg.ResourceMgr.Limits, defaultLimits)
52+
53+
var limits rcmgr.BasicLimiterConfig
54+
if cfg.ResourceMgr.Limits != nil {
55+
limits = *cfg.ResourceMgr.Limits
56+
}
57+
58+
limiter, err := rcmgr.NewLimiter(limits, defaultLimits)
5359
if err != nil {
5460
return nil, opts, err
5561
}
@@ -313,39 +319,48 @@ func NetSetLimit(mgr network.ResourceManager, repo repo.Repo, scope string, limi
313319
return fmt.Errorf("reading config to set limit: %w", err)
314320
}
315321

316-
setConfigLimit := func(f func(c *rcmgr.BasicLimiterConfig)) {
317-
if cfg.Swarm.ResourceMgr.Limits == nil {
318-
cfg.Swarm.ResourceMgr.Limits = &rcmgr.BasicLimiterConfig{}
319-
}
320-
f(cfg.Swarm.ResourceMgr.Limits)
322+
if cfg.Swarm.ResourceMgr.Limits == nil {
323+
cfg.Swarm.ResourceMgr.Limits = &rcmgr.BasicLimiterConfig{}
321324
}
325+
configLimits := cfg.Swarm.ResourceMgr.Limits
322326

327+
var setConfigFunc func()
323328
switch {
324329
case scope == config.ResourceMgrSystemScope:
325330
err = mgr.ViewSystem(func(s network.ResourceScope) error {
326331
return setLimit(s)
327332
})
328-
setConfigLimit(func(c *rcmgr.BasicLimiterConfig) { c.System = &limit })
333+
setConfigFunc = func() { configLimits.System = &limit }
329334

330335
case scope == config.ResourceMgrTransientScope:
331336
err = mgr.ViewTransient(func(s network.ResourceScope) error {
332337
return setLimit(s)
333338
})
334-
setConfigLimit(func(c *rcmgr.BasicLimiterConfig) { c.Transient = &limit })
339+
setConfigFunc = func() { configLimits.Transient = &limit }
335340

336341
case strings.HasPrefix(scope, config.ResourceMgrServiceScopePrefix):
337342
svc := strings.TrimPrefix(scope, config.ResourceMgrServiceScopePrefix)
338343
err = mgr.ViewService(svc, func(s network.ServiceScope) error {
339344
return setLimit(s)
340345
})
341-
setConfigLimit(func(c *rcmgr.BasicLimiterConfig) { c.Service[svc] = limit })
346+
setConfigFunc = func() {
347+
if configLimits.Service == nil {
348+
configLimits.Service = map[string]rcmgr.BasicLimitConfig{}
349+
}
350+
configLimits.Service[svc] = limit
351+
}
342352

343353
case strings.HasPrefix(scope, config.ResourceMgrProtocolScopePrefix):
344354
proto := strings.TrimPrefix(scope, config.ResourceMgrProtocolScopePrefix)
345355
err = mgr.ViewProtocol(protocol.ID(proto), func(s network.ProtocolScope) error {
346356
return setLimit(s)
347357
})
348-
setConfigLimit(func(c *rcmgr.BasicLimiterConfig) { c.Service[proto] = limit })
358+
setConfigFunc = func() {
359+
if configLimits.Protocol == nil {
360+
configLimits.Protocol = map[string]rcmgr.BasicLimitConfig{}
361+
}
362+
configLimits.Protocol[proto] = limit
363+
}
349364

350365
case strings.HasPrefix(scope, config.ResourceMgrPeerScopePrefix):
351366
p := strings.TrimPrefix(scope, config.ResourceMgrPeerScopePrefix)
@@ -357,15 +372,25 @@ func NetSetLimit(mgr network.ResourceManager, repo repo.Repo, scope string, limi
357372
err = mgr.ViewPeer(pid, func(s network.PeerScope) error {
358373
return setLimit(s)
359374
})
360-
setConfigLimit(func(c *rcmgr.BasicLimiterConfig) { c.Service[p] = limit })
375+
setConfigFunc = func() {
376+
if configLimits.Peer == nil {
377+
configLimits.Peer = map[string]rcmgr.BasicLimitConfig{}
378+
}
379+
configLimits.Peer[p] = limit
380+
}
361381

362382
default:
363383
return fmt.Errorf("invalid scope %q", scope)
364384
}
365385

366386
if err != nil {
367-
return err
387+
return fmt.Errorf("setting new limits on resource manager: %w", err)
388+
}
389+
390+
if cfg.Swarm.ResourceMgr.Limits == nil {
391+
cfg.Swarm.ResourceMgr.Limits = &rcmgr.BasicLimiterConfig{}
368392
}
393+
setConfigFunc()
369394

370395
if err := repo.SetConfig(cfg); err != nil {
371396
return fmt.Errorf("writing new limits to repo config: %w", err)

test/sharness/t0139-swarm-rcmgr.sh

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ test_expect_success 'disconnected: swarm stats requires running daemon' '
1818
'
1919

2020
# swarm limit|stats should fail in online mode by default
21-
# because Resource Manager is opt-in for now
21+
# because Resource Manager is opt-in
2222
test_launch_ipfs_daemon
2323

2424
test_expect_success 'ResourceMgr disabled by default: swarm limit requires Swarm.ResourceMgr.Enabled' '
@@ -30,20 +30,31 @@ test_expect_success 'ResourceMgr disabled by default: swarm stats requires Swarm
3030
test_should_contain "missing ResourceMgr" actual
3131
'
3232

33-
# swarm limit|stat should work when Swarm.ResourceMgr.Enabled
3433
test_kill_ipfs_daemon
3534

36-
test_expect_success "test_config_set succeeds" "
35+
test_expect_success "setting an invalid limit should result in a failure" "
36+
test_expect_code 1 ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 'asdf' 2> actual &&
37+
test_should_contain 'failed to unmarshal' actual
38+
"
39+
40+
# swarm limit|stat should work when Swarm.ResourceMgr.Enabled
41+
test_expect_success "test enabling resource manager" "
3742
ipfs config --json Swarm.ResourceMgr.Enabled true &&
38-
ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 99999
43+
ipfs config --json Swarm.ResourceMgr &&
44+
jq -e '.Swarm.ResourceMgr.Enabled == true'
3945
"
4046

4147
test_launch_ipfs_daemon
4248

49+
test_expect_success "test setting system conns limit" "
50+
ipfs config --json Swarm.ResourceMgr.Enabled true &&
51+
ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 99999
52+
"
53+
4354
# every scope has the same fields, so we only inspect System
4455
test_expect_success 'ResourceMgr enabled: swarm limit' '
4556
ipfs swarm limit system --enc=json | tee json &&
46-
jq -e ".Conns == 99999" < json &&
57+
jq -e .Conns < json &&
4758
jq -e .ConnsInbound < json &&
4859
jq -e .ConnsOutbound < json &&
4960
jq -e .FD < json &&
@@ -65,6 +76,20 @@ test_expect_success 'ResourceMgr enabled: swarm stats' '
6576
jq -e .Transient.Memory < json
6677
'
6778

79+
# shut down the daemon, set a limit in the config, and verify that it's applied
80+
test_kill_ipfs_daemon
81+
82+
test_expect_success "set system conn limit" "
83+
ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 99999
84+
"
85+
86+
test_launch_ipfs_daemon
87+
88+
test_expect_success 'ResourceMgr enabled: swarm limit' '
89+
ipfs swarm limit system --enc=json | tee json &&
90+
jq -e ".Conns == 99999" < json
91+
'
92+
6893
test_expect_success 'Set system memory limit while the daemon is running' '
6994
ipfs swarm limit system | jq ".Memory = 99998" > system.json &&
7095
ipfs swarm limit system system.json
@@ -78,5 +103,53 @@ test_expect_success 'The new system limits are in the swarm limit output' '
78103
ipfs swarm limit system --enc=json | jq -e ".Memory == 99998"
79104
'
80105

106+
# now test all the other scopes
107+
test_expect_success 'Set limit on transient scope' '
108+
ipfs swarm limit transient | jq ".Memory = 88888" > transient.json &&
109+
ipfs swarm limit transient transient.json &&
110+
jq -e ".Swarm.ResourceMgr.Limits.Transient.Memory == 88888" < "$IPFS_PATH/config" &&
111+
ipfs swarm limit transient --enc=json | tee limits &&
112+
jq -e ".Memory == 88888" < limits
113+
'
114+
115+
test_expect_success 'Set limit on service scope' '
116+
ipfs swarm limit svc:foo | jq ".Memory = 77777" > service-foo.json &&
117+
ipfs swarm limit svc:foo service-foo.json --enc=json &&
118+
jq -e ".Swarm.ResourceMgr.Limits.Service.foo.Memory == 77777" < "$IPFS_PATH/config" &&
119+
ipfs swarm limit svc:foo --enc=json | tee limits &&
120+
jq -e ".Memory == 77777" < limits
121+
'
122+
123+
test_expect_success 'Set limit on protocol scope' '
124+
ipfs swarm limit proto:foo | jq ".Memory = 66666" > proto-foo.json &&
125+
ipfs swarm limit proto:foo proto-foo.json --enc=json &&
126+
jq -e ".Swarm.ResourceMgr.Limits.Protocol.foo.Memory == 66666" < "$IPFS_PATH/config" &&
127+
ipfs swarm limit proto:foo --enc=json | tee limits &&
128+
jq -e ".Memory == 66666" < limits
129+
'
130+
131+
# any valid peer id
132+
PEER_ID=QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN
133+
134+
test_expect_success 'Set limit on peer scope' '
135+
ipfs swarm limit peer:$PEER_ID | jq ".Memory = 66666" > peer-$PEER_ID.json &&
136+
ipfs swarm limit peer:$PEER_ID peer-$PEER_ID.json --enc=json &&
137+
jq -e ".Swarm.ResourceMgr.Limits.Peer.${PEER_ID}.Memory == 66666" < "$IPFS_PATH/config" &&
138+
ipfs swarm limit peer:$PEER_ID --enc=json | tee limits &&
139+
jq -e ".Memory == 66666" < limits
140+
'
141+
142+
test_expect_success 'Get limit for peer scope with an invalid peer ID' '
143+
test_expect_code 1 ipfs swarm limit peer:foo 2> actual &&
144+
test_should_contain "invalid peer ID" actual
145+
'
146+
147+
test_expect_success 'Set limit for peer scope with an invalid peer ID' '
148+
echo "{\"Memory\": 99}" > invalid-peer-id.json &&
149+
test_expect_code 1 ipfs swarm limit peer:foo invalid-peer-id.json 2> actual &&
150+
test_should_contain "invalid peer ID" actual
151+
'
152+
81153
test_kill_ipfs_daemon
154+
82155
test_done

0 commit comments

Comments
 (0)