Restructure into workspace with dashboard and agent
This commit is contained in:
parent
65d31514a1
commit
82afe3d4f1
114
Cargo.lock
generated
114
Cargo.lock
generated
@ -1,5 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
# This file is automatically generated by Cargo.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
@ -237,6 +238,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"clap",
|
||||
"cm-dashboard-shared",
|
||||
"crossterm",
|
||||
"ratatui",
|
||||
"serde",
|
||||
@ -249,6 +251,33 @@ dependencies = [
|
||||
"zmq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cm-dashboard-agent"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"clap",
|
||||
"cm-dashboard-shared",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
"tracing-subscriber",
|
||||
"zmq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cm-dashboard-shared"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.4"
|
||||
@ -386,6 +415,17 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.3"
|
||||
@ -511,7 +551,7 @@ version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.3.3",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@ -624,7 +664,7 @@ version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -710,6 +750,15 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.101"
|
||||
@ -734,6 +783,36 @@ version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ratatui"
|
||||
version = "0.24.0"
|
||||
@ -1364,7 +1443,7 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1459,6 +1538,15 @@ dependencies = [
|
||||
"windows-targets 0.53.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
@ -1660,6 +1748,26 @@ version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeromq-src"
|
||||
version = "0.2.6+4.3.4"
|
||||
|
||||
27
Cargo.toml
27
Cargo.toml
@ -1,19 +1,8 @@
|
||||
[package]
|
||||
name = "cm-dashboard"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
ratatui = "0.24"
|
||||
crossterm = "0.27"
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
clap = { version = "4.0", features = ["derive"] }
|
||||
anyhow = "1.0"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
toml = "0.8"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] }
|
||||
tracing-appender = "0.2"
|
||||
zmq = "0.10"
|
||||
[workspace]
|
||||
members = [
|
||||
"dashboard",
|
||||
"agent",
|
||||
"shared"
|
||||
]
|
||||
resolver = "2"
|
||||
default-members = ["dashboard"]
|
||||
|
||||
28
README.md
28
README.md
@ -30,7 +30,7 @@ CM Dashboard is a Rust-powered terminal UI for real-time monitoring of CMTEC inf
|
||||
## Requirements
|
||||
|
||||
- Rust toolchain 1.75+ (install via [`rustup`](https://rustup.rs))
|
||||
- Network access to the CMTEC metrics gossip agents (default `tcp://<host>:6130`)
|
||||
- Network access to the CMTEC metrics gossip agents (default `tcp://<host>:6130`; install `zeromq`/`libzmq` on the host)
|
||||
- Configuration files under `config/` describing hosts and dashboard preferences
|
||||
|
||||
## Installation
|
||||
@ -46,7 +46,7 @@ cargo build --release
|
||||
The optimized binary is available at `target/release/cm-dashboard`. To install into your Cargo bin directory:
|
||||
|
||||
```bash
|
||||
cargo install --path .
|
||||
cargo install --path dashboard
|
||||
```
|
||||
|
||||
## Configuration
|
||||
@ -56,7 +56,7 @@ On first launch, the dashboard will create `config/dashboard.toml` and `config/h
|
||||
You can also generate starter configuration files manually with the built-in helper:
|
||||
|
||||
```bash
|
||||
cargo run -- init-config
|
||||
cargo run -p cm-dashboard -- init-config
|
||||
# or, once installed
|
||||
cm-dashboard init-config --dir ./config --force
|
||||
```
|
||||
@ -107,13 +107,13 @@ Adjust the host list and `data_source.zmq.endpoints` to match your CMTEC gossip
|
||||
## Getting Started
|
||||
|
||||
```bash
|
||||
cargo run -- --config config/dashboard.toml
|
||||
cargo run -p cm-dashboard -- --config config/dashboard.toml
|
||||
# specify a single host
|
||||
cargo run -- --host srv01
|
||||
cargo run -p cm-dashboard -- --host srv01
|
||||
# override ZMQ endpoints at runtime
|
||||
cargo run -- --zmq-endpoint tcp://srv01:6130,tcp://labbox:6130
|
||||
cargo run -p cm-dashboard -- --zmq-endpoint tcp://srv01:6130,tcp://labbox:6130
|
||||
# increase logging verbosity
|
||||
cargo run -- -v
|
||||
cargo run -p cm-dashboard -- -v
|
||||
```
|
||||
|
||||
### Keyboard Shortcuts
|
||||
@ -126,10 +126,20 @@ cargo run -- -v
|
||||
| `r` | Update status message |
|
||||
| `q` / `Esc` | Quit |
|
||||
|
||||
## Agent
|
||||
|
||||
The metrics agent publishes SMART/service/backup data to the gossip network. Run it on each host (or under systemd/NixOS) and point the dashboard at its endpoint. Example:
|
||||
|
||||
```bash
|
||||
cargo run -p cm-dashboard-agent -- --hostname srv01 --bind tcp://*:6130 --interval-ms 5000
|
||||
```
|
||||
|
||||
Use `--disable-*` flags to skip collectors when a host doesn’t expose those metrics.
|
||||
|
||||
## Development
|
||||
|
||||
- Format: `cargo fmt`
|
||||
- Check: `cargo check`
|
||||
- Run: `cargo run`
|
||||
- Check workspace: `cargo check`
|
||||
- Build release binaries: `cargo build --release`
|
||||
|
||||
The dashboard subscribes to the CMTEC ZMQ gossip network (default `tcp://127.0.0.1:6130`). Received metrics are cached per host and retained in an in-memory ring buffer for future trend analysis.
|
||||
|
||||
18
agent/Cargo.toml
Normal file
18
agent/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "cm-dashboard-agent"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
cm-dashboard-shared = { path = "../shared" }
|
||||
anyhow = "1.0"
|
||||
clap = { version = "4.0", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] }
|
||||
tracing-appender = "0.2"
|
||||
zmq = "0.10"
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
rand = "0.8"
|
||||
182
agent/src/main.rs
Normal file
182
agent/src/main.rs
Normal file
@ -0,0 +1,182 @@
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use chrono::Utc;
|
||||
use clap::{ArgAction, Parser};
|
||||
use cm_dashboard_shared::envelope::{AgentType, MetricsEnvelope};
|
||||
use rand::Rng;
|
||||
use serde_json::json;
|
||||
use tracing::info;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use zmq::{Context as ZmqContext, SocketType};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(
|
||||
name = "cm-dashboard-agent",
|
||||
version,
|
||||
about = "CM Dashboard metrics agent"
|
||||
)]
|
||||
struct Cli {
|
||||
/// Hostname to advertise in metric envelopes
|
||||
#[arg(long, value_name = "HOSTNAME")]
|
||||
hostname: String,
|
||||
|
||||
/// Bind endpoint for PUB socket (default tcp://*:6130)
|
||||
#[arg(long, default_value = "tcp://*:6130", value_name = "ENDPOINT")]
|
||||
bind: String,
|
||||
|
||||
/// Publish interval in milliseconds
|
||||
#[arg(long, default_value_t = 5000)]
|
||||
interval_ms: u64,
|
||||
|
||||
/// Disable smart metrics publisher
|
||||
#[arg(long, action = ArgAction::SetTrue)]
|
||||
disable_smart: bool,
|
||||
|
||||
/// Disable service metrics publisher
|
||||
#[arg(long, action = ArgAction::SetTrue)]
|
||||
disable_service: bool,
|
||||
|
||||
/// Disable backup metrics publisher
|
||||
#[arg(long, action = ArgAction::SetTrue)]
|
||||
disable_backup: bool,
|
||||
|
||||
/// Increase logging verbosity (-v, -vv)
|
||||
#[arg(short, long, action = ArgAction::Count)]
|
||||
verbose: u8,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
init_tracing(cli.verbose)?;
|
||||
|
||||
let context = ZmqContext::new();
|
||||
let socket = context
|
||||
.socket(SocketType::PUB)
|
||||
.context("failed to create ZMQ PUB socket")?;
|
||||
socket
|
||||
.bind(&cli.bind)
|
||||
.with_context(|| format!("failed to bind to {}", cli.bind))?;
|
||||
info!(endpoint = %cli.bind, host = %cli.hostname, "agent started");
|
||||
|
||||
let interval = Duration::from_millis(cli.interval_ms.max(100));
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
loop {
|
||||
let now = Utc::now();
|
||||
let timestamp = now.timestamp() as u64;
|
||||
let timestamp_rfc3339 = now.to_rfc3339();
|
||||
|
||||
if !cli.disable_smart {
|
||||
let envelope = MetricsEnvelope {
|
||||
hostname: cli.hostname.clone(),
|
||||
agent_type: AgentType::Smart,
|
||||
timestamp,
|
||||
metrics: json!({
|
||||
"status": "Healthy",
|
||||
"drives": [{
|
||||
"name": "nvme0n1",
|
||||
"temperature_c": rng.gen_range(30.0..60.0),
|
||||
"wear_level": rng.gen_range(1.0..10.0),
|
||||
"power_on_hours": rng.gen_range(1000..20000),
|
||||
"available_spare": rng.gen_range(90.0..100.0)
|
||||
}],
|
||||
"summary": {
|
||||
"healthy": 1,
|
||||
"warning": 0,
|
||||
"critical": 0,
|
||||
"capacity_total_gb": 1024,
|
||||
"capacity_used_gb": rng.gen_range(100.0..800.0)
|
||||
},
|
||||
"issues": [],
|
||||
"timestamp": timestamp_rfc3339
|
||||
}),
|
||||
};
|
||||
publish(&socket, &envelope)?;
|
||||
}
|
||||
|
||||
if !cli.disable_service {
|
||||
let envelope = MetricsEnvelope {
|
||||
hostname: cli.hostname.clone(),
|
||||
agent_type: AgentType::Service,
|
||||
timestamp,
|
||||
metrics: json!({
|
||||
"summary": {
|
||||
"healthy": 5,
|
||||
"degraded": 0,
|
||||
"failed": 0,
|
||||
"memory_used_mb": rng.gen_range(512.0..2048.0),
|
||||
"memory_quota_mb": 4096.0
|
||||
},
|
||||
"services": [
|
||||
{
|
||||
"name": "example",
|
||||
"status": "Running",
|
||||
"memory_used_mb": rng.gen_range(128.0..512.0),
|
||||
"memory_quota_mb": 1024.0,
|
||||
"cpu_percent": rng.gen_range(0.0..75.0),
|
||||
"sandbox_limit": null
|
||||
}
|
||||
],
|
||||
"timestamp": timestamp_rfc3339
|
||||
}),
|
||||
};
|
||||
publish(&socket, &envelope)?;
|
||||
}
|
||||
|
||||
if !cli.disable_backup {
|
||||
let envelope = MetricsEnvelope {
|
||||
hostname: cli.hostname.clone(),
|
||||
agent_type: AgentType::Backup,
|
||||
timestamp,
|
||||
metrics: json!({
|
||||
"overall_status": "Healthy",
|
||||
"backup": {
|
||||
"last_success": timestamp_rfc3339,
|
||||
"last_failure": null,
|
||||
"size_gb": rng.gen_range(100.0..500.0),
|
||||
"snapshot_count": rng.gen_range(10..40)
|
||||
},
|
||||
"service": {
|
||||
"enabled": true,
|
||||
"pending_jobs": 0,
|
||||
"last_message": "Backups up-to-date"
|
||||
},
|
||||
"timestamp": timestamp_rfc3339
|
||||
}),
|
||||
};
|
||||
publish(&socket, &envelope)?;
|
||||
}
|
||||
|
||||
thread::sleep(interval);
|
||||
}
|
||||
}
|
||||
|
||||
fn publish(socket: &zmq::Socket, envelope: &MetricsEnvelope) -> Result<()> {
|
||||
let serialized = serde_json::to_vec(envelope)?;
|
||||
socket.send(serialized, 0)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init_tracing(verbosity: u8) -> Result<()> {
|
||||
let level = match verbosity {
|
||||
0 => "info",
|
||||
1 => "debug",
|
||||
_ => "trace",
|
||||
};
|
||||
|
||||
let env_filter = std::env::var("RUST_LOG")
|
||||
.ok()
|
||||
.and_then(|value| EnvFilter::try_new(value).ok())
|
||||
.unwrap_or_else(|| EnvFilter::new(level));
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(env_filter)
|
||||
.with_target(false)
|
||||
.compact()
|
||||
.try_init()
|
||||
.map_err(|err| anyhow!(err))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
20
dashboard/Cargo.toml
Normal file
20
dashboard/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "cm-dashboard"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
cm-dashboard-shared = { path = "../shared" }
|
||||
ratatui = "0.24"
|
||||
crossterm = "0.27"
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
clap = { version = "4.0", features = ["derive"] }
|
||||
anyhow = "1.0"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
toml = "0.8"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] }
|
||||
tracing-appender = "0.2"
|
||||
zmq = "0.10"
|
||||
@ -220,6 +220,10 @@ impl App {
|
||||
|
||||
pub fn handle_app_event(&mut self, event: AppEvent) {
|
||||
match event {
|
||||
AppEvent::Shutdown => {
|
||||
self.should_quit = true;
|
||||
self.status = "Shutting down…".to_string();
|
||||
}
|
||||
AppEvent::MetricsUpdated {
|
||||
host,
|
||||
smart,
|
||||
@ -480,4 +484,5 @@ pub enum AppEvent {
|
||||
error: String,
|
||||
timestamp: DateTime<Utc>,
|
||||
},
|
||||
Shutdown,
|
||||
}
|
||||
@ -13,17 +13,17 @@ use crate::data::metrics::{BackupMetrics, ServiceMetrics, SmartMetrics};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use chrono::{TimeZone, Utc};
|
||||
use clap::{ArgAction, Parser, Subcommand};
|
||||
use cm_dashboard_shared::envelope::{AgentType, MetricsEnvelope};
|
||||
use crossterm::event::{self, Event};
|
||||
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
|
||||
use crossterm::{execute, terminal};
|
||||
use ratatui::backend::CrosstermBackend;
|
||||
use ratatui::Terminal;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
use tokio::sync::mpsc::{
|
||||
error::TryRecvError, unbounded_channel, UnboundedReceiver, UnboundedSender,
|
||||
};
|
||||
use tokio::task::spawn_blocking;
|
||||
use tokio::task::{spawn_blocking, JoinHandle};
|
||||
use tracing::{debug, warn};
|
||||
use tracing_appender::non_blocking::WorkerGuard;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
@ -100,13 +100,19 @@ async fn main() -> Result<()> {
|
||||
let mut app = App::new(options)?;
|
||||
let (event_tx, mut event_rx) = unbounded_channel();
|
||||
|
||||
if let Some(context) = app.zmq_context() {
|
||||
spawn_metrics_task(context, event_tx.clone());
|
||||
}
|
||||
let zmq_task = if let Some(context) = app.zmq_context() {
|
||||
Some(spawn_metrics_task(context, event_tx.clone()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut terminal = setup_terminal()?;
|
||||
let result = run_app(&mut terminal, &mut app, &mut event_rx);
|
||||
teardown_terminal(terminal)?;
|
||||
let _ = event_tx.send(AppEvent::Shutdown);
|
||||
if let Some(handle) = zmq_task {
|
||||
handle.abort();
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
@ -200,14 +206,14 @@ fn prepare_log_writer() -> Result<tracing_appender::non_blocking::NonBlocking> {
|
||||
Ok(non_blocking)
|
||||
}
|
||||
|
||||
fn spawn_metrics_task(context: ZmqContext, sender: UnboundedSender<AppEvent>) {
|
||||
fn spawn_metrics_task(context: ZmqContext, sender: UnboundedSender<AppEvent>) -> JoinHandle<()> {
|
||||
tokio::spawn(async move {
|
||||
match spawn_blocking(move || metrics_blocking_loop(context, sender)).await {
|
||||
Ok(Ok(())) => {}
|
||||
Ok(Err(error)) => warn!(%error, "ZMQ metrics worker exited with error"),
|
||||
Err(join_error) => warn!(%join_error, "ZMQ metrics worker panicked"),
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
fn metrics_blocking_loop(context: ZmqContext, sender: UnboundedSender<AppEvent>) -> Result<()> {
|
||||
@ -332,23 +338,6 @@ fn handle_zmq_message(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
enum AgentType {
|
||||
Smart,
|
||||
Service,
|
||||
Backup,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct MetricsEnvelope {
|
||||
hostname: String,
|
||||
#[serde(rename = "agent_type")]
|
||||
agent_type: AgentType,
|
||||
timestamp: u64,
|
||||
metrics: Value,
|
||||
}
|
||||
|
||||
fn ensure_default_config(cli: &Cli) -> Result<()> {
|
||||
if let Some(path) = cli.config.as_ref() {
|
||||
ensure_config_at(path, false)?;
|
||||
@ -441,13 +430,11 @@ const DASHBOARD_TEMPLATE: &str = r#"# CM Dashboard configuration
|
||||
|
||||
[[hosts.hosts]]
|
||||
name = "srv01"
|
||||
base_url = "http://srv01.local"
|
||||
enabled = true
|
||||
# metadata = { rack = "R1" }
|
||||
|
||||
[[hosts.hosts]]
|
||||
name = "labbox"
|
||||
base_url = "http://labbox.local"
|
||||
enabled = true
|
||||
|
||||
[dashboard]
|
||||
@ -482,11 +469,9 @@ const HOSTS_TEMPLATE: &str = r#"# Optional separate hosts configuration
|
||||
|
||||
[[hosts.hosts]]
|
||||
name = "srv01"
|
||||
base_url = "http://srv01.local"
|
||||
enabled = true
|
||||
|
||||
[[hosts.hosts]]
|
||||
name = "labbox"
|
||||
base_url = "http://labbox.local"
|
||||
enabled = true
|
||||
"#;
|
||||
9
shared/Cargo.toml
Normal file
9
shared/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "cm-dashboard-shared"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
19
shared/src/envelope.rs
Normal file
19
shared/src/envelope.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum AgentType {
|
||||
Smart,
|
||||
Service,
|
||||
Backup,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct MetricsEnvelope {
|
||||
pub hostname: String,
|
||||
pub agent_type: AgentType,
|
||||
pub timestamp: u64,
|
||||
#[serde(default)]
|
||||
pub metrics: Value,
|
||||
}
|
||||
1
shared/src/lib.rs
Normal file
1
shared/src/lib.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod envelope;
|
||||
Loading…
x
Reference in New Issue
Block a user