inspect --all-instances: every Aurora writer and reader behind one endpoint (experimental) - #38
alexshapalov wants to merge 4 commits into
Conversation
…d one endpoint (experimental) An Aurora cluster endpoint stands for several instances, and pg_stat_* on one says nothing about the others (#23). Discovery uses SQL and DNS only: aurora_replica_status() lists the members (exactly one writer expected; anything else is refused), each instance endpoint is derived from the entry endpoint's DNS name (<instance>.<cluster-id>.<region>.rds.amazonaws.com; a custom domain is followed through its CNAME; RDS Proxy and non-RDS names are refused), and aurora_db_instance_identifier() must confirm a derived endpoint reached the member it names before anything is collected. No AWS credentials, CLI, SDK, or API. The --all-databases fan-out is generalized to (member, database) targets, so the two flags compose; output is writer first, then readers, one member at a time. Cluster-wide findings dedupe per member (parameter groups differ per instance). Text banners each target; JSON carries server.instance and server.instance_role (SchemaVersion 1.3.0, additive); SARIF/JUnit objects are prefixed instance:<id>/; Prometheus series gain instance and role labels so two members' samples for one database are distinct. Missing members are reported as partial coverage and fail the run with exit 3. conn.ConnectDBAt overrides the host (and the TLS server name, so verify-full validates the member's own certificate). Unit tests cover endpoint derivation across cluster/reader/custom/instance endpoints and the GovCloud and China partitions, role parsing, target composition, dedupe, merge tagging, and the Prometheus labels; TestIntegration_auroraInstances (PGBOT_AURORA_TEST_DSN) is the opt-in end-to-end check against a real cluster. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013qGZKWgfGTBCoHsDjy1SuB
|
@alexshapalov sorry I haven't got around to this yet. I do intend to test it out tomorrow and I'll get back to you. |
|
Hey @alexshapalov Sorry for the wait. I gave this a run against an Aurora PostgreSQL 18.3 cluster, connecting straight to the cluster endpoint, and It is a real Aurora cluster. The catalog probe in -- Aurora exposes aurora_version(). Look it up in the catalog rather
-- than CALLING it: on every other server the call fails, which writes
-- an ERROR to the server log and books a rollback in pg_stat_database
-- on each pgbot run — the very counter pgbot reports.
(SELECT count(*) FROM pg_proc WHERE proname = 'aurora_version') > 0On 18.3 that returns 0. There are no With Swap the probe to --- a/internal/conn/connect.go
+++ b/internal/conn/connect.go
@@ -246,7 +246,11 @@
pg_is_in_recovery(),
- -- Aurora exposes aurora_version(). Look it up in the catalog rather
- -- than CALLING it: on every other server the call fails, which writes
- -- an ERROR to the server log and books a rollback in pg_stat_database
- -- on each pgbot run — the very counter pgbot reports.
- (SELECT count(*) FROM pg_proc WHERE proname = 'aurora_version') > 0`
+ -- Aurora exposes aurora_version() and aurora_replica_status(), but
+ -- does not catalogue them in pg_proc on 18.3. to_regprocedure finds
+ -- them by signature without CALLING them, so no ERROR is written to
+ -- the server log and no rollback is booked in pg_stat_database.
+ to_regprocedure('aurora_version()') IS NOT NULL
+ OR to_regprocedure('aurora_replica_status()') IS NOT NULL`and the marker comment goes stale too: --- a/internal/conn/provider.go
+++ b/internal/conn/provider.go
@@ -30,1 +30,1 @@
- IsAurora bool // aurora_version() exists in pg_proc
+ IsAurora bool // aurora_version() or aurora_replica_status() is resolvableBoth predicates are true on 18.3. I built that locally and discovery gets past detection and on to host derivation. |
--all-instances refused to start against a real Aurora PostgreSQL 18.3
cluster connected through its writer endpoint:
pgbot: discover instances: not an Aurora cluster (aurora_version()
is missing) — --all-instances needs a native Aurora endpoint
Aurora 18.3 exposes aurora_version() and aurora_replica_status() but
catalogues neither in pg_proc, so the count(*) probe returned 0, IsAurora
stayed false, detectProvider fell through to rds, and AuroraInstances bailed
out before its query ever ran.
to_regprocedure resolves a function by signature without calling it, so it
finds them where pg_proc does not while keeping the property the original
probe was written for: no ERROR in the server log and no rollback booked in
pg_stat_database — the very counter pgbot reports. Verified on PostgreSQL
15.12, where the predicate returns false and xact_rollback is unchanged
across repeated runs, while SELECT aurora_version() raises an ERROR and
increments it.
Reported-by: paul-enz, who diagnosed this against Aurora PostgreSQL 18.3
and confirmed both predicates resolve there.
#55 landed the collation_version_mismatch finding and took SchemaVersion 1.3.0, which this branch was also claiming. Three files conflicted: - internal/model/schema_version.go — both bumped the const to 1.3.0. Keep main's 1.3.0 collation note and add a 1.4.0 note for instance/instance_role, which are omitted on a single-instance run, so a 1.3.0 consumer still parses 1.4.0 output. - schema/pgbot-context-1.3.0.json — add/add. Restored byte-identical to main's (the collation schema); this branch's additions now live in a new pgbot-context-1.4.0.json regenerated by tools/schemagen, so TestSchema_matchesModel stays green. - CHANGELOG.md — both added a first entry under Unreleased. Kept both, and noted the 1.4.0 bump on the --all-instances entry. The conflict also explained why CI never ran on 7e8a373: GitHub cannot build the merge ref for a conflicted PR, so no pull_request workflow was dispatched.
Implements #23 within its own constraints: SQL and DNS only, no AWS credentials, CLI, SDK, or API.
How it works
aurora_replica_status()lists the members; exactly one writer is expected, anything else is refused rather than mislabeled.<instance>.<cluster-id>.<region>.rds.amazonaws.com). Cluster, reader, custom, and instance endpoints all work as entry points; a custom domain is followed through its CNAME; RDS Proxy and non-RDS names are refused.aurora_db_instance_identifier()must confirm each derived endpoint reached the member it names before anything is collected.--all-databasesfan-out is generalized to (member, database) targets, so the two flags compose. Writer first, then readers, one member at a time. Cluster-wide findings dedupe per member.--jsoncarriesserver.instanceandserver.instance_role(contract 1.3.0, additive); SARIF/JUnit objects are prefixedinstance:<id>/; Prometheus series gaininstanceandrolelabels.Needs validation on a real cluster. I have no Aurora to run this against, so it is marked experimental and should not merge until someone with a cluster confirms it. @paul-enz, since you asked for this and validated the PgDog work so carefully, would you try it?
What I most want to know: whether every member was found and reached, whether the writer/reader roles are right, and, if derivation fails, the exact shape of your cluster endpoint (hostname with the ids redacted is fine). Also worth trying: the reader endpoint and an instance endpoint as the entry point, and the run through RDS Proxy, which should refuse cleanly.