Round-trip load/edit/save cycle is basically working for lqos.conf files. More testing needed, passed the easy cases I tried.

This commit is contained in:
Herbert Wolverson 2024-05-01 12:36:47 -05:00
parent 001f01da98
commit e2e22ea7ae
21 changed files with 89 additions and 19 deletions

View File

@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
/// One or more `BusRequest` objects must be included in a `BusSession`
/// request. Each `BusRequest` represents a single request for action
/// or data.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum BusRequest {
/// A generic "is it alive?" test. Returns an `Ack`.
Ping,
@ -113,6 +113,9 @@ pub enum BusRequest {
/// Requests a real-time adjustment of the `lqosd` tuning settings
UpdateLqosDTuning(u64, Tunables),
/// Requests that the configuration be updated
UpdateLqosdConfig(Box<lqos_config::Config>),
/// Request that we start watching a circuit's queue
WatchQueue(String),

View File

@ -1,6 +1,8 @@
//! Manages the `/etc/lqos.conf` file.
mod etclqos_migration;
use std::path::Path;
use self::migration::migrate_if_needed;
pub use self::v15::Config;
pub use etclqos_migration::*;
@ -70,6 +72,38 @@ pub fn enable_long_term_stats(license_key: String) -> Result<(), LibreQoSConfigE
Ok(())
}
/// Update the configuration on disk
pub fn update_config(new_config: &Config) -> Result<(), LibreQoSConfigError> {
log::info!("Updating stored configuration");
let mut lock = CONFIG.lock().unwrap();
*lock = Some(new_config.clone());
// Does the configuration exist?
let config_path = Path::new("/etc/lqos.conf");
if config_path.exists() {
let backup_path = Path::new("/etc/lqos.conf.webbackup");
std::fs::copy(config_path, backup_path)
.map_err(|e| {
log::error!("Unable to create backup configuration: {e:?}");
LibreQoSConfigError::CannotCopy
})?;
}
// Serialize the new one
let serialized = toml::to_string_pretty(new_config)
.map_err(|e| {
log::error!("Unable to serialize new configuration to TOML: {e:?}");
LibreQoSConfigError::SerializeError
})?;
std::fs::write(config_path, serialized)
.map_err(|e| {
log::error!("Unable to write new configuration: {e:?}");
LibreQoSConfigError::CannotWrite
})?;
Ok(())
}
#[derive(Debug, Error)]
pub enum LibreQoSConfigError {
#[error("Unable to read /etc/lqos.conf. See other errors for details.")]
@ -90,4 +124,6 @@ pub enum LibreQoSConfigError {
CannotWrite,
#[error("Unable to read IP")]
CannotReadIP,
#[error("Unable to serialize config")]
SerializeError,
}

View File

@ -3,7 +3,7 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub struct UsageStats {
/// Are we allowed to send stats at all?
pub send_anonymous: bool,

View File

@ -5,7 +5,7 @@
use serde::{Deserialize, Serialize};
/// Represents a two-interface bridge configuration.
#[derive(Clone, Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub struct BridgeConfig {
/// Use the XDP-accelerated bridge?
pub use_xdp_bridge: bool,
@ -27,7 +27,7 @@ impl Default for BridgeConfig {
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub struct SingleInterfaceConfig {
/// The name of the interface
pub interface: String,

View File

@ -4,7 +4,7 @@
use serde::{Serialize, Deserialize};
#[derive(Clone, Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub struct FlowConfig {
pub flow_timeout_seconds: u64,
pub netflow_enabled: bool,

View File

@ -1,6 +1,6 @@
use serde::{Serialize, Deserialize};
#[derive(Clone, Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub struct InfluxDbConfig {
pub enable_influxdb: bool,
pub url: String,

View File

@ -2,7 +2,7 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub struct IntegrationConfig {
/// Replace names with addresses?
pub circuit_name_as_address: bool,

View File

@ -1,6 +1,6 @@
use serde::{Serialize, Deserialize};
#[derive(Clone, Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub struct IpRanges {
pub ignore_subnets: Vec<String>,
pub allow_subnets: Vec<String>,

View File

@ -2,7 +2,7 @@
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct LongTermStats {
/// Should we store long-term stats at all?
pub gather_stats: bool,

View File

@ -1,6 +1,6 @@
use serde::{Serialize, Deserialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct PowercodeIntegration {
pub enable_powercode: bool,
pub powercode_api_key: String,

View File

@ -2,7 +2,7 @@
use serde::{Serialize, Deserialize};
#[derive(Clone, Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub struct QueueConfig {
/// Which SQM to use by default
pub default_sqm: String,

View File

@ -1,6 +1,6 @@
use serde::{Serialize, Deserialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct SonarIntegration {
pub enable_sonar: bool,
pub sonar_api_url: String,

View File

@ -1,6 +1,6 @@
use serde::{Serialize, Deserialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct SplynxIntegration {
pub enable_spylnx: bool,
pub api_key: String,

View File

@ -8,7 +8,7 @@ use sha2::Digest;
use uuid::Uuid;
/// Top-level configuration file for LibreQoS.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Config {
/// Version number for the configuration file.
/// This will be set to "1.5". Versioning will make

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
/// Represents a set of `sysctl` and `ethtool` tweaks that may be
/// applied (in place of the previous version's offload service)
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub struct Tunables {
/// Should the `irq_balance` system service be stopped?
pub stop_irq_balance: bool,

View File

@ -1,6 +1,6 @@
use serde::{Serialize, Deserialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct UispIntegration {
pub enable_uisp: bool,
pub token: String,
@ -18,7 +18,7 @@ pub struct UispIntegration {
pub use_ptmp_as_parent: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct ExceptionCpe {
pub cpe: String,
pub parent: String,

View File

@ -13,7 +13,7 @@ mod program_control;
mod shaped_devices;
pub use authentication::{UserRole, WebUsers};
pub use etc::{load_config, Config, enable_long_term_stats, Tunables, BridgeConfig};
pub use etc::{load_config, Config, enable_long_term_stats, Tunables, BridgeConfig, update_config};
pub use network_json::{NetworkJson, NetworkJsonNode, NetworkJsonTransport};
pub use program_control::load_libreqos;
pub use shaped_devices::{ConfigShapedDevices, ShapedDevice};

View File

@ -1,5 +1,6 @@
use crate::{auth_guard::AuthGuard, cache_control::NoCache};
use default_net::get_interfaces;
use reqwest::StatusCode;
use lqos_bus::{bus_request, BusRequest, BusResponse};
use lqos_config::{Tunables, Config};
use rocket::{fs::NamedFile, serde::{json::Json, Serialize}};
@ -39,6 +40,17 @@ pub async fn get_current_lqosd_config(
NoCache::new(Json(config))
}
#[post("/api/update_config", data = "<data>")]
pub async fn update_lqosd_config(
data: Json<Config>
) -> String {
let config: Config = (*data).clone();
bus_request(vec![BusRequest::UpdateLqosdConfig(Box::new(config))])
.await
.unwrap();
"Ok".to_string()
}
#[post("/api/lqos_tuning/<period>", data = "<tuning>")]
pub async fn update_lqos_tuning(
auth: AuthGuard,

View File

@ -87,6 +87,7 @@ fn rocket() -> _ {
config_control::get_current_lqosd_config,
//config_control::update_python_config,
config_control::update_lqos_tuning,
config_control::update_lqosd_config,
auth_guard::create_first_user,
auth_guard::login,
auth_guard::admin_check,

View File

@ -975,7 +975,18 @@
if (!validationResult.valid) return;
updateSavedConfig(validationResult.changes);
console.log(lqosd_config);
$.ajax({
type: "POST",
url: "/api/update_config",
data: JSON.stringify(lqosd_config),
success: (data) => {
if (data === "Ok") {
alert("Configuration saved");
} else {
alert("Configuration not saved: " + data);
}
}
})
}
function start() {

View File

@ -178,6 +178,13 @@ fn handle_bus_requests(
lqos_bus::BusResponse::Ack
}
BusRequest::UpdateLqosDTuning(..) => tuning::tune_lqosd_from_bus(req),
BusRequest::UpdateLqosdConfig(config) => {
let result = lqos_config::update_config(config);
if result.is_err() {
log::error!("Error updating config: {:?}", result);
}
BusResponse::Ack
},
#[cfg(feature = "equinix_tests")]
BusRequest::RequestLqosEquinixTest => lqos_daht_test::lqos_daht_test(),
BusRequest::ValidateShapedDevicesCsv => {