111 lines
4.3 KiB
Bash
111 lines
4.3 KiB
Bash
#!/bin/bash
|
||
# Восстановление одного файла vzdump из restic (Yandex S3) через mount.
|
||
# Не выкачивает весь репозиторий — подгружаются только нужные данные для выбранного файла.
|
||
# Запускать на хосте Proxmox под root. Требуется FUSE (restic mount).
|
||
#
|
||
# Использование:
|
||
# restore-one-vzdump-from-restic.sh [SNAPSHOT] [ПУТЬ_В_СНИМКЕ] [КУДА_СОХРАНИТЬ]
|
||
#
|
||
# Пример (последний снимок, CT 107, сохранить в /mnt/backup):
|
||
# ./restore-one-vzdump-from-restic.sh
|
||
# ./restore-one-vzdump-from-restic.sh latest /mnt/backup/proxmox/dump/dump/vzdump-lxc-107-2026_02_26-02_03_14.tar.zst /mnt/backup
|
||
#
|
||
# Список снимков: restic snapshots
|
||
# Список файлов в снимке: restic ls SNAPSHOT
|
||
set -e
|
||
|
||
ENV_FILE="${ENV_FILE:-/root/.restic-yandex.env}"
|
||
MOUNT_DIR="${MOUNT_DIR:-/mnt/backup/restic-mount}"
|
||
RESTIC_PASSWORD_FILE="${RESTIC_PASSWORD_FILE:-/root/.restic-password}"
|
||
|
||
SNAPSHOT="${1:-latest}"
|
||
# Путь к файлу внутри снимка (как в restic ls) — бэкапим /mnt/backup, пути вида /mnt/backup/proxmox/dump/dump/vzdump-lxc-107-...
|
||
FILE_IN_SNAPSHOT="${2:-}"
|
||
OUTPUT_DIR="${3:-/mnt/backup}"
|
||
|
||
if [ "$(id -u)" -ne 0 ]; then
|
||
echo "Запускайте под root."
|
||
exit 1
|
||
fi
|
||
|
||
if [ ! -f "$ENV_FILE" ]; then
|
||
echo "Нет файла $ENV_FILE. Скопируйте restic-yandex-env.example и задайте ключи."
|
||
exit 1
|
||
fi
|
||
|
||
# shellcheck source=/dev/null
|
||
source "$ENV_FILE"
|
||
for var in RESTIC_REPOSITORY AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY; do
|
||
if [ -z "${!var}" ]; then
|
||
echo "В $ENV_FILE не задано: $var"
|
||
exit 1
|
||
fi
|
||
done
|
||
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY RESTIC_REPOSITORY
|
||
export RESTIC_PASSWORD_FILE
|
||
export AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION:-ru-central1}"
|
||
|
||
if ! command -v restic >/dev/null 2>&1; then
|
||
echo "restic не установлен. Установите: apt install restic."
|
||
exit 1
|
||
fi
|
||
|
||
if [ -z "$FILE_IN_SNAPSHOT" ]; then
|
||
echo "Использование: $0 [SNAPSHOT] ПУТЬ_В_СНИМКЕ [КУДА_СОХРАНИТЬ]"
|
||
echo "Пример: $0 latest /mnt/backup/proxmox/dump/dump/vzdump-lxc-107-2026_02_26-02_03_14.tar.zst /mnt/backup"
|
||
echo ""
|
||
echo "Доступные снимки:"
|
||
restic snapshots 2>/dev/null || true
|
||
exit 1
|
||
fi
|
||
|
||
# Resolve "latest" to snapshot ID (restic mount показывает ids/<short-id>/)
|
||
if [ "$SNAPSHOT" = "latest" ]; then
|
||
SNAPSHOT_ID=$(restic snapshots 2>/dev/null | grep -E '^[a-f0-9]{8}[[:space:]]' | tail -1 | awk '{print $1}')
|
||
else
|
||
SNAPSHOT_ID="$SNAPSHOT"
|
||
fi
|
||
[ -z "$SNAPSHOT_ID" ] && echo "Не удалось определить ID снимка." && exit 1
|
||
echo "Снимок: $SNAPSHOT_ID"
|
||
|
||
mkdir -p "$OUTPUT_DIR"
|
||
mkdir -p "$MOUNT_DIR"
|
||
|
||
# Проверяем, не смонтировано ли уже
|
||
if mountpoint -q "$MOUNT_DIR" 2>/dev/null; then
|
||
echo "Точка монтирования $MOUNT_DIR уже занята. Размонтируйте: fusermount -u $MOUNT_DIR"
|
||
exit 1
|
||
fi
|
||
|
||
echo "Монтируем репозиторий в $MOUNT_DIR ..."
|
||
restic mount "$MOUNT_DIR" &
|
||
MOUNT_PID=$!
|
||
trap 'kill $MOUNT_PID 2>/dev/null; fusermount -u "$MOUNT_DIR" 2>/dev/null; exit' EXIT INT TERM
|
||
|
||
# В смонтированном репо файлы снимка лежат в ids/<short_id>/<путь>
|
||
SOURCE_FILE="$MOUNT_DIR/ids/$SNAPSHOT_ID/$FILE_IN_SNAPSHOT"
|
||
for i in $(seq 1 45); do
|
||
if [ -e "$SOURCE_FILE" ] 2>/dev/null; then
|
||
break
|
||
fi
|
||
sleep 1
|
||
done
|
||
if [ ! -e "$SOURCE_FILE" ]; then
|
||
echo "Файл не найден: $SOURCE_FILE (подождали 45 с). Проверьте: restic ls $SNAPSHOT_ID"
|
||
exit 1
|
||
fi
|
||
|
||
BASENAME_FILE="$(basename "$FILE_IN_SNAPSHOT")"
|
||
OUTPUT_FILE="$OUTPUT_DIR/$BASENAME_FILE"
|
||
echo "Копируем $SOURCE_FILE -> $OUTPUT_FILE ..."
|
||
cp "$SOURCE_FILE" "$OUTPUT_FILE"
|
||
echo "Готово: $OUTPUT_FILE ($(du -sh "$OUTPUT_FILE" | cut -f1))"
|
||
|
||
# Размонтировать
|
||
kill $MOUNT_PID 2>/dev/null || true
|
||
wait $MOUNT_PID 2>/dev/null || true
|
||
fusermount -u "$MOUNT_DIR" 2>/dev/null || true
|
||
trap - EXIT INT TERM
|
||
echo "Размонтировано. Для восстановления контейнера:"
|
||
echo " pct create NEW_VMID $OUTPUT_FILE --restore 1 --storage local-lvm"
|