diff --git a/datman/src/bin/datman.rs b/datman/src/bin/datman.rs index df19d78..aa914ef 100644 --- a/datman/src/bin/datman.rs +++ b/datman/src/bin/datman.rs @@ -17,7 +17,9 @@ along with Yama. If not, see . use clap::{Parser, Subcommand}; use datman::backup::{backup, BackupOptions}; -use datman::descriptor_config::{load_descriptor, SourceDescriptor}; +use datman::descriptor_config::{ + load_descriptor, Descriptor, PilePathOrConnector, SourceDescriptor, +}; use datman::extract::{ extract, load_pointers_for_extraction, merge_roots_for_batch_extract, select_to_extract, }; @@ -25,6 +27,7 @@ use eyre::{bail, Context, ContextCompat}; use std::collections::{BTreeMap, BTreeSet}; use std::path::PathBuf; use std::str::FromStr; +use std::sync::Arc; use tracing::info; use tracing_indicatif::IndicatifLayer; use tracing_subscriber::filter::filter_fn; @@ -33,7 +36,9 @@ use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::Layer; use yama::debugging::register_sigusr1_backtrace_helper; use yama::get_hostname; -use yama::open::open_lock_and_update_cache; +use yama::open::{open_lock_and_update_cache, open_lock_and_update_cache_with_connector}; +use yama::pile_with_cache::PileWithCache; +use yama_wormfile::boxed::BoxedWormFileProvider; #[derive(Clone, Debug)] pub struct PileAndPointer { @@ -188,13 +193,8 @@ pub async fn main() -> eyre::Result<()> { pile_name, options, } => { - let pile_connector_path = descriptor - .piles - .get(&pile_name) - .cloned() - .context("no pile by that name")?; let lock_name = format!("{} datman backup {:?}", get_hostname(), source_name); - let pwc = open_lock_and_update_cache(pile_connector_path, lock_name).await?; + let pwc = open_destination(&descriptor, &pile_name, lock_name).await?; let source = descriptor .sources @@ -215,13 +215,8 @@ pub async fn main() -> eyre::Result<()> { backup(pwc, sources_to_backup, &options).await?; } DatmanCommand::BackupAll { pile_name, options } => { - let pile_connector_path = descriptor - .piles - .get(&pile_name) - .cloned() - .context("no pile by that name")?; let lock_name = format!("{} datman backupall", get_hostname()); - let pwc = open_lock_and_update_cache(pile_connector_path, lock_name).await?; + let pwc = open_destination(&descriptor, &pile_name, lock_name).await?; let my_hostname = get_hostname(); let sources_to_backup: BTreeMap = descriptor @@ -251,13 +246,8 @@ pub async fn main() -> eyre::Result<()> { source_name, destination, } => { - let pile_connector_path = descriptor - .piles - .get(&pile_name) - .cloned() - .context("no pile by that name")?; let lock_name = format!("{} datman extract {:?}", get_hostname(), source_name); - let pwc = open_lock_and_update_cache(pile_connector_path, lock_name).await?; + let pwc = open_destination(&descriptor, &pile_name, lock_name).await?; let mut sources = BTreeSet::new(); sources.insert(source_name.clone()); @@ -271,13 +261,8 @@ pub async fn main() -> eyre::Result<()> { pile_name, destination, } => { - let pile_connector_path = descriptor - .piles - .get(&pile_name) - .cloned() - .context("no pile by that name")?; let lock_name = format!("{} datman extractall", get_hostname()); - let pwc = open_lock_and_update_cache(pile_connector_path, lock_name).await?; + let pwc = open_destination(&descriptor, &pile_name, lock_name).await?; let sources = descriptor.sources.keys().cloned().collect(); let selected = select_to_extract(&pwc, sources, None, None, false).await?; @@ -289,3 +274,22 @@ pub async fn main() -> eyre::Result<()> { Ok(()) } + +async fn open_destination( + descriptor: &Descriptor, + pile_name: &str, + lock_name: String, +) -> eyre::Result>> { + let path_or_connector = descriptor + .piles + .get(pile_name) + .context("no pile by that name")?; + match path_or_connector { + PilePathOrConnector::PilePath(path) => { + open_lock_and_update_cache(path.clone(), lock_name).await + } + PilePathOrConnector::PileConnector { scheme, yamakey } => { + open_lock_and_update_cache_with_connector(scheme, pile_name, yamakey, lock_name).await + } + } +} diff --git a/datman/src/descriptor_config.rs b/datman/src/descriptor_config.rs index 2dba230..9f47980 100644 --- a/datman/src/descriptor_config.rs +++ b/datman/src/descriptor_config.rs @@ -19,6 +19,7 @@ use eyre::{Context, ContextCompat}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::{Path, PathBuf}; +use yama::pile_connector::PileConnectionScheme; // TODO how do we handle?: // - (important) yama push of one pile to another @@ -31,13 +32,24 @@ pub struct Descriptor { pub sources: HashMap, /// Paths to destination Yama Piles. Remote Piles need a local virtual pile to specify the layers. - pub piles: HashMap, + pub piles: HashMap, #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] pub retention: Option, } +#[derive(Clone, Serialize, Deserialize, Debug)] +#[serde(untagged)] +pub enum PilePathOrConnector { + PilePath(PathBuf), + PileConnector { + #[serde(flatten)] + scheme: PileConnectionScheme, + yamakey: PathBuf, + }, +} + #[derive(Clone, Serialize, Deserialize, Debug)] pub struct RetentionPolicyConfig { pub daily: u32, @@ -115,11 +127,28 @@ pub async fn load_descriptor(path: &Path) -> eyre::Result { .context("there must be a parent path for the descriptor file")?; // Absolutise pile paths - for (_, pile_path) in descriptor.piles.iter_mut() { - *pile_path = dir - .join(&*pile_path) - .canonicalize() - .context("Failed to canonicalise path in descriptor")?; + for (_, pile_path_or_connector) in descriptor.piles.iter_mut() { + match pile_path_or_connector { + PilePathOrConnector::PilePath(pile_path) => { + *pile_path = dir + .join(&*pile_path) + .canonicalize() + .context("Failed to canonicalise path in descriptor")?; + } + PilePathOrConnector::PileConnector { + scheme: + PileConnectionScheme::Local { + directory: pile_path, + }, + .. + } => { + *pile_path = dir + .join(&*pile_path) + .canonicalize() + .context("Failed to canonicalise path in descriptor")?; + } + PilePathOrConnector::PileConnector { .. } => { /* nop */ } + } } Ok(descriptor) diff --git a/yama/src/open.rs b/yama/src/open.rs index 55c64bb..ac59999 100644 --- a/yama/src/open.rs +++ b/yama/src/open.rs @@ -204,3 +204,25 @@ pub async fn open_lock_and_update_cache( Ok(Arc::new(pwc)) } + +pub async fn open_lock_and_update_cache_with_connector( + pile_connection_scheme: &PileConnectionScheme, + cache_base_name: &str, + keyring_path: &Path, + lock_name: String, +) -> eyre::Result>> { + let keyring = pre_open_keyring_at_path(keyring_path).await?; + let keyring = open_keyring_interactive(keyring).await?; + + let pwc = open_pile_using_connector( + pile_connection_scheme, + cache_base_name, + keyring, + LockKind::Shared, + lock_name, + ) + .await?; + update_cache(&pwc).await?; + + Ok(Arc::new(pwc)) +}