psql variables (:'gt_pass') are substituted client-side in the psql stream but NOT inside dollar-quoted DO $$..$$ bodies — those are sent to the server as literal text, causing syntax error. Replace DO block with \gexec pattern: quote_literal(:'gt_pass') builds the CREATE ROLE statement client-side, then \gexec executes it. WHERE NOT EXISTS makes both role and DB steps idempotent. Also connect to 'postgres' db (not app db) for CREATE DATABASE to work.
122 lines
5.2 KiB
Bash
122 lines
5.2 KiB
Bash
#!/usr/bin/env bash
|
||
# bootstrap_glitchtip.sh
|
||
# One-shot bootstrap for GlitchTip on the VPS.
|
||
#
|
||
# Run ONCE manually after merging feat/204-glitchtip-infra.
|
||
# Do NOT add to deploy.yml — this is idempotent setup, not a recurring step.
|
||
#
|
||
# Usage (on VPS via SSH):
|
||
# cd /opt/gendesign
|
||
# # Ensure GLITCHTIP_DB_PASS and GLITCHTIP_SECRET are set in .env
|
||
# bash scripts/bootstrap_glitchtip.sh
|
||
#
|
||
# After running:
|
||
# 1. docker compose -p gendesign -f docker-compose.prod.yml exec glitchtip-web ./manage.py createsuperuser
|
||
# 2. Log in to https://errors.gendsgn.ru → create org "gendesign"
|
||
# 3. Create projects: "backend", "frontend"
|
||
# 4. Copy DSNs → add to /opt/gendesign/backend/.env (GLITCHTIP_DSN)
|
||
# and /opt/gendesign/frontend/.env or .env.runtime (NEXT_PUBLIC_GLITCHTIP_DSN)
|
||
# 5. Recreate affected containers:
|
||
# docker compose -p gendesign -f docker-compose.prod.yml up -d --force-recreate --no-deps backend
|
||
|
||
set -euo pipefail
|
||
|
||
COMPOSE_FILE="docker-compose.prod.yml"
|
||
COMPOSE_PROJECT="gendesign"
|
||
COMPOSE="docker compose -p $COMPOSE_PROJECT -f $COMPOSE_FILE"
|
||
|
||
# ── Load .env.runtime for GLITCHTIP_DB_PASS / POSTGRES_* ──────────────────
|
||
if [ -f ".env" ]; then
|
||
set -a; source .env; set +a
|
||
fi
|
||
if [ -f "backend/.env.runtime" ]; then
|
||
set -a; source backend/.env.runtime; set +a
|
||
fi
|
||
|
||
: "${GLITCHTIP_DB_PASS:?GLITCHTIP_DB_PASS not set — add to .env or export}"
|
||
: "${POSTGRES_USER:?POSTGRES_USER not set}"
|
||
: "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD not set}"
|
||
: "${POSTGRES_DB:?POSTGRES_DB not set}"
|
||
|
||
echo "==> Ensuring postgres service is healthy..."
|
||
for i in $(seq 1 30); do
|
||
if $COMPOSE exec -T postgres pg_isready -U "$POSTGRES_USER" -q; then
|
||
break
|
||
fi
|
||
echo " Waiting for postgres... ($i/30)"
|
||
sleep 2
|
||
done
|
||
|
||
# ── Create glitchtip DB + user (idempotent) ────────────────────────────────
|
||
# psql var :'gt_pass' НЕ подставляется внутри DO $$..$$ — тело dollar-quote
|
||
# уходит на сервер as-is. Используем \gexec в psql-стриме client-side.
|
||
#
|
||
# \gexec builds SQL client-side via quote_literal(:'gt_pass'), then executes it.
|
||
# quote_literal escapes apostrophes and backslashes — no SQL injection possible.
|
||
# If WHERE NOT EXISTS filters the row, \gexec receives no input → no-op, no error.
|
||
# ON_ERROR_STOP=1 ensures \gexec-executed statements also cause psql to exit non-zero.
|
||
echo "==> Creating glitchtip database and user (idempotent)..."
|
||
$COMPOSE exec -T postgres \
|
||
psql -U "$POSTGRES_USER" -d postgres \
|
||
-v ON_ERROR_STOP=1 \
|
||
-v "gt_pass=$GLITCHTIP_DB_PASS" <<'SQL'
|
||
SELECT 'CREATE ROLE glitchtip LOGIN PASSWORD ' || quote_literal(:'gt_pass') || ';'
|
||
WHERE NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'glitchtip')
|
||
\gexec
|
||
|
||
SELECT 'CREATE DATABASE glitchtip OWNER glitchtip;'
|
||
WHERE NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = 'glitchtip')
|
||
\gexec
|
||
|
||
GRANT ALL PRIVILEGES ON DATABASE glitchtip TO glitchtip;
|
||
SQL
|
||
|
||
# ── Start GlitchTip containers ─────────────────────────────────────────────
|
||
# glitchtip-web and glitchtip-worker carry `profiles: ["glitchtip"]` in compose,
|
||
# so plain `up -d` skips them. Activate the profile explicitly here.
|
||
# After bootstrap succeeds, add COMPOSE_PROFILES=glitchtip to /opt/gendesign/.env
|
||
# so that future automatic deploys also bring these services up.
|
||
echo "==> Pulling glitchtip image..."
|
||
$COMPOSE --profile glitchtip pull glitchtip-web glitchtip-worker
|
||
|
||
echo "==> Starting glitchtip-web and glitchtip-worker..."
|
||
$COMPOSE --profile glitchtip up -d glitchtip-web glitchtip-worker
|
||
|
||
echo ""
|
||
echo "NOTE: Add the following line to /opt/gendesign/.env so future deploys"
|
||
echo " keep GlitchTip running:"
|
||
echo " COMPOSE_PROFILES=glitchtip"
|
||
|
||
# ── Wait for glitchtip-web to become healthy ───────────────────────────────
|
||
# Use wget (available in glitchtip image) matching the compose healthcheck probe.
|
||
echo "==> Waiting for glitchtip-web to become healthy (up to 60s)..."
|
||
for i in $(seq 1 30); do
|
||
if $COMPOSE exec -T glitchtip-web wget -q --spider http://localhost:8080/api/0/ >/dev/null 2>&1; then
|
||
echo " glitchtip-web is healthy."
|
||
break
|
||
fi
|
||
echo " Waiting... ($i/30)"
|
||
sleep 2
|
||
done
|
||
|
||
echo ""
|
||
echo "==> Bootstrap complete."
|
||
echo ""
|
||
echo "Next steps:"
|
||
echo " 1. Create superuser:"
|
||
echo " $COMPOSE exec glitchtip-web ./manage.py createsuperuser"
|
||
echo ""
|
||
echo " 2. Log in to https://errors.gendsgn.ru"
|
||
echo " - Create organization: gendesign"
|
||
echo " - Create project: backend (Platform: Python)"
|
||
echo " - Create project: frontend (Platform: JavaScript / Browser)"
|
||
echo ""
|
||
echo " 3. Copy DSNs from each project's Settings → DSN"
|
||
echo " - Add GLITCHTIP_DSN=<backend-dsn> to /opt/gendesign/backend/.env"
|
||
echo " - Add NEXT_PUBLIC_GLITCHTIP_DSN=<frontend-dsn> to /opt/gendesign/backend/.env or .env"
|
||
echo ""
|
||
echo " 4. Recreate services to pick up new DSNs:"
|
||
echo " $COMPOSE up -d --force-recreate --no-deps backend"
|
||
echo " $COMPOSE up -d --force-recreate --no-deps worker beat"
|
||
echo ""
|
||
echo " 5. Verify: trigger a test exception and confirm it appears in GlitchTip."
|