Skip to content

Commit 261dbb4

Browse files
Merge branch 'vishal/add_operator_details' of github.com:onflow/flow-go
2 parents 069e286 + a8f3278 commit 261dbb4

File tree

8 files changed

+129
-10
lines changed

8 files changed

+129
-10
lines changed

cmd/access/main.go

+3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func main() {
4545
receiptLimit uint
4646
collectionGRPCPort uint
4747
pingEnabled bool
48+
nodeInfoFile string
4849
ingestEng *ingestion.Engine
4950
requestEng *requester.Engine
5051
followerEng *followereng.Engine
@@ -82,6 +83,7 @@ func main() {
8283
flags.BoolVar(&logTxTimeToFinalizedExecuted, "log-tx-time-to-finalized-executed", false, "log transaction time to finalized and executed")
8384
flags.BoolVar(&pingEnabled, "ping-enabled", false, "whether to enable the ping process that pings all other peers and report the connectivity to metrics")
8485
flags.BoolVar(&retryEnabled, "retry-enabled", false, "whether to enable the retry mechanism at the access node level")
86+
flags.StringVarP(&nodeInfoFile, "node-info-file", "", "", "full path to a json file which provides more details about nodes when reporting its reachability metrics")
8587
}).
8688
Module("collection node client", func(node *cmd.FlowNodeBuilder) error {
8789
// collection node address is optional (if not specified, collection nodes will be chosen at random)
@@ -279,6 +281,7 @@ func main() {
279281
pingMetrics,
280282
pingEnabled,
281283
node.Middleware,
284+
nodeInfoFile,
282285
)
283286
if err != nil {
284287
return nil, fmt.Errorf("could not create ping engine: %w", err)

engine/access/ping/engine.go

+22-3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type Engine struct {
2323
pingEnabled bool
2424
pingInterval time.Duration
2525
middleware *p2p.Middleware
26+
nodeInfo map[flow.Identifier]string // additional details about a node such as operator name
2627
}
2728

2829
func New(
@@ -32,7 +33,9 @@ func New(
3233
metrics module.PingMetrics,
3334
pingEnabled bool,
3435
mw *p2p.Middleware,
36+
nodeInfoFile string,
3537
) (*Engine, error) {
38+
3639
eng := &Engine{
3740
unit: engine.NewUnit(),
3841
log: log.With().Str("engine", "ping").Logger(),
@@ -44,6 +47,20 @@ func New(
4447
middleware: mw,
4548
}
4649

50+
// if a node info file is provided, it is read and the additional node information is reported as part of the ping metric
51+
if nodeInfoFile != "" {
52+
nodeInfo, err := readJson(nodeInfoFile)
53+
if err != nil {
54+
log.Error().Err(err).Str("node_info_file", nodeInfoFile).Msg("failed to read node info file")
55+
} else {
56+
eng.nodeInfo = nodeInfo
57+
log.Debug().Str("node_info_file", nodeInfoFile).Msg("using node info file")
58+
}
59+
} else {
60+
// the node info file is not mandatory and should not stop the Ping engine from running
61+
log.Trace().Msg("no node info file specified")
62+
}
63+
4764
return eng, nil
4865
}
4966

@@ -85,10 +102,12 @@ func (e *Engine) startPing() {
85102
}
86103
}
87104

88-
// send ping to a given node and report the reachable result to metrics
105+
// pingNode pings the given peer and updates the metrics with the result and the additional node information
89106
func (e *Engine) pingNode(peer *flow.Identity) {
90-
reachable := e.pingAddress(peer.ID())
91-
e.metrics.NodeReachable(peer, reachable)
107+
id := peer.ID()
108+
reachable := e.pingAddress(id)
109+
info := e.nodeInfo[id]
110+
e.metrics.NodeReachable(peer, info, reachable)
92111
}
93112

94113
// pingAddress sends a ping request to the given address, and block until either receive

engine/access/ping/node_info.go

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package ping
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io/ioutil"
7+
"os"
8+
9+
"github.com/onflow/flow-go/model/flow"
10+
)
11+
12+
func readJson(jsonFileName string) (map[flow.Identifier]string, error) {
13+
14+
// read the file
15+
byteValue, err := openAndReadFile(jsonFileName)
16+
if err != nil {
17+
return nil, err
18+
}
19+
20+
// unmarshal json data
21+
result, err := unmarshalJson(byteValue)
22+
if err != nil {
23+
return nil, fmt.Errorf("failed to unmarshal %s: %w", jsonFileName, err)
24+
}
25+
return result, nil
26+
}
27+
28+
func openAndReadFile(fileName string) ([]byte, error) {
29+
//open
30+
jsonFile, err := os.Open(fileName)
31+
if err != nil {
32+
return nil, fmt.Errorf("failed to open %s: %w", fileName, err)
33+
}
34+
defer jsonFile.Close()
35+
36+
// read
37+
byteValue, err := ioutil.ReadAll(jsonFile)
38+
if err != nil {
39+
return nil, fmt.Errorf("failed to read %s: %w", fileName, err)
40+
}
41+
return byteValue, nil
42+
}
43+
44+
func unmarshalJson(jsonData []byte) (map[flow.Identifier]string, error) {
45+
var result map[flow.Identifier]string
46+
err := json.Unmarshal(jsonData, &result)
47+
if err != nil {
48+
return nil, err
49+
}
50+
return result, nil
51+
}

engine/access/ping/node_info_test.go

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package ping
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"testing"
7+
8+
"github.com/onflow/flow-go/model/flow"
9+
"github.com/onflow/flow-go/utils/unittest"
10+
11+
"github.com/stretchr/testify/require"
12+
"github.com/stretchr/testify/suite"
13+
)
14+
15+
type Suite struct {
16+
suite.Suite
17+
}
18+
19+
func TestHandler(t *testing.T) {
20+
suite.Run(t, new(Suite))
21+
}
22+
23+
func TestReadJson(t *testing.T) {
24+
totalNodes := 10
25+
ids := unittest.IdentifierListFixture(totalNodes)
26+
testJson := make(map[flow.Identifier]string, totalNodes)
27+
for i, id := range ids {
28+
testJson[id] = fmt.Sprintf("Operator%d", i+1)
29+
}
30+
jsonAsBytes, err := json.Marshal(testJson)
31+
require.NoError(t, err)
32+
content, err := unmarshalJson(jsonAsBytes)
33+
require.NoError(t, err)
34+
require.Len(t, content, totalNodes)
35+
for k, v := range testJson {
36+
require.Contains(t, content, k)
37+
require.Equal(t, content[k], v)
38+
}
39+
}

module/metrics.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -316,5 +316,7 @@ type TransactionMetrics interface {
316316
}
317317

318318
type PingMetrics interface {
319-
NodeReachable(node *flow.Identity, reachable bool)
319+
// NodeReachable tracks the node availability of the node and reports it as 1 if the node was successfully pinged, 0
320+
// otherwise. The nodeInfo provides additional information about the node such as the name of the node operator
321+
NodeReachable(node *flow.Identity, nodeInfo string, reachable bool)
320322
}

module/metrics/labels.go

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const (
88
LabelMessage = "message"
99
LabelNodeID = "nodeid"
1010
LabelNodeRole = "noderole"
11+
LabelNodeInfo = "nodeinfo"
1112
LabelPriority = "priority"
1213
)
1314

module/metrics/ping.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,19 @@ func NewPingCollector() *PingCollector {
1818
Namespace: namespaceNetwork,
1919
Subsystem: subsystemGossip,
2020
Help: "report whether a node is reachable",
21-
}, []string{LabelNodeID, LabelNodeRole}),
21+
}, []string{LabelNodeID, LabelNodeRole, LabelNodeInfo}),
2222
}
2323
return pc
2424
}
2525

26-
func (pc *PingCollector) NodeReachable(node *flow.Identity, reachable bool) {
26+
func (pc *PingCollector) NodeReachable(node *flow.Identity, nodeInfo string, reachable bool) {
2727
var val float64
2828
if reachable {
2929
val = 1
3030
}
31-
pc.reachable.With(prometheus.Labels{LabelNodeID: node.String(), LabelNodeRole: node.Role.String()}).Set(val)
31+
pc.reachable.With(prometheus.Labels{
32+
LabelNodeID: node.String(),
33+
LabelNodeRole: node.Role.String(),
34+
LabelNodeInfo: nodeInfo}).
35+
Set(val)
3236
}

module/mock/ping_metrics.go

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)