← all writeups
A Terraform plan that looked like a no-op
One renamed resource and one missing moved block. The plan said 1 to destroy, and nobody read that line.
- Date
- 2024-10-29
- Type
- postmortem
- Severity
- SEV2
- Duration
- 2h 30m
- Impact
- Production DB parameter group recreated; 11 minutes of connection failures during the forced reboot.
PLACEHOLDER POST — seed data. Replace with your real writeup.
The PR was a tidy-up that renamed a few resources to match a naming convention. The
plan output was 400 lines long. The line that mattered was in the middle of it:
Plan: 1 to add, 0 to change, 1 to destroy.
Timeline
| Time | Event |
|---|---|
| 16:10 | PR approved, pipeline runs terraform apply |
| 16:12 | Parameter group destroyed and recreated with defaults |
| 16:14 | RDS instance rebooted to apply the new group |
| 16:25 | Connections recover, but max_connections is now the default |
| 17:30 | Pool exhaustion under evening load; correct values restored |
| 18:40 | Verified settings, incident closed |
The actual cause
Renaming a resource address without a moved block tells Terraform to delete the
old resource and create a new one. Code review looked at the diff, not the plan.
The pipeline applied automatically after approval.
moved {
from = aws_db_parameter_group.pg
to = aws_db_parameter_group.orders_primary
}
What changed
- A policy check fails the pipeline on any
deleteagainst a protected resource type - The plan summary (add/change/destroy) is posted to the PR as a comment
lifecycle { prevent_destroy = true }on stateful resources
← all writeups