From 479db3919924cb01300139d7334bfd0793b3d7b4 Mon Sep 17 00:00:00 2001 From: Herbert Wolverson Date: Thu, 27 Jun 2024 13:26:59 -0500 Subject: [PATCH] Minimal network tree summary --- .../js_build/src/dashlets/dashlet_index.js | 3 + .../js_build/src/dashlets/top_tree_summary.js | 61 +++++++++++++++++++ .../src/node_manager/ws/published_channels.rs | 1 + src/rust/lqosd/src/node_manager/ws/ticker.rs | 2 + .../node_manager/ws/ticker/tree_summary.rs | 23 +++++++ 5 files changed, 90 insertions(+) create mode 100644 src/rust/lqosd/src/node_manager/js_build/src/dashlets/top_tree_summary.js create mode 100644 src/rust/lqosd/src/node_manager/ws/ticker/tree_summary.rs diff --git a/src/rust/lqosd/src/node_manager/js_build/src/dashlets/dashlet_index.js b/src/rust/lqosd/src/node_manager/js_build/src/dashlets/dashlet_index.js index 451776cc..68722753 100644 --- a/src/rust/lqosd/src/node_manager/js_build/src/dashlets/dashlet_index.js +++ b/src/rust/lqosd/src/node_manager/js_build/src/dashlets/dashlet_index.js @@ -14,6 +14,7 @@ import {IpProtocols} from "./ip_protocols"; import {Worst10Retransmits} from "./worst10_retransmits"; import {CpuDash} from "./cpu_dash"; import {RamDash} from "./ram_dash"; +import {TopTreeSummary} from "./top_tree_summary"; export const DashletMenu = [ { name: "Throughput Bits/Second", tag: "throughputBps", size: 3 }, @@ -32,6 +33,7 @@ export const DashletMenu = [ { name: "IP Protocols", tag: "ipProtocols", size: 6 }, { name: "CPU Utilization", tag: "cpu", size: 6 }, { name: "RAM Utilization", tag: "ram", size: 6 }, + { name: "Network Tree Summary", tag: "treeSummary", size: 6 }, ]; export function widgetFactory(widgetName, count) { @@ -53,6 +55,7 @@ export function widgetFactory(widgetName, count) { case "ipProtocols" : widget = new IpProtocols(count); break; case "cpu" : widget = new CpuDash(count); break; case "ram" : widget = new RamDash(count); break; + case "treeSummary" : widget = new TopTreeSummary(count); break; default: { console.log("I don't know how to construct a widget of type [" + widgetName + "]"); return null; diff --git a/src/rust/lqosd/src/node_manager/js_build/src/dashlets/top_tree_summary.js b/src/rust/lqosd/src/node_manager/js_build/src/dashlets/top_tree_summary.js new file mode 100644 index 00000000..29efe692 --- /dev/null +++ b/src/rust/lqosd/src/node_manager/js_build/src/dashlets/top_tree_summary.js @@ -0,0 +1,61 @@ +import {BaseDashlet} from "./base_dashlet"; +import {simpleRow, theading} from "../helpers/builders"; +import {scaleNumber, scaleNanos} from "../helpers/scaling"; + +export class TopTreeSummary extends BaseDashlet { + constructor(slot) { + super(slot); + } + + title() { + return "Network Tree"; + } + + subscribeTo() { + return [ "TreeSummary" ]; + } + + buildContainer() { + let base = super.buildContainer(); + base.style.height = "250px"; + base.style.overflow = "auto"; + return base; + } + + setup() { + super.setup(); + } + + onMessage(msg) { + if (msg.event === "TreeSummary") { + console.log(msg.data); + let target = document.getElementById(this.id); + + let t = document.createElement("table"); + t.classList.add("table", "table-striped", "tiny"); + + let th = document.createElement("thead"); + th.appendChild(theading("Branch")); + th.appendChild(theading("DL ⬇️")); + th.appendChild(theading("UL ⬆️")); + t.appendChild(th); + + let tbody = document.createElement("tbody"); + msg.data.forEach((r) => { + let row = document.createElement("tr"); + row.appendChild(simpleRow(r[1].name)); + row.appendChild(simpleRow(scaleNumber(r[1].current_throughput[0]))); + row.appendChild(simpleRow(scaleNumber(r[1].current_throughput[1]))); + t.appendChild(row); + }); + + t.appendChild(tbody); + + // Display it + while (target.children.length > 1) { + target.removeChild(target.lastChild); + } + target.appendChild(t); + } + } +} \ No newline at end of file diff --git a/src/rust/lqosd/src/node_manager/ws/published_channels.rs b/src/rust/lqosd/src/node_manager/ws/published_channels.rs index f5b1945d..0e30f1aa 100644 --- a/src/rust/lqosd/src/node_manager/ws/published_channels.rs +++ b/src/rust/lqosd/src/node_manager/ws/published_channels.rs @@ -17,4 +17,5 @@ pub enum PublishedChannels { IpProtocols, Cpu, Ram, + TreeSummary, } diff --git a/src/rust/lqosd/src/node_manager/ws/ticker.rs b/src/rust/lqosd/src/node_manager/ws/ticker.rs index 6a3ff6fc..1f55c4ae 100644 --- a/src/rust/lqosd/src/node_manager/ws/ticker.rs +++ b/src/rust/lqosd/src/node_manager/ws/ticker.rs @@ -7,6 +7,7 @@ mod ipstats_conversion; mod top_flows; mod flow_endpoints; pub mod system_info; +mod tree_summary; use std::sync::Arc; use crate::node_manager::ws::publish_subscribe::PubSub; @@ -32,6 +33,7 @@ pub(super) async fn channel_ticker(channels: Arc) { flow_endpoints::ip_protocols(channels.clone()), system_info::cpu_info(channels.clone()), system_info::ram_info(channels.clone()), + tree_summary::tree_summary(channels.clone()), ); } } \ No newline at end of file diff --git a/src/rust/lqosd/src/node_manager/ws/ticker/tree_summary.rs b/src/rust/lqosd/src/node_manager/ws/ticker/tree_summary.rs new file mode 100644 index 00000000..d774f5c8 --- /dev/null +++ b/src/rust/lqosd/src/node_manager/ws/ticker/tree_summary.rs @@ -0,0 +1,23 @@ +use std::sync::Arc; +use serde_json::json; +use lqos_bus::BusResponse; +use crate::node_manager::ws::publish_subscribe::PubSub; +use crate::node_manager::ws::published_channels::PublishedChannels; +use crate::shaped_devices_tracker; + +pub async fn tree_summary(channels: Arc) { + if !channels.is_channel_alive(PublishedChannels::TreeSummary).await { + return; + } + + if let BusResponse::NetworkMap(nodes) = shaped_devices_tracker::get_top_n_root_queues(10) { + + let message = json!( + { + "event": PublishedChannels::TreeSummary.to_string(), + "data": nodes, + } + ).to_string(); + channels.send(PublishedChannels::TreeSummary, message).await; + } +} \ No newline at end of file