release: 0.7.0 — crate backup/restore (incremental ZFS send)#138
Merged
Conversation
Opens the 0.7 series — enterprise-grade operations inspired by
Proxmox VE 8/9 (snapshot vzdump, replication, HA failover, RBAC).
The 0.7.x line lands these one feature per release without
breaking the 0.6.x F2 API surface.
`crate backup` + `crate restore` — first piece. ZFS-send-based
snapshot streams that operators park on cheap storage and replay
months later.
crate backup myjail --output-dir /var/backups/crate
crate backup myjail --output-dir /var/backups/crate --auto-incremental
crate backup myjail --output-dir /var/backups/crate --since backup-2026-05-01T00:00:00Z
crate restore <stream> --to tank/jails/myjail-restored
Filenames sort lexicographically by time (UTC ISO 8601 suffix), so
retention pruning is `ls -1 backup-* | sort | tail -n +N | xargs rm`.
Incremental streams carry an `inc-from-<parent>` filename tag so
operators don't need a separate index file.
No compression wrapper: ZFS already compresses datasets and send
streams are dedup-friendly. Operators who want network-pipeline
compression can chain `| zstd | ssh remote "zfs recv ..."`.
Defense in depth:
- Output dir: absolute, no `..` segments, no shell metacharacters.
- --since: rejects `@` and `/` so a manipulated flag can't reach
into an arbitrary dataset.
- Filename collision: per-second timestamps; back-to-back runs
fail at `zfs snapshot` (snapshot already exists) rather than
silently overwriting.
Implementation:
- lib/backup_pure.{h,cpp}: pure helpers — snapshotSuffix
(UTC ISO 8601, lex-sortable), streamFilename (full vs
incremental tag), validators, argv builders for zfs
snapshot/send/recv/destroy, parseRetention
(hourly/daily/weekly/monthly), choosePlan (--since > auto-
incremental > full fallback).
- lib/backup.cpp: resolves jail -> dataset, finds latest
backup-* via `zfs list` for --auto-incremental, pipes
`zfs send` into output file via Util::execPipeline. restore
runs `zfs recv` with the stream file as stdin.
- cli/args.cpp + main.cpp: CmdBackup + CmdRestore enumerators,
usageBackup/usageRestore, dispatch.
- lib/audit*.cpp: both recorded in audit.log; targets
<name>-><dir> and <file>-><dataset>.
Tests: +23 ATF cases in tests/unit/backup_pure_test.cpp covering
the lex-sort = chronological-sort invariant (the cron-pruning
property), full vs. incremental argv shape, plan-choice priority
(--since > auto > full), retention parser edge cases, and shell-
metacharacter rejection in output dir. 724/724 unit tests
expected (was 701; pure tests verified at 23/23).
Note: full unit-test rebuild not run on this Linux box — adding a
new pure module to TEST_LINK_SRCS triggers a multi-minute rebuild
of all 40+ test binaries because of the rule-level dependency in
Makefile. FreeBSD CI exercises the runtime side (which depends on
libjail + ZFS).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Opens the 0.7 series — enterprise-grade operations. Inspired by what Proxmox VE 8/9 ships (snapshot-based vzdump, replication, HA failover, RBAC). The
0.7.xline lands these one feature per release without breaking the 0.6.x F2 API surface.crate backup+crate restore— first piece. ZFS-send-based snapshot streams that operators park on cheap storage and replay months later.File naming = retention policy
Filenames sort lexicographically by time (UTC ISO 8601 suffix), so retention pruning is just shell:
Incremental streams carry an
inc-from-<parent>tag in the filename so operators don't need a separate index file:No compression wrapper
ZFS already compresses datasets and the send stream is dedup-friendly. Adding gzip/xz/zstd shrinks streams by ~5% in container workloads while doubling restore time. Operators who want network-pipeline compression can chain
| zstd | ssh remote "zfs recv ...".Defense in depth
..segments, no shell metacharacters--since: rejects@and/so a manipulated flag can't reach into arbitrary datasetszfs snapshotrather than silently overwritingImplementation
lib/backup_pure.{h,cpp}— pure helpers:snapshotSuffix(UTC ISO 8601, lex-sortable),streamFilename, validators, argv builders,parseRetention,choosePlan(--since> auto-incremental > full fallback).lib/backup.cpp— resolves jail → dataset, finds latestbackup-*viazfs listfor--auto-incremental, pipeszfs sendinto output file.restorerunszfs recvwith the stream file as stdin.cli/args.cpp+main.cpp—CmdBackup+CmdRestoreenumerators, dispatch, usage.lib/audit*.cpp— both recorded inaudit.log.Tests
tests/unit/backup_pure_test.cpp— 23 ATF cases including:--since> auto-incremental > full fallback on first run)..--sincerejection of@and/724/724 unit tests expected (was 701; pure tests verified at 23/23).
Test plan
kyua test backup_pure_test— 23/23TODO— backup moved to Done; 0.7 roadmap added (replicate, HA failover, RBAC)https://claude.ai/code/session_01X6t6tzVypHye5bDGLxzmZK
Generated by Claude Code