Анализ данных. Выбор для датасетов. Проверка на существование снимков.

This commit is contained in:
root 2024-10-29 20:26:52 +03:00
parent 3725a5c4ee
commit 1024043ab2

View File

@ -1,107 +1,158 @@
#!/bin/zsh #!/bin/zsh
backup_server="192.168.0.162" # Сервер для резервирования
inc_snapshot="manual-$(date +%Y%m%d)" # Новый создаваемый снисмок
echo -ne "Обработка аргументов...\033[0K\r"
if [[ $# == 1 ]]; then
backup_server=$1
fi
if [[ $# == 2 ]]; then
backup_server=$1
inc_snapshot=$2
fi
if [[ $# > 2 ]]; then
echo "Ожидается 0 или 2 аргумента: backup_server или ни одного для сервера по умолчанию: $backup_server"
exit
fi
echo "Резервирование на $backup_server"
echo "Снимок файловой системы $inc_snapshot"
# --------- Собираем данные ---------- # --------- Собираем данные ----------
backup_server="192.168.0.162" echo -ne "Собираю данные...\033[0K\r"
# Получить список датасетов на локальной машине
local_datasets=$(zfs list -o name | grep -v -e ix-app -e boot-pool -e system-data -e jails | grep /) # Отрезаем всё лишнее, отделяем нужные данные по 4 пробелам в выводе.
local_datasets=(${=local_datasets}) # Конвертирование в массив
# Получить список датасетов на удалённой машине
backup_datasets=$(ssh root@$backup_server zfs list -o name | grep -v -e ix-app -e boot-pool -e system-data -e jails | grep /) # Отрезаем всё лишнее, отделяем нужные данные по 4 пробелам в выводе.
backup_datasets=(${=backup_datasets}) # Конвертирование в массив
srcpool="main_pool/" # Высчитать что на что резервировать
inc_snapshot="manual-$(date +%Y%m%d)" declare -A work_datasets
for ((i = 1; i <= ${#local_datasets}; i++)); do
# Словарь, содержащий списки резервируемых датасетов for ((j = 1; j <= ${#backup_datasets}; j++)); do
declare -A datasets a=$(sed -r "s/(.*)\/(.*)/\2/" <<<"$local_datasets[i]") # Определить нижний по иерархии
# ["${srcpool}3D_Design"]="NOD/Backup/3D_Design" b=$(sed -r "s/(.*)\/(.*)/\2/" <<<"$backup_datasets[j]") # тоже дял второго
# ["${srcpool}Backups"]="NOD/Backup/Backups" if [[ "$a" == "$b" ]]; then
# ["${srcpool}Documents"]="NOD/Backup/Documents" work_datasets[${local_datasets[i]}]=${backup_datasets[j]}
# ["${srcpool}Family"]="NOD/Backup/Family"
# ["${srcpool}FTP_users"]="NOD/Backup/FTP_users"
datasets=(
["${srcpool}Media"]="NOD/Backup/Media"
["${srcpool}NOD/GenShtab"]="NOD/GenShtab"
["${srcpool}NOD/MinDiz"]="NOD/MinDiz"
["${srcpool}NOD/nod34"]="NOD/nod34"
["${srcpool}NOD/nod34_secret"]="NOD/nod34_secret"
["${srcpool}PhotoWork"]="NOD/Backup/PhotoWork"
)
# Словарь со списком последких снапшотов для датасетов
declare -A last_local_snaps
declare -A last_backup_snaps
pre_snapshots=()
for ds in ${(k)datasets}; do
tmp="$(zfs list -r -t snapshot -H -o name ${srcpool::-1} | grep ${ds} | grep "manual" | egrep -o '@.+' | tail -n1)"
tmp=${tmp:1}
if [ "$tmp" = "$inc_snapshot" ]; then
read "del_snapshot?Датасет $ds уже имеет последний снимок $inc_snapshot. Удалить? (y/N)"
if [ "$del_snapshot" = "y" ]; then
zfs destroy "${ds}@${tmp}"
tmp="$(zfs list -r -t snapshot -H -o name ${srcpool::-1} | grep ${ds} | grep "manual" | egrep -o '@.+' | tail -n1)"
pre_snapshots[$ds]="${tmp:1}"
else
# Если не удалять, то просто исключить из резервирования
unset "datasets[$ds]"
fi
else
pre_snapshots[$ds]=$tmp
fi fi
done done
done
# Словарь со списком последких снапшотов для датасетов
declare -A last_loc_snaps
declare -A last_bak_snaps
echo -ne "Проверяю на наличие $inc_snapshot...\033[0K\r"
for loc_ds bak_ds in ${(kv)work_datasets}; do
# Запросить последние снимки
loc_snap="$(zfs list -t snapshot -o name ${loc_ds} | grep "manual" | tail -n1 | egrep -o '@.+' )"
loc_snap=${loc_snap:1} # удалить @ в начале строки
bak_snap="$(ssh root@$backup_server zfs list -t snapshot -o name ${bak_ds} | grep "manual" | tail -n1 | egrep -o '@.+' )"
bak_snap=${bak_snap:1} # удалить @ в начале строки
# Если последний снимок совпадает с сегодняшним
if [[ "$loc_snap" = "$inc_snapshot" ]]; then
# Если последние снимки на обеих машинах совпадают
if [[ "$loc_snap" = "$bak_snap" ]]; then
echo "${loc_ds}@${loc_snap} существует на обеих машинах. $loc_ds Исключено из списка"
unset "work_datasets[$loc_ds]"
else
# Если на удалённой машине нет такого снимка, то предложить удалить.
read "del_snapshot?Датасет $loc_ds уже имеет последний снимок $inc_snapshot. Удалить? (y/N)"
if [ "$del_snapshot" = "y" ]; then
zfs destroy "${loc_ds}@${loc_snap}"
loc_snap="$(zfs list -t snapshot -o name ${loc_ds} | grep "manual" | tail -n1 | egrep -o '@.+' )"
loc_snap="${loc_snap:1}"
last_loc_snaps[$loc_ds]=$loc_snap
# last_bak_snaps[$bak_ds]=$bak_snap # не нужно, нигде не используется
else
# Если не удалять, то просто исключить из резервирования
echo "$ds Исключено из списка"
unset "work_datasets[$ds]"
fi
fi
else
# добавить в список снапшотов
last_loc_snaps[$loc_ds]=$loc_snap
# last_bak_snaps[$bak_ds]=$bak_snap # не нужно, нигде не используется
fi
done
# --------- Запрашиваем подтверждение пользователя ---------- # --------- Запрашиваем подтверждение пользователя ----------
echo echo " "
echo "Резервирование на $backup_server"
echo "Список резервируемых датасетов:" echo "Список резервируемых датасетов:"
for key in ${(k)datasets}; do i=0; for loc_ds bak_ds in ${(kv)work_datasets}; do
echo "$key \t ${pre_snapshots[$key]} \t -> \t${datasets[$key]}" i=$((i+1))
echo "$i - $loc_ds \t ${last_loc_snaps[$loc_ds]} \t -> \t${bak_ds}"
done done
echo echo
echo "Инкрементный снимок:\t$inc_snapshot" echo "Инкрементный снимок:\t$inc_snapshot"
read "work?Утвердите данные. Приступаем? (y/N) " # --------- Выбор датасетов ----------
read "work?Утвердите данные. В работу (y), или перечислить через пробел номера, НЕТ по умолчанию? "
if [[ $work = *[[:digit:]]* ]]; then
indx_list=(${=work})
# Если нет индекса в списке, то удалить из словаря для резервирования
i=0; for loc_ds bak_ds in ${(kv)work_datasets}; do
i=$((i+1))
if [[ ${indx_list[(r)$i]} != $i ]]; then # Если нет $i в списке $indx_list
unset "work_datasets[$loc_ds]"
else
echo "$i - $loc_ds \t ${last_loc_snaps[$loc_ds]} \t -> \t${bak_ds}"
fi
done
fi
# Если был выведен список, то запросить запуск в работу нового списка
if [[ ${#indx_list} > 0 ]]; then
work="N"
read "work?В работу (y/N) "
fi
# --------- Резервирование ---------- # --------- Резервирование ----------
if [ "$work" = "y" ] if [[ $work = "y" || $work = "Y" ]]; then
then
TS0=$(date +%s) TS0=$(date +%s)
LOGFILE="log_${inc_snapshot}_backup.txt" LOGFILE="log_${inc_snapshot}_backup.txt"
echo "Результат работы записываю в файл $LOGFILE" echo "Результат работы записываю в файл $LOGFILE"
echo "Список резервируемых датасетов:" >> $LOGFILE
for key in ${(k)datasets}; do # Записать в файл список резервируемых датасетов
echo "$key \t ${pre_snapshots[$key]} \t -> \t${datasets[$key]}" >> $LOGFILE echo "Список резервируемых датасетов:" >> "${LOGFILE}"
for loc_ds in ${(k)work_datasets}; do
echo "$key \t ${last_loc_snaps[$loc_ds]} \t -> \t${work_datasets[$loc_ds]}" >> "${LOGFILE}"
done done
echo echo
exec 6>&1 # Saves stdout exec 6>&1 # Saves stdout
exec >> >(tee $LOGFILE) # stdout replaced with file exec > >(tee $LOGFILE) # stdout replaced with file
echo "------------------------\nСоздаю снимки @${inc_snapshot}\n" echo "\n--- Резервирую данные ---"
for loc_ds bak_ds in ${(kv)work_datasets}; do
TS1=$(date +%s) TS1=$(date +%s)
for ds in ${(k)datasets}; do echo " * snapshot ${loc_ds}@${inc_snapshot}"
echo " * ${ds}"; zfs snapshot ${loc_ds}@${inc_snapshot};
zfs snapshot ${ds}@${inc_snapshot}; echo " * Start sending ${loc_ds} at $(date +'%Y.%m.%d %H:%M.%S')"
done zfs send -V -i ${loc_ds}@${last_loc_snaps[$loc_ds]} ${loc_ds}@${inc_snapshot} | ssh "root@${backup_server}" zfs receive ${bak_ds}@${inc_snapshot}
TS2=$(date +%s) TS2=$(date +%s)
echo "Готово за: $(date -d@$(($TS2-$TS1)) -u +'%H:%M.%S')" echo "Закончил ${loc_ds} за: $(date -d@$(($TS2-$TS1)) -u +%H:%M:%S)"
echo "------------------------\nРезервирую данные\n" done & # Запустить резервирование в фоне
for ds in ${(k)datasets}; do
TS1=$(date +%s)
echo " * Start sending ${ds} at $(date +'%Y.%m.%d %H:%M.%S')"
zfs send -V -i ${ds}@${pre_snapshots[$ds]} ${ds}@${inc_snapshot} | ssh "root@${backup_server}" zfs receive ${datasets[$ds]}@${inc_snapshot}
TS2=$(date +%s)
echo "Закончил ${ds} за: $(date -d@$(($TS2-$TS1)) -u +%H:%M:%S)"
done &
exec 1>&6 6>&- exec 1>&6 6>&-
# Выводить прогресс запрашивая список запущенныйх процессов
while pgrep -u $USER zfs >/dev/null; do while pgrep -u $USER zfs >/dev/null; do
PROGR=$(ps -u | grep "send" | grep -v "grep" | sed -r "s/(.*) zfs: (.*)/\2/") PROGR=$(ps -u | grep "send" | grep -v "grep" | sed -r "s/(.*) zfs: (.*)/\2/")
echo -ne "$PROGR\033[0K\r" echo -ne "$PROGR\033[0K\r"
# echo -ne "$(ps -u | grep "send" | grep -v "grep" | sed -r "s/(.*) zfs: (.*)/\2/")\033[0K\r"
sleep 60 sleep 60
done done
echo -e echo -e
exec >> >(tee $LOGFILE) exec > >(tee $LOGFILE)
echo "------------------------\nВсе завершено за $(date -d@$(($TS2-$TS0)) -u +%H:%M.%S)" echo "\n---Все завершено за $(date -d@$(($TS2-$TS0)) -u +%H:%M.%S) ---"
exec 1>&6 6>&- # Restore stdout and close file descriptor #6. exec 1>&6 6>&- # Restore stdout and close file descriptor #6.