ensure-postgres.sh 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #!/bin/bash
  2. # Ensures a local PostgreSQL server is available for the live integration
  3. # tests. Idempotent and safe to re-run.
  4. #
  5. # Layout (matches the goal plan):
  6. # data dir: /tmp/pgdata
  7. # socket dir: /tmp/pgrun
  8. # port: 5433
  9. # test role: postgres (the initdb superuser)
  10. # test db: sqltest (created if missing)
  11. #
  12. # Must run as root (uses `su postgres`); if not root we try without su
  13. # so the script still works in environments where we already are the
  14. # postgres user or own the server.
  15. set -u
  16. PGBIN="${PGBIN:-/usr/bin}"
  17. PGDATA="${PGDATA:-/tmp/pgdata}"
  18. PGSOCK="${PGSOCK:-/tmp/pgrun}"
  19. PGPORT="${PGPORT:-5433}"
  20. PGUSER_NAME="${PGUSER_NAME:-postgres}"
  21. PGDATABASE="${PGDATABASE:-sqltest}"
  22. PSQL="$PGBIN/psql"
  23. INITDB="$PGBIN/initdb"
  24. PG_CTL="$PGBIN/pg_ctl"
  25. PG_ISREADY="$PGBIN/pg_isready"
  26. run_as_pg() {
  27. # Run a command as the postgres user when we are root; otherwise
  28. # run it directly.
  29. if [ "$(id -u)" = "0" ]; then
  30. su "$PGUSER_NAME" -s /bin/bash -c "$*"
  31. else
  32. bash -c "$*"
  33. fi
  34. }
  35. # --- 1. Server binaries present? -----------------------------------------
  36. for bin in psql initdb pg_ctl; do
  37. if [ ! -x "$PGBIN/$bin" ]; then
  38. echo "ensure-postgres: $PGBIN/$bin not found — PostgreSQL server not installed" >&2
  39. exit 2
  40. fi
  41. done
  42. # --- 2. Data directory ----------------------------------------------------
  43. if [ ! -f "$PGDATA/PG_VERSION" ]; then
  44. echo "ensure-postgres: initialising data directory at $PGDATA"
  45. mkdir -p "$(dirname "$PGDATA")"
  46. mkdir -p "$PGDATA"
  47. chown "$PGUSER_NAME":"$PGUSER_NAME" "$PGDATA" 2>/dev/null || true
  48. chmod 700 "$PGDATA"
  49. if ! run_as_pg "$INITDB -D $PGDATA --auth=trust -E SQL_ASCII --locale=C" \
  50. > /tmp/ensure-postgres-initdb.log 2>&1; then
  51. echo "ensure-postgres: initdb failed:" >&2
  52. tail -20 /tmp/ensure-postgres-initdb.log >&2
  53. exit 3
  54. fi
  55. # trust auth for local + loopback so the test binary can connect as
  56. # the postgres role without a password from any local user.
  57. cat > "$PGDATA/pg_hba.conf" << 'HBA'
  58. local all all trust
  59. host all all 127.0.0.1/32 trust
  60. host all all ::1/128 trust
  61. local replication all trust
  62. host replication all 127.0.0.1/32 trust
  63. host replication all ::1/128 trust
  64. HBA
  65. chown "$PGUSER_NAME":"$PGUSER_NAME" "$PGDATA/pg_hba.conf" 2>/dev/null || true
  66. fi
  67. # --- 3. Server running? ----------------------------------------------------
  68. mkdir -p "$PGSOCK"
  69. chown "$PGUSER_NAME":"$PGUSER_NAME" "$PGSOCK" 2>/dev/null || true
  70. chmod 775 "$PGSOCK"
  71. if ! run_as_pg "$PG_ISREADY -h $PGSOCK -p $PGPORT -q"; then
  72. echo "ensure-postgres: starting server on socket $PGSOCK port $PGPORT"
  73. if ! run_as_pg "$PG_CTL -D $PGDATA -l /tmp/ensure-postgres.log -w -t 30 start -o '-k $PGSOCK -p $PGPORT'" \
  74. >> /tmp/ensure-postgres.log 2>&1; then
  75. echo "ensure-postgres: server failed to start:" >&2
  76. tail -20 /tmp/ensure-postgres.log >&2
  77. exit 4
  78. fi
  79. fi
  80. # --- 4. Test database ------------------------------------------------------
  81. # SQL is piped over stdin so no nested shell quoting (and no shared
  82. # temp files with permission races) are needed.
  83. CHECK_SQL="SELECT 1 FROM pg_database WHERE datname = '$PGDATABASE'"
  84. CREATE_SQL="CREATE DATABASE \"$PGDATABASE\""
  85. if ! printf '%s\n' "$CHECK_SQL" | run_as_pg "$PSQL -h $PGSOCK -p $PGPORT -U $PGUSER_NAME -d postgres -tA" | grep -q 1; then
  86. echo "ensure-postgres: creating database $PGDATABASE"
  87. printf '%s\n' "$CREATE_SQL" | run_as_pg "$PSQL -h $PGSOCK -p $PGPORT -U $PGUSER_NAME -d postgres" >/dev/null
  88. fi
  89. echo "ensure-postgres: server ready (socket $PGSOCK, port $PGPORT, db $PGDATABASE)"
  90. exit 0