Skip to content

Commit b202e89

Browse files
feat(cmd/gossamer): implement --telemetry-url parameter (#1890)
* Implement --telemetry-url Parameter Fixes #1502 * Added tests for --telemetry-url parameter * Fixed tests failing because of nil telemetry endpoints * Addressed some small review comments * Fixing tests by using []TelemetryEndpoint(nil) as TelemetryURLs * tests for telemetry-url with some failure cases * replace telemetry endpoints instead of appending them * trying to increase coverage * Revert "trying to increase coverage" This reverts commit ee3b096.
1 parent de2a12e commit b202e89

File tree

11 files changed

+200
-44
lines changed

11 files changed

+200
-44
lines changed

chain/dev/defaults.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package dev
1818

1919
import (
20+
"github.com/ChainSafe/gossamer/lib/genesis"
2021
"github.com/ChainSafe/gossamer/lib/runtime/wasmer"
2122
log "github.com/ChainSafe/log15"
2223
)
@@ -44,6 +45,9 @@ var (
4445
// DefaultRetainBlocks is the default retained blocks
4546
DefaultRetainBlocks = int64(512)
4647

48+
// DefaultTelemetryURLs is the default URL of the telemetry server to connect to.
49+
DefaultTelemetryURLs []genesis.TelemetryEndpoint
50+
4751
// InitConfig
4852

4953
// DefaultGenesis is the default genesis configuration path

chain/gssmr/defaults.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package gssmr
1919
import (
2020
"time"
2121

22+
"github.com/ChainSafe/gossamer/lib/genesis"
2223
"github.com/ChainSafe/gossamer/lib/runtime/wasmer"
2324
log "github.com/ChainSafe/log15"
2425
)
@@ -46,6 +47,9 @@ var (
4647
// DefaultRetainBlocks is the default retained blocks
4748
DefaultRetainBlocks = int64(512)
4849

50+
// DefaultTelemetryURLs is the default URL of the telemetry server to connect to.
51+
DefaultTelemetryURLs []genesis.TelemetryEndpoint
52+
4953
// InitConfig
5054

5155
// DefaultGenesis is the default genesis configuration path

chain/kusama/defaults.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package kusama
1818

1919
import (
20+
"github.com/ChainSafe/gossamer/lib/genesis"
2021
"github.com/ChainSafe/gossamer/lib/runtime/wasmer"
2122
log "github.com/ChainSafe/log15"
2223
)
@@ -44,6 +45,9 @@ var (
4445
// DefaultRetainBlocks is the default retained blocks
4546
DefaultRetainBlocks = int64(512)
4647

48+
// DefaultTelemetryURLs is the default URL of the telemetry server to connect to.
49+
DefaultTelemetryURLs []genesis.TelemetryEndpoint
50+
4751
// InitConfig
4852

4953
// DefaultGenesis is the default genesis configuration path

chain/polkadot/defaults.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package polkadot
1818

1919
import (
20+
"github.com/ChainSafe/gossamer/lib/genesis"
2021
"github.com/ChainSafe/gossamer/lib/runtime/wasmer"
2122
log "github.com/ChainSafe/log15"
2223
)
@@ -41,6 +42,9 @@ var (
4142
// DefaultRetainBlocks is the default pruning mode
4243
DefaultRetainBlocks = int64(512)
4344

45+
// DefaultTelemetryURLs is the default URL of the telemetry server to connect to.
46+
DefaultTelemetryURLs []genesis.TelemetryEndpoint
47+
4448
// InitConfig
4549

4650
// DefaultGenesis is the default genesis configuration path

cmd/gossamer/config.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,9 @@ func setDotInitConfig(ctx *cli.Context, tomlCfg ctoml.InitConfig, cfg *dot.InitC
421421

422422
func setDotGlobalConfig(ctx *cli.Context, tomlConfig *ctoml.Config, cfg *dot.GlobalConfig) error {
423423
setDotGlobalConfigFromToml(tomlConfig, cfg)
424-
setDotGlobalConfigFromFlags(ctx, cfg)
424+
if err := setDotGlobalConfigFromFlags(ctx, cfg); err != nil {
425+
return fmt.Errorf("could not set global config from flags: %w", err)
426+
}
425427

426428
if err := setDotGlobalConfigName(ctx, tomlConfig, cfg); err != nil {
427429
return fmt.Errorf("could not set global node name: %w", err)
@@ -460,7 +462,7 @@ func setDotGlobalConfigFromToml(tomlCfg *ctoml.Config, cfg *dot.GlobalConfig) {
460462
}
461463

462464
// setDotGlobalConfigFromFlags sets dot.GlobalConfig using flag values from the cli context
463-
func setDotGlobalConfigFromFlags(ctx *cli.Context, cfg *dot.GlobalConfig) {
465+
func setDotGlobalConfigFromFlags(ctx *cli.Context, cfg *dot.GlobalConfig) error {
464466
// check --basepath flag and update node configuration
465467
if basepath := ctx.GlobalString(BasePathFlag.Name); basepath != "" {
466468
cfg.BasePath = basepath
@@ -488,6 +490,28 @@ func setDotGlobalConfigFromFlags(ctx *cli.Context, cfg *dot.GlobalConfig) {
488490
cfg.RetainBlocks = ctx.Int64(RetainBlockNumberFlag.Name)
489491
cfg.Pruning = pruner.Mode(ctx.String(PruningFlag.Name))
490492
cfg.NoTelemetry = ctx.Bool("no-telemetry")
493+
494+
var telemetryEndpoints []genesis.TelemetryEndpoint
495+
for _, telemetryURL := range ctx.GlobalStringSlice(TelemetryURLFlag.Name) {
496+
splits := strings.Split(telemetryURL, " ")
497+
if len(splits) != 2 {
498+
return fmt.Errorf("%s must be in the format 'URL VERBOSITY'", TelemetryURLFlag.Name)
499+
}
500+
501+
verbosity, err := strconv.Atoi(splits[1])
502+
if err != nil {
503+
return fmt.Errorf("could not parse verbosity from %s: %w", TelemetryURLFlag.Name, err)
504+
}
505+
506+
telemetryEndpoints = append(telemetryEndpoints, genesis.TelemetryEndpoint{
507+
Endpoint: splits[0],
508+
Verbosity: verbosity,
509+
})
510+
}
511+
512+
cfg.TelemetryURLs = telemetryEndpoints
513+
514+
return nil
491515
}
492516

493517
func setDotGlobalConfigName(ctx *cli.Context, tomlCfg *ctoml.Config, cfg *dot.GlobalConfig) error {

cmd/gossamer/config_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,28 @@ func TestGlobalConfigFromFlags(t *testing.T) {
245245
NoTelemetry: true,
246246
},
247247
},
248+
{
249+
"Test gossamer --telemetry-url",
250+
[]string{"config", "telemetry-url", "name"},
251+
[]interface{}{
252+
testCfgFile.Name(),
253+
[]string{"ws://localhost:8001/submit 0", "ws://foo/bar 0"},
254+
testCfg.Global.Name,
255+
},
256+
dot.GlobalConfig{
257+
Name: testCfg.Global.Name,
258+
ID: testCfg.Global.ID,
259+
BasePath: testCfg.Global.BasePath,
260+
LogLvl: log.LvlInfo,
261+
PublishMetrics: testCfg.Global.PublishMetrics,
262+
MetricsPort: testCfg.Global.MetricsPort,
263+
NoTelemetry: false,
264+
TelemetryURLs: []genesis.TelemetryEndpoint{
265+
{Endpoint: "ws://localhost:8001/submit", Verbosity: 0},
266+
{Endpoint: "ws://foo/bar", Verbosity: 0},
267+
},
268+
},
269+
},
248270
}
249271

250272
for _, c := range testcases {
@@ -260,6 +282,58 @@ func TestGlobalConfigFromFlags(t *testing.T) {
260282
}
261283
}
262284

285+
func TestGlobalConfigFromFlagsFails(t *testing.T) {
286+
testCfg, testCfgFile := newTestConfigWithFile(t)
287+
require.NotNil(t, testCfg)
288+
require.NotNil(t, testCfgFile)
289+
290+
defer utils.RemoveTestDir(t)
291+
292+
testApp := cli.NewApp()
293+
testApp.Writer = ioutil.Discard
294+
295+
testcases := []struct {
296+
description string
297+
flags []string
298+
values []interface{}
299+
err string
300+
}{
301+
{
302+
"Test gossamer --telemetry-url invalid format",
303+
[]string{"config", "telemetry-url", "name"},
304+
[]interface{}{
305+
testCfgFile.Name(),
306+
[]string{"ws://localhost:8001/submit"},
307+
testCfg.Global.Name,
308+
},
309+
"could not set global config from flags: telemetry-url must be in the format 'URL VERBOSITY'",
310+
},
311+
{
312+
"Test gossamer invalid --telemetry-url invalid verbosity",
313+
[]string{"config", "telemetry-url", "name"},
314+
[]interface{}{
315+
testCfgFile.Name(),
316+
[]string{"ws://foo/bar k"},
317+
testCfg.Global.Name,
318+
},
319+
"could not set global config from flags: could not parse verbosity from telemetry-url: strconv.Atoi: parsing \"k\": invalid syntax",
320+
},
321+
}
322+
323+
for _, c := range testcases {
324+
c := c // bypass scopelint false positive
325+
t.Run(c.description, func(t *testing.T) {
326+
ctx, err := newTestContext(c.description, c.flags, c.values)
327+
require.Nil(t, err)
328+
329+
cfg, err := createDotConfig(ctx)
330+
require.NotNil(t, err)
331+
require.Nil(t, cfg)
332+
require.Equal(t, c.err, err.Error())
333+
})
334+
}
335+
}
336+
263337
// TestAccountConfigFromFlags tests createDotAccountConfig using relevant account flags
264338
func TestAccountConfigFromFlags(t *testing.T) {
265339
testCfg, testCfgFile := newTestConfigWithFile(t)
@@ -696,6 +770,7 @@ func TestUpdateConfigFromGenesisJSON(t *testing.T) {
696770
LogLvl: testCfg.Global.LogLvl,
697771
PublishMetrics: testCfg.Global.PublishMetrics,
698772
MetricsPort: testCfg.Global.MetricsPort,
773+
TelemetryURLs: testCfg.Global.TelemetryURLs,
699774
},
700775
Log: dot.LogConfig{
701776
CoreLvl: log.LvlInfo,
@@ -749,6 +824,7 @@ func TestUpdateConfigFromGenesisJSON_Default(t *testing.T) {
749824
LogLvl: testCfg.Global.LogLvl,
750825
PublishMetrics: testCfg.Global.PublishMetrics,
751826
MetricsPort: testCfg.Global.MetricsPort,
827+
TelemetryURLs: testCfg.Global.TelemetryURLs,
752828
},
753829
Log: dot.LogConfig{
754830
CoreLvl: log.LvlInfo,
@@ -798,6 +874,7 @@ func TestUpdateConfigFromGenesisData(t *testing.T) {
798874
LogLvl: testCfg.Global.LogLvl,
799875
PublishMetrics: testCfg.Global.PublishMetrics,
800876
MetricsPort: testCfg.Global.MetricsPort,
877+
TelemetryURLs: testCfg.Global.TelemetryURLs,
801878
},
802879
Log: dot.LogConfig{
803880
CoreLvl: log.LvlInfo,

cmd/gossamer/flags.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,19 @@ var (
105105
Name: "no-telemetry",
106106
Usage: "Disable connecting to the Substrate telemetry server",
107107
}
108+
109+
// TelemetryURLFlag is URL of the telemetry server to connect to.
110+
// This flag can be passed multiple times as a means to specify multiple
111+
// telemetry endpoints. Verbosity levels range from 0-9, with 0 denoting the
112+
// least verbosity.
113+
// Expected format is 'URL VERBOSITY', e.g. `--telemetry-url 'wss://foo/bar 0'`.
114+
TelemetryURLFlag = cli.StringSliceFlag{
115+
Name: "telemetry-url",
116+
Usage: `The URL of the telemetry server to connect to, this flag can be
117+
passed multiple times, the verbosity levels range from 0-9, with 0 denoting
118+
least verbosity.
119+
Expected format --telemetry-url 'wss://foo/bar 0'`,
120+
}
108121
)
109122

110123
// Initialization-only flags
@@ -374,6 +387,7 @@ var (
374387

375388
// telemetry flags
376389
NoTelemetryFlag,
390+
TelemetryURLFlag,
377391

378392
// BABE flags
379393
BABELeadFlag,

cmd/gossamer/utils.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ func newTestConfig(t *testing.T) *dot.Config {
9595
MetricsPort: dot.GssmrConfig().Global.MetricsPort,
9696
RetainBlocks: dot.GssmrConfig().Global.RetainBlocks,
9797
Pruning: dot.GssmrConfig().Global.Pruning,
98+
TelemetryURLs: dot.GssmrConfig().Global.TelemetryURLs,
9899
},
99100
Log: dot.LogConfig{
100101
CoreLvl: log.LvlInfo,

cmd/gossamer/utils_test.go

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ import (
2929

3030
// newTestContext creates a cli context for a test given a set of flags and values
3131
func newTestContext(description string, flags []string, values []interface{}) (*cli.Context, error) {
32+
if len(flags) != len(values) {
33+
return nil, fmt.Errorf("number of flags and values are not same, number of flags: %d, number of values: %d", len(flags), len(values))
34+
}
35+
36+
// Define flags with its name and default value
3237
set := flag.NewFlagSet(description, 0)
3338
for i := range values {
3439
switch v := values[i].(type) {
@@ -40,6 +45,8 @@ func newTestContext(description string, flags []string, values []interface{}) (*
4045
set.Uint(flags[i], v, "")
4146
case int64:
4247
set.Int64(flags[i], v, "")
48+
case []string:
49+
set.Var(&cli.StringSlice{}, flags[i], "")
4350
default:
4451
return nil, fmt.Errorf("unexpected cli value type: %T", values[i])
4552
}
@@ -50,31 +57,31 @@ func newTestContext(description string, flags []string, values []interface{}) (*
5057
for i := range values {
5158
switch v := values[i].(type) {
5259
case bool:
53-
if v {
54-
err := ctx.Set(flags[i], "true")
55-
if err != nil {
56-
return nil, fmt.Errorf("failed to set cli flag: %T", flags[i])
57-
}
58-
} else {
59-
err := ctx.Set(flags[i], "false")
60-
if err != nil {
61-
return nil, fmt.Errorf("failed to set cli flag: %T", flags[i])
62-
}
60+
err := ctx.Set(flags[i], strconv.FormatBool(v))
61+
if err != nil {
62+
return nil, fmt.Errorf("failed to set cli flag: %T, err: %w", flags[i], err)
6363
}
6464
case string:
6565
err := ctx.Set(flags[i], values[i].(string))
6666
if err != nil {
67-
return nil, fmt.Errorf("failed to set cli flag: %T", flags[i])
67+
return nil, fmt.Errorf("failed to set cli flag: %T, err: %w", flags[i], err)
6868
}
6969
case uint:
7070
err := ctx.Set(flags[i], strconv.Itoa(int(values[i].(uint))))
7171
if err != nil {
72-
return nil, fmt.Errorf("failed to set cli flag: %T", flags[i])
72+
return nil, fmt.Errorf("failed to set cli flag: %T, err: %w", flags[i], err)
7373
}
7474
case int64:
7575
err := ctx.Set(flags[i], strconv.Itoa(int(values[i].(int64))))
7676
if err != nil {
77-
return nil, fmt.Errorf("failed to set cli flag: %T", flags[i])
77+
return nil, fmt.Errorf("failed to set cli flag: %T, err: %w", flags[i], err)
78+
}
79+
case []string:
80+
for _, str := range values[i].([]string) {
81+
err := ctx.Set(flags[i], str)
82+
if err != nil {
83+
return nil, fmt.Errorf("failed to set cli flag: %T, err: %w", flags[i], err)
84+
}
7885
}
7986
default:
8087
return nil, fmt.Errorf("unexpected cli value type: %T", values[i])

0 commit comments

Comments
 (0)