(docs) Add targeted restore examples

Extend the restore guidance with directory and single-file dry-run
examples so operators can restore a focused path without copying an
entire snapshot.

Render the examples on snapshot detail pages using the selected
snapshot's data path and the host-specific staging destination.
This commit is contained in:
2026-05-21 02:05:19 +02:00
parent b78f102e9d
commit 20a9f93378
4 changed files with 34 additions and 0 deletions

View File

@@ -82,6 +82,16 @@
<div><strong>Restore to staging:</strong></div>
<pre>{{ restore.local_command }}</pre>
</div>
<div class="stack spaced">
<div><strong>Dry-run a directory restore:</strong></div>
<pre>{{ restore.partial_dry_run_command }}</pre>
<div class="muted">Replace <code>{{ restore.example_relative_path }}</code> with the path you want to restore.</div>
</div>
<div class="stack spaced">
<div><strong>Dry-run a single file restore:</strong></div>
<pre>{{ restore.file_dry_run_command }}</pre>
<div class="muted">Replace <code>{{ restore.example_file_relative_path }}</code> with the file you want to restore.</div>
</div>
<div class="stack spaced">
<div><strong>Dry-run restore back to the source host:</strong></div>
<pre>{{ restore.remote_dry_run_command }}</pre>

View File

@@ -1427,6 +1427,12 @@ class ViewTests(TestCase):
self.assertContains(response, "rsync -aHAX --numeric-ids --info=progress2 --dry-run")
self.assertContains(response, f"{base.path}/data/")
self.assertContains(response, "root@web-01.example.test:/")
self.assertContains(response, "Dry-run a directory restore")
self.assertContains(response, f"{base.path}/data/etc/nginx/")
self.assertContains(response, f"/restore/{host.host}/etc/nginx/")
self.assertContains(response, "Dry-run a single file restore")
self.assertContains(response, f"{base.path}/data/home/example/site/public_html/index.php")
self.assertContains(response, f"/restore/{host.host}/home/example/site/public_html/index.php")
self.assertContains(response, "Treat snapshot directories as read-only")
self.assertContains(response, child.dirname)
self.assertContains(response, f"Run {run.id}")

View File

@@ -796,17 +796,27 @@ def _pretty_json(value: object) -> str:
def _snapshot_restore_guidance(snapshot: SnapshotRecord) -> dict[str, str]:
source_path = Path(snapshot.path) / "data"
destination_path = Path("/restore") / snapshot.host.host
example_relative_path = Path("etc") / "nginx"
example_file_relative_path = Path("home") / "example" / "site" / "public_html" / "index.php"
quoted_source = _quote_path_with_trailing_slash(source_path)
quoted_destination = _quote_path_with_trailing_slash(destination_path)
quoted_partial_source = _quote_path_with_trailing_slash(source_path / example_relative_path)
quoted_partial_destination = _quote_path_with_trailing_slash(destination_path / example_relative_path)
quoted_file_source = shlex.quote(str(source_path / example_file_relative_path))
quoted_file_destination = shlex.quote(str(destination_path / example_file_relative_path))
quoted_remote_destination = shlex.quote(f"root@{snapshot.host.address or snapshot.host.host}:/")
common_args = "rsync -aHAX --numeric-ids --info=progress2"
return {
"source_path": str(source_path),
"destination_path": str(destination_path),
"example_relative_path": str(example_relative_path),
"example_file_relative_path": str(example_file_relative_path),
"inspect_command": f"ls -la {quoted_source}",
"dry_run_command": f"{common_args} --dry-run {quoted_source} {quoted_destination}",
"local_command": f"{common_args} {quoted_source} {quoted_destination}",
"partial_dry_run_command": f"{common_args} --dry-run {quoted_partial_source} {quoted_partial_destination}",
"file_dry_run_command": f"{common_args} --dry-run {quoted_file_source} {quoted_file_destination}",
"remote_dry_run_command": f"{common_args} --dry-run {quoted_source} {quoted_remote_destination}",
}