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 = [
|
const columns = [
|
||||||
{heading: 'Path', path: 'path'},
|
{heading: 'Path', path: 'path'},
|
||||||
{heading: 'Type', path: 'type'},
|
{heading: 'Action', path: 'action'},
|
||||||
{heading: 'From', path: 'from'},
|
{heading: 'ID', path: 'id'},
|
||||||
{heading: 'To', path: 'to'},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const displayData = $computed(() => {
|
const displayData = $computed(() => {
|
||||||
|
@ -20,9 +19,8 @@ const displayData = $computed(() => {
|
||||||
for (const change of changelog) {
|
for (const change of changelog) {
|
||||||
data.push({
|
data.push({
|
||||||
path: change.path,
|
path: change.path,
|
||||||
type: change.type,
|
action: change.action,
|
||||||
from: change.from,
|
id: change.id,
|
||||||
to: change.to,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use jsonrpsee::types::Params;
|
use jsonrpsee::types::Params;
|
||||||
|
|
||||||
|
use crate::config_manager::Change;
|
||||||
use crate::state::RpcState;
|
use crate::state::RpcState;
|
||||||
|
|
||||||
use super::ApiError;
|
use super::ApiError;
|
||||||
use super::ApiError::ConfigError;
|
use super::ApiError::ConfigError;
|
||||||
|
|
||||||
pub fn get_pending_changelog(_: Params, state: &RpcState) -> Result<(), ApiError> {
|
pub fn get_pending_changelog(_: Params, state: &RpcState) -> Result<Vec<Change>, ApiError> {
|
||||||
Err(ApiError::NotImplemented)
|
Ok(state.config_manager.clone().get_pending_changelog())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_pending_changes(_: Params, state: &RpcState) -> Result<(), ApiError> {
|
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 crate::{definitions::system::User, state::RpcState};
|
||||||
use jsonrpsee::types::Params;
|
use jsonrpsee::types::Params;
|
||||||
use pwhash::sha512_crypt;
|
use pwhash::sha512_crypt;
|
||||||
|
@ -10,6 +13,8 @@ use ApiError::ParameterDeserialize;
|
||||||
|
|
||||||
use super::{ApiError, GetStringID};
|
use super::{ApiError, GetStringID};
|
||||||
|
|
||||||
|
const USER_CHANGE_PATH: &str = "system.user";
|
||||||
|
|
||||||
#[derive(Serialize, Clone)]
|
#[derive(Serialize, Clone)]
|
||||||
pub struct GetUser {
|
pub struct GetUser {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -68,11 +73,11 @@ pub fn create_user(p: Params, state: &RpcState) -> Result<(), ApiError> {
|
||||||
let mut tx = cm.start_transaction();
|
let mut tx = cm.start_transaction();
|
||||||
|
|
||||||
if tx
|
if tx
|
||||||
.changes
|
.config
|
||||||
.system
|
.system
|
||||||
.users
|
.users
|
||||||
.insert(
|
.insert(
|
||||||
u.name,
|
u.name.clone(),
|
||||||
User {
|
User {
|
||||||
comment: match u.comment {
|
comment: match u.comment {
|
||||||
Some(c) => c,
|
Some(c) => c,
|
||||||
|
@ -83,8 +88,12 @@ pub fn create_user(p: Params, state: &RpcState) -> Result<(), ApiError> {
|
||||||
)
|
)
|
||||||
.is_none()
|
.is_none()
|
||||||
{
|
{
|
||||||
tx.commit().map_err(ConfigError)?;
|
tx.commit(Change {
|
||||||
Ok(())
|
action: Create,
|
||||||
|
path: USER_CHANGE_PATH,
|
||||||
|
id: u.name,
|
||||||
|
})
|
||||||
|
.map_err(ConfigError)
|
||||||
} else {
|
} else {
|
||||||
tx.revert();
|
tx.revert();
|
||||||
Err(NotFound)
|
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 cm = state.config_manager.clone();
|
||||||
let mut tx = cm.start_transaction();
|
let mut tx = cm.start_transaction();
|
||||||
|
|
||||||
match tx.changes.system.users.get(&u.name) {
|
match tx.config.system.users.get(&u.name) {
|
||||||
Some(user) => {
|
Some(user) => {
|
||||||
// Only Update Password if field is not empty
|
// Only Update Password if field is not empty
|
||||||
let hash = if u.password == "" {
|
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)?
|
sha512_crypt::hash(u.password).map_err(HashError)?
|
||||||
};
|
};
|
||||||
|
|
||||||
tx.changes.system.users.insert(
|
tx.config.system.users.insert(
|
||||||
u.name,
|
u.name.clone(),
|
||||||
User {
|
User {
|
||||||
comment: match u.comment {
|
comment: match u.comment {
|
||||||
Some(c) => c,
|
Some(c) => c,
|
||||||
|
@ -123,7 +132,12 @@ pub fn update_user(p: Params, state: &RpcState) -> Result<(), ApiError> {
|
||||||
hash,
|
hash,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
Ok(())
|
tx.commit(Change {
|
||||||
|
action: Update,
|
||||||
|
path: USER_CHANGE_PATH,
|
||||||
|
id: u.name,
|
||||||
|
})
|
||||||
|
.map_err(ConfigError)
|
||||||
}
|
}
|
||||||
None => Err(NotFound),
|
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 cm = state.config_manager.clone();
|
||||||
let mut tx = cm.start_transaction();
|
let mut tx = cm.start_transaction();
|
||||||
|
|
||||||
match tx.changes.system.users.remove(&u.name) {
|
match tx.config.system.users.remove(&u.name) {
|
||||||
Some(_) => tx.commit().map_err(ConfigError),
|
Some(_) => tx
|
||||||
|
.commit(Change {
|
||||||
|
action: Delete,
|
||||||
|
path: USER_CHANGE_PATH,
|
||||||
|
id: u.name,
|
||||||
|
})
|
||||||
|
.map_err(ConfigError),
|
||||||
None => {
|
None => {
|
||||||
tx.revert();
|
tx.revert();
|
||||||
Err(NotFound)
|
Err(NotFound)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use serde::Serialize;
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
|
|
||||||
use super::definitions::config::Config;
|
use super::definitions::config::Config;
|
||||||
|
@ -35,9 +36,30 @@ pub struct ConfigManager {
|
||||||
shared_data: Arc<Mutex<SharedData>>,
|
shared_data: Arc<Mutex<SharedData>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ConfigTransaction<'a> {
|
||||||
|
finished: bool,
|
||||||
|
shared_data: MutexGuard<'a, SharedData>,
|
||||||
|
pub config: Config,
|
||||||
|
}
|
||||||
|
|
||||||
struct SharedData {
|
struct SharedData {
|
||||||
current_config: Config,
|
current_config: Config,
|
||||||
pending_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
|
// 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)?,
|
current_config: read_file_to_config(CURRENT_CONFIG_PATH)?,
|
||||||
// TODO Dont Fail if pending config is missing, use current instead
|
// TODO Dont Fail if pending config is missing, use current instead
|
||||||
pending_config: read_file_to_config(PENDING_CONFIG_PATH)?,
|
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()
|
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> {
|
pub fn apply_pending_changes(&mut self) -> Result<(), ConfigError> {
|
||||||
let mut data = self.shared_data.lock().unwrap();
|
let mut data = self.shared_data.lock().unwrap();
|
||||||
// TODO run Apply functions
|
// TODO run Apply functions
|
||||||
|
@ -69,6 +97,7 @@ impl ConfigManager {
|
||||||
// TODO revert if config save fails
|
// TODO revert if config save fails
|
||||||
// TODO Remove Pending Config File
|
// TODO Remove Pending Config File
|
||||||
data.current_config = data.pending_config.clone();
|
data.current_config = data.pending_config.clone();
|
||||||
|
data.changelog = Vec::new();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +106,7 @@ impl ConfigManager {
|
||||||
// TODO Remove Pending Config File
|
// TODO Remove Pending Config File
|
||||||
|
|
||||||
data.pending_config = data.current_config.clone();
|
data.pending_config = data.current_config.clone();
|
||||||
|
data.changelog = Vec::new();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,23 +115,18 @@ impl ConfigManager {
|
||||||
|
|
||||||
ConfigTransaction {
|
ConfigTransaction {
|
||||||
finished: false,
|
finished: false,
|
||||||
changes: data.pending_config.clone(),
|
config: data.pending_config.clone(),
|
||||||
shared_data: data,
|
shared_data: data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConfigTransaction<'a> {
|
|
||||||
finished: bool,
|
|
||||||
shared_data: MutexGuard<'a, SharedData>,
|
|
||||||
pub changes: Config,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ConfigTransaction<'a> {
|
impl<'a> ConfigTransaction<'a> {
|
||||||
pub fn commit(mut self) -> Result<(), ConfigError> {
|
pub fn commit(mut self, change: Change) -> Result<(), ConfigError> {
|
||||||
let ch = self.changes.clone();
|
let ch = self.config.clone();
|
||||||
ch.validate()?;
|
ch.validate()?;
|
||||||
self.shared_data.pending_config = ch.clone();
|
self.shared_data.pending_config = ch.clone();
|
||||||
|
self.shared_data.changelog.push(change);
|
||||||
write_config_to_file(PENDING_CONFIG_PATH, ch.clone())?;
|
write_config_to_file(PENDING_CONFIG_PATH, ch.clone())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue