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,13 @@ 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 about all resources in use by libp2p Resource Manager." ,
330
+ LongDescription : `Get a summary about all resources in use by libp2p Resource Manager.
331
+ This can output human readable table and JSON encoding.
343
332
` },
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
333
Run : func (req * cmds.Request , res cmds.ResponseEmitter , env cmds.Environment ) error {
351
334
node , err := cmdenv .GetNode (env )
352
335
if err != nil {
@@ -357,128 +340,68 @@ To see all resources that are close to hitting their respective limit, one can d
357
340
return libp2p .ErrNoResourceMgr
358
341
}
359
342
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 )
343
+ cfg , err := node .Repo .Config ()
372
344
if err != nil {
373
345
return err
374
346
}
375
347
376
- b := new (bytes.Buffer )
377
- enc := json .NewEncoder (b )
378
- err = enc .Encode (result )
348
+ userResourceOverrides , err := node .Repo .UserResourceOverrides ()
379
349
if err != nil {
380
350
return err
381
351
}
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
352
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 )
353
+ // FIXME: we shouldn't recompute limits, either save them or load them from libp2p (https://github.com/libp2p/go-libp2p/issues/2166)
354
+ limitConfig , _ , err := libp2p .LimitConfig (cfg .Swarm , userResourceOverrides )
421
355
if err != nil {
422
356
return err
423
357
}
424
358
425
- if node .ResourceManager == nil {
359
+ rapi , ok := node .ResourceManager .(rcmgr.ResourceManagerState )
360
+ if ! ok { // NullResourceManager
426
361
return libp2p .ErrNoResourceMgr
427
362
}
428
363
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 )
364
+ return cmds .EmitOnce (res , libp2p .MergeLimitsAndStatsIntoUsageAndLimitsConfig (limitConfig , rapi .Stat ()))
365
+ },
366
+ Encoders : cmds.EncoderMap {
367
+ cmds .JSON : cmds .MakeTypedEncoder (func (req * cmds.Request , w io.Writer , usageAndLimits libp2p.UsageAndLimitsConfig ) error {
368
+ return json .NewEncoder (w ).Encode (usageAndLimits )
369
+ }),
370
+ cmds .Text : cmds .MakeTypedEncoder (func (req * cmds.Request , w io.Writer , usageAndLimits libp2p.UsageAndLimitsConfig ) error {
371
+ tw := tabwriter .NewWriter (w , 20 , 8 , 0 , '\t' , 0 )
372
+ defer tw .Flush ()
373
+
374
+ 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" )
375
+ for _ , ri := range libp2p .LimitConfigsToInfo (usageAndLimits ) {
376
+ var limit , percentage string
377
+ switch ri .LimitValue {
378
+ case rcmgr .Unlimited64 :
379
+ limit = "unlimited"
380
+ percentage = "n/a"
381
+ case rcmgr .BlockAllLimit64 :
382
+ limit = "0"
383
+ percentage = "n/a"
384
+ default :
385
+ limit = strconv .FormatInt (int64 (ri .LimitValue ), 10 )
386
+ if ri .CurrentUsage == 0 {
387
+ percentage = "0%"
388
+ } else {
389
+ percentage = strconv .FormatFloat (float64 (ri .CurrentUsage )/ float64 (ri .LimitValue )* 100 , 'f' , 1 , 64 ) + "%"
390
+ }
445
391
}
446
- return libp2p .NetSetLimit (node .ResourceManager , node .Repo , scope , newLimit )
392
+ fmt .Fprintf (tw , "%s\t %s\t %s\t %d\t %s\t \n " ,
393
+ ri .ScopeName ,
394
+ ri .LimitName ,
395
+ limit ,
396
+ ri .CurrentUsage ,
397
+ percentage ,
398
+ )
447
399
}
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
400
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 ,
401
+ return nil
402
+ }),
481
403
},
404
+ Type : libp2p.UsageAndLimitsConfig {},
482
405
}
483
406
484
407
type streamInfo struct {
0 commit comments