Skip to content

Commit 13fdb31

Browse files
committed
Add opendal as backup source
1 parent 62cd42d commit 13fdb31

10 files changed

Lines changed: 102 additions & 13 deletions

config/README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -277,15 +277,22 @@ See [Global Metrics labels](#global-metrics-labels-globalmetrics-labels).
277277
**Note**: All of the backup options mentioned before can also be used as
278278
snapshot-specific option and then only apply to this snapshot.
279279

280-
| Attribute | Description | Default Value | Example Value |
281-
| --------- | ---------------------------------------------------------------------- | ------------- | ---------------------------------------------------------------------- |
282-
| name | Name to identify this snapshot (to be used with the --name CLI option) | "" | "myid" |
283-
| sources | Array of source directories or file(s) to back up. | [] | ["/dir1", "/dir2"] |
284-
| hooks | Hooks to run before and after backing up the defined sources. | Not set | { run-before = [], run-after = [], run-failed = [], run-finally = [] } |
280+
| Attribute | Description | Default Value | Example Value |
281+
| --------- | ------------------------------------------------------------------------------------------------------------------------ | ------------- | ---------------------------------------------------------------------- |
282+
| name | Name to identify this snapshot (to be used with the --name CLI option) | "" | "myid" |
283+
| sources | Array of source directories or file(s) to back up. Allows "opendal:" for a remote source if only a single source is used | [] | ["/dir1", "/dir2"], ["opendal:s3"] |
284+
| hooks | Hooks to run before and after backing up the defined sources. | Not set | { run-before = [], run-after = [], run-failed = [], run-finally = [] } |
285285

286286
Source-specific hooks are called additionally to global, repository and backup
287287
hooks when backing up the defined sources into a snapshot.
288288

289+
### Snapshot Sourcey Options `[backup.snapshots.options]`
290+
291+
Additional source options - depending on the used source. This is currently only
292+
relevant for an opendal source. These can be only set in the config file.
293+
294+
see [Repository Options](#repository-options-repository)
295+
289296
### Forget Options `[forget]`
290297

291298
**Note**: At least one of the `keep-*` options must be given. Use

config/full.toml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,19 @@ label-a = "xxx"
172172

173173
# Backup options for specific sources - all above options are also available here and replace them for the given source
174174
[[backup.snapshots]]
175-
sources = ["/path/to/source1"]
175+
sources = [
176+
"opendal:s3",
177+
] # Note: For opendal, currently only a single source is supported; see next [[backup.snapshots]] section for a local path example
176178
label = "label" # Default: not set
177179
# .. and so on. see [backup]
178180

181+
# Additional backup source options - depending on source; currently only relevant for a "opendal:" source.
182+
# These can be only set in the config file.
183+
[backup.snapshots.options]
184+
connections = "20" # Default: Not set
185+
# Note that an opendal source use several service-dependent options which may be specified here, see
186+
# https://opendal.apache.org/docs/rust/opendal/services/index.html
187+
179188
# Source-specific hooks: The given commands when backing up the defined source
180189
[backup.snapshots.hooks]
181190
run-before = ["echo before"] # Default: []

config/opendal-source.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# rustic config file to backup a s3 storage to a local repository
2+
[repository]
3+
repository = "/path/to/repo"
4+
password = "password"
5+
6+
[[backup.snapshots]]
7+
# Here only a single opendal source is allowed, the used service is given here
8+
sources = ["opendal:s3"]
9+
host = "s3" # we manually set the hostname, so we can easily distinguish the snapshot(s) created from here
10+
11+
# 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
12+
[backup.snapshots.options]
13+
access_key_id = "xxx" # this can be omitted, when AWS config is used
14+
secret_access_key = "xxx" # this can be omitted, when AWS config is used
15+
bucket = "bucket_name"
16+
root = "/path/to/repo"

src/commands/backup.rs

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ use clap::ValueHint;
2121
use comfy_table::Cell;
2222
use conflate::{Merge, MergeFrom};
2323
use log::{debug, error, info, warn};
24-
use rustic_core::{Excludes, StringList};
24+
use rustic_backend::OpenDALBackend;
25+
use rustic_core::{ChildStdoutSource, Excludes, LocalSource, StdinSource, StringList};
2526
use serde::{Deserialize, Serialize};
2627
use serde_with::serde_as;
2728

@@ -145,6 +146,11 @@ pub struct BackupCmd {
145146
#[merge(skip)]
146147
sources: Vec<String>,
147148

149+
/// Other options for this source
150+
#[clap(skip)]
151+
#[merge(strategy = conflate::btreemap::append_or_ignore)]
152+
options: BTreeMap<String, String>,
153+
148154
/// Job name for the metrics. Default: rustic-backup
149155
#[clap(long, value_name = "JOB_NAME", env = "RUSTIC_METRICS_JOB")]
150156
#[merge(strategy=conflate::option::overwrite_none)]
@@ -327,6 +333,51 @@ impl BackupCmd {
327333
hooks.with_env(&hooks_variables)
328334
}
329335

336+
fn backup_source(
337+
source: &PathList,
338+
options: BTreeMap<String, String>,
339+
backup_opts: BackupOptions,
340+
snap: SnapshotFile,
341+
repo: &IndexedIdsRepo,
342+
) -> Result<SnapshotFile> {
343+
let backup_stdin = PathList::from_string("-")?;
344+
let source = source
345+
.clone()
346+
.sanitize()
347+
.with_context(|| format!("error sanitizing source=s\"{:?}\"", source))?
348+
.merge();
349+
350+
let snap = if source.len() == 1
351+
// TODO: This check should not be done on PathList, but in the sources list directly
352+
&& let Some(path) = source[0].to_string_lossy().strip_prefix("opendal:")
353+
{
354+
let source = OpenDALBackend::new(path, options)?.as_source()?;
355+
repo.archive(&backup_opts, &source, snap, &[PathBuf::new()])?
356+
} else if source == backup_stdin {
357+
let path = PathBuf::from(&backup_opts.stdin_filename);
358+
let backup_paths = vec![path.clone()];
359+
if let Some(command) = &backup_opts.stdin_command {
360+
let src = ChildStdoutSource::new(command, path)?;
361+
let res = repo.archive(&backup_opts, &src, snap, &backup_paths)?;
362+
src.finish()?;
363+
res
364+
} else {
365+
let src = StdinSource::new(path);
366+
repo.archive(&backup_opts, &src, snap, &backup_paths)?
367+
}
368+
} else {
369+
let backup_path = source.paths();
370+
let src = LocalSource::new(
371+
backup_opts.ignore_save_opts,
372+
&backup_opts.excludes,
373+
&backup_opts.ignore_filter_opts,
374+
&backup_path,
375+
)?;
376+
repo.archive(&backup_opts, &src, snap, &backup_path)?
377+
};
378+
Ok(snap)
379+
}
380+
330381
fn backup_snapshot(mut self, source: PathList, repo: &IndexedIdsRepo) -> Result<()> {
331382
let config = RUSTIC_APP.config();
332383
let snapshot_opts = &config.backup.snapshots;
@@ -369,13 +420,9 @@ impl BackupCmd {
369420
.no_scan(self.no_scan)
370421
.dry_run(config.global.dry_run);
371422

423+
let snap = self.snap_opts.to_snapshot()?;
372424
let snap = hooks.use_with(|| -> Result<_> {
373-
let source = source
374-
.clone()
375-
.sanitize()
376-
.with_context(|| format!("error sanitizing source=s\"{:?}\"", source))?
377-
.merge();
378-
Ok(repo.backup(&backup_opts, &source, self.snap_opts.to_snapshot()?)?)
425+
Self::backup_source(&source, self.options, backup_opts, snap, repo)
379426
})?;
380427

381428
if config.global.progress_options.json_progress {

src/snapshots/rustic_rs__config__tests__default_config_display_passes.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ run-after = []
7878
run-failed = []
7979
run-finally = []
8080

81+
[backup.options]
82+
8183
[backup.metrics-labels]
8284

8385
[copy]

src/snapshots/rustic_rs__config__tests__default_config_passes.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ RusticConfig {
171171
},
172172
snapshots: [],
173173
sources: [],
174+
options: {},
174175
metrics_job: None,
175176
metrics_labels: {},
176177
},

src/snapshots/rustic_rs__config__tests__global_env_roundtrip_passes-2.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ run-after = []
8888
run-failed = []
8989
run-finally = []
9090

91+
[backup.options]
92+
9193
[backup.metrics-labels]
9294

9395
[copy]

src/snapshots/rustic_rs__config__tests__global_env_roundtrip_passes-3.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ RusticConfig {
182182
},
183183
snapshots: [],
184184
sources: [],
185+
options: {},
185186
metrics_job: None,
186187
metrics_labels: {},
187188
},

src/snapshots/rustic_rs__config__tests__global_env_roundtrip_passes.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ run-after = []
8888
run-failed = []
8989
run-finally = []
9090

91+
[backup.options]
92+
9193
[backup.metrics-labels]
9294

9395
[copy]

tests/snapshots/show_config__show_config_passes.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ run-after = []
7878
run-failed = []
7979
run-finally = []
8080

81+
[backup.options]
82+
8183
[backup.metrics-labels]
8284

8385
[copy]

0 commit comments

Comments
 (0)