mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2025-01-30 13:55:10 +01:00
implement dumping and loading the full database
This commit is contained in:
parent
ee21f74d2d
commit
1d2ba9eddc
27
bffhd/lib.rs
27
bffhd/lib.rs
@ -8,7 +8,7 @@
|
|||||||
//! This is the capnp component of the FabAccess project.
|
//! This is the capnp component of the FabAccess project.
|
||||||
//! The entry point of bffhd can be found in [bin/bffhd/main.rs](../bin/bffhd/main.rs)
|
//! The entry point of bffhd can be found in [bin/bffhd/main.rs](../bin/bffhd/main.rs)
|
||||||
|
|
||||||
use miette::Diagnostic;
|
use miette::{Diagnostic, IntoDiagnostic};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
@ -67,6 +67,8 @@ use lightproc::recoverable_handle::RecoverableHandle;
|
|||||||
use signal_hook::consts::signal::*;
|
use signal_hook::consts::signal::*;
|
||||||
use tracing::Span;
|
use tracing::Span;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct Difluoroborane {
|
pub struct Difluoroborane {
|
||||||
config: Config,
|
config: Config,
|
||||||
executor: Executor<'static>,
|
executor: Executor<'static>,
|
||||||
@ -135,6 +137,12 @@ pub enum BFFHError {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
struct DatabaseDump {
|
||||||
|
users: HashMap<String, users::db::UserData>,
|
||||||
|
state: HashMap<String, resources::state::State>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Difluoroborane {
|
impl Difluoroborane {
|
||||||
pub fn setup() {}
|
pub fn setup() {}
|
||||||
|
|
||||||
@ -197,6 +205,23 @@ impl Difluoroborane {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dump_db(&mut self, file: &str) -> Result<(), miette::Error> {
|
||||||
|
let users = self.users.dump_map()?;
|
||||||
|
let state = self.statedb.dump_map()?;
|
||||||
|
let dump = DatabaseDump{users, state};
|
||||||
|
let data = toml::ser::to_vec(&dump).map_err(|e| miette::Error::msg(format!("Serializing database dump failed: {}", e)))?;
|
||||||
|
std::fs::write(file, &data).map_err(|e| miette::Error::msg(format!("writing database dump failed: {}", e)))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_db(&mut self, file: &str) -> Result<(), miette::Error> {
|
||||||
|
let data = std::fs::read(file).into_diagnostic()?;
|
||||||
|
let dump: DatabaseDump = toml::de::from_slice(&data).into_diagnostic()?;
|
||||||
|
self.users.load_map(&dump.users)?;
|
||||||
|
self.statedb.load_map(&dump.state)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) -> Result<(), BFFHError> {
|
pub fn run(&mut self) -> Result<(), BFFHError> {
|
||||||
let _guard = self.span.enter();
|
let _guard = self.span.enter();
|
||||||
let mut signals = signal_hook_async_std::Signals::new(&[SIGINT, SIGQUIT, SIGTERM])
|
let mut signals = signal_hook_async_std::Signals::new(&[SIGINT, SIGQUIT, SIGTERM])
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use rkyv::ser::Serializer;
|
||||||
|
use rkyv::ser::serializers::AllocSerializer;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::db;
|
use crate::db;
|
||||||
@ -97,6 +99,30 @@ impl StateDB {
|
|||||||
self.db.put(&mut txn, key, val, flags)?;
|
self.db.put(&mut txn, key, val, flags)?;
|
||||||
Ok(txn.commit()?)
|
Ok(txn.commit()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_map(&self, map: &std::collections::HashMap<String, State>) -> miette::Result<()> {
|
||||||
|
use miette::IntoDiagnostic;
|
||||||
|
let mut txn = self.env.begin_rw_txn().into_diagnostic()?;
|
||||||
|
let flags = WriteFlags::empty();
|
||||||
|
for (key, val) in map {
|
||||||
|
let mut serializer = AllocSerializer::<1024>::default();
|
||||||
|
serializer.serialize_value(val).into_diagnostic()?;
|
||||||
|
let serialized = ArchivedValue::new(serializer.into_serializer().into_inner());
|
||||||
|
self.db.put(&mut txn, &key.as_bytes(), &serialized, flags)?;
|
||||||
|
}
|
||||||
|
txn.commit().into_diagnostic()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dump_map(&self) -> miette::Result<std::collections::HashMap<String, State>> {
|
||||||
|
let mut map = std::collections::HashMap::new();
|
||||||
|
for (key, val) in self.get_all(&self.begin_ro_txn()?)? {
|
||||||
|
let key_str = core::str::from_utf8(&key).map_err(|_e| miette::Error::msg("state key not UTF8"))?.to_string();
|
||||||
|
let val_state: State = rkyv::Deserialize::deserialize(val.as_ref(), &mut rkyv::Infallible).unwrap();
|
||||||
|
map.insert(key_str, val_state);
|
||||||
|
}
|
||||||
|
Ok(map)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -173,6 +173,29 @@ impl Users {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_map(&mut self, dump: &HashMap<String,UserData>) -> miette::Result<()> {
|
||||||
|
let mut txn = unsafe { self.userdb.get_rw_txn() }?;
|
||||||
|
|
||||||
|
self.userdb.clear_txn(&mut txn)?;
|
||||||
|
|
||||||
|
for (uid, data) in dump {
|
||||||
|
let user = db::User {
|
||||||
|
id: uid.clone(),
|
||||||
|
userdata: data.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
tracing::trace!(%uid, ?user, "Storing user object");
|
||||||
|
if let Err(e) = self.userdb.put_txn(&mut txn, uid.as_str(), &user) {
|
||||||
|
tracing::warn!(error=?e, "failed to add user")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
txn.commit().map_err(crate::db::Error::from)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dump_map(&self) -> miette::Result<HashMap<String, UserData>> {
|
||||||
|
return Ok(self.userdb.get_all()?)
|
||||||
|
}
|
||||||
pub fn dump_file(&self, path_str: &str, force: bool) -> miette::Result<usize> {
|
pub fn dump_file(&self, path_str: &str, force: bool) -> miette::Result<usize> {
|
||||||
let path = Path::new(path_str);
|
let path = Path::new(path_str);
|
||||||
let exists = path.exists();
|
let exists = path.exists();
|
||||||
@ -203,7 +226,7 @@ impl Users {
|
|||||||
}
|
}
|
||||||
let mut file = fs::File::create(path).into_diagnostic()?;
|
let mut file = fs::File::create(path).into_diagnostic()?;
|
||||||
|
|
||||||
let users = self.userdb.get_all()?;
|
let users = self.dump_map()?;
|
||||||
let encoded = toml::ser::to_vec(&users).into_diagnostic()?;
|
let encoded = toml::ser::to_vec(&users).into_diagnostic()?;
|
||||||
file.write_all(&encoded[..]).into_diagnostic()?;
|
file.write_all(&encoded[..]).into_diagnostic()?;
|
||||||
|
|
||||||
|
@ -57,10 +57,18 @@ fn main() -> miette::Result<()> {
|
|||||||
.help("Check config for validity")
|
.help("Check config for validity")
|
||||||
.long("check"))
|
.long("check"))
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("dump")
|
Arg::new("dump-db")
|
||||||
.help("Dump all internal databases")
|
.help("Dump all internal databases")
|
||||||
.long("dump")
|
.long("dump-db")
|
||||||
.conflicts_with("load"))
|
.alias("dump")
|
||||||
|
.conflicts_with("dump-users")
|
||||||
|
.conflicts_with("load-users")
|
||||||
|
.conflicts_with("load-db")
|
||||||
|
.takes_value(true)
|
||||||
|
.value_name("FILE")
|
||||||
|
.value_hint(ValueHint::AnyPath)
|
||||||
|
.default_missing_value("bffh-db.toml")
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("dump-users")
|
Arg::new("dump-users")
|
||||||
.help("Dump the users db to the given file as TOML")
|
.help("Dump the users db to the given file as TOML")
|
||||||
@ -69,18 +77,33 @@ fn main() -> miette::Result<()> {
|
|||||||
.value_name("FILE")
|
.value_name("FILE")
|
||||||
.value_hint(ValueHint::AnyPath)
|
.value_hint(ValueHint::AnyPath)
|
||||||
.default_missing_value("users.toml")
|
.default_missing_value("users.toml")
|
||||||
.conflicts_with("load"))
|
.conflicts_with("load-users")
|
||||||
|
.conflicts_with("load-db")
|
||||||
|
.conflicts_with("dump-db")
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("force")
|
Arg::new("force")
|
||||||
.help("force ops that may clobber")
|
.help("force ops that may clobber")
|
||||||
.long("force")
|
.long("force")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("load")
|
Arg::new("load-users")
|
||||||
.help("Load values into the internal databases")
|
.help("Load users into the internal databases")
|
||||||
.long("load")
|
.long("load-users")
|
||||||
|
.alias("load")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.conflicts_with("dump"))
|
.conflicts_with("dump-db")
|
||||||
|
.conflicts_with("load-db")
|
||||||
|
.conflicts_with("dump-users")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("load-db")
|
||||||
|
.help("Load values into the internal databases")
|
||||||
|
.long("load-db")
|
||||||
|
.takes_value(true)
|
||||||
|
.conflicts_with("dump-db")
|
||||||
|
.conflicts_with("load-users")
|
||||||
|
.conflicts_with("dump-users"))
|
||||||
.arg(Arg::new("keylog")
|
.arg(Arg::new("keylog")
|
||||||
.help("log TLS keys into PATH. If no path is specified the value of the envvar SSLKEYLOGFILE is used.")
|
.help("log TLS keys into PATH. If no path is specified the value of the envvar SSLKEYLOGFILE is used.")
|
||||||
.long("tls-key-log")
|
.long("tls-key-log")
|
||||||
@ -137,8 +160,16 @@ fn main() -> miette::Result<()> {
|
|||||||
|
|
||||||
let mut config = config::read(&PathBuf::from_str(configpath).unwrap())?;
|
let mut config = config::read(&PathBuf::from_str(configpath).unwrap())?;
|
||||||
|
|
||||||
if matches.is_present("dump") {
|
if matches.is_present("dump-db") {
|
||||||
return Err(miette::miette!("DB Dumping is currently not implemented, except for the users db, using `--dump-users`"));
|
let mut bffh = Difluoroborane::new(config)?;
|
||||||
|
let fname = matches.value_of("dump-db").unwrap();
|
||||||
|
bffh.dump_db(fname)?;
|
||||||
|
return Ok(());
|
||||||
|
} else if matches.is_present("load-db") {
|
||||||
|
let mut bffh = Difluoroborane::new(config)?;
|
||||||
|
let fname = matches.value_of("load-db").unwrap();
|
||||||
|
bffh.load_db(fname)?;
|
||||||
|
return Ok(());
|
||||||
} else if matches.is_present("dump-users") {
|
} else if matches.is_present("dump-users") {
|
||||||
let bffh = Difluoroborane::new(config)?;
|
let bffh = Difluoroborane::new(config)?;
|
||||||
|
|
||||||
@ -150,12 +181,12 @@ fn main() -> miette::Result<()> {
|
|||||||
tracing::info!("successfully dumped {} users", number);
|
tracing::info!("successfully dumped {} users", number);
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else if matches.is_present("load") {
|
} else if matches.is_present("load-users") {
|
||||||
let bffh = Difluoroborane::new(config)?;
|
let bffh = Difluoroborane::new(config)?;
|
||||||
|
|
||||||
bffh.users.load_file(matches.value_of("load").unwrap())?;
|
bffh.users.load_file(matches.value_of("load-users").unwrap())?;
|
||||||
|
|
||||||
tracing::info!("loaded users from {}", matches.value_of("load").unwrap());
|
tracing::info!("loaded users from {}", matches.value_of("load-users").unwrap());
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user