Резервное копирование bj на SMB: настройки (хранилище, расписание, хранение), копия сейчас, список и проверка копий; восстановление из копии на шаге 1 мастера; таймер bj-backup, smbclient в установщике
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
Executable
+63
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
# bj-backup — резервная копия сервера bj на сетевое хранилище (SMB): базы PostgreSQL bj и igate,
|
||||
# данные bj (/var/lib/bj/.bj, /etc/bj) и шлюза НРД (/var/lib/igate без журналов).
|
||||
# Куда, как часто и сколько хранить — /etc/bj/backup.conf (пишет bj-backup-admin из настроек bj),
|
||||
# логин хранилища — /etc/bj/backup-smb.cred (только root). Итог — /var/lib/bj/backup-status.json.
|
||||
set -uo pipefail
|
||||
CONF=/etc/bj/backup.conf
|
||||
CRED=/etc/bj/backup-smb.cred
|
||||
STATUS=/var/lib/bj/backup-status.json
|
||||
[ -r "$CONF" ] && . "$CONF"
|
||||
SHARE=${SHARE:-}
|
||||
DIR=${DIR:-BJ_Backup/bj}
|
||||
KEEP_DAYS=${KEEP_DAYS:-14}
|
||||
TS=$(date +%Y-%m-%d_%H%M)
|
||||
W=$(mktemp -d /var/tmp/bj-backup.XXXXXX)
|
||||
trap 'rm -rf "$W"' EXIT
|
||||
cd /
|
||||
status() { python3 - "$STATUS" "$1" "$DIR/$TS" "$2" <<'PY'
|
||||
import json,sys,datetime
|
||||
p,ok,d,msg=sys.argv[1:]
|
||||
json.dump({"at":datetime.datetime.now().astimezone().isoformat(timespec="seconds"),"ok":ok=="true","dir":d,"msg":msg},open(p,"w"),ensure_ascii=False)
|
||||
PY
|
||||
chown bj:bj "$STATUS" 2>/dev/null || true; }
|
||||
fail() { status false "$1"; echo "ОШИБКА: $1" >&2; exit 1; }
|
||||
smb() { smbclient "$SHARE" -A "$CRED" -m SMB3 -c "$1"; }
|
||||
# tar: «файл изменился во время чтения» (код 1) для работающих служб — не ошибка
|
||||
tarok() { tar "$@"; local rc=$?; [ $rc -le 1 ]; }
|
||||
|
||||
[ -n "$SHARE" ] || fail "не задано хранилище (Настройка → Резервное копирование)"
|
||||
[ -r "$CRED" ] || fail "нет логина хранилища (Настройка → Резервное копирование)"
|
||||
|
||||
runuser -u postgres -- pg_dump -Fc bj > "$W/bj.pgdump" || fail "дамп базы bj"
|
||||
if runuser -u postgres -- psql -Atc "select 1 from pg_database where datname='igate'" 2>/dev/null | grep -q 1; then
|
||||
runuser -u postgres -- pg_dump -Fc igate > "$W/igate.pgdump" || fail "дамп базы igate"
|
||||
fi
|
||||
tarok -C / -czf "$W/bj-data.tar.gz" --exclude=etc/bj/backup-smb.cred var/lib/bj/.bj etc/bj || fail "архив данных bj"
|
||||
if [ -d /var/lib/igate ]; then
|
||||
tarok -C / -czf "$W/igate-data.tar.gz" --warning=no-file-changed --exclude='var/lib/igate/.cache' \
|
||||
--exclude='var/lib/igate/NSD Integration Gateway/logs*' --exclude='var/lib/igate/logs-cli' var/lib/igate || fail "архив шлюза НРД"
|
||||
fi
|
||||
cat > "$W/backup-info.txt" <<INFO
|
||||
Bridge&Join — резервная копия сервера $(hostname) от $(date '+%d.%m.%Y %H:%M:%S')
|
||||
Версия bj: $(/opt/bj/bj-server -version 2>/dev/null | head -1)
|
||||
Восстановление: мастер настройки → «Восстановить из резервной копии» или bj-backup-admin restore.
|
||||
INFO
|
||||
(cd "$W" && sha256sum * > SHA256SUMS)
|
||||
SIZE=$(du -sh "$W" | cut -f1)
|
||||
|
||||
top=${DIR%%/*}
|
||||
smb "mkdir \"$top\"; mkdir \"$DIR\"" >/dev/null 2>&1 || true
|
||||
smb "mkdir \"$DIR/$TS\"; cd \"$DIR/$TS\"; lcd $W; prompt; mput *" >/dev/null || fail "запись на $SHARE/$DIR"
|
||||
for f in $(cd "$W" && ls); do
|
||||
smb "cd \"$DIR/$TS\"; ls \"$f\"" >/dev/null 2>&1 || fail "на хранилище нет $f"
|
||||
done
|
||||
|
||||
CUT=$(date -d "-$KEEP_DAYS days" +%Y-%m-%d_%H%M)
|
||||
smb "cd \"$DIR\"; ls" 2>/dev/null | awk '{print $1}' | grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{4}$' | while read -r d; do
|
||||
if [[ "$d" < "$CUT" ]]; then
|
||||
smb "cd \"$DIR/$d\"; prompt; mask *; mdel *; cd ..; rmdir \"$d\"" >/dev/null 2>&1 && echo "удалена старая копия $d"
|
||||
fi
|
||||
done
|
||||
status true "размер $SIZE"
|
||||
echo "копия $DIR/$TS готова ($SIZE)"
|
||||
Reference in New Issue
Block a user