add stuff
This commit is contained in:
@@ -3,6 +3,8 @@ snapshot_interval = "monthly"
|
||||
|
||||
local_pool_name = "tank"
|
||||
|
||||
do_not_backup_datasets = ["docker", "cache"]
|
||||
|
||||
[backup_pools]
|
||||
backup1 = 'a235c116-764f-4082-97fc-47ca31e11e53'
|
||||
backup2 = '200ced55-894c-4f70-b089-b140e60193fc'
|
||||
|
||||
@@ -8,6 +8,7 @@ pub struct Config {
|
||||
pub snapshot_tag: String,
|
||||
pub snapshot_interval: String,
|
||||
pub local_pool_name: String,
|
||||
pub do_not_backup_datasets: Vec<String>,
|
||||
pub backup_pools: BackupPools,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pub mod cmd;
|
||||
pub mod config;
|
||||
pub mod encryption;
|
||||
pub mod pathbuf;
|
||||
pub mod todo;
|
||||
pub mod zfs;
|
||||
|
||||
+10
-2
@@ -26,6 +26,7 @@ fn main() -> Result<()> {
|
||||
&backup_pool,
|
||||
config.snapshot_tag,
|
||||
config.snapshot_interval,
|
||||
config.do_not_backup_datasets,
|
||||
)?;
|
||||
|
||||
if something_was_done {
|
||||
@@ -56,9 +57,16 @@ fn do_backup(
|
||||
backup_pool: &ZPool,
|
||||
snapshot_tag: String,
|
||||
snapshot_interval: String,
|
||||
datasets: Vec<String>,
|
||||
) -> Result<bool> {
|
||||
let todos = todo::Todo::plan(local_pool, backup_pool, snapshot_tag, snapshot_interval)
|
||||
.context("planning todos")?;
|
||||
let todos = todo::Todo::plan(
|
||||
local_pool,
|
||||
backup_pool,
|
||||
datasets,
|
||||
snapshot_tag,
|
||||
snapshot_interval,
|
||||
)
|
||||
.context("planning todos")?;
|
||||
|
||||
if todos.is_empty() {
|
||||
println!("nothing to do");
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
use crate::zfs::Dataset;
|
||||
|
||||
pub trait Relative {
|
||||
fn is_child_of(&self, other: &Dataset) -> bool;
|
||||
}
|
||||
|
||||
impl Relative for Dataset {
|
||||
fn is_child_of(&self, other: &Dataset) -> bool {
|
||||
let self_components: Vec<_> = self.0.components().collect();
|
||||
let other_components: Vec<_> = other.0.components().collect();
|
||||
|
||||
if self_components.len() < other_components.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
other
|
||||
.0
|
||||
.iter()
|
||||
.zip(self.0.iter())
|
||||
.map(|(left, right)| left == right)
|
||||
.reduce(|left, right| left && right)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn base() {
|
||||
let mut pb1 = PathBuf::new();
|
||||
pb1.push("/a/b/c");
|
||||
let ds1 = Dataset::new(pb1);
|
||||
|
||||
let mut pb2 = PathBuf::new();
|
||||
pb2.push("/a/b/c/d");
|
||||
let ds2 = Dataset::new(pb2);
|
||||
|
||||
assert!(ds2.is_child_of(&ds1));
|
||||
assert!(!ds1.is_child_of(&ds2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_related() {
|
||||
let mut pb1 = PathBuf::new();
|
||||
pb1.push("/a/z/c");
|
||||
let ds1 = Dataset::new(pb1);
|
||||
|
||||
let mut pb2 = PathBuf::new();
|
||||
pb2.push("/a/b/c");
|
||||
let ds2 = Dataset::new(pb2);
|
||||
|
||||
assert!(!ds2.is_child_of(&ds1));
|
||||
}
|
||||
}
|
||||
+13
-1
@@ -1,8 +1,12 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::zfs::Snapshot;
|
||||
use crate::zfs::ZPool;
|
||||
|
||||
use crate::pathbuf::Relative;
|
||||
|
||||
use crate::zfs::Dataset;
|
||||
|
||||
pub enum Todo {
|
||||
@@ -29,12 +33,20 @@ impl Todo {
|
||||
pub fn plan(
|
||||
local: &ZPool,
|
||||
remote: &ZPool,
|
||||
do_not_backup_datasets: Vec<String>,
|
||||
snapshot_tag: String,
|
||||
snapshot_interval: String,
|
||||
) -> Result<Vec<Self>> {
|
||||
let mut result = vec![];
|
||||
|
||||
for local_dataset in &local.datasets {
|
||||
'outer: for local_dataset in &local.datasets {
|
||||
for do_not_backup in &do_not_backup_datasets {
|
||||
let ds = Dataset::new(PathBuf::from(do_not_backup));
|
||||
if local_dataset.is_child_of(&ds) {
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
|
||||
let last_snapshot_with_tag =
|
||||
local_dataset.find_last_snapshot_with_tag(&snapshot_tag, &snapshot_interval)?;
|
||||
|
||||
|
||||
+2
-2
@@ -120,10 +120,10 @@ impl ZPool {
|
||||
/// E.g. if the name of the pool is `tank`, with the elements `ROOT` and `default` below it, this
|
||||
/// struct would contain `tank/ROOT/default`.
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Dataset(PathBuf);
|
||||
pub struct Dataset(pub(crate) PathBuf);
|
||||
|
||||
impl Dataset {
|
||||
fn new(path: PathBuf) -> Self {
|
||||
pub fn new(path: PathBuf) -> Self {
|
||||
Self(path)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user