--- Build: pass | Tests: pass — 51 passed (3 files) --- Build: pass | Tests: pass — 2189 passed (648 files)
180 lines
8 KiB
Bash
Executable file
180 lines
8 KiB
Bash
Executable file
#!/bin/sh
|
|
# setup-db-jail.sh — create the ai_brain PostgreSQL jail
|
|
#
|
|
# Usage: sudo sh docs/internal/scripts/setup-db-jail.sh
|
|
#
|
|
# Reads .env from the project root. Idempotent — safe to re-run.
|
|
# Requires bastille and a bootstrapped FreeBSD release (bastille bootstrap).
|
|
#
|
|
# What it does:
|
|
# 1. Create a thick bastille jail at WARDEN_DB_IP
|
|
# 2. Install postgresql18-server + postgresql18-pgvector inside
|
|
# 3. Configure PostgreSQL to accept connections from the host subnet
|
|
# 4. Create the ai_brain database, user, extensions
|
|
# 5. Apply schema migrations from docs/internal/sql/
|
|
# 6. Enable jail on boot via sysrc
|
|
|
|
set -e
|
|
|
|
# ── Locate project root ───────────────────────────────────────────────────────
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
cd "${PROJECT_ROOT}"
|
|
|
|
# ── Read .env ─────────────────────────────────────────────────────────────────
|
|
|
|
env_get() {
|
|
local key="$1" default="$2"
|
|
local val
|
|
val=$(grep -m1 "^${key}=" .env 2>/dev/null | cut -d= -f2- | sed "s/^['\"]//;s/['\"]$//")
|
|
printf '%s' "${val:-$default}"
|
|
}
|
|
|
|
TENANT_ID=$(env_get TENANT_ID "$(env_get AGENT_NAME clawdie)")
|
|
SUBNET_BASE=$(env_get AGENT_SUBNET_BASE "$(env_get JAIL_SUBNET_BASE "$(env_get WARDEN_SUBNET_BASE 10.0.0)")")
|
|
DB_IP=$(env_get WARDEN_DB_IP "$(env_get DB_JAIL_IP "${SUBNET_BASE}.3")")
|
|
JAIL=$(env_get DB_JAIL_NAME "${TENANT_ID}-db")
|
|
DB_NAME=$(env_get MEMORY_DB_NAME "${TENANT_ID}_brain")
|
|
DB_USER=$(env_get MEMORY_DB_USER "${TENANT_ID}_brain")
|
|
DB_PASS=$(env_get MEMORY_DB_PASSWORD "")
|
|
FREEBSD_REL=$(freebsd-version -u | cut -d- -f1,2)
|
|
PGDATA="/var/db/postgres/data"
|
|
JAIL_ROOT="/usr/local/bastille/jails/${JAIL}/root"
|
|
SUBNET="${SUBNET_BASE}.0/24"
|
|
|
|
# ── Validate ──────────────────────────────────────────────────────────────────
|
|
|
|
if [ -z "${DB_PASS}" ]; then
|
|
echo "ERROR: MEMORY_DB_PASSWORD not set in .env" >&2
|
|
echo " Add it: echo 'MEMORY_DB_PASSWORD=changeme' >> .env" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "==> DB jail setup"
|
|
echo " Jail: ${JAIL} @ ${DB_IP}"
|
|
echo " Release: ${FREEBSD_REL}"
|
|
echo " DB: ${DB_NAME} / user: ${DB_USER}"
|
|
echo ""
|
|
|
|
# ── 1. Create jail ────────────────────────────────────────────────────────────
|
|
|
|
if bastille list 2>/dev/null | grep -qw "${JAIL}"; then
|
|
echo "==> Jail ${JAIL} already exists — skipping creation"
|
|
else
|
|
echo "==> Creating jail ${JAIL}"
|
|
bastille create "${JAIL}" "${FREEBSD_REL}" "${DB_IP}"
|
|
fi
|
|
|
|
# PostgreSQL requires System V IPC (shmget). Bastille does not add this
|
|
# automatically — it must be in jail.conf or postgres will fail with:
|
|
# FATAL: could not create shared memory segment: Function not implemented
|
|
JAIL_CONF="/usr/local/bastille/jails/${JAIL}/jail.conf"
|
|
if ! grep -q "allow.sysvipc" "${JAIL_CONF}" 2>/dev/null; then
|
|
echo "==> Adding allow.sysvipc to jail.conf"
|
|
sed -i '' 's/^}/ allow.sysvipc = 1;\n}/' "${JAIL_CONF}"
|
|
bastille restart "${JAIL}"
|
|
fi
|
|
|
|
# ── 2. Install packages ───────────────────────────────────────────────────────
|
|
|
|
echo "==> Installing postgresql18-server postgresql18-contrib postgresql18-pgvector"
|
|
bastille pkg "${JAIL}" install -y postgresql18-server postgresql18-contrib postgresql18-pgvector
|
|
|
|
# ── 3. Init PostgreSQL ────────────────────────────────────────────────────────
|
|
|
|
# Note: postgres uid is 770 in pkgbase jails (not 70 from older packages).
|
|
# If restoring data from an older jail, run:
|
|
# chown -R 770:770 ${JAIL_ROOT}${PGDATA}
|
|
bastille sysrc "${JAIL}" postgresql_enable=YES
|
|
bastille sysrc "${JAIL}" postgresql_data="${PGDATA}"
|
|
|
|
if bastille cmd "${JAIL}" test -f "${PGDATA}/PG_VERSION" 2>/dev/null; then
|
|
echo "==> PostgreSQL already initialized — skipping initdb"
|
|
else
|
|
echo "==> Initializing PostgreSQL data directory"
|
|
bastille service "${JAIL}" postgresql initdb
|
|
fi
|
|
|
|
# ── 4. Configure PostgreSQL ───────────────────────────────────────────────────
|
|
|
|
echo "==> Configuring postgresql.conf and pg_hba.conf"
|
|
|
|
PG_CONF="${JAIL_ROOT}${PGDATA}/postgresql.conf"
|
|
HBA_CONF="${JAIL_ROOT}${PGDATA}/pg_hba.conf"
|
|
|
|
# Allow external connections (append wins over commented defaults)
|
|
if ! grep -qE "^listen_addresses\s*=" "${PG_CONF}"; then
|
|
echo "listen_addresses = '*'" >> "${PG_CONF}"
|
|
fi
|
|
|
|
# Allow all users/databases from the host subnet (covers ai_brain + future CMS DB)
|
|
if ! grep -q "^host.*all.*${SUBNET}" "${HBA_CONF}"; then
|
|
printf "host\tall\tall\t%s\tscram-sha-256\n" "${SUBNET}" >> "${HBA_CONF}"
|
|
fi
|
|
|
|
# ── 5. Start PostgreSQL ───────────────────────────────────────────────────────
|
|
|
|
echo "==> Starting PostgreSQL"
|
|
if bastille service "${JAIL}" postgresql status 2>/dev/null | grep -q running; then
|
|
bastille service "${JAIL}" postgresql reload
|
|
else
|
|
bastille service "${JAIL}" postgresql start
|
|
fi
|
|
|
|
# ── 6. Create user and database ───────────────────────────────────────────────
|
|
|
|
echo "==> Creating user '${DB_USER}' and database '${DB_NAME}'"
|
|
|
|
bastille cmd "${JAIL}" su -l postgres -c "
|
|
psql -tc \"SELECT 1 FROM pg_roles WHERE rolname='${DB_USER}'\" | grep -q 1 ||
|
|
psql -c \"CREATE USER ${DB_USER} WITH PASSWORD '${DB_PASS}' LOGIN\"
|
|
"
|
|
|
|
bastille cmd "${JAIL}" su -l postgres -c "
|
|
psql -tc \"SELECT 1 FROM pg_database WHERE datname='${DB_NAME}'\" | grep -q 1 ||
|
|
psql -c \"CREATE DATABASE ${DB_NAME} OWNER ${DB_USER}\"
|
|
"
|
|
|
|
# ── 7. Extensions and schema ──────────────────────────────────────────────────
|
|
|
|
echo "==> Installing extensions (pgcrypto, vector)"
|
|
bastille cmd "${JAIL}" su -l postgres -c "
|
|
psql -d ${DB_NAME} -c \"
|
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
CREATE EXTENSION IF NOT EXISTS vector;
|
|
\"
|
|
"
|
|
|
|
echo "==> Applying schema migrations"
|
|
SQL_TMP="${JAIL_ROOT}/tmp/clawdie-sql"
|
|
mkdir -p "${SQL_TMP}"
|
|
cp docs/internal/sql/ai-brain-base.sql "${SQL_TMP}/"
|
|
cp docs/internal/sql/clawdie-brain-hybrid-upgrade.sql "${SQL_TMP}/"
|
|
cp docs/internal/sql/search-memories.sql "${SQL_TMP}/"
|
|
cp docs/internal/sql/permissions.sql "${SQL_TMP}/"
|
|
|
|
bastille cmd "${JAIL}" su -l postgres -c "
|
|
psql -d ${DB_NAME} -f /tmp/clawdie-sql/ai-brain-base.sql &&
|
|
psql -d ${DB_NAME} -f /tmp/clawdie-sql/clawdie-brain-hybrid-upgrade.sql &&
|
|
psql -d ${DB_NAME} -f /tmp/clawdie-sql/search-memories.sql &&
|
|
psql -v db_user=${DB_USER} -d ${DB_NAME} -f /tmp/clawdie-sql/permissions.sql
|
|
"
|
|
|
|
rm -rf "${SQL_TMP}"
|
|
|
|
# ── 8. Enable on boot ─────────────────────────────────────────────────────────
|
|
|
|
echo "==> Enabling jail on boot"
|
|
sysrc jail_list+="${JAIL}"
|
|
|
|
# ── Done ──────────────────────────────────────────────────────────────────────
|
|
|
|
echo ""
|
|
echo "==> Done."
|
|
echo ""
|
|
echo " Add to .env if not already present:"
|
|
echo " WARDEN_DB_IP=${DB_IP}"
|
|
echo " MEMORY_DB_URL=postgresql://${DB_USER}:${DB_PASS}@${DB_IP}:5432/${DB_NAME}"
|
|
echo ""
|
|
echo " Verify: bastille cmd ${JAIL} su -l postgres -c 'psql -d ${DB_NAME} -c \"\\dt\"'"
|