Add per Node Hardware Information to Telemetry Feed (#519)

* code: Add `sysinfo` and `hwbench` to the `AddedNode` message

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* code: Update `AddedNode` on `hwbench` updates

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* core: Rename cli flag `expose_node_ips` to `expose_node_details`

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* core: Add hardware info only if the cli flag is enabled

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* tests: Adjust testing to the new `AddedNode` message

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* core: Move serialization of fields to the details array

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

---------

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
This commit is contained in:
Alexandru Vasile
2023-01-27 17:33:48 +02:00
committed by GitHub
parent 779c5698a0
commit b25f3fbf22
8 changed files with 65 additions and 21 deletions
+2 -2
View File
@@ -46,7 +46,7 @@ pub struct NodeDetails {
} }
/// Hardware and software information for the node. /// Hardware and software information for the node.
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct NodeSysInfo { pub struct NodeSysInfo {
/// The exact CPU model. /// The exact CPU model.
pub cpu: Option<Box<str>>, pub cpu: Option<Box<str>>,
@@ -63,7 +63,7 @@ pub struct NodeSysInfo {
} }
/// Hardware benchmark results for the node. /// Hardware benchmark results for the node.
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct NodeHwBench { pub struct NodeHwBench {
/// The CPU speed, as measured in how many MB/s it can hash using the BLAKE2b-256 hash. /// The CPU speed, as measured in how many MB/s it can hash using the BLAKE2b-256 hash.
pub cpu_hashrate_score: u64, pub cpu_hashrate_score: u64,
@@ -44,8 +44,9 @@ pub struct AggregatorOpts {
/// How many nodes from third party chains are allowed to connect /// How many nodes from third party chains are allowed to connect
/// before we prevent connections from them. /// before we prevent connections from them.
pub max_third_party_nodes: usize, pub max_third_party_nodes: usize,
/// Flag to expose the IP addresses of all connected nodes to the feed subscribers. /// Flag to expose the node's details (IP address, SysInfo, HwBench) of all connected
pub expose_node_ips: bool, /// nodes to the feed subscribers.
pub expose_node_details: bool,
} }
struct AggregatorInternal { struct AggregatorInternal {
@@ -174,8 +174,9 @@ pub struct InnerLoop {
/// are prioritised and dropped to try and get back on track. /// are prioritised and dropped to try and get back on track.
max_queue_len: usize, max_queue_len: usize,
/// Flag to expose the IP addresses of all connected nodes to the feed subscribers. /// Flag to expose the node's details (IP address, SysInfo, HwBench) of all connected
expose_node_ips: bool, /// nodes to the feed subscribers.
expose_node_details: bool,
} }
impl InnerLoop { impl InnerLoop {
@@ -189,7 +190,7 @@ impl InnerLoop {
chain_to_feed_conn_ids: MultiMapUnique::new(), chain_to_feed_conn_ids: MultiMapUnique::new(),
tx_to_locator, tx_to_locator,
max_queue_len: opts.max_queue_len, max_queue_len: opts.max_queue_len,
expose_node_ips: opts.expose_node_ips, expose_node_details: opts.expose_node_details,
} }
} }
@@ -326,7 +327,7 @@ impl InnerLoop {
genesis_hash, genesis_hash,
} => { } => {
// Conditionally modify the node's details to include the IP address. // Conditionally modify the node's details to include the IP address.
node.ip = self.expose_node_ips.then_some(ip.to_string().into()); node.ip = self.expose_node_details.then_some(ip.to_string().into());
match self.node_state.add_node(genesis_hash, node) { match self.node_state.add_node(genesis_hash, node) {
state::AddNodeResult::ChainOnDenyList => { state::AddNodeResult::ChainOnDenyList => {
if let Some(shard_conn) = self.shard_channels.get_mut(&shard_conn_id) { if let Some(shard_conn) = self.shard_channels.get_mut(&shard_conn_id) {
@@ -360,6 +361,7 @@ impl InnerLoop {
feed_messages_for_chain.push(feed_message::AddedNode( feed_messages_for_chain.push(feed_message::AddedNode(
node_id.get_chain_node_id().into(), node_id.get_chain_node_id().into(),
&details.node, &details.node,
self.expose_node_details,
)); ));
self.finalize_and_broadcast_to_chain_feeds( self.finalize_and_broadcast_to_chain_feeds(
&genesis_hash, &genesis_hash,
@@ -409,8 +411,12 @@ impl InnerLoop {
}; };
let mut feed_message_serializer = FeedMessageSerializer::new(); let mut feed_message_serializer = FeedMessageSerializer::new();
self.node_state self.node_state.update_node(
.update_node(node_id, payload, &mut feed_message_serializer); node_id,
payload,
&mut feed_message_serializer,
self.expose_node_details,
);
if let Some(chain) = self.node_state.get_chain_by_node_id(node_id) { if let Some(chain) = self.node_state.get_chain_by_node_id(node_id) {
let genesis_hash = chain.genesis_hash(); let genesis_hash = chain.genesis_hash();
@@ -531,7 +537,11 @@ impl InnerLoop {
.iter() .iter()
.filter_map(|&(idx, n)| n.as_ref().map(|n| (idx, n))) .filter_map(|&(idx, n)| n.as_ref().map(|n| (idx, n)))
{ {
feed_serializer.push(feed_message::AddedNode(node_id, node)); feed_serializer.push(feed_message::AddedNode(
node_id,
node,
self.expose_node_details,
));
feed_serializer.push(feed_message::FinalizedBlock( feed_serializer.push(feed_message::FinalizedBlock(
node_id, node_id,
node.finalized().height, node.finalized().height,
+13 -3
View File
@@ -134,7 +134,7 @@ pub struct BestBlock(pub BlockNumber, pub Timestamp, pub Option<u64>);
#[derive(Serialize)] #[derive(Serialize)]
pub struct BestFinalized(pub BlockNumber, pub BlockHash); pub struct BestFinalized(pub BlockNumber, pub BlockHash);
pub struct AddedNode<'a>(pub FeedNodeId, pub &'a Node); pub struct AddedNode<'a>(pub FeedNodeId, pub &'a Node, pub bool);
#[derive(Serialize)] #[derive(Serialize)]
pub struct RemovedNode(pub FeedNodeId); pub struct RemovedNode(pub FeedNodeId);
@@ -180,16 +180,26 @@ pub struct StaleNode(pub FeedNodeId);
impl FeedMessageWrite for AddedNode<'_> { impl FeedMessageWrite for AddedNode<'_> {
fn write_to_feed(&self, ser: &mut FeedMessageSerializer) { fn write_to_feed(&self, ser: &mut FeedMessageSerializer) {
let AddedNode(nid, node) = self; let AddedNode(nid, node, expose_node_details) = self;
let details = node.details(); let details = node.details();
// Hide the ip, sysinfo and hwbench if the `expose_node_details` flag was not specified.
let node_hwbench = node.hwbench();
let (ip, sys_info, hwbench) = if *expose_node_details {
(&details.ip, &details.sysinfo, &node_hwbench)
} else {
(&None, &None, &None)
};
let details = ( let details = (
&details.name, &details.name,
&details.implementation, &details.implementation,
&details.version, &details.version,
&details.validator, &details.validator,
&details.network_id, &details.network_id,
&details.ip, &ip,
&sys_info,
&hwbench,
); );
ser.write(&( ser.write(&(
+4 -3
View File
@@ -82,9 +82,10 @@ struct Opts {
/// How many nodes from third party chains are allowed to connect before we prevent connections from them. /// How many nodes from third party chains are allowed to connect before we prevent connections from them.
#[structopt(long, default_value = "1000")] #[structopt(long, default_value = "1000")]
max_third_party_nodes: usize, max_third_party_nodes: usize,
/// Flag to expose the IP addresses of all connected nodes to the feed subscribers. /// Flag to expose the node's details (IP address, SysInfo, HwBench) of all connected
/// nodes to the feed subscribers.
#[structopt(long)] #[structopt(long)]
pub expose_node_ips: bool, pub expose_node_details: bool,
} }
fn main() { fn main() {
@@ -135,7 +136,7 @@ async fn start_server(num_aggregators: usize, opts: Opts) -> anyhow::Result<()>
max_queue_len: aggregator_queue_len, max_queue_len: aggregator_queue_len,
denylist: opts.denylist, denylist: opts.denylist,
max_third_party_nodes: opts.max_third_party_nodes, max_third_party_nodes: opts.max_third_party_nodes,
expose_node_ips: opts.expose_node_ips, expose_node_details: opts.expose_node_details,
}, },
) )
.await?; .await?;
+17 -1
View File
@@ -175,6 +175,7 @@ impl Chain {
nid: ChainNodeId, nid: ChainNodeId,
payload: Payload, payload: Payload,
feed: &mut FeedMessageSerializer, feed: &mut FeedMessageSerializer,
expose_node_details: bool,
) { ) {
if let Some(block) = payload.best_block() { if let Some(block) = payload.best_block() {
self.handle_block(block, nid, feed); self.handle_block(block, nid, feed);
@@ -198,7 +199,11 @@ impl Chain {
// If our node validator address (and thus details) change, send an // If our node validator address (and thus details) change, send an
// updated "add node" feed message: // updated "add node" feed message:
if node.set_validator_address(authority.authority_id.clone()) { if node.set_validator_address(authority.authority_id.clone()) {
feed.push(feed_message::AddedNode(nid.into(), &node)); feed.push(feed_message::AddedNode(
nid.into(),
&node,
expose_node_details,
));
} }
return; return;
} }
@@ -210,6 +215,17 @@ impl Chain {
disk_random_write_score: hwbench.disk_random_write_score, disk_random_write_score: hwbench.disk_random_write_score,
}; };
let old_hwbench = node.update_hwbench(new_hwbench); let old_hwbench = node.update_hwbench(new_hwbench);
// The `hwbench` for this node has changed, send an updated "add node".
// Note: There is no need to send this message if the details
// will not be serialized over the wire.
if expose_node_details {
feed.push(feed_message::AddedNode(
nid.into(),
&node,
expose_node_details,
));
}
self.stats_collator self.stats_collator
.update_hwbench(old_hwbench.as_ref(), CounterValue::Decrement); .update_hwbench(old_hwbench.as_ref(), CounterValue::Decrement);
self.stats_collator self.stats_collator
+2 -1
View File
@@ -218,6 +218,7 @@ impl State {
NodeId(chain_id, chain_node_id): NodeId, NodeId(chain_id, chain_node_id): NodeId,
payload: Payload, payload: Payload,
feed: &mut FeedMessageSerializer, feed: &mut FeedMessageSerializer,
expose_node_details: bool,
) { ) {
let chain = match self.chains.get_mut(chain_id) { let chain = match self.chains.get_mut(chain_id) {
Some(chain) => chain, Some(chain) => chain,
@@ -227,7 +228,7 @@ impl State {
} }
}; };
chain.update_node(chain_node_id, payload, feed) chain.update_node(chain_node_id, payload, feed, expose_node_details)
} }
/// Update the location for a node. Return `false` if the node was not found. /// Update the location for a node. Return `false` if the node was not found.
+7 -2
View File
@@ -16,7 +16,8 @@
use anyhow::Context; use anyhow::Context;
use common::node_types::{ use common::node_types::{
BlockDetails, BlockHash, BlockNumber, NodeLocation, NodeStats, Timestamp, BlockDetails, BlockHash, BlockNumber, NodeHwBench, NodeLocation, NodeStats, NodeSysInfo,
Timestamp,
}; };
use serde_json::value::RawValue; use serde_json::value::RawValue;
@@ -41,6 +42,7 @@ pub enum FeedMessage {
block_details: BlockDetails, block_details: BlockDetails,
location: Option<NodeLocation>, location: Option<NodeLocation>,
startup_time: Option<Timestamp>, startup_time: Option<Timestamp>,
hwbench: Option<NodeHwBench>,
}, },
RemovedNode { RemovedNode {
node_id: usize, node_id: usize,
@@ -135,6 +137,7 @@ pub struct NodeDetails {
pub validator: Option<String>, pub validator: Option<String>,
pub network_id: Option<String>, pub network_id: Option<String>,
pub ip: Option<String>, pub ip: Option<String>,
pub sysinfo: Option<NodeSysInfo>,
} }
impl FeedMessage { impl FeedMessage {
@@ -186,7 +189,7 @@ impl FeedMessage {
3 => { 3 => {
let ( let (
node_id, node_id,
(name, implementation, version, validator, network_id, ip), (name, implementation, version, validator, network_id, ip, sysinfo, hwbench),
stats, stats,
io, io,
hardware, hardware,
@@ -207,11 +210,13 @@ impl FeedMessage {
validator, validator,
network_id, network_id,
ip, ip,
sysinfo,
}, },
stats, stats,
block_details, block_details,
location, location,
startup_time, startup_time,
hwbench,
} }
} }
// RemoveNode // RemoveNode