aboutsummaryrefslogtreecommitdiff
path: root/hbak/src
diff options
context:
space:
mode:
authorHimbeerserverDE <himbeerserverde@gmail.com>2024-02-14 19:26:04 +0100
committerHimbeerserverDE <himbeerserverde@gmail.com>2024-02-14 19:26:04 +0100
commit3a6db968f49ce3b65dd2f6e875aed21475c87138 (patch)
tree803ebe93644d092f2dcf63b22eac0620e5ef3350 /hbak/src
parentff6e33a26a69ea47e63932becdcb85f715dad532 (diff)
add ability to offline-restore
Diffstat (limited to 'hbak/src')
-rw-r--r--hbak/src/main.rs116
1 files changed, 62 insertions, 54 deletions
diff --git a/hbak/src/main.rs b/hbak/src/main.rs
index 6a9e2ce..00aa28a 100644
--- a/hbak/src/main.rs
+++ b/hbak/src/main.rs
@@ -132,9 +132,10 @@ enum Commands {
device: String,
/// The name this node was previously known under.
node_name: String,
- /// The network address and optional port of the node to restore from.
- address: String,
- /// The subvolumes to limit recovery to.
+ /// The network address and optional port of the node to download from.
+ address: Option<String>,
+ /// The subvolumes to recover.
+ #[arg(short, long)]
subvols: Vec<String>,
},
}
@@ -316,8 +317,13 @@ fn logic() -> Result<()> {
},
)?;
- println!("Restoring from {}...", address);
- restore(&local_node, &address, no_restore, ignore_fstab)?;
+ if let Some(address) = &address {
+ println!("Restoring from {}...", address);
+ } else {
+ println!("Restoring locally...");
+ }
+
+ restore(&local_node, address.as_deref(), no_restore, ignore_fstab)?;
}
}
@@ -437,41 +443,42 @@ fn sync(
fn restore(
local_node: &LocalNode,
- address: &str,
+ address: Option<&str>,
no_restore: bool,
ignore_fstab: bool,
) -> Result<()> {
- let address = match address.parse() {
- Ok(address) => address,
- Err(_) => SocketAddr::new(address.parse()?, DEFAULT_PORT),
- };
+ // Synchronize with remote node if an address was passed in.
+ if let Some(address) = address {
+ let address = match address.parse() {
+ Ok(address) => address,
+ Err(_) => SocketAddr::new(address.parse()?, DEFAULT_PORT),
+ };
- let auth_conn = AuthConn::new(&address)?;
- let stream_conn = auth_conn.secure_stream(
- local_node.name().to_string(),
- address.to_string(),
- &local_node.config().passphrase,
- )?;
+ let auth_conn = AuthConn::new(&address)?;
+ let stream_conn = auth_conn.secure_stream(
+ local_node.name().to_string(),
+ address.to_string(),
+ &local_node.config().passphrase,
+ )?;
- println!("Authentication to {} successful", address);
+ println!("Authentication to {} successful", address);
- let mut local_sync_info = SyncInfo {
- volumes: HashMap::new(),
- };
+ let mut local_sync_info = SyncInfo {
+ volumes: HashMap::new(),
+ };
- for subvol in &local_node.config().subvols {
- let volume = Volume::new_local(local_node, subvol.to_string())?;
- local_sync_info
- .volumes
- .insert(volume.clone(), local_node.latest_snapshots(volume)?);
- }
+ for subvol in &local_node.config().subvols {
+ let volume = Volume::new_local(local_node, subvol.to_string())?;
+ local_sync_info
+ .volumes
+ .insert(volume.clone(), local_node.latest_snapshots(volume)?);
+ }
- let (stream_conn, _) = stream_conn.meta_sync(local_sync_info)?;
+ let (stream_conn, _) = stream_conn.meta_sync(local_sync_info)?;
- let children = Mutex::new(HashMap::new());
+ let children = Mutex::new(HashMap::new());
- let rx_setup =
- |snapshot: &Snapshot| {
+ let rx_setup = |snapshot: &Snapshot| {
if !local_node.config().subvols.iter().any(|subvol| {
snapshot.subvol() == subvol && snapshot.node_name() == local_node.name()
}) {
@@ -491,33 +498,34 @@ fn restore(
Ok(recovery_stream)
};
- let rx_finish = |snapshot: Snapshot| {
- println!("Received {} from {}", snapshot, address);
-
- let mut child = children
- .lock()
- .unwrap()
- .remove(&snapshot)
- .ok_or(RemoteError::NotStreaming)?;
-
- if child.wait().map_err(|_| RemoteError::RxError)?.success() {
- Ok(())
- } else {
- Err(RemoteError::RxError)
- }
- };
+ let rx_finish = |snapshot: Snapshot| {
+ println!("Received {} from {}", snapshot, address);
- match stream_conn.data_sync(Vec::<(Empty, Snapshot)>::default(), rx_setup, rx_finish) {
- Ok(_) => {}
- Err(e) => {
- for (snapshot, child) in children.lock().unwrap().iter_mut() {
- match child.kill() {
- Ok(_) => {}
- Err(e) => eprintln!("Cannot kill failed receiver for {}: {}", snapshot, e),
- }
+ let mut child = children
+ .lock()
+ .unwrap()
+ .remove(&snapshot)
+ .ok_or(RemoteError::NotStreaming)?;
+
+ if child.wait().map_err(|_| RemoteError::RxError)?.success() {
+ Ok(())
+ } else {
+ Err(RemoteError::RxError)
}
+ };
+
+ match stream_conn.data_sync(Vec::<(Empty, Snapshot)>::default(), rx_setup, rx_finish) {
+ Ok(_) => {}
+ Err(e) => {
+ for (snapshot, child) in children.lock().unwrap().iter_mut() {
+ match child.kill() {
+ Ok(_) => {}
+ Err(e) => eprintln!("Cannot kill failed receiver for {}: {}", snapshot, e),
+ }
+ }
- return Err(e.into());
+ return Err(e.into());
+ }
}
}