Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ opentelemetry-otlp = { version = "0.31.0", features = ["metrics"], optional = tr
opentelemetry_sdk = { version = "0.31.0", default-features = false, features = ["metrics"], optional = true }
rhai = { version = "1", features = ["sync", "serde", "no_optimize", "no_module", "no_custom_syntax", "only_i64"], optional = true }
subst = "0.3.8"
password-strength = "1.0.0"

[dev-dependencies]
abscissa_core = { version = "0.9.0", default-features = false, features = ["testing"] }
Expand Down
32 changes: 10 additions & 22 deletions config/local.toml
Original file line number Diff line number Diff line change
@@ -1,31 +1,19 @@
# rustic config file to backup /home, /etc and /root to a local repository
#
# backup usage: "rustic -P local backup
# cleanup: "rustic -P local forget --prune
#
# Local repository example. This follows the output style of `rustic setup`.

[repository]
repository = "/backup/rustic"
password-file = "/root/key-rustic"
no-cache = true # no cache needed for local repository

[forget]
keep-hourly = 20
keep-daily = 14
keep-weekly = 8
keep-monthly = 24
keep-yearly = 10
no-cache = true

[backup]
git-ignore = true
exclude-if-present = [".nobackup", "CACHEDIR.TAG"]
glob-files = ["/root/rustic-local.glob"]
one-file-system = true
globs = ["!**/target/**", "!**/node_modules/**"]

[[backup.snapshots]]
sources = ["/home"]
git-ignore = true

[[backup.snapshots]]
sources = ["/etc"]

[[backup.snapshots]]
sources = ["/root"]
[forget]
keep-daily = 7
keep-weekly = 4
keep-monthly = 12
keep-yearly = 5
33 changes: 8 additions & 25 deletions config/services/rclone_ovh-hot-cold.toml
Original file line number Diff line number Diff line change
@@ -1,34 +1,17 @@
# rustic config file to backup /home, /etc and /root to a hot/cold repository hosted by OVH
# using OVH cloud archive and OVH object storage
#
# backup usage: "rustic --use-profile ovh-hot-cold backup
# cleanup: "rustic --use-profile ovh-hot-cold forget --prune
# rclone repository example. Configure the `backup-remote` remote with rclone.

[repository]
repository = "rclone:ovh:backup-home"
repo-hot = "rclone:ovh:backup-home-hot"
password-file = "/root/key-rustic-ovh"
cache-dir = "/var/lib/cache/rustic" # explicitly specify cache dir for remote repository
warm-up = true # cold storage needs warm-up, just trying to access a file is sufficient to start the warm-up
warm-up-wait = "10m" # in my examples, 10 minutes wait-time was sufficient, according to docu it can be up to 12h

[forget]
keep-daily = 8
keep-weekly = 5
keep-monthly = 13
keep-yearly = 10
repository = "rclone:backup-remote:rustic"

[backup]
git-ignore = true
exclude-if-present = [".nobackup", "CACHEDIR.TAG"]
glob-files = ["/root/rustic-ovh.glob"]
one-file-system = true

[[backup.snapshots]]
sources = ["/home"]
git-ignore = true

[[backup.snapshots]]
sources = ["/etc"]

[[backup.snapshots]]
sources = ["/root"]
[forget]
keep-daily = 7
keep-weekly = 4
keep-monthly = 12
keep-yearly = 5
28 changes: 19 additions & 9 deletions config/services/s3_aws.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
# rustic config file to use s3 storage
# Note that this internally uses opendal S3 service, see https://opendal.apache.org/docs/rust/opendal/services/struct.S3.html
# where endpoint, bucket and root are extracted from the repository URL.
# S3-compatible repository example. Provide access keys through AWS/OpenDAL
# environment variables or your provider's standard config files.

[repository]
repository = "opendal:s3"
password = "password"

# Other options can be given here - note that opendal also support reading config from env files or AWS config dirs, see the opendal S3 docu
[repository.options]
access_key_id = "xxx" # this can be omitted, when AWS config is used
secret_access_key = "xxx" # this can be omitted, when AWS config is used
bucket = "bucket_name"
root = "/path/to/repo"
bucket = "example-backups"
root = "/rustic"
region = "eu-central-1"

[backup]
git-ignore = true
exclude-if-present = [".nobackup", "CACHEDIR.TAG"]

[[backup.snapshots]]
sources = ["/home"]

[forget]
keep-daily = 7
keep-weekly = 4
keep-monthly = 12
keep-yearly = 5
28 changes: 19 additions & 9 deletions config/services/sftp.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
# rustic config file to use sftp storage
# Note:
# - currently sftp only works on unix
# - Using sftp with password is not supported yet, use key authentication, e.g. use
# ssh-copy-id user@host
# SFTP repository example. Use SSH key authentication or provide credentials
# through the environment.

[repository]
repository = "opendal:sftp"
password = "mypassword"

[repository.options]
user = "myuser"
endpoint = "host:port"
root = "path/to/repo"
endpoint = "backup.example.com:22"
user = "backup"
root = "/srv/rustic"

[backup]
git-ignore = true
exclude-if-present = [".nobackup", "CACHEDIR.TAG"]

[[backup.snapshots]]
sources = ["/home"]

[forget]
keep-daily = 7
keep-weekly = 4
keep-monthly = 12
keep-yearly = 5
20 changes: 14 additions & 6 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pub(crate) mod backup;
pub(crate) mod cat;
pub(crate) mod check;
pub(crate) mod check_config;
pub(crate) mod completions;
pub(crate) mod config;
pub(crate) mod copy;
Expand All @@ -24,6 +25,7 @@ pub(crate) mod repoinfo;
pub(crate) mod restore;
pub(crate) mod rewrite;
pub(crate) mod self_update;
pub(crate) mod setup;
pub(crate) mod show_config;
pub(crate) mod snapshots;
pub(crate) mod tag;
Expand All @@ -44,12 +46,12 @@ use crate::commands::webdav::WebDavCmd;
use crate::{
Application, RUSTIC_APP,
commands::{
backup::BackupCmd, cat::CatCmd, check::CheckCmd, completions::CompletionsCmd,
config::ConfigCmd, copy::CopyCmd, diff::DiffCmd, docs::DocsCmd, dump::DumpCmd,
forget::ForgetCmd, init::InitCmd, key::KeyCmd, list::ListCmd, ls::LsCmd, merge::MergeCmd,
prune::PruneCmd, repair::RepairCmd, repoinfo::RepoInfoCmd, restore::RestoreCmd,
rewrite::RewriteCmd, self_update::SelfUpdateCmd, show_config::ShowConfigCmd,
snapshots::SnapshotCmd, tag::TagCmd,
backup::BackupCmd, cat::CatCmd, check::CheckCmd, check_config::CheckConfigCmd,
completions::CompletionsCmd, config::ConfigCmd, copy::CopyCmd, diff::DiffCmd,
docs::DocsCmd, dump::DumpCmd, forget::ForgetCmd, init::InitCmd, key::KeyCmd, list::ListCmd,
ls::LsCmd, merge::MergeCmd, prune::PruneCmd, repair::RepairCmd, repoinfo::RepoInfoCmd,
restore::RestoreCmd, rewrite::RewriteCmd, self_update::SelfUpdateCmd, setup::SetupCmd,
show_config::ShowConfigCmd, snapshots::SnapshotCmd, tag::TagCmd,
},
config::RusticConfig,
};
Expand Down Expand Up @@ -88,6 +90,9 @@ enum RusticCmd {
/// Check the repository
Check(Box<CheckCmd>),

/// Validate merged configuration without opening the repository
CheckConfig(Box<CheckConfigCmd>),

/// Copy snapshots to other repositories
Copy(Box<CopyCmd>),

Expand Down Expand Up @@ -150,6 +155,9 @@ enum RusticCmd {
/// Show general information about the repository
Repoinfo(Box<RepoInfoCmd>),

/// Interactive setup wizard for configuring backups
Setup(Box<SetupCmd>),

/// Change tags of snapshots
Tag(Box<TagCmd>),

Expand Down
6 changes: 4 additions & 2 deletions src/commands/backup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ pub struct BackupCmd {
}

impl BackupCmd {
fn validate(&self) -> Result<(), &str> {
pub(crate) fn validate(&self) -> Result<(), &'static str> {
// manually check for a "source" field, check is not done by serde, see above.
if !self.sources.is_empty() {
return Err("key \"sources\" is not valid in the [backup] section!");
Expand Down Expand Up @@ -290,7 +290,9 @@ impl BackupCmd {
.collect();

if config_snapshots.is_empty() {
bail!("no backup source given.");
bail!(
"No backup source given. Specify source paths on the command line (e.g. 'rustic backup /path/to/data') or define [[backup.snapshots]] sections in your config profile. Run 'rustic setup' for guided configuration."
);
}

info!("using backup sources from config file.");
Expand Down
31 changes: 31 additions & 0 deletions src/commands/check_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//! `check-config` subcommand

use crate::{Application, RUSTIC_APP, status_err};

use abscissa_core::{Command, Runnable, Shutdown};
use anyhow::{Result, bail};

/// `check-config` subcommand
#[derive(clap::Parser, Command, Debug)]
pub(crate) struct CheckConfigCmd {}

impl Runnable for CheckConfigCmd {
fn run(&self) {
if let Err(err) = self.inner_run() {
status_err!("{}", err);
RUSTIC_APP.shutdown(Shutdown::Crash);
};
}
}

impl CheckConfigCmd {
fn inner_run(&self) -> Result<()> {
let config = RUSTIC_APP.config();
if let Err(err) = config.backup.validate() {
bail!("{err}");
}

println!("config ok");
Ok(())
}
}
4 changes: 2 additions & 2 deletions src/commands/copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
Application, RUSTIC_APP, RusticConfig,
commands::init::init_credentials,
helpers::table_with_titles,
repository::{AllRepositoryOptions, IndexedRepo, Repo, get_snapots_from_ids},
repository::{AllRepositoryOptions, IndexedRepo, Repo, get_snapshots_from_ids},
status_err,
};
use abscissa_core::{Command, FrameworkError, Runnable, Shutdown, config::Override};
Expand Down Expand Up @@ -83,7 +83,7 @@ impl CopyCmd {
fn inner_run(&self, repo: IndexedRepo) -> Result<()> {
let config = RUSTIC_APP.config();
let config = config;
let mut snapshots = get_snapots_from_ids(&repo, &self.ids)?;
let mut snapshots = get_snapshots_from_ids(&repo, &self.ids)?;
// sort for nicer output
snapshots.sort_unstable();

Expand Down
4 changes: 2 additions & 2 deletions src/commands/merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{
Application, RUSTIC_APP,
repository::{OpenRepo, get_snapots_from_ids},
repository::{OpenRepo, get_snapshots_from_ids},
status_err,
};
use abscissa_core::{Command, Runnable, Shutdown};
Expand Down Expand Up @@ -50,7 +50,7 @@ impl MergeCmd {
let config = RUSTIC_APP.config();
let repo = repo.to_indexed_ids()?;

let snapshots = get_snapots_from_ids(&repo, &self.ids)?;
let snapshots = get_snapshots_from_ids(&repo, &self.ids)?;

// Handle dry-run mode
if config.global.dry_run {
Expand Down
4 changes: 2 additions & 2 deletions src/commands/repair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{
Application, RUSTIC_APP,
repository::{IndexedRepo, OpenRepo, get_snapots_from_ids},
repository::{IndexedRepo, OpenRepo, get_snapshots_from_ids},
status_err,
};
use abscissa_core::{Command, Runnable, Shutdown};
Expand Down Expand Up @@ -85,7 +85,7 @@ impl Runnable for SnapSubCmd {
impl SnapSubCmd {
fn inner_run(&self, repo: IndexedRepo) -> Result<()> {
let config = RUSTIC_APP.config();
let snaps = get_snapots_from_ids(&repo, &self.ids)?;
let snaps = get_snapshots_from_ids(&repo, &self.ids)?;
repo.repair_snapshots(&self.opts, snaps, config.global.dry_run)?;
Ok(())
}
Expand Down
6 changes: 3 additions & 3 deletions src/commands/rewrite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use crate::{
Application, RUSTIC_APP,
commands::snapshots::print_snapshots,
repository::{IndexedRepo, OpenRepo, get_snapots_from_ids},
repository::{IndexedRepo, OpenRepo, get_snapshots_from_ids},
status_err,
};

Expand Down Expand Up @@ -75,7 +75,7 @@ impl RewriteCmd {
}

fn inner_run_open(&self, repo: OpenRepo) -> Result<()> {
let snapshots = get_snapots_from_ids(&repo, &self.ids)?;
let snapshots = get_snapshots_from_ids(&repo, &self.ids)?;

let snaps = repo.rewrite_snapshots(snapshots, &self.opts())?;

Expand All @@ -85,7 +85,7 @@ impl RewriteCmd {
}

fn inner_run_indexed(&self, repo: IndexedRepo) -> Result<()> {
let snapshots = get_snapots_from_ids(&repo, &self.ids)?;
let snapshots = get_snapshots_from_ids(&repo, &self.ids)?;
let tree_opts = RewriteTreesOptions::default()
.all_trees(self.all_trees)
.excludes(self.excludes.clone())
Expand Down
Loading
Loading