139 lines
6.4 KiB
Bash
139 lines
6.4 KiB
Bash
#!/bin/bash
|
|
# Docker entrypoint: initialize DB tables, then start the app.
|
|
# Order matters:
|
|
# 1. create_all - creates all tables using SQLAlchemy models (idempotent)
|
|
# 2. alembic stamp head - tells alembic we are at the latest revision (skips migrations)
|
|
# For existing installs that may have missing columns, safe ALTER TABLE patches run first.
|
|
# 3. uvicorn - starts the FastAPI app
|
|
|
|
set -e
|
|
|
|
# --- Added: Permission fixing and privilege dropping ---
|
|
if [ "$(id -u)" = '0' ]; then
|
|
echo "[entrypoint] Detected root user, fixing permissions..."
|
|
# Ensure directories exist and are owned by clawith
|
|
chown -R clawith:clawith ${AGENT_DATA_DIR}
|
|
|
|
echo "[entrypoint] Dropping privileges to 'clawith' and re-executing..."
|
|
exec gosu clawith /bin/bash "$0" "$@"
|
|
fi
|
|
# -------------------------------------------------------
|
|
|
|
echo "[entrypoint] Step 1: Creating/verifying database tables..."
|
|
|
|
python << 'PYEOF'
|
|
import asyncio, sys
|
|
|
|
async def main():
|
|
# Import all models to populate Base.metadata before create_all
|
|
from app.database import Base, engine
|
|
import app.models.user # noqa
|
|
import app.models.agent # noqa
|
|
import app.models.task # noqa
|
|
import app.models.llm # noqa
|
|
import app.models.tool # noqa
|
|
import app.models.audit # noqa
|
|
import app.models.skill # noqa
|
|
import app.models.channel_config # noqa
|
|
import app.models.schedule # noqa
|
|
import app.models.plaza # noqa
|
|
import app.models.activity_log # noqa
|
|
import app.models.org # noqa
|
|
import app.models.system_settings # noqa
|
|
import app.models.invitation_code # noqa
|
|
import app.models.tenant # noqa
|
|
import app.models.participant # noqa
|
|
import app.models.chat_session # noqa
|
|
import app.models.trigger # noqa
|
|
import app.models.notification # noqa
|
|
import app.models.gateway_message # noqa
|
|
|
|
# Create all tables that don't exist yet (safe to run on every startup)
|
|
async with engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.create_all)
|
|
print("[entrypoint] Tables created/verified")
|
|
|
|
# Apply safe column patches for existing installs that may be missing columns.
|
|
# All statements use IF NOT EXISTS so they are fully idempotent.
|
|
patches = [
|
|
# Quota fields added in v0.2
|
|
"ALTER TABLE users ADD COLUMN IF NOT EXISTS quota_message_limit INTEGER DEFAULT 50",
|
|
"ALTER TABLE users ADD COLUMN IF NOT EXISTS quota_message_period VARCHAR(20) DEFAULT 'permanent'",
|
|
"ALTER TABLE users ADD COLUMN IF NOT EXISTS quota_messages_used INTEGER DEFAULT 0",
|
|
"ALTER TABLE users ADD COLUMN IF NOT EXISTS quota_period_start TIMESTAMPTZ",
|
|
"ALTER TABLE users ADD COLUMN IF NOT EXISTS quota_max_agents INTEGER DEFAULT 2",
|
|
"ALTER TABLE users ADD COLUMN IF NOT EXISTS quota_agent_ttl_hours INTEGER DEFAULT 48",
|
|
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS expires_at TIMESTAMPTZ",
|
|
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS is_expired BOOLEAN DEFAULT FALSE",
|
|
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS llm_calls_today INTEGER DEFAULT 0",
|
|
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS max_llm_calls_per_day INTEGER DEFAULT 100",
|
|
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS llm_calls_reset_at TIMESTAMPTZ",
|
|
# agent_tools source tracking added later
|
|
"ALTER TABLE agent_tools ADD COLUMN IF NOT EXISTS source VARCHAR(20) NOT NULL DEFAULT 'system'",
|
|
"ALTER TABLE agent_tools ADD COLUMN IF NOT EXISTS installed_by_agent_id UUID",
|
|
# chat_sessions channel tracking
|
|
"ALTER TABLE chat_sessions ADD COLUMN IF NOT EXISTS source_channel VARCHAR(20) NOT NULL DEFAULT 'web'",
|
|
# Token reset tracking
|
|
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS last_daily_reset TIMESTAMPTZ",
|
|
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS last_monthly_reset TIMESTAMPTZ",
|
|
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS tokens_used_total INTEGER DEFAULT 0",
|
|
# OpenClaw Agent support
|
|
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS agent_type VARCHAR(20) NOT NULL DEFAULT 'native'",
|
|
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS api_key_hash VARCHAR(128)",
|
|
"ALTER TABLE agents ADD COLUMN IF NOT EXISTS openclaw_last_seen TIMESTAMPTZ",
|
|
# SSO fields
|
|
"ALTER TABLE tenants ADD COLUMN IF NOT EXISTS sso_enabled BOOLEAN DEFAULT FALSE",
|
|
"ALTER TABLE tenants ADD COLUMN IF NOT EXISTS sso_domain VARCHAR(255)",
|
|
"CREATE UNIQUE INDEX IF NOT EXISTS ux_tenants_sso_domain ON tenants(sso_domain) WHERE sso_domain IS NOT NULL",
|
|
]
|
|
|
|
from sqlalchemy import text
|
|
async with engine.begin() as conn:
|
|
for sql in patches:
|
|
try:
|
|
await conn.execute(text(sql))
|
|
except Exception as e:
|
|
print(f"[entrypoint] Patch skipped ({e})")
|
|
|
|
await engine.dispose()
|
|
print("[entrypoint] Column patches applied")
|
|
|
|
asyncio.run(main())
|
|
PYEOF
|
|
|
|
echo "[entrypoint] Step 2: Running alembic migrations..."
|
|
# Run all migrations to ensure database schema is up to date.
|
|
# Capture exit code explicitly — do NOT let a migration failure go unnoticed.
|
|
set +e
|
|
ALEMBIC_OUTPUT=$(alembic upgrade head 2>&1)
|
|
ALEMBIC_EXIT=$?
|
|
set -e
|
|
|
|
if [ $ALEMBIC_EXIT -ne 0 ]; then
|
|
echo ""
|
|
echo "========================================================================"
|
|
echo "[entrypoint] WARNING: Alembic migration FAILED (exit code $ALEMBIC_EXIT)"
|
|
echo "========================================================================"
|
|
echo ""
|
|
echo "$ALEMBIC_OUTPUT"
|
|
echo ""
|
|
echo "------------------------------------------------------------------------"
|
|
echo " The database schema may be INCOMPLETE. Some features will NOT work."
|
|
echo " Common causes:"
|
|
echo " - Migration cycle detected (pull latest code to fix)"
|
|
echo " - Database connection issue"
|
|
echo " - Incompatible migration state"
|
|
echo ""
|
|
echo " To fix: pull the latest code and restart the backend."
|
|
echo " Docker: git pull && docker compose restart backend"
|
|
echo " Source: git pull && alembic upgrade head"
|
|
echo "------------------------------------------------------------------------"
|
|
echo ""
|
|
echo "[entrypoint] Continuing startup despite migration failure..."
|
|
else
|
|
echo "[entrypoint] Alembic migrations completed successfully."
|
|
fi
|
|
|
|
echo "[entrypoint] Step 3: Starting uvicorn..."
|
|
exec uvicorn app.main:app --host 0.0.0.0 --port 8000
|