feat: per-stage PostgreSQL users for database isolation (stonks_beta, stonks_paper)
This commit is contained in:
@@ -15,6 +15,7 @@ config:
|
|||||||
POSTGRES_DB: "stonks_beta"
|
POSTGRES_DB: "stonks_beta"
|
||||||
REDIS_DB: "1"
|
REDIS_DB: "1"
|
||||||
DEPLOY_STAGE: "beta"
|
DEPLOY_STAGE: "beta"
|
||||||
|
POSTGRES_USER: "stonks_beta"
|
||||||
|
|
||||||
## All services pinned to 1 replica with lighter resource limits
|
## All services pinned to 1 replica with lighter resource limits
|
||||||
services:
|
services:
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ config:
|
|||||||
POSTGRES_DB: "stonks_paper"
|
POSTGRES_DB: "stonks_paper"
|
||||||
REDIS_DB: "2"
|
REDIS_DB: "2"
|
||||||
DEPLOY_STAGE: "paper"
|
DEPLOY_STAGE: "paper"
|
||||||
|
POSTGRES_USER: "stonks_paper"
|
||||||
|
|
||||||
## Secrets override: Alpaca paper trading API endpoint
|
## Secrets override: Alpaca paper trading API endpoint
|
||||||
secrets:
|
secrets:
|
||||||
|
|||||||
+46
-16
@@ -272,6 +272,12 @@ ALPACA_URL=$(cat /root/sources/celesrenata/stonks-oracle/alpaca.url 2>/dev/null
|
|||||||
POLYGON_KEY=$(cat /root/sources/celesrenata/stonks-oracle/polygon.io.key 2>/dev/null || echo "")
|
POLYGON_KEY=$(cat /root/sources/celesrenata/stonks-oracle/polygon.io.key 2>/dev/null || echo "")
|
||||||
|
|
||||||
for ns in stonks-beta stonks-paper stonks-oracle; do
|
for ns in stonks-beta stonks-paper stonks-oracle; do
|
||||||
|
# Determine the correct Postgres user for this namespace
|
||||||
|
case "$ns" in
|
||||||
|
stonks-beta) PG_USER="stonks_beta" ;;
|
||||||
|
stonks-paper) PG_USER="stonks_paper" ;;
|
||||||
|
*) PG_USER="stonks" ;;
|
||||||
|
esac
|
||||||
kubectl create secret generic stonks-core-secrets \
|
kubectl create secret generic stonks-core-secrets \
|
||||||
--from-literal=POSTGRES_PASSWORD='St0nks0racl3!' \
|
--from-literal=POSTGRES_PASSWORD='St0nks0racl3!' \
|
||||||
--from-literal=REDIS_PASSWORD="$REDIS_PW" \
|
--from-literal=REDIS_PASSWORD="$REDIS_PW" \
|
||||||
@@ -305,25 +311,47 @@ echo ""
|
|||||||
echo "--- Step 6d: Creating stage-isolated databases ---"
|
echo "--- Step 6d: Creating stage-isolated databases ---"
|
||||||
PG_POD=$(kubectl get pods -n postgresql-service -l cnpg.io/cluster=postgresql,role=primary -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "postgresql-1")
|
PG_POD=$(kubectl get pods -n postgresql-service -l cnpg.io/cluster=postgresql,role=primary -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "postgresql-1")
|
||||||
|
|
||||||
# Create databases (idempotent)
|
# Create databases and per-stage users (idempotent)
|
||||||
for db in stonks_beta stonks_paper; do
|
for pair in "stonks_beta:stonks_beta" "stonks_paper:stonks_paper"; do
|
||||||
kubectl exec -n postgresql-service "$PG_POD" -c postgres -- \
|
DB="${pair%%:*}"
|
||||||
psql -U postgres -tc "SELECT 1 FROM pg_database WHERE datname='$db'" | grep -q 1 || \
|
USER="${pair##*:}"
|
||||||
kubectl exec -n postgresql-service "$PG_POD" -c postgres -- \
|
kubectl exec -i -n postgresql-service "$PG_POD" -c postgres -- psql -U postgres << SQL
|
||||||
psql -U postgres -c "CREATE DATABASE $db OWNER stonks;"
|
DO \$\$ BEGIN
|
||||||
echo " ✓ Database $db exists"
|
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '$USER') THEN
|
||||||
|
CREATE USER $USER WITH PASSWORD 'St0nks0racl3!';
|
||||||
|
END IF;
|
||||||
|
END \$\$;
|
||||||
|
SELECT 'CREATE DATABASE $DB OWNER $USER' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname='$DB')\gexec
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE $DB TO $USER;
|
||||||
|
SQL
|
||||||
|
# Ensure schema permissions
|
||||||
|
kubectl exec -i -n postgresql-service "$PG_POD" -c postgres -- psql -U postgres -d "$DB" << SQL
|
||||||
|
GRANT ALL ON SCHEMA public TO $USER;
|
||||||
|
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO $USER;
|
||||||
|
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO $USER;
|
||||||
|
SQL
|
||||||
|
echo " ✓ Database $DB with user $USER"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Run migrations on all three databases (idempotent — IF NOT EXISTS in DDL)
|
# Live DB stays as 'stonks' user (already exists)
|
||||||
|
kubectl exec -i -n postgresql-service "$PG_POD" -c postgres -- \
|
||||||
|
psql -U postgres -tc "SELECT 1 FROM pg_database WHERE datname='stonks'" | grep -q 1 || \
|
||||||
|
kubectl exec -i -n postgresql-service "$PG_POD" -c postgres -- \
|
||||||
|
psql -U postgres -c "CREATE DATABASE stonks OWNER stonks;"
|
||||||
|
echo " ✓ Database stonks with user stonks"
|
||||||
|
|
||||||
|
# Run migrations on all three databases as their respective users
|
||||||
REPO_ROOT="${SCRIPT_DIR}/../stonks-oracle"
|
REPO_ROOT="${SCRIPT_DIR}/../stonks-oracle"
|
||||||
if [ -d "$REPO_ROOT/infra/migrations" ]; then
|
if [ -d "$REPO_ROOT/infra/migrations" ]; then
|
||||||
for db in stonks stonks_beta stonks_paper; do
|
for pair in "stonks:stonks" "stonks_beta:stonks_beta" "stonks_paper:stonks_paper"; do
|
||||||
echo " Running migrations on $db..."
|
DB="${pair%%:*}"
|
||||||
|
USER="${pair##*:}"
|
||||||
|
echo " Running migrations on $DB as $USER..."
|
||||||
for migration in $(ls "$REPO_ROOT/infra/migrations/"*.sql 2>/dev/null | sort); do
|
for migration in $(ls "$REPO_ROOT/infra/migrations/"*.sql 2>/dev/null | sort); do
|
||||||
kubectl exec -i -n postgresql-service "$PG_POD" -c postgres -- \
|
kubectl exec -i -n postgresql-service "$PG_POD" -c postgres -- \
|
||||||
psql -U postgres -d "$db" < "$migration" > /dev/null 2>&1 || true
|
psql -U "$USER" -d "$DB" < "$migration" > /dev/null 2>&1 || true
|
||||||
done
|
done
|
||||||
echo " ✓ Migrations applied to $db"
|
echo " ✓ Migrations applied to $DB"
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
echo " ⚠ Migrations directory not found at $REPO_ROOT/infra/migrations — skipping"
|
echo " ⚠ Migrations directory not found at $REPO_ROOT/infra/migrations — skipping"
|
||||||
@@ -331,12 +359,14 @@ fi
|
|||||||
|
|
||||||
# Seed symbol registry data on all three databases
|
# Seed symbol registry data on all three databases
|
||||||
if [ -d "$REPO_ROOT/services/symbol_registry" ]; then
|
if [ -d "$REPO_ROOT/services/symbol_registry" ]; then
|
||||||
for db in stonks stonks_beta stonks_paper; do
|
for pair in "stonks:stonks" "stonks_beta:stonks_beta" "stonks_paper:stonks_paper"; do
|
||||||
echo " Seeding $db..."
|
DB="${pair%%:*}"
|
||||||
|
USER="${pair##*:}"
|
||||||
|
echo " Seeding $DB..."
|
||||||
POSTGRES_HOST=postgresql-rw.postgresql-service.svc.cluster.local \
|
POSTGRES_HOST=postgresql-rw.postgresql-service.svc.cluster.local \
|
||||||
POSTGRES_PASSWORD='St0nks0racl3!' POSTGRES_USER=stonks POSTGRES_DB="$db" \
|
POSTGRES_PASSWORD='St0nks0racl3!' POSTGRES_USER="$USER" POSTGRES_DB="$DB" \
|
||||||
python3 -m services.symbol_registry.seed 2>/dev/null || true
|
python3 -m services.symbol_registry.seed 2>/dev/null || true
|
||||||
echo " ✓ Seed data applied to $db"
|
echo " ✓ Seed data applied to $DB"
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
Reference in New Issue
Block a user