diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 299ff8b1..2f8f803f 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -812,7 +812,7 @@ dependencies = [ "atomic", "pear", "serde", - "toml 0.5.11", + "toml", "uncased", "version_check", ] @@ -1436,7 +1436,7 @@ dependencies = [ "serde_json", "sha2", "thiserror", - "toml 0.7.2", + "toml_edit", "uuid", ] @@ -2787,18 +2787,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - [[package]] name = "toml_datetime" version = "0.6.1" diff --git a/src/rust/lqos_config/Cargo.toml b/src/rust/lqos_config/Cargo.toml index 41e037be..0b17e88b 100644 --- a/src/rust/lqos_config/Cargo.toml +++ b/src/rust/lqos_config/Cargo.toml @@ -6,7 +6,7 @@ license = "GPL-2.0-only" [dependencies] thiserror = "1" -toml = "0" +toml_edit = { version = "0", features = [ "serde" ] } serde = { version = "1.0", features = [ "derive" ] } serde_json = "1" csv = "1" diff --git a/src/rust/lqos_config/src/authentication.rs b/src/rust/lqos_config/src/authentication.rs index e6c3effe..a80de0d6 100644 --- a/src/rust/lqos_config/src/authentication.rs +++ b/src/rust/lqos_config/src/authentication.rs @@ -68,7 +68,7 @@ impl WebUsers { fn save_to_disk(&self) -> Result<(), AuthenticationError> { let path = Self::path()?; - let new_contents = toml::to_string(&self); + let new_contents = toml_edit::ser::to_string(&self); if let Err(e) = new_contents { return Err(AuthenticationError::SerializationError(e)); } @@ -109,7 +109,7 @@ impl WebUsers { } else { // Load from disk if let Ok(raw) = read_to_string(path) { - let parse_result = toml::from_str(&raw); + let parse_result = toml_edit::de::from_str(&raw); if let Ok(users) = parse_result { Ok(users) } else { @@ -255,7 +255,7 @@ pub enum AuthenticationError { #[error("Unable to load /etc/lqos.conf")] UnableToLoadEtcLqos, #[error("Unable to serialize to TOML")] - SerializationError(toml::ser::Error), + SerializationError(toml_edit::ser::Error), #[error("Unable to remove existing web users file")] UnableToDelete, #[error("Unable to open lqusers.toml for writing. Check permissions?")] diff --git a/src/rust/lqos_config/src/etc.rs b/src/rust/lqos_config/src/etc.rs index 83090d70..8d47327b 100644 --- a/src/rust/lqos_config/src/etc.rs +++ b/src/rust/lqos_config/src/etc.rs @@ -1,6 +1,7 @@ //! Manages the `/etc/lqos.conf` file. use log::error; use serde::{Deserialize, Serialize}; +use toml_edit::{Document, value}; use std::{fs, path::Path}; use thiserror::Error; @@ -136,17 +137,27 @@ impl EtcLqos { return Err(EtcLqosError::ConfigDoesNotExist); } if let Ok(raw) = std::fs::read_to_string("/etc/lqos.conf") { - let config_result: Result = toml::from_str(&raw); - match config_result { - Ok(mut config) => { - check_config(&mut config); - Ok(config) - } + let document = raw.parse::(); + match document { Err(e) => { error!("Unable to parse TOML from /etc/lqos.conf"); error!("Full error: {:?}", e); Err(EtcLqosError::CannotParseToml) } + Ok(mut config_doc) => { + let cfg = toml_edit::de::from_document::(config_doc.clone()); + match cfg { + Ok(mut cfg) => { + check_config(&mut config_doc, &mut cfg); + Ok(cfg) + } + Err(e) => { + error!("Unable to parse TOML from /etc/lqos.conf"); + error!("Full error: {:?}", e); + Err(EtcLqosError::CannotParseToml) + } + } + } } } else { error!("Unable to read contents of /etc/lqos.conf"); @@ -156,7 +167,7 @@ impl EtcLqos { /// Saves changes made to /etc/lqos.conf /// Copies current configuration into /etc/lqos.conf.backup first - pub fn save(&self) -> Result<(), EtcLqosError> { + pub fn save(&self, document: &mut Document) -> 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) { @@ -164,26 +175,17 @@ impl EtcLqos { 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); - } - } + let new_cfg = document.to_string(); + 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) { +fn check_config(cfg_doc: &mut Document, cfg: &mut EtcLqos) { use sha2::digest::Update; use sha2::Digest; @@ -191,6 +193,12 @@ fn check_config(cfg: &mut EtcLqos) { if let Ok(machine_id) = std::fs::read_to_string("/etc/machine-id") { let hash = sha2::Sha256::new().chain(machine_id).finalize(); cfg.node_id = Some(format!("{:x}", hash)); + cfg_doc["node_id"] = value(format!("{:x}", hash)); + println!("Updating"); + if let Err(e) = cfg.save(cfg_doc) { + log::error!("Unable to save /etc/lqos.conf"); + log::error!("{e:?}"); + } } } } @@ -212,3 +220,23 @@ pub enum EtcLqosError { #[error("Unable to write to /etc/lqos.conf")] WriteFail, } + +#[cfg(test)] +mod test { + const EXAMPLE_LQOS_CONF: &str = include_str!("../../../lqos.example"); + + #[test] + fn round_trip_toml() { + let doc = EXAMPLE_LQOS_CONF.parse::().unwrap(); + let reserialized = doc.to_string(); + assert_eq!(EXAMPLE_LQOS_CONF, reserialized); + } + + #[test] + fn add_node_id() { + let mut doc = EXAMPLE_LQOS_CONF.parse::().unwrap(); + doc["node_id"] = toml_edit::value("test"); + let reserialized = doc.to_string(); + assert!(reserialized.contains("node_id = \"test\"")); + } +} \ No newline at end of file