68 lines
2.7 KiB
Bash
Executable file
68 lines
2.7 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# dbq -- run READ-ONLY SQL against any Thermograph Postgres (LAN dev / beta / prod).
|
|
#
|
|
# infra/ops/dbq.sh dev "select count(*) from climate_history"
|
|
# infra/ops/dbq.sh prod -tA "select max(date) from climate_history"
|
|
# infra/ops/dbq.sh beta -c '\dt'
|
|
# echo "select 1" | infra/ops/dbq.sh prod -f -
|
|
#
|
|
# Why exec-into-the-container instead of a connection string:
|
|
# none of the databases are exposed over TCP. Each listens only on its private
|
|
# docker network -- and prod's is a Swarm *overlay* (10.0.2.0/24) that the host
|
|
# itself cannot route to, so `ssh -L` works for beta but is impossible for prod.
|
|
# Publishing 5432 would mean new firewall + Swarm endpoint changes on production.
|
|
# Running psql *inside* the db container works identically in all three
|
|
# environments with no ports, no tunnels and no infra changes -- locally for LAN
|
|
# dev, over SSH for beta/prod.
|
|
#
|
|
# Safety: always connects as `thermograph_ro`, a NOSUPERUSER role granted only
|
|
# pg_read_all_data. Read-only is enforced by Postgres itself, not by convention,
|
|
# so a stray INSERT/DDL fails with "permission denied" even against prod. (The
|
|
# app's own `thermograph` role is a superuser -- deliberately not used here.)
|
|
#
|
|
# Any extra arguments are passed straight through to psql, so -tA, -c, -f, -x,
|
|
# --csv etc. all work. Stdin is forwarded, so `-f -` reads piped SQL.
|
|
set -euo pipefail
|
|
|
|
KEYFILE="${THERMOGRAPH_AGENT_KEY:-$HOME/.ssh/thermograph_agent_ed25519}"
|
|
DB_USER="${THERMOGRAPH_DB_QUERY_USER:-thermograph_ro}"
|
|
DB_NAME="${THERMOGRAPH_DB_NAME:-thermograph}"
|
|
|
|
usage() {
|
|
sed -n '2,9p' "$0" | sed 's/^# \{0,1\}//' >&2
|
|
echo "environments: dev | beta | prod" >&2
|
|
exit 2
|
|
}
|
|
|
|
env_name="${1:-}"
|
|
[ -n "$env_name" ] || usage
|
|
shift
|
|
|
|
case "$env_name" in
|
|
dev) filter=thermograph-dev-db ; ssh_target= ;;
|
|
beta) filter=thermograph-db-1 ; ssh_target=agent@75.119.132.91 ;;
|
|
prod) filter=thermograph_db ; ssh_target=agent@169.58.46.181 ;;
|
|
-h|--help) usage ;;
|
|
*) echo "dbq: unknown environment '$env_name' (want: dev|beta|prod)" >&2; exit 2 ;;
|
|
esac
|
|
|
|
[ $# -gt 0 ] || usage
|
|
|
|
# Quote the psql arguments so they survive the remote shell intact.
|
|
psql_args=$(printf '%q ' "$@")
|
|
|
|
# The container name is resolved on the target host at call time: prod's Swarm
|
|
# task name changes on every redeploy, so it can never be hardcoded.
|
|
remote=$(cat <<REMOTE
|
|
cid=\$(docker ps -qf name=${filter} | head -1)
|
|
[ -n "\$cid" ] || { echo "dbq: no running db container matching '${filter}'" >&2; exit 1; }
|
|
exec docker exec -i "\$cid" psql -U ${DB_USER} -d ${DB_NAME} -v ON_ERROR_STOP=1 ${psql_args}
|
|
REMOTE
|
|
)
|
|
|
|
if [ -z "$ssh_target" ]; then
|
|
exec bash -c "$remote"
|
|
else
|
|
exec ssh -i "$KEYFILE" -o StrictHostKeyChecking=no -o ConnectTimeout=15 \
|
|
"$ssh_target" "$remote"
|
|
fi
|