#!/bin/bash # deploy-rag-credentials.sh — деплой кредов RAG-service в CT 105 # Секреты из Vaultwarden (объект RAG_SERVICE). Атомарная запись .env. # # Использование: # /root/scripts/deploy-rag-credentials.sh # /root/scripts/deploy-rag-credentials.sh --dry-run # # Ротация: сменил RAG_API_KEY в Vaultwarden → запустил скрипт → docker compose up -d --force-recreate # # Требования: bw, jq, /root/.bw-master (chmod 600) # Vaultwarden: создать запись RAG_SERVICE с полем RAG_API_KEY (тип hidden). set -e CT_ID=105 RAG_PATH="/home/rag-service" BW_MASTER_FILE="${BW_MASTER_PASSWORD_FILE:-/root/.bw-master}" DRY_RUN=false for arg in "$@"; do case "$arg" in --dry-run) DRY_RUN=true ;; esac done export PATH="/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PATH}" log() { echo "[$(date -Iseconds)] $*"; } err() { echo "[$(date -Iseconds)] ERROR: $*" >&2; } ensure_bw_unlocked() { local status status=$(bw status 2>/dev/null | jq -r '.status' 2>/dev/null || echo "unknown") if [ "$status" = "unlocked" ]; then log "bw already unlocked, reusing session" return 0 fi if [ ! -f "$BW_MASTER_FILE" ]; then err "Missing $BW_MASTER_FILE" exit 1 fi export BW_SESSION=$(bw unlock --passwordfile "$BW_MASTER_FILE" --raw 2>/dev/null) || { err "bw unlock failed" exit 1 } log "bw unlocked" } get_secrets() { local item item=$(bw get item "RAG_SERVICE" 2>/dev/null) || { err "RAG_SERVICE not found in Vaultwarden. Create it: type Login, add custom field RAG_API_KEY (hidden)." exit 1 } RAG_API_KEY=$(echo "$item" | jq -r '.fields[] | select(.name=="RAG_API_KEY") | .value // empty') if [ -z "$RAG_API_KEY" ]; then err "RAG_SERVICE: missing RAG_API_KEY field" exit 1 fi } gen_env() { local tmp tmp=$(mktemp) cat > "$tmp" << EOF # RAG Service Configuration (generated from Vaultwarden) # Модель RAG_MODEL=sentence-transformers/all-MiniLM-L12-v2 RAG_CACHE_DIR=data/models # VectorStore RAG_VECTORS_PATH=data/vectors/vectors.npz RAG_MAX_EXAMPLES=10000 RAG_SCORE_MULTIPLIER=5.0 # Батч-обработка RAG_BATCH_SIZE=16 # Минимальная длина текста RAG_MIN_TEXT_LENGTH=3 # API настройки RAG_API_HOST=0.0.0.0 RAG_API_PORT=8000 # Безопасность RAG_API_KEY=${RAG_API_KEY} RAG_ALLOW_NO_AUTH=false # Автосохранение векторов RAG_AUTOSAVE_INTERVAL=600 # Логирование LOG_LEVEL=INFO EOF echo "$tmp" } push_env_atomic() { local tmp="$1" < "$tmp" pct exec "$CT_ID" -- bash -c "cat > ${RAG_PATH}/.env.tmp && chmod 600 ${RAG_PATH}/.env.tmp && mv ${RAG_PATH}/.env.tmp ${RAG_PATH}/.env" log ".env written (atomic), chmod 600" } run_compose() { pct exec "$CT_ID" -- bash -c "cd ${RAG_PATH} && docker compose up -d --force-recreate" log "RAG-service started" } main() { log "deploy-rag-credentials start (dry_run=$DRY_RUN)" ensure_bw_unlocked get_secrets if [ "$DRY_RUN" = true ]; then log "DRY-RUN: would push .env and run compose" log " RAG_API_KEY=***" exit 0 fi tmp=$(gen_env) trap "rm -f $tmp" EXIT push_env_atomic "$tmp" run_compose log "done" } main