Files
LLM-Server/scripts/update.sh
T
haylan 7e8b5069d4 fix(scripts): update.sh never applied litellm-pgvector's db schema
litellm-pgvector's Dockerfile only runs 'prisma generate' (codegen) at
build time — nothing ever ran 'prisma db push' against pgvector-db, so the
vector_stores/embeddings tables plain didn't exist on a fresh deploy. Every
vector store call failed with 'relation "vector_stores" does not exist'.

update.sh now runs the push itself after bringing litellm-pgvector up.
2026-09-02 21:32:33 +00:00

121 lines
4.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# The one command to run after any change to this repo (compose file,
# litellm-config.yaml, .env, or a git pull) to bring the running stack in
# sync. Ensures secrets/keys exist, pulls, validates, rebuilds/re-pulls
# images, and recreates only what changed — safe to run any time, including
# with nothing to do.
#
# ponytail: no rollback/backup logic — this is a single-user homelab box,
# not a fleet. If a bad config lands, `git revert` + re-run is the recovery
# path, not this script.
set -euo pipefail
cd "$(dirname "$0")/.."
[ -f .env ] || cp .env.example .env
# Handles all three cases: the KEY=value line is missing entirely (.env
# predates that var being added to .env.example — sed can't fix what isn't
# there, so this appends it), present but blank, or already set.
set_if_blank() {
local key="$1" value="$2"
if grep -qE "^${key}=.*[^[:space:]]" .env; then
echo "${key}: already set, skipping."
elif grep -qE "^${key}=" .env; then
sed -i "s|^${key}=.*|${key}=${value}|" .env
echo "${key}: set."
else
echo "${key}=${value}" >> .env
echo "${key}: added (was missing from .env)."
fi
}
echo "==> filling in missing secrets"
# Random values — safe to re-run, never overwrites what's already set.
# LITELLM_SALT_KEY especially: never change it after first run, existing
# encrypted data becomes unreadable if you do.
set_if_blank LITELLM_MASTER_KEY "$(openssl rand -hex 32)"
set_if_blank LITELLM_SALT_KEY "$(openssl rand -hex 32)"
set_if_blank LITELLM_DB_PASSWORD "$(openssl rand -hex 32)"
set_if_blank REDIS_PASSWORD "$(openssl rand -hex 32)"
set_if_blank UI_PASSWORD "$(openssl rand -hex 16)"
set_if_blank PGVECTOR_DB_PASSWORD "$(openssl rand -hex 32)"
set_if_blank LITELLM_PGVECTOR_API_KEY "$(openssl rand -hex 32)"
echo "==> resolving SEARXNG_LAN_IP"
# search.home is a LAN mDNS/local-DNS name — resolvable from this host, just
# not from inside the litellm container (see docs/research/litellm-searxng-search.md).
searxng_ip="$(getent hosts search.home 2>/dev/null | awk '{print $1}' | head -1)"
if [ -n "$searxng_ip" ]; then
set_if_blank SEARXNG_LAN_IP "$searxng_ip"
else
echo "SEARXNG_LAN_IP: couldn't resolve search.home from this host, set it manually if still blank."
fi
echo "==> git pull"
git pull --ff-only
echo "==> validating compose config"
docker compose config -q
echo "==> pulling images"
docker compose pull --ignore-buildable
echo "==> rebuilding local-build services"
docker compose build --pull
echo "==> ensuring models are downloaded (skips already-present files)"
docker compose --profile tools run --rm downloader
docker compose --profile tools run --rm downloader-embedding
echo "==> bringing up litellm (needed to mint virtual keys below)"
docker compose up -d --wait litellm-db litellm
# OPENWEBUI_LITELLM_KEY / LITELLM_PGVECTOR_EMBEDDING_KEY are per-workload
# virtual keys, not random secrets — minted via LiteLLM's own API
# (docs/proxy-key-onboarding.md documents the manual Admin UI route; this is
# the same thing over the REST endpoint LITELLM_MASTER_KEY already
# authenticates against).
set -a && . ./.env && set +a
mint_key_if_blank() {
local key="$1" alias="$2"
if grep -qE "^${key}=.*[^[:space:]]" .env; then
echo "${key}: already set, skipping."
return
fi
local minted
minted=$(curl -sf -X POST "http://localhost:${LITELLM_PORT:-4000}/key/generate" \
-H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
-H "Content-Type: application/json" \
-d "{\"key_alias\": \"${alias}\"}" | jq -r '.key')
if [ -n "$minted" ] && [ "$minted" != "null" ]; then
# Same missing-line-vs-blank-line handling as set_if_blank above.
if grep -qE "^${key}=" .env; then
sed -i "s|^${key}=.*|${key}=${minted}|" .env
else
echo "${key}=${minted}" >> .env
fi
echo "${key}: minted."
else
echo "${key}: mint failed, create it by hand per docs/proxy-key-onboarding.md."
fi
}
mint_key_if_blank OPENWEBUI_LITELLM_KEY openwebui
mint_key_if_blank LITELLM_PGVECTOR_EMBEDDING_KEY litellm-pgvector
set -a && . ./.env && set +a
echo "==> recreating changed services"
docker compose up -d --remove-orphans
# litellm-pgvector's Dockerfile only runs `prisma generate` (codegen) at
# build time — nothing ever applied the schema to pgvector-db itself, so the
# vector_stores/embeddings tables plain didn't exist until this was added
# (see issue #24). --accept-data-loss is the same "no rollback/backup logic,
# git revert is the recovery path" tradeoff as the rest of this script — a
# schema-incompatible change here would need a manual look regardless.
echo "==> syncing litellm-pgvector's database schema"
docker compose up -d --wait pgvector-db litellm-pgvector
docker compose exec -T litellm-pgvector prisma db push --accept-data-loss
echo "==> status"
docker compose ps