Some checks failed
deploy / Build prerendered web (push) Successful in 6m59s
deploy / Build api + worker (static musl) (push) Failing after 11m22s
deploy / Deploy web to oolon (push) Successful in 28s
deploy / Deploy moments-api to nikola (push) Has been skipped
deploy / Deploy moments-worker to frootmig (push) Has been skipped
refresh / Rebuild prerendered web (push) Successful in 6m49s
refresh / Deploy refreshed web to oolon (push) Successful in 19s
Write the cert_cn -> role mappings to pg_ident.conf.d/moments.conf instead of per-host <cert_cn>.conf files, so provisioning for other apps that own drop-ins for the same hosts can never clobber or drop moments access. db-perms.sh now also migrates any moments_ro/rw lines found in legacy host-named files into moments.conf verbatim (deleting legacy files left empty), corrects the standby hostname to frankie.hanzalova.internal, and warns-and-continues on an unreachable pg host instead of aborting the run. Closes #3 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dcsi987fK5ftZEP6w3HXEd
106 lines
3.7 KiB
Bash
Executable File
106 lines
3.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Idempotently maintain the moments cert_cn → role mappings in an app-owned
|
|
# pg_ident.conf.d/moments.conf on the moments postgres primary and standby,
|
|
# then reload postgres so the changes take effect. Re-running is a no-op
|
|
# (no duplicate lines, no spurious reload).
|
|
#
|
|
# The file is named for the app, not the cert_cn host, so provisioning for
|
|
# other apps (which may own files for the same hosts) can never clobber or
|
|
# interleave with moments access. Any moments_* lines found in legacy
|
|
# host-named files are migrated here and removed from the legacy file.
|
|
#
|
|
# Run from a workstation with ssh access to both pg hosts. This script ssh's
|
|
# out; do NOT run it on magrathea/frankie directly.
|
|
|
|
set -euo pipefail
|
|
|
|
api_host=nikola.kosherinata.internal
|
|
worker_host=frootmig.kosherinata.internal
|
|
|
|
pg_hosts=(
|
|
magrathea.kosherinata.internal
|
|
frankie.hanzalova.internal
|
|
)
|
|
|
|
# Each (cert_cn host, role) pair becomes one cert_cn line in
|
|
# pg_ident.conf.d/moments.conf on every pg host listed above.
|
|
mapping_pairs=(
|
|
"$api_host" moments_ro
|
|
"$worker_host" moments_rw
|
|
)
|
|
|
|
ident_dir=/var/lib/pgsql/18/data/pg_ident.conf.d
|
|
app_file=moments.conf
|
|
|
|
failed=0
|
|
for pg_host in "${pg_hosts[@]}"; do
|
|
printf '==> %s\n' "$pg_host"
|
|
if ! ssh -o BatchMode=yes -o ConnectTimeout=5 "$pg_host" \
|
|
"sudo bash -s -- ${ident_dir@Q} ${app_file@Q} ${mapping_pairs[@]@Q}" <<'REMOTE_EOF'
|
|
set -euo pipefail
|
|
ident_dir="$1"; shift
|
|
file="${ident_dir}/$1"; shift
|
|
|
|
changed=0
|
|
|
|
# Migrate any moments_* lines out of legacy host-named files into the
|
|
# app-owned file, so other apps' provisioning (which may own files for the
|
|
# same hosts) can never clobber or drop moments access. Lines are preserved
|
|
# verbatim (this covers mappings beyond mapping_pairs, e.g. a workstation's).
|
|
# A legacy file left empty is removed.
|
|
moments_re='^cert_cn[[:space:]]+[^[:space:]]+[[:space:]]+moments_(ro|rw)[[:space:]]*$'
|
|
for legacy in "$ident_dir"/*.conf; do
|
|
[[ "$legacy" == "$file" ]] && continue
|
|
grep --extended-regexp --quiet "$moments_re" "$legacy" || continue
|
|
while read -r line; do
|
|
if [[ -f "$file" ]] && grep --fixed-strings --line-regexp --quiet -- "$line" "$file"; then
|
|
printf ' already in %s, dropping from %s: %s\n' "${file##*/}" "${legacy##*/}" "$line"
|
|
else
|
|
printf '%s\n' "$line" | sudo -u postgres tee --append "$file" >/dev/null
|
|
printf ' migrated from %s: %s\n' "${legacy##*/}" "$line"
|
|
fi
|
|
done < <(grep --extended-regexp "$moments_re" "$legacy")
|
|
remaining="$(grep --extended-regexp --invert-match "$moments_re" "$legacy" || true)"
|
|
if [[ -n "$remaining" ]]; then
|
|
printf '%s\n' "$remaining" | sudo -u postgres tee "$legacy" >/dev/null
|
|
else
|
|
rm "$legacy"
|
|
printf ' removed empty legacy file %s\n' "${legacy##*/}"
|
|
fi
|
|
changed=1
|
|
done
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
cert_cn_host="$1"
|
|
role="$2"
|
|
shift 2
|
|
|
|
line="cert_cn ${cert_cn_host} ${role}"
|
|
|
|
# The heredoc runs as root via sudo bash, so [[ -f ]] and grep are fine
|
|
# without dropping privs. tee --append runs as postgres so a newly-created
|
|
# file lands with the conventional postgres:postgres ownership.
|
|
if [[ -f "$file" ]] && grep --fixed-strings --line-regexp --quiet -- "$line" "$file"; then
|
|
printf ' present: %s\n' "$line"
|
|
else
|
|
printf '%s\n' "$line" | sudo -u postgres tee --append "$file" >/dev/null
|
|
printf ' added: %s\n' "$line"
|
|
changed=1
|
|
fi
|
|
done
|
|
|
|
if (( changed )); then
|
|
systemctl reload postgresql-18
|
|
echo " reloaded postgresql-18"
|
|
else
|
|
echo " no changes; reload skipped"
|
|
fi
|
|
REMOTE_EOF
|
|
then
|
|
echo " WARNING: ${pg_host} unreachable or failed — re-run when it is back"
|
|
failed=1
|
|
fi
|
|
done
|
|
exit "$failed"
|