Restructure into workspace with dashboard and agent
This commit is contained in:
138
dashboard/src/data/config.rs
Normal file
138
dashboard/src/data/config.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct HostsConfig {
|
||||
pub default_host: Option<String>,
|
||||
#[serde(default)]
|
||||
pub hosts: Vec<HostTarget>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct HostTarget {
|
||||
pub name: String,
|
||||
#[serde(default = "default_true")]
|
||||
pub enabled: bool,
|
||||
#[serde(default)]
|
||||
pub metadata: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl HostTarget {
|
||||
pub fn from_name(name: String) -> Self {
|
||||
Self {
|
||||
name,
|
||||
enabled: true,
|
||||
metadata: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct DashboardConfig {
|
||||
#[serde(default = "default_tick_rate_ms")]
|
||||
pub tick_rate_ms: u64,
|
||||
#[serde(default)]
|
||||
pub history_duration_minutes: u64,
|
||||
#[serde(default)]
|
||||
pub widgets: Vec<WidgetConfig>,
|
||||
}
|
||||
|
||||
impl Default for DashboardConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
tick_rate_ms: default_tick_rate_ms(),
|
||||
history_duration_minutes: 60,
|
||||
widgets: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct WidgetConfig {
|
||||
pub id: String,
|
||||
#[serde(default)]
|
||||
pub enabled: bool,
|
||||
#[serde(default)]
|
||||
pub options: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct AppFilesystem {
|
||||
pub cache_dir: Option<PathBuf>,
|
||||
pub history_dir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct AppConfig {
|
||||
pub hosts: HostsConfig,
|
||||
#[serde(default)]
|
||||
pub dashboard: DashboardConfig,
|
||||
#[serde(default = "default_data_source_config")]
|
||||
pub data_source: DataSourceConfig,
|
||||
#[serde(default)]
|
||||
pub filesystem: Option<AppFilesystem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct DataSourceConfig {
|
||||
#[serde(default = "default_data_source_kind")]
|
||||
pub kind: DataSourceKind,
|
||||
#[serde(default)]
|
||||
pub zmq: ZmqConfig,
|
||||
}
|
||||
|
||||
impl Default for DataSourceConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
kind: DataSourceKind::Zmq,
|
||||
zmq: ZmqConfig::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum DataSourceKind {
|
||||
Zmq,
|
||||
}
|
||||
|
||||
fn default_data_source_kind() -> DataSourceKind {
|
||||
DataSourceKind::Zmq
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct ZmqConfig {
|
||||
#[serde(default = "default_zmq_endpoints")]
|
||||
pub endpoints: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub subscribe: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for ZmqConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
endpoints: default_zmq_endpoints(),
|
||||
subscribe: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fn default_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
const fn default_tick_rate_ms() -> u64 {
|
||||
500
|
||||
}
|
||||
|
||||
fn default_data_source_config() -> DataSourceConfig {
|
||||
DataSourceConfig::default()
|
||||
}
|
||||
|
||||
fn default_zmq_endpoints() -> Vec<String> {
|
||||
vec!["tcp://127.0.0.1:6130".to_string()]
|
||||
}
|
||||
54
dashboard/src/data/history.rs
Normal file
54
dashboard/src/data/history.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::time::Duration;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
use crate::data::metrics::{BackupMetrics, ServiceMetrics, SmartMetrics};
|
||||
|
||||
/// Ring buffer for retaining recent samples for trend analysis.
|
||||
#[derive(Debug)]
|
||||
pub struct MetricsHistory {
|
||||
capacity: usize,
|
||||
smart: VecDeque<(DateTime<Utc>, SmartMetrics)>,
|
||||
services: VecDeque<(DateTime<Utc>, ServiceMetrics)>,
|
||||
backups: VecDeque<(DateTime<Utc>, BackupMetrics)>,
|
||||
}
|
||||
|
||||
impl MetricsHistory {
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
capacity,
|
||||
smart: VecDeque::with_capacity(capacity),
|
||||
services: VecDeque::with_capacity(capacity),
|
||||
backups: VecDeque::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn record_smart(&mut self, metrics: SmartMetrics) {
|
||||
let entry = (Utc::now(), metrics);
|
||||
Self::push_with_limit(&mut self.smart, entry, self.capacity);
|
||||
}
|
||||
|
||||
pub fn record_services(&mut self, metrics: ServiceMetrics) {
|
||||
let entry = (Utc::now(), metrics);
|
||||
Self::push_with_limit(&mut self.services, entry, self.capacity);
|
||||
}
|
||||
|
||||
pub fn record_backup(&mut self, metrics: BackupMetrics) {
|
||||
let entry = (Utc::now(), metrics);
|
||||
Self::push_with_limit(&mut self.backups, entry, self.capacity);
|
||||
}
|
||||
|
||||
pub fn retention(&self) -> Duration {
|
||||
Duration::from_secs((self.capacity as u64) * 30)
|
||||
}
|
||||
|
||||
fn push_with_limit<T>(deque: &mut VecDeque<T>, item: T, capacity: usize) {
|
||||
if deque.len() == capacity {
|
||||
deque.pop_front();
|
||||
}
|
||||
deque.push_back(item);
|
||||
}
|
||||
}
|
||||
96
dashboard/src/data/metrics.rs
Normal file
96
dashboard/src/data/metrics.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SmartMetrics {
|
||||
pub status: String,
|
||||
pub drives: Vec<DriveInfo>,
|
||||
pub summary: DriveSummary,
|
||||
pub issues: Vec<String>,
|
||||
pub timestamp: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DriveInfo {
|
||||
pub name: String,
|
||||
pub temperature_c: f32,
|
||||
pub wear_level: f32,
|
||||
pub power_on_hours: u64,
|
||||
pub available_spare: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DriveSummary {
|
||||
pub healthy: usize,
|
||||
pub warning: usize,
|
||||
pub critical: usize,
|
||||
pub capacity_total_gb: f32,
|
||||
pub capacity_used_gb: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ServiceMetrics {
|
||||
pub summary: ServiceSummary,
|
||||
pub services: Vec<ServiceInfo>,
|
||||
pub timestamp: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ServiceSummary {
|
||||
pub healthy: usize,
|
||||
pub degraded: usize,
|
||||
pub failed: usize,
|
||||
pub memory_used_mb: f32,
|
||||
pub memory_quota_mb: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ServiceInfo {
|
||||
pub name: String,
|
||||
pub status: ServiceStatus,
|
||||
pub memory_used_mb: f32,
|
||||
pub memory_quota_mb: f32,
|
||||
pub cpu_percent: f32,
|
||||
pub sandbox_limit: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ServiceStatus {
|
||||
Running,
|
||||
Degraded,
|
||||
Restarting,
|
||||
Stopped,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BackupMetrics {
|
||||
pub overall_status: BackupStatus,
|
||||
pub backup: BackupInfo,
|
||||
pub service: BackupServiceInfo,
|
||||
pub timestamp: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BackupInfo {
|
||||
pub last_success: Option<DateTime<Utc>>,
|
||||
pub last_failure: Option<DateTime<Utc>>,
|
||||
pub size_gb: f32,
|
||||
pub snapshot_count: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BackupServiceInfo {
|
||||
pub enabled: bool,
|
||||
pub pending_jobs: u32,
|
||||
pub last_message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum BackupStatus {
|
||||
Healthy,
|
||||
Warning,
|
||||
Failed,
|
||||
Unknown,
|
||||
}
|
||||
3
dashboard/src/data/mod.rs
Normal file
3
dashboard/src/data/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod config;
|
||||
pub mod history;
|
||||
pub mod metrics;
|
||||
Reference in New Issue
Block a user