Skip to content

inspect --all-instances: every Aurora writer and reader behind one endpoint (experimental) - #38

Open
alexshapalov wants to merge 2 commits into
mainfrom
feat/aurora-all-instances
Open

alexshapalov wants to merge 2 commits into
mainfrom
feat/aurora-all-instances

Conversation

@alexshapalov

@alexshapalov alexshapalov commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

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.
  • Each instance endpoint is derived from the entry endpoint's DNS name (<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.
  • The --all-databases fan-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.
  • Output: text banners each target; --json carries server.instance and server.instance_role (contract 1.3.0, additive); SARIF/JUnit objects are prefixed instance:<id>/; Prometheus series gain instance and role labels.
  • Any member that can't be reached is reported as partial coverage and the run exits 3.

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?

git fetch origin pull/38/head:aurora && git checkout aurora && go build -o /tmp/pgbot ./cmd/pgbot

# 1. discovery + derivation + identity check, no collection
PGBOT_AURORA_TEST_DSN="$AURORA_CLUSTER_URL" go test ./internal/conn/ -run TestIntegration_auroraInstances -v

# 2. the real thing
/tmp/pgbot inspect "$AURORA_CLUSTER_URL" --all-instances
/tmp/pgbot inspect "$AURORA_CLUSTER_URL" --all-instances --all-databases --json | jq '.[] | .server | {instance, instance_role, database}'

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.

…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
@paul-enz

paul-enz commented Sep 9, 2026

Copy link
Copy Markdown

@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.

@paul-enz

Copy link
Copy Markdown

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 --all-instances refuses to start:

pgbot: discover instances: not an Aurora cluster (aurora_version() is missing) — --all-instances needs a native Aurora endpoint

It is a real Aurora cluster. The catalog probe in internal/conn/connect.go:249-253 is what misses it:

-- 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

On 18.3 that returns 0. There are no aurora% rows in pg_proc at all, even though the functions are there and return exactly what discovery wants:

select aurora_version();            -> 18.3.4
select server_id, session_id from aurora_replica_status();
  -> one writer row (MASTER_SESSION_ID) plus one reader row

With IsAurora false, detectProvider falls through to rds, so AuroraInstances bails out before it ever runs the query.

Swap the probe to to_regprocedure. It finds them where pg_proc does not, and resolves the signature instead of calling it, so nothing lands in the server log or in pg_stat_database:

--- 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 resolvable

Both predicates are true on 18.3. I built that locally and discovery gets past detection and on to host derivation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants