litellm/migrations/run.py
Yassin Kortam 014cb8fa9d
feat: add componentized proxy deployment with gateway, backend, ui, and migrations (#27557)
Split the monolithic LiteLLM proxy into independently scalable Kubernetes components to allow separate horizontal scaling of the LLM data plane and management API surfaces

- Add DatabaseURLSettings pydantic-settings model that assembles DATABASE_URL (and optional DATABASE_URL_READ_REPLICA) from discrete DATABASE_* env vars before Prisma initializes, supporting both IAM token auth (minting short-lived RDS tokens) and password auth; replaces the CLI-only path that componentized entrypoints bypass
- Add gateway component (port 4000) that trims the proxy route table to the LLM data-plane surface (chat, embeddings, completions, audio, realtime, provider passthroughs, health/metrics) via an allowlist applied inside the lifespan context so plugin-registered routes are captured
- Add backend component (port 4001) that exposes the management/admin surface (keys, users, teams, orgs, spend analytics, model management, SSO, audit logs) with a complementary allowlist
- Add ui component — Next.js static export served by nginx (port 3000) with RSC payload routing, asset prefix aliasing, and SPA fallback for dashboard routes
- Add migrations component with dedicated Dockerfile that runs prisma migrate deploy via a Helm pre-install/pre-upgrade Job, eliminating per-pod schema contention on the Prisma advisory lock
- Add Helm chart (helm/litellm) with separate Deployments, Services, HPAs, and ConfigMap for each component; shared _helpers.tpl emits DATABASE_*, IAM_TOKEN_DB_AUTH, REDIS_*, and DISABLE_SCHEMA_UPDATE env vars from chart values; ingress template routes traffic to the correct component by path prefix
- Add comprehensive tests for DatabaseURLSettings covering IAM auth, password auth, read replica fallbacks, operator-pinned URL preservation, and percent-encoding; add coverage test asserting gateway + backend allowlist union equals the full proxy route set
- Add pydantic-settings>=2.14.1 as a proxy extra dependency and update liccheck allowlist

Co-authored-by: Yassin Kortam <yassinkortam@g.ucla.edu>
2026-05-16 09:25:17 -07:00

68 lines
2.7 KiB
Python

"""Entrypoint for the migrations Job container.
Runs `prisma migrate deploy` against the LiteLLM writer database using the
recovery logic in `litellm_proxy_extras.ProxyExtrasDBManager.setup_database`
(P3005 baseline + P3009/P3018 idempotent-error handling, retries, etc.).
Env vars:
DATABASE_URL required unless it can be assembled at
startup from the discrete DATABASE_* vars
(password auth) or minted from an IAM token
(`IAM_TOKEN_DB_AUTH=true`)
DIRECT_URL optional — used by `migrate diff` when the
primary URL is a pooler (e.g. Neon -pooler)
USE_V2_MIGRATION_RESOLVER "false" → fall back to the v1 resolver
(legacy diff-and-force recovery). Defaults
to "true": the v2 resolver avoids the schema
thrashing seen during rolling deploys when
two LiteLLM versions contend for the same DB.
USE_PRISMA_DB_PUSH "true" → use `prisma db push` instead of
`migrate deploy`. Default false.
"""
import os
import sys
from litellm.proxy.db.db_url_settings import DatabaseURLSettings
from litellm_proxy_extras._logging import logger
from litellm_proxy_extras.utils import ProxyExtrasDBManager, str_to_bool
def main() -> int:
# Assemble DATABASE_URL from the discrete DATABASE_* env vars, matching
# the gateway/backend startup path (IAM mint or password auth). Leaves an
# operator-pinned DATABASE_URL untouched.
DatabaseURLSettings.from_env().apply_to_env()
if not os.getenv("DATABASE_URL"):
logger.error(
"DATABASE_URL is not set and could not be assembled from the "
"DATABASE_* env vars — cannot run migrations."
)
return 1
# v2 is the safer default for componentized deploys: it skips the
# diff-and-force recovery from v1 that caused schema thrashing during
# rolling deploys. Set USE_V2_MIGRATION_RESOLVER=false to opt back into v1.
use_v2 = str_to_bool(os.getenv("USE_V2_MIGRATION_RESOLVER", "true"))
use_db_push = str_to_bool(os.getenv("USE_PRISMA_DB_PUSH"))
logger.info(
"Starting prisma migration job (use_migrate=%s, use_v2_resolver=%s)",
not use_db_push,
use_v2,
)
ok = ProxyExtrasDBManager.setup_database(
use_migrate=not use_db_push,
use_v2_resolver=use_v2,
)
if not ok:
logger.error("Migration job failed after retries.")
return 1
logger.info("Migration job completed successfully.")
return 0
if __name__ == "__main__":
sys.exit(main())