1
1
package commands
2
2
3
3
import (
4
- "bytes"
5
4
"context"
6
5
"encoding/json"
7
6
"errors"
8
7
"fmt"
9
8
"io"
10
9
"path"
11
10
"sort"
11
+ "strconv"
12
12
"sync"
13
+ "text/tabwriter"
13
14
"time"
14
15
15
- "github.com/ipfs/go-libipfs/files"
16
16
"github.com/ipfs/kubo/commands"
17
17
"github.com/ipfs/kubo/config"
18
18
"github.com/ipfs/kubo/core/commands/cmdenv"
@@ -57,8 +57,8 @@ ipfs peers in the internet.
57
57
"filters" : swarmFiltersCmd ,
58
58
"peers" : swarmPeersCmd ,
59
59
"peering" : swarmPeeringCmd ,
60
- "stats " : swarmStatsCmd , // libp2p Network Resource Manager
61
- "limit" : swarmLimitCmd , // libp2p Network Resource Manager
60
+ "resources " : swarmResourcesCmd , // libp2p Network Resource Manager
61
+
62
62
},
63
63
}
64
64
@@ -323,30 +323,15 @@ var swarmPeersCmd = &cmds.Command{
323
323
Type : connInfos {},
324
324
}
325
325
326
- var swarmStatsCmd = & cmds.Command {
326
+ var swarmResourcesCmd = & cmds.Command {
327
327
Status : cmds .Experimental ,
328
328
Helptext : cmds.HelpText {
329
- Tagline : "Report resource usage for a scope." ,
330
- LongDescription : `Report resource usage for a scope.
331
- The scope can be one of the following:
332
- - system -- reports the system aggregate resource usage.
333
- - transient -- reports the transient resource usage.
334
- - svc:<service> -- reports the resource usage of a specific service.
335
- - proto:<proto> -- reports the resource usage of a specific protocol.
336
- - peer:<peer> -- reports the resource usage of a specific peer.
337
- - all -- reports the resource usage for all currently active scopes.
338
-
339
- The output of this command is JSON.
340
-
341
- To see all resources that are close to hitting their respective limit, one can do something like:
342
- ipfs swarm stats --min-used-limit-perc=90 all
329
+ Tagline : "Get a summary of all resources accounted for by the libp2p Resource Manager." ,
330
+ LongDescription : `
331
+ Get a summary of all resources accounted for by the libp2p Resource Manager.
332
+ This includes the limits and the usage against those limits.
333
+ This can output a human readable table and JSON encoding.
343
334
` },
344
- Arguments : []cmds.Argument {
345
- cmds .StringArg ("scope" , true , false , "scope of the stat report" ),
346
- },
347
- Options : []cmds.Option {
348
- cmds .IntOption (swarmUsedResourcesPercentageName , "Only display resources that are using above the specified percentage of their respective limit" ),
349
- },
350
335
Run : func (req * cmds.Request , res cmds.ResponseEmitter , env cmds.Environment ) error {
351
336
node , err := cmdenv .GetNode (env )
352
337
if err != nil {
@@ -357,128 +342,68 @@ To see all resources that are close to hitting their respective limit, one can d
357
342
return libp2p .ErrNoResourceMgr
358
343
}
359
344
360
- if len (req .Arguments ) != 1 {
361
- return fmt .Errorf ("must specify exactly one scope" )
362
- }
363
-
364
- percentage , _ := req .Options [swarmUsedResourcesPercentageName ].(int )
365
- scope := req .Arguments [0 ]
366
-
367
- if percentage != 0 && scope != "all" {
368
- return fmt .Errorf ("%q can only be used when scope is %q" , swarmUsedResourcesPercentageName , "all" )
369
- }
370
-
371
- result , err := libp2p .NetStat (node .ResourceManager , scope , percentage )
345
+ cfg , err := node .Repo .Config ()
372
346
if err != nil {
373
347
return err
374
348
}
375
349
376
- b := new (bytes.Buffer )
377
- enc := json .NewEncoder (b )
378
- err = enc .Encode (result )
350
+ userResourceOverrides , err := node .Repo .UserResourceOverrides ()
379
351
if err != nil {
380
352
return err
381
353
}
382
- return cmds .EmitOnce (res , b )
383
- },
384
- Encoders : cmds.EncoderMap {
385
- cmds .Text : HumanJSONEncoder ,
386
- },
387
- }
388
-
389
- var swarmLimitCmd = & cmds.Command {
390
- Status : cmds .Experimental ,
391
- Helptext : cmds.HelpText {
392
- Tagline : "Get or set resource limits for a scope." ,
393
- LongDescription : `Get or set resource limits for a scope.
394
- The scope can be one of the following:
395
- - all -- all limits actually being applied.
396
- - system -- limits for the system aggregate resource usage.
397
- - transient -- limits for the transient resource usage.
398
- - svc:<service> -- limits for the resource usage of a specific service.
399
- - proto:<proto> -- limits for the resource usage of a specific protocol.
400
- - peer:<peer> -- limits for the resource usage of a specific peer.
401
-
402
- The output of this command is JSON.
403
-
404
- It is possible to use this command to inspect and tweak limits at runtime:
405
-
406
- $ ipfs swarm limit system > limit.json
407
- $ vi limit.json
408
- $ ipfs swarm limit system limit.json
409
354
410
- Changes made via command line are persisted in the Swarm.ResourceMgr.Limits field of the $IPFS_PATH/config file.
411
- ` },
412
- Arguments : []cmds.Argument {
413
- cmds .StringArg ("scope" , true , false , "scope of the limit" ),
414
- cmds .FileArg ("limit.json" , false , false , "limits to be set" ).EnableStdin (),
415
- },
416
- Options : []cmds.Option {
417
- cmds .BoolOption (swarmResetLimitsOptionName , "reset limit to default" ),
418
- },
419
- Run : func (req * cmds.Request , res cmds.ResponseEmitter , env cmds.Environment ) error {
420
- node , err := cmdenv .GetNode (env )
355
+ // FIXME: we shouldn't recompute limits, either save them or load them from libp2p (https://github.com/libp2p/go-libp2p/issues/2166)
356
+ limitConfig , _ , err := libp2p .LimitConfig (cfg .Swarm , userResourceOverrides )
421
357
if err != nil {
422
358
return err
423
359
}
424
360
425
- if node .ResourceManager == nil {
361
+ rapi , ok := node .ResourceManager .(rcmgr.ResourceManagerState )
362
+ if ! ok { // NullResourceManager
426
363
return libp2p .ErrNoResourceMgr
427
364
}
428
365
429
- scope := req .Arguments [0 ]
430
-
431
- // set scope limit to new values (when limit.json is passed as a second arg)
432
- if req .Files != nil {
433
- var newLimit rcmgr.ResourceLimits
434
- it := req .Files .Entries ()
435
- if it .Next () {
436
- file := files .FileFromEntry (it )
437
- if file == nil {
438
- return errors .New ("expected a JSON file" )
439
- }
440
-
441
- r := io .LimitReader (file , 32 * 1024 * 1024 ) // 32MiB
442
-
443
- if err := json .NewDecoder (r ).Decode (& newLimit ); err != nil {
444
- return fmt .Errorf ("decoding JSON as ResourceMgrScopeConfig: %w" , err )
366
+ return cmds .EmitOnce (res , libp2p .MergeLimitsAndStatsIntoLimitsConfigAndUsage (limitConfig , rapi .Stat ()))
367
+ },
368
+ Encoders : cmds.EncoderMap {
369
+ cmds .JSON : cmds .MakeTypedEncoder (func (req * cmds.Request , w io.Writer , limitsAndUsage libp2p.LimitsConfigAndUsage ) error {
370
+ return json .NewEncoder (w ).Encode (limitsAndUsage )
371
+ }),
372
+ cmds .Text : cmds .MakeTypedEncoder (func (req * cmds.Request , w io.Writer , limitsAndUsage libp2p.LimitsConfigAndUsage ) error {
373
+ tw := tabwriter .NewWriter (w , 20 , 8 , 0 , '\t' , 0 )
374
+ defer tw .Flush ()
375
+
376
+ fmt .Fprintf (tw , "%s\t %s\t %s\t %s\t %s\t \n " , "Scope" , "Limit Name" , "Limit Value" , "Limit Usage Amount" , "Limit Usage Percent" )
377
+ for _ , ri := range libp2p .LimitConfigsToInfo (limitsAndUsage ) {
378
+ var limit , percentage string
379
+ switch ri .LimitValue {
380
+ case rcmgr .Unlimited64 :
381
+ limit = "unlimited"
382
+ percentage = "n/a"
383
+ case rcmgr .BlockAllLimit64 :
384
+ limit = "blockAll"
385
+ percentage = "n/a"
386
+ default :
387
+ limit = strconv .FormatInt (int64 (ri .LimitValue ), 10 )
388
+ if ri .CurrentUsage == 0 {
389
+ percentage = "0%"
390
+ } else {
391
+ percentage = strconv .FormatFloat (float64 (ri .CurrentUsage )/ float64 (ri .LimitValue )* 100 , 'f' , 1 , 64 ) + "%"
392
+ }
445
393
}
446
- return libp2p .NetSetLimit (node .ResourceManager , node .Repo , scope , newLimit )
394
+ fmt .Fprintf (tw , "%s\t %s\t %s\t %d\t %s\t \n " ,
395
+ ri .ScopeName ,
396
+ ri .LimitName ,
397
+ limit ,
398
+ ri .CurrentUsage ,
399
+ percentage ,
400
+ )
447
401
}
448
- if err := it .Err (); err != nil {
449
- return fmt .Errorf ("error opening limit JSON file: %w" , err )
450
- }
451
- }
452
-
453
- var result interface {}
454
- switch _ , reset := req .Options [swarmResetLimitsOptionName ]; {
455
- case reset :
456
- result , err = libp2p .NetResetLimit (node .ResourceManager , node .Repo , scope )
457
- case scope == "all" :
458
- result , err = libp2p .NetLimitAll (node .ResourceManager )
459
- default :
460
- // get scope limit
461
- result , err = libp2p .NetLimit (node .ResourceManager , scope )
462
- }
463
- if err != nil {
464
- return err
465
- }
466
402
467
- if base , ok := result .(rcmgr.BaseLimit ); ok {
468
- result = base .ToResourceLimits ()
469
- }
470
-
471
- b := new (bytes.Buffer )
472
- enc := json .NewEncoder (b )
473
- err = enc .Encode (result )
474
- if err != nil {
475
- return err
476
- }
477
- return cmds .EmitOnce (res , b )
478
- },
479
- Encoders : cmds.EncoderMap {
480
- cmds .Text : HumanJSONEncoder ,
403
+ return nil
404
+ }),
481
405
},
406
+ Type : libp2p.LimitsConfigAndUsage {},
482
407
}
483
408
484
409
type streamInfo struct {
0 commit comments