More data in anonymous stats.

This commit is contained in:
Herbert Wolverson 2023-03-17 14:19:33 +00:00
parent 08e7788efb
commit 8146472479
5 changed files with 110 additions and 5 deletions

View File

@ -3,6 +3,18 @@
/// Defines data to be submitted if anonymous usage submission is
/// enabled. This is protocol version 1.
pub struct AnonymousUsageV1 {
/// Unique but anonymous node identifier
pub node_id: String,
/// The git hash from which this version was compiled
pub git_hash: String,
/// Are they using the Bifrost bridge?
pub using_xdp_bridge: bool,
/// Is it an "On a stick" config?
pub on_a_stick: bool,
/// Total installed RAM (bytes)
pub total_memory: u64,
@ -12,6 +24,9 @@ pub struct AnonymousUsageV1 {
/// Linux Kernel Version
pub kernel_version: String,
/// Linux distro
pub distro: String,
/// Number of "usable" CPU cores, as used by eBPF. This may not
/// be exactly equal to the number of actual cores.
pub usable_cores: u32,

View File

@ -1,7 +1,8 @@
//! Manages the `/etc/lqos.conf` file.
use log::error;
use serde::{Deserialize, Serialize};
use std::path::Path;
use uuid::Uuid;
use std::{path::Path, fs};
use thiserror::Error;
/// Represents the top-level of the `/etc/lqos.conf` file. Serialization
@ -15,6 +16,12 @@ pub struct EtcLqos {
/// In ms.
pub queue_check_period_ms: u64,
/// If present, provides a unique ID for the node. Used for
/// anonymous stats (to identify nodes without providing an actual
/// identity), and will be used for long-term data retention to
/// disambiguate cluster or multi-head-end nodes.
pub node_id: Option<String>,
/// If present, defines how the Bifrost XDP bridge operates.
pub bridge: Option<BridgeConfig>,
@ -127,7 +134,10 @@ impl EtcLqos {
if let Ok(raw) = std::fs::read_to_string("/etc/lqos.conf") {
let config_result: Result<Self, toml::de::Error> = toml::from_str(&raw);
match config_result {
Ok(config) => Ok(config),
Ok(mut config) => {
check_config(&mut config);
Ok(config)
}
Err(e) => {
error!("Unable to parse TOML from /etc/lqos.conf");
error!("Full error: {:?}", e);
@ -139,8 +149,50 @@ impl EtcLqos {
Err(EtcLqosError::CannotReadFile)
}
}
/// Saves changes made to /etc/lqos.conf
/// Copies current configuration into /etc/lqos.conf.backup first
pub fn save(&self) -> Result<(), EtcLqosError> {
let cfg_path = Path::new("/etc/lqos.conf");
let backup_path = Path::new("/etc/lqos.conf.backup");
if let Err(e) = std::fs::copy(cfg_path, backup_path) {
log::error!("Unable to backup /etc/lqos.conf");
log::error!("{e:?}");
return Err(EtcLqosError::BackupFail);
}
let new_cfg = toml::to_string_pretty(&self);
match new_cfg {
Err(e) => {
log::error!("Unable to serialize new /etc/lqos.conf");
log::error!("{e:?}");
return Err(EtcLqosError::SerializeFail);
}
Ok(new_cfg) => {
if let Err(e) = fs::write(cfg_path, new_cfg) {
log::error!("Unable to write to /etc/lqos.conf");
log::error!("{e:?}");
return Err(EtcLqosError::WriteFail);
}
}
}
Ok(())
}
}
fn check_config(cfg: &mut EtcLqos) {
let mut changed = false;
if cfg.node_id.is_none() {
let new_id = Uuid::new_v4();
cfg.node_id = Some(new_id.to_string());
changed = true;
}
if changed {
let _ = cfg.save();
}
}
#[derive(Error, Debug)]
pub enum EtcLqosError {
#[error(
@ -151,4 +203,10 @@ pub enum EtcLqosError {
CannotReadFile,
#[error("Unable to parse TOML in /etc/lqos.conf")]
CannotParseToml,
#[error("Unable to backup /etc/lqos.conf to /etc/lqos.conf.backup")]
BackupFail,
#[error("Unable to serialize new configuration")]
SerializeFail,
#[error("Unable to write to /etc/lqos.conf")]
WriteFail,
}

7
src/rust/lqosd/build.rs Normal file
View File

@ -0,0 +1,7 @@
use std::process::Command;
fn main() {
// Adds a git commit hash to the program
let output = Command::new("git").args(["rev-parse", "HEAD"]).output().unwrap();
let git_hash = String::from_utf8(output.stdout).unwrap();
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
}

View File

@ -1,10 +1,10 @@
mod lshw;
mod version;
use std::time::Duration;
use lqos_bus::anonymous::AnonymousUsageV1;
use lqos_config::{EtcLqos, LibreQoSConfig};
use lqos_sys::num_possible_cpus;
use sysinfo::{System, SystemExt, CpuExt};
use crate::shaped_devices_tracker::{SHAPED_DEVICES, NETWORK_JSON};
const SLOW_START_SECS: u64 = 1;
@ -44,8 +44,13 @@ fn anonymous_usage_dump() -> anyhow::Result<()> {
data.cpu_vendor = cpu.vendor_id().to_string();
data.cpu_frequency = cpu.frequency();
}
for nic in lshw::get_nic_info()? {
data.nics.push(nic.into());
if let Ok(nics) = lshw::get_nic_info() {
for nic in nics {
data.nics.push(nic.into());
}
}
if let Ok(pv) = version::get_proc_version() {
data.distro = pv.trim().to_string();
}
if let Ok(cfg) = LibreQoSConfig::load() {
@ -59,8 +64,19 @@ fn anonymous_usage_dump() -> anyhow::Result<()> {
cfg.generated_download_mbps,
cfg.generated_upload_mbps,
);
data.on_a_stick = cfg.on_a_stick_mode;
}
if let Ok(cfg) = EtcLqos::load() {
if let Some(node_id) = cfg.node_id {
data.node_id = node_id;
if let Some(bridge) = cfg.bridge {
data.using_xdp_bridge = bridge.use_xdp_bridge;
}
}
}
data.git_hash = env!("GIT_HASH").to_string();
data.shaped_device_count = SHAPED_DEVICES.read().unwrap().devices.len();
data.net_json_len = NETWORK_JSON.read().unwrap().nodes.len();

View File

@ -0,0 +1,9 @@
use std::process::Command;
pub(crate) fn get_proc_version() -> anyhow::Result<String> {
let output = Command::new("/bin/cat")
.args(["/proc/version"])
.output()?;
let stdout = String::from_utf8(output.stdout)?;
Ok(stdout)
}