]> begriffs open source - pg_scribe/blob - doc/cli.md
Fix some shellcheck errors
[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 is a one-time initialization operation** - following PostgreSQL conventions (`initdb`, `pg_basebackup`), it requires an empty backup directory and will fail if already initialized. If initialization fails, partial state is automatically cleaned up (replication slot dropped, partial backup files removed).
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. Verifies backup directory is empty (or doesn't exist)
86 2. Creates the wal2sql extension if it doesn't exist (`CREATE EXTENSION IF NOT EXISTS wal2sql;`)
87    - This automatically installs the DDL event trigger
88 3. Creates a logical replication slot (fails if slot already exists)
89 4. Takes synchronized base backup using `pg_dump`
90 5. Creates initial `pg_dumpall --globals-only` backup
91 6. Generates metadata file with PostgreSQL version, extensions, encoding
92
93 **Example:**
94
95 ```bash
96 pg_scribe --init -d mydb -f /backups/mydb -S mydb_backup
97 ```
98
99 **Output should convey:**
100
101 - **Validation results** with clear pass/fail status for:
102   - PostgreSQL configuration (wal_level, max_replication_slots, max_wal_senders)
103   - Replica identity for all tables
104   - Coverage warnings (unlogged tables, large objects)
105 - **If validation fails**: List CRITICAL issues with specific fix commands, then exit with error code 5 (unless `--force` used)
106 - **If validation passes** (or `--force`): Progress through setup steps (extension creation, slot creation with snapshot ID, backup paths)
107 - **Final status**: Success message or warning if forced past validation failures
108
109 ---
110
111 ### `--start`
112
113 Start streaming incremental backups continuously from a replication slot.
114
115 **Additional options:**
116
117 ```
118 -f, --file=FILENAME          Output file (use '-' for stdout, required)
119 -S, --slot=SLOTNAME          Replication slot name (default: pg_scribe)
120 -s, --status-interval=SECS   Status update interval in seconds (default: 10)
121 -F, --fsync-interval=SECS    Fsync interval in seconds (default: 10, 0 to disable)
122 ```
123
124 **What it does:**
125
126 1. Wraps `pg_recvlogical` to stream from the specified replication slot
127 2. Streams decoded changes using the wal2sql plugin
128 3. Writes SQL to output file
129 4. Periodically fsyncs output file for crash safety
130 5. Reports LSN position and lag to stderr
131 6. Responds to SIGHUP by closing and reopening output file (for log rotation)
132
133 **Implementation:** `pg_scribe --start` is a thin wrapper around `pg_recvlogical --start` that:
134 - Invokes `pg_recvlogical` with the `wal2sql` plugin and appropriate options
135 - Forwards signals (SIGHUP, SIGTERM, SIGINT) to the child process
136 - Provides consistent interface with other pg_scribe commands
137
138 **Log rotation support:** File rotation is provided automatically by `pg_recvlogical`:
139
140 1. Rename the current output file
141 2. Send SIGHUP to pg_scribe process (which forwards it to pg_recvlogical)
142 3. pg_recvlogical closes the old file and opens a new one with the same name
143
144 **Example:**
145
146 ```bash
147 # Stream to a file (foreground)
148 pg_scribe --start -d mydb -f /backups/mydb/incremental.sql -S mydb_backup
149
150 # Run as background daemon (redirect stderr to log file)
151 pg_scribe --start -d mydb -f /backups/mydb/incremental.sql -S mydb_backup \
152   2>/var/log/pg_scribe.log &
153
154 # Stream to stdout (for processing with other tools)
155 pg_scribe --start -d mydb -f - -S mydb_backup > /backups/mydb/incremental.sql
156 ```
157
158 **Log rotation:**
159
160 ```bash
161 #!/bin/bash
162 BACKUP_FILE="/backups/mydb/incremental.sql"
163 mv "$BACKUP_FILE" "$BACKUP_FILE.$(date +%Y%m%d)"
164 killall -SIGHUP pg_scribe
165 ```
166
167 **Output (to stderr):** Connection status, output file path, periodic LSN position and lag, file rotation events
168
169 ---
170
171 ### `--full-backup`
172
173 Take a full backup using `pg_dump` and `pg_dumpall --globals-only`.
174
175 **Additional options:**
176
177 ```
178 -f, --file=DIRECTORY         Backup output directory (required)
179 -Z, --compress=METHOD        Compression method: gzip, lz4, zstd, or none
180                              Can include level (e.g., zstd:9) (default: zstd:9)
181 ```
182
183 **What it does:**
184
185 1. Takes full `pg_dump` backup
186 2. Takes `pg_dumpall --globals-only` backup
187 3. Generates metadata file
188 4. Compresses backups if enabled
189
190 **Example:**
191
192 ```bash
193 pg_scribe --full-backup -d mydb -f /backups/mydb
194 pg_scribe --full-backup -d mydb -f /backups/mydb --compress=zstd:9
195 ```
196
197 **Output should convey:** Progress for pg_dump and pg_dumpall steps, file paths, backup size (compressed and uncompressed if applicable)
198
199 ---
200
201 ### `--restore`
202
203 Restore database from base backup plus incremental backups.
204
205 **Additional options:**
206
207 ```
208 -f, --file=DIRECTORY         Backup input directory (required)
209 -d, --dbname=DBNAME          Target database name (required)
210 -C, --create                 Create target database
211 --base-backup=FILENAME       Specific base backup file (default: latest)
212 --no-sync-sequences          Skip sequence synchronization
213 ```
214
215 **What it does:**
216
217 1. Locates base backup (latest or specified)
218 2. Finds all incremental backups since base
219 3. Creates target database (if `--create` specified)
220 4. Restores globals (roles, tablespaces)
221 5. Restores base backup
222 6. Applies incremental backups in chronological order
223 7. Synchronizes sequences using `setval()` (unless `--no-sync-sequences`)
224 8. Reports basic statistics
225
226 **Example:**
227
228 ```bash
229 # Restore latest to new database
230 pg_scribe --restore -f /backups/mydb -d mydb_restored --create
231
232 # Restore specific base backup
233 pg_scribe --restore -f /backups/mydb -d mydb_restored \
234   --base-backup=/backups/mydb/base-2024-01-10.sql
235 ```
236
237 **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)
238
239 ---
240
241 ### `--status`
242
243 Check replication slot health and backup system status.
244
245 **Additional options:**
246
247 ```
248 -S, --slot=SLOTNAME          Replication slot name (default: pg_scribe)
249 -f, --file=DIRECTORY         Backup directory to analyze (optional)
250 ```
251
252 **What it does:**
253
254 1. Queries `pg_replication_slots` for slot health
255 2. Shows replication lag and WAL retention
256 3. Analyzes backup directory if provided
257 4. Reports warnings about potential issues
258
259 **Example:**
260
261 ```bash
262 pg_scribe --status -d mydb -S mydb_backup -f /backups/mydb
263 ```
264
265 **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
266
267 ---
268
269 ## Exit Status
270
271 ```
272 0   Success
273 1   General error
274 2   Database connection error
275 3   Replication slot error
276 4   Backup/restore error
277 5   Invalid arguments or validation failure (--init without --force)
278 10  Warning conditions (--status only)
279 ```
280
281 ---
282
283 ## Environment Variables
284
285 Standard PostgreSQL environment variables are supported:
286
287 ```
288 PGHOST              Database host
289 PGPORT              Database port
290 PGDATABASE          Database name
291 PGUSER              Database user
292 PGPASSWORD          Database password (not recommended, use .pgpass instead)
293 PG_COLOR            Use color in diagnostics: always, auto, or never
294 ```
295
296 ---
297
298 ## Example Workflows
299
300 ### Initial Setup and Daily Operation
301
302 ```bash
303 # 1. Initialize backup system (one-time setup, requires empty directory)
304 pg_scribe --init -d production -f /backups/production -S prod_backup
305
306 # 2. Start streaming backups (run as daemon/service)
307 pg_scribe --start -d production -f /backups/production/incremental.sql \
308   -S prod_backup 2>/var/log/pg_scribe.log &
309
310 # 3. Set up log rotation (logrotate or custom script)
311 cat > /etc/logrotate.d/pg_scribe <<EOF
312 /backups/production/incremental.sql {
313     daily
314     rotate 7
315     dateext
316     postrotate
317         killall -SIGHUP pg_scribe
318     endscript
319 }
320 EOF
321
322 # 4. Schedule daily full backups (cron: 0 2 * * *)
323 pg_scribe --full-backup -d production -f /backups/production
324
325 # 5. Monitor slot health (cron: */15 * * * *)
326 pg_scribe --status -d production -S prod_backup
327 ```
328
329 ### Disaster Recovery
330
331 ```bash
332 # 1. Check available backups
333 pg_scribe --status -f /backups/production
334
335 # 2. Restore to new database
336 pg_scribe --restore -f /backups/production \
337   -d production_restored --create
338
339 # 3. Test restored database
340 psql -d production_restored -c "SELECT COUNT(*) FROM users;"
341
342 # 4. Switch application to restored database (manual step)
343 ```
344
345 ---
346
347 ## Comparison with PostgreSQL Tools
348
349 pg_scribe follows the same CLI conventions as core PostgreSQL tools:
350
351 | Tool | Action Flags | Connection Options | File Options |
352 |------|-------------|-------------------|--------------|
353 | **pg_recvlogical** | `--create-slot`, `--drop-slot`, `--start` | `-d`, `-h`, `-p`, `-U` | `-f` (output file), `-S` (slot) |
354 | **pg_dump** | (positional dbname) | `-d`, `-h`, `-p`, `-U` | `-f` (output file) |
355 | **pg_basebackup** | (none) | `-d`, `-h`, `-p`, `-U` | `-D` (data directory!) |
356 | **pg_restore** | (none) | `-d`, `-h`, `-p`, `-U` | positional (archive file) |
357 | **pg_scribe** | `--init`, `--start`, `--full-backup`, `--restore`, `--status` | `-d`, `-h`, `-p`, `-U` | `-f` (file/directory), `-S` (slot) |
358
359 **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.
360
361 ---
362
363 ## Implementation Notes
364
365 ### Design Principles
366
367 1. **Consistent with PostgreSQL**: Follow exact same conventions as `pg_recvlogical`, `pg_dump`, `initdb`, `pg_basebackup`
368 2. **Fail-fast initialization**: `--init` requires empty directory, cleans up on failure (like `initdb` and `pg_basebackup`)
369 3. **Clear output**: Progress to stderr, data to stdout (when using `-f -`)
370 4. **Scriptable**: Clear text output format, proper exit codes
371
372 ### Technology Choices (POC)
373
374 - **Language**: Bash or Python
375   - Bash: Minimal dependencies, matches PostgreSQL tool style
376   - Python: Better error handling, easier testing
377 - **Dependencies**: Only PostgreSQL client tools (pg_recvlogical, pg_dump, pg_dumpall, psql)
378
379 ### Key Implementation Components
380
381 1. **Connection management**: Use libpq environment variables, .pgpass
382 2. **Error handling**: Validate prerequisites before starting operations
383 3. **File management**:
384    - For `--start`: Invoke `pg_recvlogical` with file specified by `-f`
385    - For `--full-backup`: Write to directory specified by `-f`
386    - For `--restore`: Read from directory specified by `-f`
387 4. **Signal handling**:
388    - SIGTERM/SIGINT for graceful shutdown (forward to child processes)
389    - SIGHUP for file rotation (--start only, forwarded to pg_recvlogical)
390 5. **Output conventions**:
391    - Progress and status messages → stderr
392    - SQL output → file specified by `-f` (or stdout if `-f -`)
393 6. **Process management for --start**:
394    - Spawn `pg_recvlogical` as child process
395    - Forward signals to child process
396    - Monitor child exit status
397    - Wrap child output to provide consistent pg_scribe formatting
398
399 **Extensibility Note**: This POC design uses a modular, action-based CLI that can accommodate additional features and options in future versions without breaking compatibility.