178 lines
6.0 KiB
Bash
Executable File
178 lines
6.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# dump_project.sh — собирает всё нужное для аудита проекта в один файл
|
||
# Запуск: sudo bash dump_project.sh
|
||
# Результат: /root/morozovka_dump_YYYY-MM-DD_HH-MM.txt
|
||
|
||
set -uo pipefail
|
||
|
||
PROJECT_DIR="/opt/morozovka-portal"
|
||
OUT="/root/morozovka_dump_$(date +%F_%H-%M).txt"
|
||
MAX_FILE_SIZE=$((512 * 1024)) # файлы больше 512 КБ пропускаем (обычно мусор)
|
||
|
||
# ----- исключения -----
|
||
EXCLUDES=(
|
||
"*/venv/*"
|
||
"*/__pycache__/*"
|
||
"*.pyc"
|
||
"*/.git/*"
|
||
"*/node_modules/*"
|
||
"*.log"
|
||
"*.sqlite"
|
||
"*.db"
|
||
"google_credentials.json" # СЕКРЕТ — не включаем
|
||
"*.png" "*.jpg" "*.jpeg" "*.gif" "*.ico" "*.pdf" "*.zip" "*.tar" "*.gz" "*.woff" "*.woff2" "*.ttf"
|
||
)
|
||
|
||
should_skip() {
|
||
local f="$1"
|
||
for pat in "${EXCLUDES[@]}"; do
|
||
# shellcheck disable=SC2053
|
||
[[ "$f" == $pat ]] && return 0
|
||
done
|
||
return 1
|
||
}
|
||
|
||
section() {
|
||
echo "" >> "$OUT"
|
||
echo "================================================================================" >> "$OUT"
|
||
echo "== $*" >> "$OUT"
|
||
echo "================================================================================" >> "$OUT"
|
||
}
|
||
|
||
dump_file() {
|
||
local f="$1"
|
||
[[ -f "$f" ]] || { echo "[skip: not a file] $f" >> "$OUT"; return; }
|
||
local size
|
||
size=$(stat -c%s "$f" 2>/dev/null || echo 0)
|
||
if (( size > MAX_FILE_SIZE )); then
|
||
echo "" >> "$OUT"
|
||
echo "---- FILE: $f (SKIPPED, size=${size}B > ${MAX_FILE_SIZE}B) ----" >> "$OUT"
|
||
return
|
||
fi
|
||
echo "" >> "$OUT"
|
||
echo "---- FILE: $f (size=${size}B) ----" >> "$OUT"
|
||
cat "$f" >> "$OUT"
|
||
echo "" >> "$OUT"
|
||
echo "---- END: $f ----" >> "$OUT"
|
||
}
|
||
|
||
# ----- начинаем -----
|
||
: > "$OUT"
|
||
echo "DUMP GENERATED: $(date -Is)" >> "$OUT"
|
||
echo "HOSTNAME: $(hostname -f 2>/dev/null || hostname)" >> "$OUT"
|
||
echo "UPTIME: $(uptime -p 2>/dev/null || uptime)" >> "$OUT"
|
||
|
||
# 1) Дерево файлов проекта
|
||
section "TREE: $PROJECT_DIR"
|
||
if command -v tree >/dev/null 2>&1; then
|
||
tree -a -I 'venv|__pycache__|.git|node_modules' -L 4 "$PROJECT_DIR" >> "$OUT" 2>&1
|
||
else
|
||
find "$PROJECT_DIR" \
|
||
\( -path '*/venv' -o -path '*/__pycache__' -o -path '*/.git' -o -path '*/node_modules' \) -prune -o \
|
||
-type f -print | sort >> "$OUT"
|
||
fi
|
||
|
||
# 2) requirements.txt + версия Python
|
||
section "ENVIRONMENT"
|
||
echo "python: $(command -v python3) $(python3 --version 2>&1)" >> "$OUT"
|
||
if [[ -f "$PROJECT_DIR/requirements.txt" ]]; then
|
||
echo "" >> "$OUT"
|
||
echo "--- pip freeze (из venv) ---" >> "$OUT"
|
||
if [[ -x "$PROJECT_DIR/venv/bin/pip" ]]; then
|
||
"$PROJECT_DIR/venv/bin/pip" freeze >> "$OUT" 2>&1
|
||
else
|
||
cat "$PROJECT_DIR/requirements.txt" >> "$OUT"
|
||
fi
|
||
fi
|
||
|
||
# 3) Все текстовые файлы проекта
|
||
section "PROJECT FILES ($PROJECT_DIR)"
|
||
while IFS= read -r -d '' f; do
|
||
should_skip "$f" && continue
|
||
# бинарные — пропускаем по mime
|
||
if command -v file >/dev/null 2>&1; then
|
||
case "$(file -b --mime-encoding "$f" 2>/dev/null)" in
|
||
binary) echo "" >> "$OUT"; echo "---- BINARY SKIPPED: $f ----" >> "$OUT"; continue ;;
|
||
esac
|
||
fi
|
||
dump_file "$f"
|
||
done < <(find "$PROJECT_DIR" \
|
||
\( -path '*/venv' -o -path '*/__pycache__' -o -path '*/.git' -o -path '*/node_modules' \) -prune -o \
|
||
-type f -print0 | sort -z)
|
||
|
||
# 4) systemd-юниты и таймеры проекта
|
||
section "SYSTEMD UNITS"
|
||
for u in \
|
||
/etc/systemd/system/morozovka-portal.service \
|
||
/etc/systemd/system/morozovka-sync.service \
|
||
/etc/systemd/system/morozovka-sync.timer \
|
||
/etc/systemd/system/gitea.service \
|
||
/etc/systemd/system/bridge-webui.service; do
|
||
[[ -f "$u" ]] && dump_file "$u" || echo "[missing] $u" >> "$OUT"
|
||
done
|
||
|
||
echo "" >> "$OUT"
|
||
echo "--- systemctl list-units (morozovka*) ---" >> "$OUT"
|
||
systemctl list-units --type=service --type=timer --no-pager --all --no-legend 2>/dev/null \
|
||
| grep -Ei 'morozovka|gitea|bridge' >> "$OUT" || true
|
||
|
||
echo "" >> "$OUT"
|
||
echo "--- systemctl status (кратко) ---" >> "$OUT"
|
||
for s in morozovka-portal morozovka-sync.timer gitea; do
|
||
echo "" >> "$OUT"
|
||
echo "### $s" >> "$OUT"
|
||
systemctl is-enabled "$s" 2>&1 >> "$OUT" || true
|
||
systemctl is-active "$s" 2>&1 >> "$OUT" || true
|
||
done
|
||
|
||
# 5) Nginx-конфиги (сервер 3)
|
||
section "NGINX CONFIGS (server 3)"
|
||
for d in /etc/nginx/sites-available /etc/nginx/sites-enabled /etc/nginx/conf.d; do
|
||
[[ -d "$d" ]] || continue
|
||
while IFS= read -r -d '' f; do
|
||
dump_file "$f"
|
||
done < <(find "$d" -maxdepth 1 -type f -o -type l -print0 2>/dev/null | sort -z)
|
||
done
|
||
|
||
section "NGINX TEST OUTPUT"
|
||
nginx -t 2>&1 >> "$OUT" || true
|
||
|
||
# 6) PostgreSQL: список таблиц и схема (без данных)
|
||
section "POSTGRESQL SCHEMA (morozovka_portal)"
|
||
if command -v psql >/dev/null 2>&1 || [[ -x /usr/bin/sudo ]]; then
|
||
sudo -u postgres psql -d morozovka_portal -c "\dt" >> "$OUT" 2>&1 || true
|
||
sudo -u postgres psql -d morozovka_portal -c "\d+" >> "$OUT" 2>&1 || true
|
||
echo "" >> "$OUT"
|
||
echo "--- pg_dump --schema-only ---" >> "$OUT"
|
||
sudo -u postgres pg_dump --schema-only --no-owner --no-privileges morozovka_portal >> "$OUT" 2>&1 || true
|
||
else
|
||
echo "[psql not found]" >> "$OUT"
|
||
fi
|
||
|
||
# 7) Проверка, что портал отвечает
|
||
section "PORTAL HEALTH"
|
||
curl -sS -m 5 http://127.0.0.1:8000/healthz >> "$OUT" 2>&1 || echo "[healthz failed]" >> "$OUT"
|
||
echo "" >> "$OUT"
|
||
curl -sS -m 5 -o /dev/null -w "HTTP %{http_code} time=%{time_total}s\n" http://127.0.0.1:8000/ >> "$OUT" 2>&1 || true
|
||
|
||
# 8) Последние логи (обрезанные)
|
||
section "RECENT LOGS (last 40 lines each)"
|
||
for u in morozovka-portal morozovka-sync; do
|
||
echo "" >> "$OUT"
|
||
echo "### journalctl -u $u -n 40 --no-pager" >> "$OUT"
|
||
journalctl -u "$u" -n 40 --no-pager >> "$OUT" 2>&1 || true
|
||
done
|
||
|
||
# 9) Проверка VPN/маршрутов на всякий
|
||
section "NETWORK (server 3)"
|
||
ip -brief addr >> "$OUT" 2>&1 || true
|
||
echo "" >> "$OUT"
|
||
ip route >> "$OUT" 2>&1 || true
|
||
|
||
echo "" >> "$OUT"
|
||
echo "DUMP COMPLETE: $(date -Is)" >> "$OUT"
|
||
echo "SIZE: $(du -h "$OUT" | cut -f1)" >> "$OUT"
|
||
|
||
echo "Готово: $OUT"
|
||
echo "Размер: $(du -h "$OUT" | cut -f1)"
|