difftreelog
refactor db data
in: trunk
4 files changed
src/db/db.rsdiffbeforeafterbothno changes
src/db/dbr.rsdiffbeforeafterboth--- /dev/null
+++ b/src/db/dbr.rs
@@ -0,0 +1,117 @@
+//! Small .toml based readable data store
+
+use anyhow::{Context, Result};
+use serde::{de::DeserializeOwned, Serialize};
+use std::{
+ cell::Cell,
+ collections::HashSet,
+ io::Write,
+ ops::{Deref, DerefMut},
+ path::Path,
+ path::PathBuf,
+ sync::{Arc, Mutex},
+};
+
+struct DbInternal {
+ root: PathBuf,
+ locked_paths: HashSet<PathBuf>,
+}
+
+pub trait DbData: DeserializeOwned + Serialize + Default {
+ const DB_NAME: &'static str;
+
+ fn open(db: &Db) -> Result<DbFile<Self>> {
+ db.db::<Self>()
+ }
+}
+
+#[derive(Clone)]
+pub struct Db(Arc<Mutex<DbInternal>>);
+impl Db {
+ pub fn new(root: impl AsRef<Path>) -> Result<Self> {
+ let root: &Path = root.as_ref();
+ std::fs::create_dir_all(&root).context("db root")?;
+ Ok(Db(Arc::new(Mutex::new(DbInternal {
+ root: root.to_owned(),
+ locked_paths: HashSet::new(),
+ }))))
+ }
+
+ pub fn db<T: DbData>(&self) -> Result<DbFile<T>> {
+ let name = T::DB_NAME;
+ assert!(!name.contains('/') && !name.contains('\\'));
+ let mut db = self.0.lock().unwrap();
+ let mut data_path = db.root.clone();
+ data_path.push(format!("{}.toml", name));
+
+ if !db.locked_paths.insert(data_path.clone()) {
+ anyhow::bail!("file is already open");
+ }
+
+ let data = if data_path.exists() {
+ let raw_data = std::fs::read(&data_path).context("reading file")?;
+ toml::from_slice(&raw_data).context("parsing file")?
+ } else {
+ T::default()
+ };
+
+ Ok(DbFile {
+ db: self.clone(),
+ root: db.root.clone(),
+ path: data_path,
+ data,
+ dirty: Cell::new(false),
+ })
+ }
+}
+
+pub struct DbFile<T: DbData> {
+ db: Db,
+ root: PathBuf,
+ path: PathBuf,
+ data: T,
+ dirty: Cell<bool>,
+}
+
+impl<T: DbData> Deref for DbFile<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.data
+ }
+}
+
+impl<T: DbData> DerefMut for DbFile<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.dirty.set(true);
+ &mut self.data
+ }
+}
+
+impl<T: DbData> DbFile<T> {
+ pub fn write(&self) -> Result<()> {
+ if !self.dirty.get() {
+ return Ok(());
+ }
+ let mut temp = tempfile::Builder::new()
+ .prefix("~")
+ .suffix(".toml")
+ .tempfile_in(&self.root)?;
+ let mut out = String::new();
+ let mut serializer = toml::Serializer::new(&mut out);
+ serializer.pretty_array(true).pretty_string(true);
+ self.data.serialize(&mut serializer)?;
+ temp.write_all(out.as_bytes())?;
+ temp.persist(&self.path)?;
+ self.dirty.set(false);
+ Ok(())
+ }
+}
+
+impl<T: DbData> Drop for DbFile<T> {
+ fn drop(&mut self) {
+ let mut db = self.db.0.lock().unwrap();
+ self.write().unwrap();
+ db.locked_paths.remove(&self.path);
+ }
+}
src/db/mod.rsdiffbeforeafterboth--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -1,4 +1,4 @@
-mod db;
+mod dbr;
pub mod secret;
-pub use db::*;
+pub use dbr::*;
src/db/secret.rsdiffbeforeafterboth--- a/src/db/secret.rs
+++ b/src/db/secret.rs
@@ -1,5 +1,5 @@
-use crate::{command::CommandExt, host::FleetConfig, nix::SECRETS_ATTRIBUTE};
-use anyhow::{bail, Result};
+use crate::{command::CommandExt, host::FleetOpts, nix::SECRETS_ATTRIBUTE};
+use anyhow::{bail, Context, Result};
use log::info;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{
@@ -10,7 +10,7 @@
};
use time::{Duration, PrimitiveDateTime};
-use super::db::DbData;
+use super::DbData;
#[derive(Serialize, Deserialize, Debug)]
pub struct SecretListData {
@@ -31,7 +31,9 @@
}) s)
"#,
)
+ .arg("--json")
.run_json()
+ .context("while getting secret list")
}
struct ReadableDate(PrimitiveDateTime);
@@ -109,17 +111,18 @@
// Secrets are generated on machine running fleet command
pub fn generate_secret(
&mut self,
- fleet_config: FleetConfig,
+ _fleet_config: &FleetOpts,
secret: &str,
data: &SecretListData,
) -> Result<()> {
let mut rage_keys = String::new();
- for (i, owner) in data.owners.iter().enumerate() {
+ for (i, _owner) in data.owners.iter().enumerate() {
if i != 0 {
rage_keys.push(' ');
}
rage_keys.push_str("--recipient \"");
- // rage_keys.push_str(&keys.get_host_key(&owner)?);
+ // rage_keys.push_str(&fleet_config.clone().build()?.host(owner)?.key()?);
+ //rage_keys.push_str(&keys.get_host_key(&owner)?);
rage_keys.push('"')
}
let created_at: PrimitiveDateTime = SystemTime::now().into();
@@ -154,7 +157,7 @@
let name = entry.file_name();
let name = name
.to_str()
- .ok_or(anyhow::anyhow!("file name should be utf-8"))?;
+ .ok_or_else(|| anyhow::anyhow!("file name should be utf-8"))?;
let value = String::from_utf8(std::fs::read(entry.path())?)?;
if let Some(name) = name.strip_prefix("pub_") {
secret_data.public_data.insert(name.into(), value);
@@ -176,7 +179,7 @@
return Ok(true);
}
- if !secret.is_valid(&data) {
+ if !secret.is_valid(data) {
return Ok(true);
}
@@ -185,12 +188,13 @@
pub fn ensure_generated(
&mut self,
// keys: &KeyDb,
+ fleet_config: &FleetOpts,
secret: &str,
data: &SecretListData,
) -> Result<()> {
if self.need_to_generate(secret, data)? {
info!("Generating secret {}", secret);
- // self.generate_secret(keys, secret, data)?;
+ self.generate_secret(fleet_config, secret, data)?;
}
Ok(())