Бэкап: защита истории от пустых данных
run отказывается бэкапить БД без игроков и партий, если последний снимок в репозитории был с данными: новый Pi до восстановления иначе отправил бы пустой снимок на VPS, он стал бы latest, а keep-daily мог вытеснить настоящий снимок того же дня. Обход — run --allow-empty. Очистка дополнительно всегда оставляет 3 последних снимка. Проверено сценарием «Pi умер»: отказ бэкапа → restore latest --repo vps → следующий бэкап проходит. #64 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jBxs9nBCk5nBdTLzcGz91
This commit is contained in:
@@ -166,14 +166,33 @@ backup_to() { # backup_to <repo> [--tag …]
|
||||
}
|
||||
|
||||
# Именованные снимки (run --tag …, метка keep) и страховочные (pre-restore) политика не
|
||||
# удаляет — только вручную: fs-backup restic <repo> forget <id> --prune.
|
||||
# удаляет — только вручную: fs-backup restic <repo> forget <id> --prune. Три последних
|
||||
# снимка остаются всегда (keep-daily иначе заменил бы более ранний снимок того же дня).
|
||||
forget_repo() {
|
||||
log "Очистка по политике: $KEEP_DAILY дн. / $KEEP_WEEKLY нед. / $KEEP_MONTHLY мес. (+ все keep и pre-restore)…"
|
||||
r "$1" forget --host "$SNAP_HOST" --group-by host \
|
||||
log "Очистка по политике: $KEEP_DAILY дн. / $KEEP_WEEKLY нед. / $KEEP_MONTHLY мес. (+ 3 последних, keep и pre-restore)…"
|
||||
r "$1" forget --host "$SNAP_HOST" --group-by host --keep-last 3 \
|
||||
--keep-daily "$KEEP_DAILY" --keep-weekly "$KEEP_WEEKLY" --keep-monthly "$KEEP_MONTHLY" \
|
||||
--keep-tag keep --keep-tag pre-restore --prune >&2
|
||||
}
|
||||
|
||||
# Защита истории от пустых данных: новый Pi до восстановления или случайно очищенная БД не
|
||||
# должны становиться «последним снимком» (restore latest вернул бы пустоту).
|
||||
guard_empty() { # guard_empty <игроков> <партий>
|
||||
if [ "$1" != 0 ] || [ "$2" != 0 ]; then return 0; fi
|
||||
for _repo in $(repos); do
|
||||
_prev="$(r "$_repo" snapshots latest --host "$SNAP_HOST" --json 2>/dev/null | jq -r \
|
||||
'[.[0].tags[]? | select(startswith("players:") or startswith("matches:"))
|
||||
| ltrimstr("players:") | ltrimstr("matches:") | (tonumber? // 0)] | add // 0')" || _prev=0
|
||||
if [ "${_prev:-0}" -gt 0 ]; then
|
||||
for _r in $(repos); do mark "run-$_r" err "БД пуста, а в репозитории есть данные — бэкап не сделан (см. README, «Катастрофа»)"; done
|
||||
log "В БД нет ни игроков, ни партий, а последний снимок в репозитории $_repo — с данными."
|
||||
log "Похоже на новый или очищенный сервер: бэкап НЕ сделан, чтобы пустые данные не вытеснили историю."
|
||||
log "Восстановите данные (deploy/backup/README.md, «Катастрофа»). Если БД очищена намеренно:"
|
||||
die "fs-backup run --allow-empty"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
latest_short_id() {
|
||||
r "$1" snapshots latest --host "$SNAP_HOST" --json 2>/dev/null | jq -r '.[0].short_id // empty'
|
||||
}
|
||||
@@ -202,9 +221,11 @@ warn_leftovers() {
|
||||
cmd_run() {
|
||||
_kind=manual
|
||||
_tag=""
|
||||
_allow_empty=no
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--scheduled) _kind=scheduled ;;
|
||||
--allow-empty) _allow_empty=yes ;;
|
||||
--tag)
|
||||
[ $# -ge 2 ] || die "--tag требует значение"
|
||||
shift
|
||||
@@ -229,6 +250,7 @@ cmd_run() {
|
||||
_players="${_counts%%|*}"
|
||||
_matches="${_counts##*|}"
|
||||
log "БД в порядке: игроков $_players, партий $_matches."
|
||||
if [ "$_allow_empty" = no ]; then guard_empty "$_players" "$_matches"; fi
|
||||
|
||||
_failed=""
|
||||
for _repo in $(repos); do
|
||||
@@ -297,7 +319,7 @@ cmd_status() {
|
||||
echo " Расписание бэкапа: ${BACKUP_SCHEDULE:-отключено}"
|
||||
echo " Расписание проверки: ${BACKUP_VERIFY_SCHEDULE:-отключено}"
|
||||
echo " Часовой пояс: ${TZ:-UTC}"
|
||||
echo " Хранение: $KEEP_DAILY дн. / $KEEP_WEEKLY нед. / $KEEP_MONTHLY мес. + именованные (keep) и pre-restore"
|
||||
echo " Хранение: $KEEP_DAILY дн. / $KEEP_WEEKLY нед. / $KEEP_MONTHLY мес. + 3 последних, именованные (keep) и pre-restore"
|
||||
echo " Сжатие restic: $RESTIC_COMPRESSION"
|
||||
echo " Имя хоста в снимках: $SNAP_HOST"
|
||||
vps_enabled || echo " VPS: не настроен (только локальная копия)"
|
||||
@@ -765,8 +787,10 @@ fs-backup — бэкапы Forbidden Stars (restic). Запуск на Pi из
|
||||
Повседневное:
|
||||
status состояние: последние бэкапы/проверки, размеры репозиториев
|
||||
list [local|vps] хронология снимков (время, игроков, партий, размер, прирост)
|
||||
run [--tag имя] сделать снимок сейчас; с --tag снимок именованный и очисткой
|
||||
не удаляется (например, --tag before-update)
|
||||
run [--tag имя] [--allow-empty]
|
||||
сделать снимок сейчас; с --tag снимок именованный и очисткой
|
||||
не удаляется (например, --tag before-update); --allow-empty —
|
||||
разрешить снимок пустой БД, когда в истории есть данные
|
||||
verify проверить целостность данных в репозиториях
|
||||
|
||||
Восстановление (сначала: docker compose stop app; после: docker compose start app):
|
||||
|
||||
Reference in New Issue
Block a user