Давно стояла задача создания небольшого скрипта, по созданию резервных копий и восстановлению различных конфигурационных файлов.
Обрисую задачи, которые решает этот скрипт:
- Скрипт создаёт резервную копию конфига, дописывая к нему дату и время, и перемещает его в папку для хранения;
- Скрипт имеет ротацию, т.е. следит за кол-вом конфигов в папке и удаляет самый старый, если их число превышает заданное.
- Восстановление происходит через меню в 3 этапа:
- выбираем конфиг, который хотим восстановить.
- выбираем резервную копию для восстановления.
- подтверждаем наш выбор.
- Перед восстановлением скрипт делает резервную копию восстанавливаемого файла с пометкой "_before_restore".
- В скрипте присутвует быстрое восстановление всех конфигов на их последние резервные копии.
Сам код:
#!/bin/bash
#
# Config backup/restore
#
# AUTHOR: nol1ght (nol1ght.mail@gmail.com)
# VERSION: 1.0
# LICENSE: public
#
#Устанавливаем разделитель
Separator=";"
#Устанавливаем путь до конфига
backup_config="bconf_config"
#Устанавливаем максимальное кол-во резервных копий конфигов
configRotate=12;
#Выбираем вид отображения диалогов. (dialog/xdialog/gdialog и все подобные)
DIALOG=${DIALOG=dialog}
#Переменная для копирования конфига перед восстановлением
backupRestore=""
number=-1;
#Функция чтения конфига
function read_config {
#читаем построчно
while read line
do
#увеличиваем счётчик
((number++))
#Записываем путь до конфига(в строке до разделителя)
pathToConfig[${number}]=${line%%$Separator*};
#Записываем путь до каталога резервных копий(в строке после разделителя)
pathToBackup[${number}]=${line#*$Separator};
done < $backup_config
}
#Установка переменных пути
function paths {
#Смотрим, есть ли параметры у функции
if [ -z "$1" ]
then
#если нет - выходим
exit
fi
#Записываем в переменную имя конфига + избавляемся от проблем с пробелами в имени файла
configName=`basename ${pathToConfig[$1]} | sed 's/ /\?/g'`
#Записываем в переменную путь до конфига + избавляемся от проблем с пробелами в имени файла
pathToConf=`dirname ${pathToConfig[$1]} | sed 's/ /\?/g'`
#Добавляем / в конец
pathToConf=$pathToConf"/"
#Записываем в переменную путь до резервных копий + избавляемся от проблем с пробелами в имени файла
pathToBack=`echo ${pathToBackup[$1]} | sed 's/ /\?/g'`
}
#Функция резервного копирования
function backup {
#Смотрим есть ли параметры у функции
if [ -z "$1" ]
then
#если нет - устанавливаем на перебор всех конфигов
i_begin=0;
max=$number;
else
#если да - устанавливаем на конкретный конфиг
i_begin=$1;
max=$1;
fi
#Перебираем конфиг(и)
for ((i = $i_begin; i <= $max; i++)); do
#Задаём переменные пути
paths $i
#Задаём имя резервной копии (формат - "имя конфига_ГГГГММДД_ЧЧММСС")
backupName=$configName"_"$(date +%Y%m%d)"_"$(date +%H%M%S)
#Создаём каталог для резернвых копий
mkdir -p $pathToBack
#Подсчитываем кол-во резервных копий в каталоге
count=`cd $pathToBack;ls $pathToBack$configName_* | wc -l`
#Создаём резервную копию
cp $pathToConf$configName $pathToBack$backupName$backupRestore
#Смотрим если число конфигов достигло максимального числа - удаляем последний.
if [ $count -gt $configRotate ]; then
ls -t -1 $pathToBack$configName_* | tail --lines 1 | xargs rm
fi
done
}
#Функция восстановления
function restore {
#Создаём временный файл
temp_file=`tempfile 2> /dev/null`
#Перебираем все конфиги
for ((i = 0; i <= number; i++)); do
#Подготавливаем строчку для меню
dialog_config="$dialog_config $i \"${pathToConfig[$i]}\" "
done
#Отоброжаем меню
$DIALOG --menu "Select config to restore" 30 60 30 $dialog_config 2> $temp_file
#Читаем ответ
conf=`cat $temp_file`
#Если ничего не выбранно - выходим из программы.
if [ -z $conf ];then
clear
exit
fi
#Задаём переменные пути
paths $conf
#Смотрим кол-во резервных копий в каталоге
files=(`ls -t -1 $pathToBack$pathToConf_*`)
max_index=$((${#files[@]} - 1))
#Перебираем все конфиги
for ((i = 0; i <= max_index; i++)); do
filename=`basename "${files[i]}"`
#Подготавливаем строчку для меню
dialog_array="$dialog_array $i $filename "
done
#Отоброжаем меню
$DIALOG --menu "Select backup to restore" 30 60 30 $dialog_array 2> $temp_file
#Читаем ответ
answer=`cat $temp_file`
#Если ничего не выбранно - выходим из программы.
if [ -z $answer ];then
clear
exit
fi
#Отоброжаем меню yes/no
$DIALOG --yesno "Do you really want to restore ${files[$answer]}?" 10 70
case $? in
0)
#Устанавливаем метку
backupRestore="_before_restore"
#Делаем резервную копию текущей конфигурации
backup $conf
#Восстанавливаем файл
cp ${files[$answer]} $pathToConf$configName;;
1)
exit;;
255)
exit;;
esac
}
function restore_last {
$DIALOG --yesno "Do you really want to restore all backup files?" 10 70
case $? in
0)
#Устанавливаем метку
backupRestore="_before_mass_restore"
#Делаем резервную копию
backup
#Перебираем все конфиги
for ((i = 0; i <= number; i++)); do
paths $i
backupname=`ls -t -1 $pathToBack$configName_* | head --lines 1`
cp $backupname $pathToConf$configName
done;;
1)
exit;;
255)
exit;;
esac
}
#Функция вывода конфигов на экран
function list_config {
echo "Configs to backup: "
for ((i = 0; i <= number; i++)); do
echo ${pathToConfig[$i]};
done
}
#Функция показывает как работать с программой
function usage {
echo "Backup/Restore Config by nol1ght v1.0"
echo "Usage:"
echo "-b backup config"
echo "-l list of configs"
echo "-r restore config"
echo "-rl restore all last configs"
echo "-help this message"
}
#Проверяем под рутом ли мы зашли
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" 1>&2
exit 1
fi
#Загружаем конфиги
read_config
#переключаемся по пунку меню
case $1 in
-b)
backup;;
-r)
restore;;
-rl)
restore_last;;
-l)
list_config;;
--help)
usage;;
esac
clear
exit
Файл bconf_config имеет следующую структуру:
Путь_до_конфига Разделитель Путь_до_каталога_хранения
К примеру:
/etc/apache2/apache2.conf;/home/nol1ght/backup/apache2/ /etc/php5/apache2/php.ini;/home/nol1ght/backup/php/
Всё теперь осталось поставить в крон, я ставлю на раз в час
0 * * * * /home/nol1ght/bconf -b
Скриншоты процесса восстановления в dialog и gdialog:
Берегите Ваши конфиги и меньше их восстанавливайте :)



Комментариев нет:
Отправить комментарий