LinuxCommandLibrary
GitHubF-DroidGoogle Play Store

restoredrill

Prove PostgreSQL backups actually restore in a throwaway container

TLDR

Run a local restore drill from a YAML config (marks the run as manual)
$ restoredrill --config [quickstart.yml] --trigger manual
copy
Record who started a manual drill
$ restoredrill --config [restoredrill.yml] --trigger manual --triggered-by [you@example.com]
copy
Run on a scheduler (the default trigger) and keep the CI job id
$ restoredrill --config [restoredrill.yml] --pipeline-job-id [github:123]
copy
Print version and build metadata
$ restoredrill --version
copy

SYNOPSIS

restoredrill [--config file] [--trigger scheduled|manual] [--triggered-by who] [--pipeline-job-id id] [--version]

DESCRIPTION

restoredrill fetches a PostgreSQL backup, restores it into an ephemeral Postgres container, runs fail-closed checks, and writes a JSON evidence report with restore duration. It is a CI-native drill, not a backup dashboard: one command, one timestamped report, a non-zero exit if anything is wrong — including a notify sink that failed to deliver.Checks run in tiers. Prechecks (before restore) look at file size, pg_dump -Fc archive headers, and backup age against an optional RPO target. Structural checks cover restore success, table count, and sequence integrity (a serial/identity sequence that lags its column only fails on the first INSERT after a real disaster). Read-path checks are row counts and user SQL assertions (each query must return exactly one row with a single boolean; an error is a failure, not a skip). RTO compares measured restore time to an optional target. The container must accept connections or the drill fails.Backup sources are a local path, a file:// URL, or s3:// (the aws CLI is required). An S3 URL ending in / is a prefix: the newest matching object is chosen, after a content sniff for custom-format dumps so a newer checksum sidecar cannot win. Formats are pg_dump_custom (default) and pg_dump_sql.v0.1.0, Postgres only. Build with go build ./cmd/restoredrill. GitHub Action and example workflow live in the repository.

PARAMETERS

--config file

Path to the YAML config (default restoredrill.yml).
--trigger scheduled|manual
How this drill was started. Must be scheduled (default) or manual.
--triggered-by who
Who started it. For manual runs, defaults to the OS username when omitted.
--pipeline-job-id id
CI job identifier recorded on the report. If unset, auto-detected from GITHUB_RUN_ID (github: prefix), CI_JOB_ID (gitlab:), or BUILD_ID (jenkins:).
--version
Print version, commit, and build date, then exit.
-h, --help
Print flag help (double-dash names) and exit 0.

CONFIGURATION

YAML keys (required: backup.source):backup.source / backup.format / backup.s3_object_pattern

File or URL to drill; pg_dump_custom or pg_dump_sql; glob required for an S3 prefix plus plain SQL (no PGDMP header to sniff).
postgres.image
Container image (default postgres:16). Match the production major version.
sandbox.keep
never (default), on-failure, or always. Kept containers print docker exec / docker rm hints.
checks.min_size_bytes
Fail if the dump is too small. Unset uses a 100-byte floor; -1 disables the floor.
checks.archive_integrity
Inspect the custom-format table of contents before restore (no equivalent for plain SQL).
checks.rpo_target / checks.rto_target
Go durations such as 48h and 30m. RPO fails closed if the backup timestamp cannot be determined.
checks.min_tables / checks.sequence_integrity
Structural gates after restore.
checks.row_counts / checks.queries
table + min row counts; named SQL assertions.
notify.webhook_url / notify.slack_webhook_url
POST the full JSON report, or a one-line Slack summary. Failed delivery is a drill failure.
output.prometheus_textfile
nodeexporter textfile metrics. Alert on the age of **restoredrilllastruntimestamp_seconds**.
report.path
JSON report path (default restoredrill-report.json). Every field is always present; timestamps are "YYYY-MM-DD HH:MM:SS UTC" strings.

CAVEATS

Needs Docker. The ephemeral-container model assumes the database fits on the runner; multi-terabyte estates need dedicated restore infra. pg_dump-level verification does not exercise PITR or WAL replay (pgBackRest is on the roadmap). Plain SQL dumps have no archive-header precheck, so corruption is caught at restore time.A passed restore with a report that could not be written, or with failed notifications, still exits 1. Flag parse errors exit 2. Status is early: schema and flags may still change.

HISTORY

Written by Ahmad Piran as a narrow, auditor-shaped restore check (MIT). v0.1.0 is Postgres-only.

SEE ALSO

pg_dump(1), pg_dumpall(1), pg_restore(1), psql(1), postgres(1), docker(1), aws(1)

RESOURCES

Braincup
Open source brain training for math, memory and focus
Braincup mini-games
41 mini-games · Apache-2.0
No ads · No tracking
Play in browser
Download Braincup on the App StoreGet Braincup on Google PlayGet Braincup on F-Droid
276 stars
From the maker of Linux Command Library
Copied to clipboard
Braincup
Open source brain training for math, memory and focus. 41 mini-games, from mental arithmetic to Sudoku, N-Back and Solo Chess.
Apache-2.0 licensed · No ads · No tracking · No account
From the maker of Linux Command Library
Download Braincup on the App StoreGet Braincup on Google PlayGet Braincup on F-Droid