feat(postgresql): request extensions on CNPG clusters #350

Merged
leokumojin merged 3 commits from feat/postgres-extensions into master 2026-10-19 15:24:40 +00:00
Collaborator

Lets PostgreSQLScore request Postgres extensions on CNPG clusters.

What

  • PostgreSQLConfig.extensions: Vec<String> (default empty).
  • When non-empty, the CNPG interpret applies a postgresql.cnpg.io/v1 Database (<cluster>-app) for the app database, with each extension set to ensure: present.
  • The Score applies the resource and returns; CNPG reconciles it. A failure shows in the Database status, and the app that needs the extension fails on its own until it is there.

Why
Untrusted extensions such as pgvector's vector need the superuser; the app role cannot create them. A Database resource reconciles on existing clusters too, while initdb.postInitApplicationSQL only runs when a cluster is created. iaai needs vector for Keep's vector search (NationTech/iaai#30 follow-up).

Tested

  • Unit test on the generated Database (apiVersion, kind, spec).
  • cargo fmt --check, cargo check --workspace --all-targets, cargo test --workspace --exclude harmony-fleet-e2e (880 passed). harmony-fleet-e2e does not link on macOS (libvirt), unrelated.
  • kubectl apply --dry-run=server of the generated manifest against a CNPG 1.x cluster: accepted.

Not covered

  • Removing an extension from the list does not drop it from the database.
Lets `PostgreSQLScore` request Postgres extensions on CNPG clusters. **What** - `PostgreSQLConfig.extensions: Vec<String>` (default empty). - When non-empty, the CNPG interpret applies a `postgresql.cnpg.io/v1` `Database` (`<cluster>-app`) for the `app` database, with each extension set to `ensure: present`. - The Score applies the resource and returns; CNPG reconciles it. A failure shows in the `Database` status, and the app that needs the extension fails on its own until it is there. **Why** Untrusted extensions such as pgvector's `vector` need the superuser; the `app` role cannot create them. A `Database` resource reconciles on existing clusters too, while `initdb.postInitApplicationSQL` only runs when a cluster is created. iaai needs `vector` for Keep's vector search (NationTech/iaai#30 follow-up). **Tested** - Unit test on the generated `Database` (apiVersion, kind, spec). - `cargo fmt --check`, `cargo check --workspace --all-targets`, `cargo test --workspace --exclude harmony-fleet-e2e` (880 passed). `harmony-fleet-e2e` does not link on macOS (libvirt), unrelated. - `kubectl apply --dry-run=server` of the generated manifest against a CNPG 1.x cluster: accepted. **Not covered** - Removing an extension from the list does not drop it from the database.
leokumojin added 1 commit 2026-10-19 13:32:36 +00:00
feat(postgresql): request extensions on CNPG clusters
All checks were successful
Run Check Script / check (pull_request) Successful in 32s
ae60403756
PostgreSQLConfig gains `extensions`. When non-empty, the CNPG interpret
applies a postgresql.cnpg.io/v1 Database for the app database and waits
until CNPG reports it applied, so superuser-only extensions like
`vector` work, on existing clusters too.
leokumojin added 1 commit 2026-10-19 13:39:41 +00:00
chore(postgresql): drop redundant comments
All checks were successful
Run Check Script / check (pull_request) Successful in 23s
8d3b63b7b0
leokumojin requested review from johnride 2026-10-19 13:43:30 +00:00
johnride requested changes 2026-10-19 13:51:47 +00:00
@@ -333,0 +415,4 @@
.create_interpret()
.execute(inventory, topology)
.await?;
if self.config.wait_for_ready {
Owner

why nest this inside extensions empty check? And why add wait for database in this file? K8s (and harmony's) design is eventually consistent, we don't want to block a deployment because a db takes time or fails to fire up, we want the DB itself to fail and let us know but other systems to handle that gracefully, retrying until the DB comes up.

So at the higher level it is ok to have a mechanism to wait on the DB, or at least to know if it is healthy, but blocking deployment within a nested if only active when there is an extension feels wrong.

why nest this inside extensions empty check? And why add wait for database in this file? K8s (and harmony's) design is eventually consistent, we don't want to block a deployment because a db takes time or fails to fire up, we want the DB itself to fail and let us know but other systems to handle that gracefully, retrying until the DB comes up. So at the higher level it is ok to have a mechanism to wait on the DB, or at least to know if it is healthy, but blocking deployment within a nested if only active when there is an extension feels wrong.
Author
Collaborator

I removed the wait for db, it was indeed out of place

I removed the wait for db, it was indeed out of place
leokumojin added 1 commit 2026-10-19 14:00:22 +00:00
fix(postgresql): apply the extensions Database without blocking the deploy
All checks were successful
Run Check Script / check (pull_request) Successful in 18s
8cbdaff3bb
leokumojin requested review from johnride 2026-10-19 15:17:43 +00:00
Owner

LGTM

Didn't know that extensions were per database, I thought they were per instance (cluster) in CNPG.

LGTM Didn't know that extensions were per database, I thought they were per instance (cluster) in CNPG.
leokumojin merged commit 0cc24b6fe1 into master 2026-10-19 15:24:40 +00:00
leokumojin deleted branch feat/postgres-extensions 2026-10-19 15:24:40 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: NationTech/harmony#350
No description provided.