Skip to content

fix(scripts): complete teardowns and truthful update aborts (NEH-214, NEH-215) - #287

Merged
juancobo merged 2 commits into
devfrom
scripts/neh-214-215-truthful-teardown
Aug 3, 2026
Merged

fix(scripts): complete teardowns and truthful update aborts (NEH-214, NEH-215)#287
juancobo merged 2 commits into
devfrom
scripts/neh-214-215-truthful-teardown

Conversation

@juancobo

@juancobo juancobo commented Aug 3, 2026

Copy link
Copy Markdown
Member

Fixes the two urgent bugs from the 2026-08-03 Rionegro production incident.

What happened

update.sh's pre-stop up -d db recreated the db container under the live stack; network removal wedged on an orphaned container from a service dropped between releases (dtk-docs-1); the db was left stopped and detached from its published port while the abort path printed "nothing changed". Compose exits 0 on that partial teardown (reproduced locally), so set -e never fires — the failure is invisible to the script and to the operator.

Changes

  • --remove-orphans on every compose down (update.sh, stop.sh, rollback-update.sh, setup.sh, the restore path) and on start.sh's boot-time up, so containers from services dropped between releases can never hold the project network hostage.
  • update.sh step 5 no longer mutates the running stack: it probes container state first and only runs up -d --no-recreate db when db is not already running. The full recreate happens post-stop, from a clean slate.
  • update.sh step 6 tears down explicitly after systemctl stop dtk — systemd only runs ExecStop for an active unit — and a new assert_stack_gone verifies no project containers or the network survive, aborting loudly if they do (this is what catches the exit-0 partial teardown). Same assertion after the post-migration down.
  • New STACK_TOUCHED tracking: "nothing changed" now prints only when container state is genuinely untouched. Otherwise the abort reports the service state, per-container states, whether 127.0.0.1:5432 is listening on the host, and the recovery command.
  • generate-secrets.sh's rotation path gets the same gating (no recreate from the boot-time oneshot; never stops a db it did not start).
  • check-stack-health.sh now also requires the db's published port to be listening on the host (ss, no connection made; skipped if ss is absent) — the incident's exact signature was a container reporting healthy while nothing listened on the host.

Validation

  • bash -n clean on all seven scripts.
  • Local Docker simulation: reproduced the wedge with a scratch project (orphaned service survives a bare down, network removal fails "Resource is still in use", exit code 0); down --remove-orphans clears container and network; the project-name derivation used by assert_stack_gone works on compose v5.3.0.
  • Profile-gated services (dev backend) are NOT treated as orphans — verified a running profile-gated container survives down --remove-orphans, so this cannot destroy a developer's backend container.
  • Pending hardware validation on the bench unit at Friday's bench test: plant an orphan, run the update end-to-end (bench checklist updated separately).

Linear: NEH-214, NEH-215 (GitHub mirrors #283, #284).

… NEH-215)

The 2026-08-03 Rionegro outage: update.sh's pre-stop `up -d db` recreated
the db container under the live stack, network removal wedged on an
orphaned container from a service dropped between releases (dtk-docs-1),
and the abort path then printed "nothing changed" while the database sat
stopped and detached. Compose exits 0 on that partial teardown, so set -e
never fires.

- add --remove-orphans to every compose down (update, stop, rollback,
  setup, restore path) and to start.sh's boot-time up
- update.sh step 5 no longer mutates the running stack: probe first, and
  only `up -d --no-recreate db` when db is not already running
- update.sh step 6 tears down explicitly after `systemctl stop dtk`
  (ExecStop only runs for an active unit) and asserts nothing from the
  compose project survives before proceeding; same assertion after the
  post-migration down
- new STACK_TOUCHED tracking: the "nothing changed" abort message now
  prints only when container state was genuinely untouched; otherwise the
  abort reports service/container/port state and a recovery command
- generate-secrets.sh rotation path gets the same gating (no recreate,
  no stopping a db it did not start)
- check-stack-health.sh also requires the db's published port to be
  listening on the host (ss), catching the healthy-but-detached state
Copilot AI review requested due to automatic review settings August 3, 2026 20:05
@linear-code

linear-code Bot commented Aug 3, 2026

Copy link
Copy Markdown

NEH-214

NEH-215

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves update and teardown reliability following the Rionegro production incident.

Changes:

  • Removes orphaned containers during lifecycle operations.
  • Verifies update teardowns and reports actual abort state.
  • Adds safer database startup gating and host-port health checks.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
scripts/update.sh Adds teardown assertions and state-aware recovery reporting.
scripts/stop.sh Removes orphaned containers during shutdown.
scripts/start.sh Removes orphans during startup reconciliation.
scripts/setup.sh Cleans up orphans during setup teardown paths.
scripts/rollback-update.sh Cleans up orphans during rollback operations.
scripts/generate-secrets.sh Avoids unnecessary database recreation and shutdown.
scripts/check-stack-health.sh Checks for a host-side database listener.

Comment on lines +154 to +159
DB_WAS_RUNNING=0
if [ -n "$($COMPOSE ps --services --status running 2>/dev/null | grep -x db || true)" ]; then
DB_WAS_RUNNING=1
else
$COMPOSE up -d --no-recreate db >/dev/null
fi
Comment thread scripts/update.sh
Comment on lines +364 to +365
STACK_TOUCHED=1
$COMPOSE up -d --no-recreate db
…-clear text

generate-secrets.sh: a compose ps failure no longer reads as "db not
running" (which could have stopped a db the script did not start); the
oneshot now fails loudly instead, blocking dtk.service as designed.

update.sh: the db-timeout and empty-dump aborts no longer claim the
appliance was not touched — the EXIT trap now owns that call and reports
the actual state.
@juancobo
juancobo requested a review from Copilot August 3, 2026 20:10
@juancobo
juancobo merged commit c210ccb into dev Aug 3, 2026
1 check passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Suppressed comments (3)

scripts/update.sh:193

  • If docker ps cannot query the daemon, || true converts that failure into an empty container list. If the subsequent network inspection also returns nonzero, this function reports success even though it verified nothing, defeating the fail-loud teardown assertion. Treat an inspection failure as an incomplete teardown.
    leftovers="$(docker ps -aq --filter "label=com.docker.compose.project=$project" 2>/dev/null || true)"

scripts/generate-secrets.sh:166

  • When this branch starts the database, a later ALTER USER failure exits immediately because of set -e, before the conditional stop at lines 183–185. The script therefore leaves a previously stopped database running; handle the ALTER failure explicitly and stop only the container started here before exiting.
        $COMPOSE up -d --no-recreate db >/dev/null

scripts/check-stack-health.sh:102

  • When ss is unavailable, db_port_listening intentionally returns success without checking the port, but this message still claims the host listener was verified. Report that the port check was skipped so startup diagnostics remain truthful.
        echo "✓ Stack healthy: db healthy and listening on the host, frontend running${NGINX_NOTE}."

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