refactor(nix,postgres): provision database declaratively, connect via socket#5337
refactor(nix,postgres): provision database declaratively, connect via socket#5337JakobLichterfeld wants to merge 8 commits into
Conversation
✅ Deploy Preview for teslamate ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
|
|
I would really like to update this sometime to use the socket connection to the database by default rather then the TCP connection. Not only is there likely to be a tiny performance gain, but means there is one less password to worry about. Not sure about grafana though, is that supports socket connections or not. And it probably should have a dedicated postgresql user too. Don't know if any of this is in scope for this change or not. But maybe something to think about. |
|
Exactly. I wonder the same, would it be possible to use socket connection and grafana (yes I do it similar with Prometheus in my homelab) and TeslaMate as well to connect to the DB at the same time? Why not. As it seems like the options I tried to use won't be available (old links in mynixos.com) I will look more into it. |
4a82f1e to
e712294
Compare
Replaced with the familiar once and use |
e712294 to
9d9df9f
Compare
9d9df9f to
f8ed8a2
Compare
f8ed8a2 to
0260706
Compare
0260706 to
cb34f3f
Compare
testing showed it didn't work as expected for password, so I solved it correctly.
I refactored to use socket connection for TeslaMate in default. |
187a076 to
490fce2
Compare
|
I also fixed the RELEASE_COOKIE sourcing issue (from #4904) |
89ee6a5 to
8f4b376
Compare
a0f0644 to
682b7df
Compare
Self-review notes (maintainer hat on)Since this touches provisioning and secrets handling, here is a summary of what I verified before asking for review: Verified:
Known minor follow-ups (happy to fix in this PR if reviewers agree):
Tested on my own NixOS install (fresh provisioning and upgrade from the 🤖 Review drafted with Claude Code (Fable 5 high) — sponsored by Claude for Open Source |
682b7df to
0b835b3
Compare
|
Both follow-ups from my self-review notes above are now fixed:
While at it, the 🤖 Review drafted with Claude Code (Fable 5 high) — sponsored by Claude for Open Source |
… socket Replace the single `initialScript` with declarative `ensureDatabases` and `ensureUsers`, freeing the `services.postgresql.initialScript` option, which is single-valued and could not be combined with other modules that need it (e.g. to `CREATE EXTENSION`). TeslaMate now connects to a local PostgreSQL via the unix socket using peer authentication, so no password is sent over TCP and startup no longer depends on the password being set first. The role password is still applied at runtime from DATABASE_PASS via `postStart` (kept out of the Nix store) because Grafana and the TCP fallback still require it.
Sourcing the environment file executed it as a shell script (arbitrary code execution if a secret contained $(...) or backticks) and broke on values containing quotes. Extract RELEASE_COOKIE literally with sed instead and strip one optional surrounding pair of double quotes, so the value is handled safely whether or not it is quoted in the file.
The password was interpolated into the SQL string as '$DATABASE_PASS', which breaks (and risks SQL injection) for passwords containing single quotes. Read it from the environment with psql's \getenv and quote it with :'password', producing a correctly escaped SQL string literal. The password is no longer placed on the command line either. Requires PostgreSQL >= 14 for \getenv.
38e96c8 to
5a86e81
Compare
|
This mostly looks good to me. AI Report:
Most of these are minor issues I think. Not quite comprehending the "Standby/replica breakage" stuff right now. Possibly because I have never done this with postgresql :-) |
…ersion Address review feedback: ALTER USER cannot run on a read-only standby (the password is replicated from the primary anyway), so postStart now checks pg_is_in_recovery() and exits cleanly. Overriding postgres.package now fails at eval time unless it meets TeslaMate's runtime requirement (>= 16.7 for 16.x, >= 17.3 for 17.x, or >= 18, mirroring lib/teslamate/database_check.ex), instead of surfacing as a runtime error; this also covers the psql \getenv used to set the role password.
|
Thanks for the thorough look, Brian! Quick explainer on the standby point, since it's a bit obscure: a standby is a streaming-replication replica running in recovery mode — it is read-only, so any write statement fails, including Also addressed:
🤖 Review drafted with Claude Code (Fable 5 high) — sponsored by Claude for Open Source |
Without -d, psql connects to the database named after databaseUser, so the DROP SCHEMA/CREATE EXTENSION step ran against the wrong database whenever databaseName differs from databaseUser, while the subsequent restore targeted the correct one and failed on the existing data.
|
Pushed one more fix found while testing the restore path: Without Two related observations, deliberately left for the follow-up issue (#5533) on the maintenance scripts: the backup/restore scripts share the same peer-auth limitation as the delete scripts (they only work with the default role name), and the restore psql invocations run without 🤖 Review drafted with Claude Code (Fable 5 high) — sponsored by Claude for Open Source |
The NixOS module defaults analytics.check_for_plugin_updates to "declarativePlugins == null", so with our plain nixpkgs-managed plugins the check ran every 10 minutes against grafana.com. Plugins only ever change through nixpkgs here, so the check is pure log noise and an unnecessary external call.
|
One more small hardening found while reviewing the Grafana defaults: the NixOS module disables Grafana's update checks by default, except 🤖 Review drafted with Claude Code (Fable 5 high) — sponsored by Claude for Open Source |
Replace the single
initialScriptwith declarativeensureDatabasesandensureUsers, freeing theservices.postgresql.initialScriptoption, which is single-valued and could not be combined with other modules that need it (e.g. toCREATE EXTENSION).TeslaMate now connects to a local PostgreSQL via the unix socket using peer authentication, so no password is sent over TCP and startup no longer depends on the password being set first. The role password is still applied at runtime from DATABASE_PASS via
postStart(kept out of the Nix store) because Grafana and the TCP fallback still require it.Additionally read
RELEASE_COOKIEwithout sourcing the env fileSourcing the environment file executed it as a shell script (arbitrary code execution if a secret contained $(...) or backticks) and broke on values containing quotes. Extract RELEASE_COOKIE literally with sed
instead and strip one optional surrounding pair of double quotes, so the value is handled safely whether or not it is quoted in the file.
This closes #4904