- harness/paths.py: единая карта персистентных путей; SIMBIOT_HOME → db/ rag/ env/ docs/ digests/ audit/ inbox/ run/ voice/; без него — legacy-пути без изменений; точечные env (SIMBIOT_DB и пр.) сильнее схемы - es/tg_inbox/voice/portal_channel/aum/audit/runtime/rag_lookup/isolated_ runner/cli: все записи-чтения памяти через paths - scripts/init_instance.py: новый инстанс — чистая база + идентичность владельца + его доки (+RAG) + селективный импорт выжимок/доков - tests/test_instance_isolation.py: копия с пустой памятью не вспоминает наши проекты (контекст тика/RAG/прод — 14 проверок ALL PASS, регресс 7/7) - scripts/migrate_to_home.sh: перенос боевого инстанса в хом (тихое окно, идемпотентно, RAG-корпус коопа сохраняется точечным SIMBIOT_RAG_DB) - install.sh/service/README: свежие установки сразу с ~/.simbiot-data
140 lines
7.3 KiB
Bash
Executable file
140 lines
7.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
||
# ============================================================================
|
||
# Simbiot — перенос памяти инстанса из репо в SIMBIOT_HOME (t-261004113351).
|
||
#
|
||
# Репозиторий становится чистым кодом: ES-база, .env, ключи аудита, балансы,
|
||
# выжимки, штампы каналов переезжают в один каталог-хом (по умолчанию
|
||
# /var/lib/simbiot-harness). Идемпотентен: повторный запуск — SKIP уже
|
||
# перенесённого.
|
||
#
|
||
# БЕЗОПАСНОСТЬ: скрипт сам ждёт «тихого окна» (нет живых LLM-воркеров —
|
||
# паттерн scripts/safe-restart.sh), останавливает три сервиса харнеса,
|
||
# переносит файлы, добавляет SIMBIOT_HOME в systemd-юниты и обёртки,
|
||
# поднимает сервисы и проверяет здоровье. Откат: см. конец файла.
|
||
#
|
||
# scripts/migrate_to_home.sh [HOME] # по умолчанию /var/lib/simbiot-harness
|
||
# ============================================================================
|
||
set -u
|
||
REPO="$(cd "$(dirname "$(readlink -f "$0")")/.." && pwd)"
|
||
HOME_DIR="${1:-/var/lib/simbiot-harness}"
|
||
SERVICES="simbiot-harness.service simbiot-harness-tg.service simbiot-dashboard.service"
|
||
LOG="${SIMBIOT_MIGRATION_LOG:-/tmp/simbiot-migrate-to-home.log}"
|
||
MAX_WAIT="${SIMBIOT_MIGRATION_WAIT:-1800}"
|
||
PAT='/harness/_llm_worker\.py$'
|
||
|
||
log() { echo "[$(date -u '+%F %T')] $*" >> "$LOG"; echo "$*"; }
|
||
|
||
# ── 0) тихое окно: мигрировать можно только когда ни один тик не пишет в БД ─
|
||
deadline=$(( $(date +%s) + MAX_WAIT ))
|
||
while :; do
|
||
if ! pgrep -f "$PAT" > /dev/null; then
|
||
sleep 3
|
||
if ! pgrep -f "$PAT" > /dev/null; then
|
||
log "тихое окно поймано — начинаю миграцию в $HOME_DIR"
|
||
break
|
||
fi
|
||
fi
|
||
if [ "$(date +%s)" -ge "$deadline" ]; then
|
||
log "тихого окна нет ${MAX_WAIT}s — отмена (повторить позже)"
|
||
exit 0
|
||
fi
|
||
sleep 10
|
||
done
|
||
|
||
# ── 1) структура хома (audit НЕ создаём: туда переедет каталог целиком) ─────
|
||
mkdir -p "$HOME_DIR"/{db,env,inbox,digests,run,voice,docs/aum}
|
||
log "home создан: $HOME_DIR"
|
||
|
||
moved() { # mv если источник есть и цель отсутствует
|
||
[ -e "$1" ] || { [ -L "$1" ] && rm -f "$1"; return 0; }
|
||
if [ -e "$2" ]; then log "SKIP (цель есть): $2"; return 0; fi
|
||
mkdir -p "$(dirname "$2")"
|
||
mv "$1" "$2" && log "moved: $1 → $2"
|
||
}
|
||
|
||
copied() { # cp если источник есть (переносить нельзя: git-трекается)
|
||
[ -e "$1" ] || return 0
|
||
if [ -e "$2" ]; then log "SKIP (цель есть): $2"; return 0; fi
|
||
mkdir -p "$(dirname "$2")"
|
||
cp -a "$1" "$2" && log "copied: $1 → $2"
|
||
}
|
||
|
||
# ── 2) стоп сервисов (писателей больше нет — mv БД с WAL безопасен) ─────────
|
||
systemctl stop $SERVICES
|
||
log "сервисы остановлены: $SERVICES"
|
||
|
||
# ── 3) перенос памяти ───────────────────────────────────────────────────────
|
||
moved "$REPO/harness/harness.db" "$HOME_DIR/db/harness.db"
|
||
moved "$REPO/harness/harness.db-wal" "$HOME_DIR/db/harness.db-wal"
|
||
moved "$REPO/harness/harness.db-shm" "$HOME_DIR/db/harness.db-shm"
|
||
moved "$REPO/.env" "$HOME_DIR/env/.env"
|
||
moved "$REPO/.audit" "$HOME_DIR/audit" # ключи ed25519
|
||
copied "$REPO/docs/aum/balances.json" "$HOME_DIR/docs/aum/balances.json"
|
||
copied "$REPO/out" "$HOME_DIR/digests/out" # выжимки-файлы
|
||
copied "$REPO/portal/inbox/.channel-last" "$HOME_DIR/inbox/.channel-last"
|
||
for f in "$REPO"/harness/channel_*.json; do
|
||
[ -e "$f" ] && { cp -a "$f" "$HOME_DIR/run/" && log "copied: $f"; }
|
||
done
|
||
[ -f "$HOME_DIR/env/.env" ] && chmod 600 "$HOME_DIR/env/.env"
|
||
|
||
# ── 4) SIMBIOT_HOME в юнитах и обёртках ─────────────────────────────────────
|
||
# RAG-корпус кооператива (/root/rag/rag.db) — общая инфраструктура хоста,
|
||
# его индексируют и другие инструменты (board hook): основному инстансу
|
||
# оставляем точечное переопределение, иначе SIMBIOT_HOME уведёт поиск на
|
||
# пустой <home>/rag/rag.db (t-261004113351).
|
||
RAG_KEEP=""
|
||
if [ -e /root/rag/rag.db ]; then
|
||
RAG_KEEP="/root/rag/rag.db"
|
||
fi
|
||
for svc in $SERVICES; do
|
||
f="/etc/systemd/system/$svc"
|
||
[ -f "$f" ] || continue
|
||
if ! grep -q "^Environment=SIMBIOT_HOME=" "$f"; then
|
||
sed -i "/^\[Service\]/a Environment=SIMBIOT_HOME=$HOME_DIR" "$f"
|
||
log "юнит обновлён: $f (+SIMBIOT_HOME)"
|
||
fi
|
||
if [ -n "$RAG_KEEP" ] && ! grep -q "^Environment=SIMBIOT_RAG_DB=" "$f"; then
|
||
sed -i "/^Environment=SIMBIOT_HOME=/a Environment=SIMBIOT_RAG_DB=$RAG_KEEP" "$f"
|
||
log "юнит обновлён: $f (+SIMBIOT_RAG_DB=$RAG_KEEP)"
|
||
fi
|
||
done
|
||
systemctl daemon-reload
|
||
|
||
for w in "$REPO/bin/simbiot" /root/.local/bin/simbiot; do
|
||
[ -f "$w" ] || continue
|
||
if ! grep -q "SIMBIOT_HOME" "$w"; then
|
||
sed -i "3a export SIMBIOT_HOME=\"\${SIMBIOT_HOME:-$HOME_DIR}\"" "$w"
|
||
log "обёртка обновлена: $w"
|
||
fi
|
||
done
|
||
|
||
# ── 5) подъём и проверка здоровья ───────────────────────────────────────────
|
||
systemctl start simbiot-harness.service simbiot-harness-tg.service simbiot-dashboard.service
|
||
sleep 8
|
||
health="FAIL"
|
||
if systemctl is-active --quiet simbiot-harness.service \
|
||
&& [ -s "$HOME_DIR/db/harness.db" ] \
|
||
&& ! ls "$REPO/harness/harness.db" >/dev/null 2>&1; then
|
||
health="OK"
|
||
fi
|
||
log "health: $health (db: $(du -h "$HOME_DIR/db/harness.db" 2>/dev/null | cut -f1))"
|
||
|
||
# контрольный прогон CLI из хома (не должен пересоздавать репо-базу)
|
||
SIMBIOT_HOME="$HOME_DIR" "$REPO/venv/bin/python" "$REPO/cli.py" status >/dev/null 2>&1 \
|
||
&& log "cli status: OK" || log "cli status: FAIL"
|
||
[ -e "$REPO/harness/harness.db" ] && log "ВНИМАНИЕ: репо-база пересоздана чем-то!"
|
||
|
||
# отчёт + идемпотентное уведомление (не curl — защита от дублей в cli.py)
|
||
cat > "$HOME_DIR/migration-report.json" <<EOF
|
||
{"task": "t-261004113351-2858c1", "home": "$HOME_DIR",
|
||
"health": "$health", "ts": "$(date -u '+%F %T')"}
|
||
EOF
|
||
SIMBIOT_HOME="$HOME_DIR" "$REPO/venv/bin/python" "$REPO/cli.py" tg-notify \
|
||
"📦 Память харнеса изолирована в $HOME_DIR (репо = чистый код). Здоровье: $health" \
|
||
-k t-261004113351-migrated 2>/dev/null || true
|
||
|
||
log "миграция завершена: $health"
|
||
# ОТКАТ (если что-то не так): systemctl stop $SERVICES;
|
||
# mv "$HOME_DIR"/db/harness.db* "$REPO/harness/"; mv "$HOME_DIR/env/.env" "$REPO/.env";
|
||
# убрать Environment=SIMBIOT_HOME из юнитов; systemctl daemon-reload; start
|
||
exit 0
|