1# Chapter 12: postjevsql-sidecar/cli, the one engine 2 3This is the binary, `postjevsql-sidecar`, and the only part of the sidecar 4that talks to Postgres. It takes the config from chapter 11 and one of three 5commands: 6 7```text 8postjevsql-sidecar [--sidecar <conninfo>] <config.toml> converge 9postjevsql-sidecar [--sidecar <conninfo>] <config.toml> sync [--apply] 10postjevsql-sidecar <config.toml> serve [-- <postgres options>…] 11``` 12 13- **`converge`** creates `postgres_fdw` and `postjevsql` on the sidecar, 14 declares the foreign server with exactly the configured options (so an 15 option someone added by hand is dropped), and declares the user mappings: 16 a password from its secret, or PG18's `use_scram_passthrough` when none 17 is given. 18- **`sync`** reads the target's catalog and prints the plan from 19 `sync::plan`. **`sync --apply`** applies it in one transaction, unless a 20 change touches something a sidecar view, `BEGIN ATOMIC` function or grant 21 depends on (pg_depend), in which case it names each dependent and changes 22 nothing. 23- **`serve`** is the container image's entrypoint: initialise `$PGDATA` if 24 it is empty, start Postgres, wait for it, `converge`, `sync --apply`, stop 25 it with `pg_ctl stop`, and then exec `postgres` in its own place, so the 26 server is PID 1 and gets the container runtime's signals directly. A 27 refusal stops the server and exits non-zero with the reason. 28 29`--sidecar` is the conninfo of the sidecar itself; by default 30`host=/run/postgresql user=postgres dbname=postgres`. Every secret is 31resolved before anything connects, so a config that names a secret twice is 32refused first. 33 34```mermaid 35sequenceDiagram 36 participant CLI as postjevsql-sidecar sync 37 participant S as Sidecar Postgres 38 participant T as Target (through the foreign server) 39 CLI->>S: BEGIN, then CREATE SCHEMA postjevsql_sync_0 40 CLI->>S: as the first mapping's user, IMPORT FOREIGN SCHEMA public FROM SERVER target INTO postjevsql_sync_0 41 S->>T: read the catalog 42 T-->>S: the target's tables, as postgres_fdw imports them 43 CLI->>S: read the scratch tables and the existing foreign tables 44 CLI->>S: ROLLBACK 45 CLI->>CLI: sync::plan, then (with --apply) check pg_depend and apply in one transaction 46``` 47 48> **Aside.** Notice that the CLI never connects to the target. It reads the 49> target's catalog *through the sidecar's own foreign server*, importing it 50> into a scratch schema inside a transaction that is rolled back. So there is 51> no second connection to configure, no second set of credentials, and the 52> column types it compares are exactly the ones postgres_fdw would import. 53> One cost, stated: a function with a string body is not tracked by 54> pg_depend, so a change it depends on is not found. 55 56> **Try it.** `nix develop -c buck2 test //tests:sidecar_cli` starts a 57> throwaway target and a throwaway sidecar and checks that `converge` 58> declares exactly the configured server, that `sync` changes nothing, that 59> `sync --apply` changes only what differs, and that a change a view depends 60> on is refused with nothing applied. 61 62## For the people who maintain it 63 64| File | What | 65| --- | --- | 66| [main.rs](main.rs) | The three commands, the secret resolution before connecting, the catalog read through `IMPORT FOREIGN SCHEMA`, the pg_depend check, and `serve`'s start, converge, stop and exec. Built as `//crates/postjevsql-sidecar:cli`, packaged by `nix/sidecar-cli.nix`. | 67 68← Previous: [Chapter 11, postjevsql-sidecar/src/](../src/) · Up: [postjevsql-sidecar](../) · Next: [Chapter 13, tests/](../../../tests/) →