Skip to content

fix(postgres-migration): expose the instance id and region as outputs, make the seed re-runnable - #98

Merged
sishuo-yang merged 1 commit into
mainfrom
sishuo-yang/fix-postgres-migration-instance-lookup
Aug 19, 2026
Merged

sishuo-yang merged 1 commit into
mainfrom
sishuo-yang/fix-postgres-migration-instance-lookup

Conversation

@sishuo-yang

@sishuo-yang sishuo-yang commented Aug 19, 2026 •

Copy link
Copy Markdown
Collaborator

Two lab-code fixes for the Postgres migration workshop, both found by running module 01 end to end on a live RDS stack. The playbook half ships in WorkshopHouse#60.

1. The RDS instance id and region as outputs

The playbook recovered the generated DB instance identifier by filtering describe-db-instances on the endpoint address:

export RDS_INSTANCE_ID="$(aws rds describe-db-instances \
  --query "DBInstances[?Endpoint.Address=='${RDS_HOST}'].DBInstanceIdentifier | [0]" --output text)"

A learner hit this and got:

None
aws: [ERROR]: An error occurred (DBInstanceNotFound) when calling the RebootDBInstance
operation: DBInstance not found: none

| [0] over an empty match is JSON null, which --output text renders as the literal string None. export X="$(...)" swallows the exit code, so the next two commands ran against garbage and the error named RDS instead of the lookup.

Three unrelated conditions collapse to that same None, confirmed by evaluating the expression directly:

Condition Result
RDS_HOST matches an instance the identifier
RDS_HOST empty None
RDS_HOST carries the :5432 suffix None
region contains no instances None

The last is the one that fires in practice. Terraform takes its region from region in terraform.tfvars; the AWS CLI takes its own from AWS_REGION, AWS_DEFAULT_REGION or the profile, and inherits nothing from Terraform. Aimed at the wrong region the CLI does not error -- it reports an account with no such instance in it. The reporting learner had a profile on us-east-1 against a stack in us-east-2.

identifier_prefix means the identifier cannot be written down in advance, but it is still a known attribute of the resource. The playbook's premise -- that generated therefore means unavailable -- was the actual defect. Two new outputs make it exact, with no API call and nothing to mismatch:

  • rds_instance_id -- aws_db_instance.shop.identifier, for reboot-db-instance and module 03's CloudWatch dimension
  • region -- var.region, so the playbook can export AWS_REGION from the applied stack and every raw aws call in modules 01, 03 and 06 lands in the right region

2. The seed is re-runnable

A seed that died partway could not be restarted: the second run re-inserted products, hit sku's unique constraint and aborted, so recovering meant manual cleanup before the file would run at all -- and nothing in the file hinted at that. This is not hypothetical; it is what a killed seed leaves you with.

Each INSERT now carries a count guard against its own target. Each table is loaded by one statement, so a table is either empty of seed rows or complete and there is no partially-seeded state for the guard to misjudge. The orders and order_items guards compare against the target rather than testing for emptiness, because app/writer.py inserts into both and would otherwise make them look finished while the seed rows are still missing.

Verified in four states:

State Result
Fresh load 500 / 100 / 2000 / 8000
Re-run, fully seeded INSERT 0 0 x4
order_items lost, rest intact reloads only order_items
Writer rows present guards correctly skip

Against the live already-seeded RDS instance, a re-run reports four INSERT 0 0 and takes 20 seconds.

3. Two file-header examples

sql/01_schema.sql and sql/02_seed.sql both showed psql -h "$PGHOST" -U postgres -d shop. Neither is right for this lab: PGHOST is never exported, and the master user is shopadmin, so a reader who pasted either got a connection to localhost or a role that does not exist.

Note for reviewers

The outputs need a terraform apply to take effect. Outputs are only written to state by apply, so an existing stack reports Output "region" not found until it runs. It is a no-op for infrastructure -- 0 added, 0 changed, 0 destroyed -- but it is not optional.

Verification

  • terraform fmt -check and terraform validate pass
  • terraform apply against a live stack from this lab: No changes, 0 added, 0 changed, 0 destroyed, both new outputs present
  • seed guards exercised in the four states above, on both a local Postgres 17 and the live RDS instance
  • the two lab copies (private authoring repo and this one) diff clean apart from the expected .gitignore, README.md and the private scripts/manifest.sh

🤖 Generated with Claude Code

…puts

The playbook recovered the generated DB instance identifier by filtering
`aws rds describe-db-instances` on the endpoint address. That lookup has no
error path: `| [0]` over an empty match is JSON null, which `--output text`
renders as the literal string `None`, so `reboot-db-instance` then failed with
`DBInstance not found: none` and pointed at RDS rather than at the lookup.

Three unrelated conditions collapsed to that same `None` -- an empty RDS_HOST,
an endpoint that does not match, and a region containing no instances. The last
is the common one, because Terraform reads its region from terraform.tfvars and
the AWS CLI reads its own from AWS_REGION, AWS_DEFAULT_REGION or the profile,
and inherits nothing from Terraform. Aimed at the wrong region the CLI does not
error; it reports an account with no such instance in it.

`identifier_prefix` means the identifier cannot be written down in advance, but
it is still a known attribute of the resource, so an output is exact and needs
no API call. Add `rds_instance_id` and `region`, which lets the playbook export
both from state and removes the failure class rather than guarding it.

Also correct two file-header examples that invoked psql as `-h "$PGHOST" -U
postgres`. Neither is right for this lab: PGHOST is never exported, and the
master user is shopadmin, so a reader who pasted either got a connection to
localhost or a role that does not exist.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sishuo-yang
sishuo-yang merged commit 778185e into main Aug 19, 2026
2 checks passed
@sishuo-yang sishuo-yang changed the title fix(postgres-migration): expose the RDS instance id and region as outputs fix(postgres-migration): expose the instance id and region as outputs, make the seed re-runnable Aug 19, 2026
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.

1 participant