mirror of
https://github.com/speatzle/nfsense.git
synced 2025-05-10 18:38:22 +00:00
Add config Change tracking
This commit is contained in:
parent
56e5bf1f2c
commit
18ef592c55
4 changed files with 71 additions and 27 deletions
|
@ -9,9 +9,8 @@ let loading = $ref(false);
|
|||
|
||||
const columns = [
|
||||
{heading: 'Path', path: 'path'},
|
||||
{heading: 'Type', path: 'type'},
|
||||
{heading: 'From', path: 'from'},
|
||||
{heading: 'To', path: 'to'},
|
||||
{heading: 'Action', path: 'action'},
|
||||
{heading: 'ID', path: 'id'},
|
||||
];
|
||||
|
||||
const displayData = $computed(() => {
|
||||
|
@ -20,9 +19,8 @@ const displayData = $computed(() => {
|
|||
for (const change of changelog) {
|
||||
data.push({
|
||||
path: change.path,
|
||||
type: change.type,
|
||||
from: change.from,
|
||||
to: change.to,
|
||||
action: change.action,
|
||||
id: change.id,
|
||||
});
|
||||
}
|
||||
return data;
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use jsonrpsee::types::Params;
|
||||
|
||||
use crate::config_manager::Change;
|
||||
use crate::state::RpcState;
|
||||
|
||||
use super::ApiError;
|
||||
use super::ApiError::ConfigError;
|
||||
|
||||
pub fn get_pending_changelog(_: Params, state: &RpcState) -> Result<(), ApiError> {
|
||||
Err(ApiError::NotImplemented)
|
||||
pub fn get_pending_changelog(_: Params, state: &RpcState) -> Result<Vec<Change>, ApiError> {
|
||||
Ok(state.config_manager.clone().get_pending_changelog())
|
||||
}
|
||||
|
||||
pub fn apply_pending_changes(_: Params, state: &RpcState) -> Result<(), ApiError> {
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
use crate::config_manager::{
|
||||
Change, ChangeAction::Create, ChangeAction::Delete, ChangeAction::Update,
|
||||
};
|
||||
use crate::{definitions::system::User, state::RpcState};
|
||||
use jsonrpsee::types::Params;
|
||||
use pwhash::sha512_crypt;
|
||||
|
@ -10,6 +13,8 @@ use ApiError::ParameterDeserialize;
|
|||
|
||||
use super::{ApiError, GetStringID};
|
||||
|
||||
const USER_CHANGE_PATH: &str = "system.user";
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
pub struct GetUser {
|
||||
name: String,
|
||||
|
@ -68,11 +73,11 @@ pub fn create_user(p: Params, state: &RpcState) -> Result<(), ApiError> {
|
|||
let mut tx = cm.start_transaction();
|
||||
|
||||
if tx
|
||||
.changes
|
||||
.config
|
||||
.system
|
||||
.users
|
||||
.insert(
|
||||
u.name,
|
||||
u.name.clone(),
|
||||
User {
|
||||
comment: match u.comment {
|
||||
Some(c) => c,
|
||||
|
@ -83,8 +88,12 @@ pub fn create_user(p: Params, state: &RpcState) -> Result<(), ApiError> {
|
|||
)
|
||||
.is_none()
|
||||
{
|
||||
tx.commit().map_err(ConfigError)?;
|
||||
Ok(())
|
||||
tx.commit(Change {
|
||||
action: Create,
|
||||
path: USER_CHANGE_PATH,
|
||||
id: u.name,
|
||||
})
|
||||
.map_err(ConfigError)
|
||||
} else {
|
||||
tx.revert();
|
||||
Err(NotFound)
|
||||
|
@ -104,7 +113,7 @@ pub fn update_user(p: Params, state: &RpcState) -> Result<(), ApiError> {
|
|||
let mut cm = state.config_manager.clone();
|
||||
let mut tx = cm.start_transaction();
|
||||
|
||||
match tx.changes.system.users.get(&u.name) {
|
||||
match tx.config.system.users.get(&u.name) {
|
||||
Some(user) => {
|
||||
// Only Update Password if field is not empty
|
||||
let hash = if u.password == "" {
|
||||
|
@ -113,8 +122,8 @@ pub fn update_user(p: Params, state: &RpcState) -> Result<(), ApiError> {
|
|||
sha512_crypt::hash(u.password).map_err(HashError)?
|
||||
};
|
||||
|
||||
tx.changes.system.users.insert(
|
||||
u.name,
|
||||
tx.config.system.users.insert(
|
||||
u.name.clone(),
|
||||
User {
|
||||
comment: match u.comment {
|
||||
Some(c) => c,
|
||||
|
@ -123,7 +132,12 @@ pub fn update_user(p: Params, state: &RpcState) -> Result<(), ApiError> {
|
|||
hash,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
tx.commit(Change {
|
||||
action: Update,
|
||||
path: USER_CHANGE_PATH,
|
||||
id: u.name,
|
||||
})
|
||||
.map_err(ConfigError)
|
||||
}
|
||||
None => Err(NotFound),
|
||||
}
|
||||
|
@ -140,8 +154,14 @@ pub fn delete_user(p: Params, state: &RpcState) -> Result<(), ApiError> {
|
|||
let mut cm = state.config_manager.clone();
|
||||
let mut tx = cm.start_transaction();
|
||||
|
||||
match tx.changes.system.users.remove(&u.name) {
|
||||
Some(_) => tx.commit().map_err(ConfigError),
|
||||
match tx.config.system.users.remove(&u.name) {
|
||||
Some(_) => tx
|
||||
.commit(Change {
|
||||
action: Delete,
|
||||
path: USER_CHANGE_PATH,
|
||||
id: u.name,
|
||||
})
|
||||
.map_err(ConfigError),
|
||||
None => {
|
||||
tx.revert();
|
||||
Err(NotFound)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use serde::Serialize;
|
||||
use validator::Validate;
|
||||
|
||||
use super::definitions::config::Config;
|
||||
|
@ -35,9 +36,30 @@ pub struct ConfigManager {
|
|||
shared_data: Arc<Mutex<SharedData>>,
|
||||
}
|
||||
|
||||
pub struct ConfigTransaction<'a> {
|
||||
finished: bool,
|
||||
shared_data: MutexGuard<'a, SharedData>,
|
||||
pub config: Config,
|
||||
}
|
||||
|
||||
struct SharedData {
|
||||
current_config: Config,
|
||||
pending_config: Config,
|
||||
changelog: Vec<Change>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
pub struct Change {
|
||||
pub action: ChangeAction,
|
||||
pub path: &'static str,
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
pub enum ChangeAction {
|
||||
Create,
|
||||
Update,
|
||||
Delete,
|
||||
}
|
||||
|
||||
// Note, using unwarp on a mutex lock is ok since that only errors with mutex poisoning
|
||||
|
@ -49,6 +71,8 @@ impl ConfigManager {
|
|||
current_config: read_file_to_config(CURRENT_CONFIG_PATH)?,
|
||||
// TODO Dont Fail if pending config is missing, use current instead
|
||||
pending_config: read_file_to_config(PENDING_CONFIG_PATH)?,
|
||||
// TODO Figure out how to restore changes
|
||||
changelog: Vec::new(),
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
@ -61,6 +85,10 @@ impl ConfigManager {
|
|||
self.shared_data.lock().unwrap().pending_config.clone()
|
||||
}
|
||||
|
||||
pub fn get_pending_changelog(&self) -> Vec<Change> {
|
||||
self.shared_data.lock().unwrap().changelog.clone()
|
||||
}
|
||||
|
||||
pub fn apply_pending_changes(&mut self) -> Result<(), ConfigError> {
|
||||
let mut data = self.shared_data.lock().unwrap();
|
||||
// TODO run Apply functions
|
||||
|
@ -69,6 +97,7 @@ impl ConfigManager {
|
|||
// TODO revert if config save fails
|
||||
// TODO Remove Pending Config File
|
||||
data.current_config = data.pending_config.clone();
|
||||
data.changelog = Vec::new();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -77,6 +106,7 @@ impl ConfigManager {
|
|||
// TODO Remove Pending Config File
|
||||
|
||||
data.pending_config = data.current_config.clone();
|
||||
data.changelog = Vec::new();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -85,23 +115,18 @@ impl ConfigManager {
|
|||
|
||||
ConfigTransaction {
|
||||
finished: false,
|
||||
changes: data.pending_config.clone(),
|
||||
config: data.pending_config.clone(),
|
||||
shared_data: data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConfigTransaction<'a> {
|
||||
finished: bool,
|
||||
shared_data: MutexGuard<'a, SharedData>,
|
||||
pub changes: Config,
|
||||
}
|
||||
|
||||
impl<'a> ConfigTransaction<'a> {
|
||||
pub fn commit(mut self) -> Result<(), ConfigError> {
|
||||
let ch = self.changes.clone();
|
||||
pub fn commit(mut self, change: Change) -> Result<(), ConfigError> {
|
||||
let ch = self.config.clone();
|
||||
ch.validate()?;
|
||||
self.shared_data.pending_config = ch.clone();
|
||||
self.shared_data.changelog.push(change);
|
||||
write_config_to_file(PENDING_CONFIG_PATH, ch.clone())?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue