]> begriffs open source - pg_scribe/blob - doc/cli.md
More about initial validation, less prescriptive output
[pg_scribe] / doc / cli.md
1 # pg_scribe Command Line Interface
2
3 This document describes the command line interface for **pg_scribe**, an incremental SQL backup system for PostgreSQL.
4
5 ## Overview
6
7 pg_scribe uses action flags similar to other PostgreSQL tools like `pg_recvlogical`. The tool performs one primary action per invocation, specified by action flags.
8
9 ## Synopsis
10
11 ```bash
12 # Initialize backup system
13 pg_scribe --init [OPTIONS]
14
15 # Start streaming incremental backups
16 pg_scribe --start [OPTIONS]
17
18 # Take a full backup
19 pg_scribe --full-backup [OPTIONS]
20
21 # Restore from backups
22 pg_scribe --restore [OPTIONS]
23
24 # Check replication slot status
25 pg_scribe --status [OPTIONS]
26 ```
27
28 ## Common Options
29
30 These options apply to all actions:
31
32 ### Connection Options
33
34 ```
35 -d, --dbname=DBNAME          Database name (can be a connection string)
36 -h, --host=HOSTNAME          Database server host (default: localhost)
37 -p, --port=PORT              Database server port (default: 5432)
38 -U, --username=USERNAME      Database user (default: $PGUSER or $USER)
39 -w, --no-password            Never prompt for password
40 -W, --password               Force password prompt
41 ```
42
43 ### General Options
44
45 ```
46 -v, --verbose                Enable verbose mode
47 -V, --version                Print version and exit
48 -?, --help                   Show help and exit
49 ```
50
51 ## Action Flags
52
53 Exactly one of the following action flags must be specified:
54
55 ### `--init`
56
57 Initialize the backup system by creating a replication slot, setting up DDL capture via the wal2sql extension, and taking an initial base backup.
58
59 **This operation is idempotent** - it can be safely re-run if initialization fails partway through. Existing slots and extensions will not cause errors.
60
61 **Additional options:**
62
63 ```
64 -f, --file=DIRECTORY         Backup output directory (required)
65 -S, --slot=SLOTNAME          Replication slot name (default: pg_scribe)
66     --force                  Skip validation and force initialization (dangerous!)
67 ```
68
69 **What it does:**
70
71 **Phase 1: Validation** (runs first, can fail)
72
73 1. **CRITICAL Checks** (must pass or initialization fails):
74    - Verify `wal_level = logical`
75    - Verify `max_replication_slots >= 1`
76    - Verify `max_wal_senders >= 1`
77    - Check all tables have adequate replica identity (PRIMARY KEY, USING INDEX, or FULL)
78
79 2. **Coverage Warnings** (non-blocking, informational):
80    - List unlogged tables (will not be backed up)
81    - Check for large objects (not incrementally backed up)
82
83 **Phase 2: Setup** (only runs if validation passes or `--force` used)
84
85 1. Creates the wal2sql extension if it doesn't exist (`CREATE EXTENSION IF NOT EXISTS wal2sql;`)
86    - This automatically installs the DDL event trigger
87 2. Creates a logical replication slot with snapshot export (skips if slot exists)
88 3. Takes synchronized base backup using `pg_dump --snapshot`
89 4. Creates initial `pg_dumpall --globals-only` backup
90 5. Generates metadata file with PostgreSQL version, extensions, encoding
91
92 **Example:**
93
94 ```bash
95 pg_scribe --init -d mydb -f /backups/mydb -S mydb_backup
96 ```
97
98 **Output should convey:**
99
100 - **Validation results** with clear pass/fail status for:
101   - PostgreSQL configuration (wal_level, max_replication_slots, max_wal_senders)
102   - Replica identity for all tables
103   - Coverage warnings (unlogged tables, large objects)
104 - **If validation fails**: List CRITICAL issues with specific fix commands, then exit with error code 5 (unless `--force` used)
105 - **If validation passes** (or `--force`): Progress through setup steps (extension creation, slot creation with snapshot ID, backup paths)
106 - **Final status**: Success message or warning if forced past validation failures
107
108 ---
109
110 ### `--start`
111
112 Start streaming incremental backups continuously from a replication slot.
113
114 **Additional options:**
115
116 ```
117 -f, --file=FILENAME          Output file (use '-' for stdout, required)
118 -S, --slot=SLOTNAME          Replication slot name (default: pg_scribe)
119 -s, --status-interval=SECS   Status update interval in seconds (default: 10)
120 -F, --fsync-interval=SECS    Fsync interval in seconds (default: 10, 0 to disable)
121 ```
122
123 **What it does:**
124
125 1. Wraps `pg_recvlogical` to stream from the specified replication slot
126 2. Streams decoded changes using the wal2sql plugin
127 3. Writes SQL to output file
128 4. Periodically fsyncs output file for crash safety
129 5. Reports LSN position and lag to stderr
130 6. Responds to SIGHUP by closing and reopening output file (for log rotation)
131
132 **Implementation:** `pg_scribe --start` is a thin wrapper around `pg_recvlogical --start` that:
133 - Invokes `pg_recvlogical` with the `wal2sql` plugin and appropriate options
134 - Forwards signals (SIGHUP, SIGTERM, SIGINT) to the child process
135 - Provides consistent interface with other pg_scribe commands
136
137 **Log rotation support:** File rotation is provided automatically by `pg_recvlogical`:
138
139 1. Rename the current output file
140 2. Send SIGHUP to pg_scribe process (which forwards it to pg_recvlogical)
141 3. pg_recvlogical closes the old file and opens a new one with the same name
142
143 **Example:**
144
145 ```bash
146 # Stream to a file (foreground)
147 pg_scribe --start -d mydb -f /backups/mydb/incremental.sql -S mydb_backup
148
149 # Run as background daemon (redirect stderr to log file)
150 pg_scribe --start -d mydb -f /backups/mydb/incremental.sql -S mydb_backup \
151   2>/var/log/pg_scribe.log &
152
153 # Stream to stdout (for processing with other tools)
154 pg_scribe --start -d mydb -f - -S mydb_backup > /backups/mydb/incremental.sql
155 ```
156
157 **Log rotation:**
158
159 ```bash
160 #!/bin/bash
161 BACKUP_FILE="/backups/mydb/incremental.sql"
162 mv "$BACKUP_FILE" "$BACKUP_FILE.$(date +%Y%m%d)"
163 killall -SIGHUP pg_scribe
164 ```
165
166 **Output (to stderr):** Connection status, output file path, periodic LSN position and lag, file rotation events
167
168 ---
169
170 ### `--full-backup`
171
172 Take a full backup using `pg_dump` and `pg_dumpall --globals-only`.
173
174 **Additional options:**
175
176 ```
177 -f, --file=DIRECTORY         Backup output directory (required)
178 -Z, --compress=METHOD        Compression method: gzip, lz4, zstd, or none
179                              Can include level (e.g., zstd:9) (default: zstd:9)
180 ```
181
182 **What it does:**
183
184 1. Takes full `pg_dump` backup
185 2. Takes `pg_dumpall --globals-only` backup
186 3. Generates metadata file
187 4. Compresses backups if enabled
188
189 **Example:**
190
191 ```bash
192 pg_scribe --full-backup -d mydb -f /backups/mydb
193 pg_scribe --full-backup -d mydb -f /backups/mydb --compress=zstd:9
194 ```
195
196 **Output should convey:** Progress for pg_dump and pg_dumpall steps, file paths, backup size (compressed and uncompressed if applicable)
197
198 ---
199
200 ### `--restore`
201
202 Restore database from base backup plus incremental backups.
203
204 **Additional options:**
205
206 ```
207 -f, --file=DIRECTORY         Backup input directory (required)
208 -d, --dbname=DBNAME          Target database name (required)
209 -C, --create                 Create target database
210 --base-backup=FILENAME       Specific base backup file (default: latest)
211 --no-sync-sequences          Skip sequence synchronization
212 ```
213
214 **What it does:**
215
216 1. Locates base backup (latest or specified)
217 2. Finds all incremental backups since base
218 3. Creates target database (if `--create` specified)
219 4. Restores globals (roles, tablespaces)
220 5. Restores base backup
221 6. Applies incremental backups in chronological order
222 7. Synchronizes sequences using `setval()` (unless `--no-sync-sequences`)
223 8. Reports basic statistics
224
225 **Example:**
226
227 ```bash
228 # Restore latest to new database
229 pg_scribe --restore -f /backups/mydb -d mydb_restored --create
230
231 # Restore specific base backup
232 pg_scribe --restore -f /backups/mydb -d mydb_restored \
233   --base-backup=/backups/mydb/base-2024-01-10.sql
234 ```
235
236 **Output should convey:** Base backup identified, number of incremental backups to apply, progress through each restore phase (globals, base, incrementals with counts), sequence synchronization details, final statistics (duration, row counts)
237
238 ---
239
240 ### `--status`
241
242 Check replication slot health and backup system status.
243
244 **Additional options:**
245
246 ```
247 -S, --slot=SLOTNAME          Replication slot name (default: pg_scribe)
248 -f, --file=DIRECTORY         Backup directory to analyze (optional)
249 ```
250
251 **What it does:**
252
253 1. Queries `pg_replication_slots` for slot health
254 2. Shows replication lag and WAL retention
255 3. Analyzes backup directory if provided
256 4. Reports warnings about potential issues
257
258 **Example:**
259
260 ```bash
261 pg_scribe --status -d mydb -S mydb_backup -f /backups/mydb
262 ```
263
264 **Output should convey:** Replication slot details (active status, LSN positions, lag, WAL retention, age), backup directory analysis (base backup count and dates, incremental file count and size, last backup timestamp, coverage continuity), overall health status with warnings if applicable
265
266 ---
267
268 ## Exit Status
269
270 ```
271 0   Success
272 1   General error
273 2   Database connection error
274 3   Replication slot error
275 4   Backup/restore error
276 5   Invalid arguments or validation failure (--init without --force)
277 10  Warning conditions (--status only)
278 ```
279
280 ---
281
282 ## Environment Variables
283
284 Standard PostgreSQL environment variables are supported:
285
286 ```
287 PGHOST              Database host
288 PGPORT              Database port
289 PGDATABASE          Database name
290 PGUSER              Database user
291 PGPASSWORD          Database password (not recommended, use .pgpass instead)
292 PG_COLOR            Use color in diagnostics: always, auto, or never
293 ```
294
295 ---
296
297 ## Example Workflows
298
299 ### Initial Setup and Daily Operation
300
301 ```bash
302 # 1. Initialize backup system (idempotent - safe to re-run)
303 pg_scribe --init -d production -f /backups/production -S prod_backup
304
305 # 2. Start streaming backups (run as daemon/service)
306 pg_scribe --start -d production -f /backups/production/incremental.sql \
307   -S prod_backup 2>/var/log/pg_scribe.log &
308
309 # 3. Set up log rotation (logrotate or custom script)
310 cat > /etc/logrotate.d/pg_scribe <<EOF
311 /backups/production/incremental.sql {
312     daily
313     rotate 7
314     dateext
315     postrotate
316         killall -SIGHUP pg_scribe
317     endscript
318 }
319 EOF
320
321 # 4. Schedule daily full backups (cron: 0 2 * * *)
322 pg_scribe --full-backup -d production -f /backups/production
323
324 # 5. Monitor slot health (cron: */15 * * * *)
325 pg_scribe --status -d production -S prod_backup
326 ```
327
328 ### Disaster Recovery
329
330 ```bash
331 # 1. Check available backups
332 pg_scribe --status -f /backups/production
333
334 # 2. Restore to new database
335 pg_scribe --restore -f /backups/production \
336   -d production_restored --create
337
338 # 3. Test restored database
339 psql -d production_restored -c "SELECT COUNT(*) FROM users;"
340
341 # 4. Switch application to restored database (manual step)
342 ```
343
344 ---
345
346 ## Comparison with PostgreSQL Tools
347
348 pg_scribe follows the same CLI conventions as core PostgreSQL tools:
349
350 | Tool | Action Flags | Connection Options | File Options |
351 |------|-------------|-------------------|--------------|
352 | **pg_recvlogical** | `--create-slot`, `--drop-slot`, `--start` | `-d`, `-h`, `-p`, `-U` | `-f` (output file), `-S` (slot) |
353 | **pg_dump** | (positional dbname) | `-d`, `-h`, `-p`, `-U` | `-f` (output file) |
354 | **pg_basebackup** | (none) | `-d`, `-h`, `-p`, `-U` | `-D` (data directory!) |
355 | **pg_restore** | (none) | `-d`, `-h`, `-p`, `-U` | positional (archive file) |
356 | **pg_scribe** | `--init`, `--start`, `--full-backup`, `--restore`, `--status` | `-d`, `-h`, `-p`, `-U` | `-f` (file/directory), `-S` (slot) |
357
358 **Note:** `pg_basebackup` uses `-D/--pgdata` because it creates an actual PostgreSQL data directory cluster. `pg_scribe` uses `-f/--file` like `pg_dump` and `pg_recvlogical` because it creates backup files.
359
360 ---
361
362 ## Implementation Notes
363
364 ### Design Principles
365
366 1. **Consistent with PostgreSQL**: Follow exact same conventions as pg_recvlogical, pg_dump, etc.
367 2. **Idempotent where sensible**: `--init` can be safely re-run
368 3. **Clear output**: Progress to stderr, data to stdout (when using `-f -`)
369 4. **Scriptable**: Clear text output format, proper exit codes
370
371 ### Technology Choices (POC)
372
373 - **Language**: Bash or Python
374   - Bash: Minimal dependencies, matches PostgreSQL tool style
375   - Python: Better error handling, easier testing
376 - **Dependencies**: Only PostgreSQL client tools (pg_recvlogical, pg_dump, pg_dumpall, psql)
377
378 ### Key Implementation Components
379
380 1. **Connection management**: Use libpq environment variables, .pgpass
381 2. **Error handling**: Validate prerequisites before starting operations
382 3. **File management**:
383    - For `--start`: Invoke `pg_recvlogical` with file specified by `-f`
384    - For `--full-backup`: Write to directory specified by `-f`
385    - For `--restore`: Read from directory specified by `-f`
386 4. **Signal handling**:
387    - SIGTERM/SIGINT for graceful shutdown (forward to child processes)
388    - SIGHUP for file rotation (--start only, forwarded to pg_recvlogical)
389 5. **Output conventions**:
390    - Progress and status messages → stderr
391    - SQL output → file specified by `-f` (or stdout if `-f -`)
392 6. **Process management for --start**:
393    - Spawn `pg_recvlogical` as child process
394    - Forward signals to child process
395    - Monitor child exit status
396    - Wrap child output to provide consistent pg_scribe formatting
397
398 **Extensibility Note**: This POC design uses a modular, action-based CLI that can accommodate additional features and options in future versions without breaking compatibility.