Pull to refresh

svnconfbackup: скрипт для резервного копирования конфигурационных файлов

Reading time7 min
Views3.9K
Несколько лет назад передо мной встала задача резервного копирования конфигурационных файлов. Да не простого, а такого, чтоб в любой момент можно было бы просмотреть что и когда изменилось. Я знал о существовании csvbackup, но хотелось свой скрипт, с Subversion и без Perl'а.

Для тех, кто не знаком с Subversion, поясню. Subversion — это одна из систем управления версиями. Такие системы позволяют хранить несколько версий одного и того же файла. Это невероятно удобно. Представьте себе, что на фирме два админа — вы и ваша напарница. Понедельник. Вы первый день как вышли из отпуска, а ваша напарница ещё в субботу уехала в отпуск в заграницу, естественно, без телефона. И внезапно вы обнаруживаете, что один из сервисов, например, веб-сервер, неправильно работает. Но до вашего ухода в отпуск всё работало! Что изменилось? Имея резервную копию конфигурационных файлов в системе управления версиями вы не только сможете откатиться на рабочую версию конфигов, но и проследить все изменения, сделанные в конфигурационных файлах за период вашего отсутствия, фактически, выявить проблему.

Скрипт хотелось сделать простым, кросс-платформенным, если можно так выразится, и с минимальными зависимостями. В качестве интерпретатора был выбран sh, т.к. идёт в базовой системе FreeBSD. Для копирования файлов используется pax, потому что pax при копировании файла воссоздаёт полный путь к нему, то есть после команды

pax -rw /etc/ssh/ssh_config /var/tmp

мы получим файл /var/tmp/etc/ssh/ssh_config. pax также идёт в базовой системе FreeBSD. Позднее, когда я пересел на Debian, для меня было неприятной неожиданностью, что pax надо устанавливать дополнительно.
Список файлов для резервного копирования будем задавать двумя способами — как результат работы команды find и как просто список файлов через пробел, что удобно для единичных файлов.

Переменные вынесем в файл настроек /usr/local/etc/svnconfbackup.conf:

#Каталог, где система хранит временные файлы
TMPDIR="/var/tmp"
#Название нашего каталога
REPDIR="conf"
#Сделаем название уникальным
DESTDIR=$REPDIR.`date +%s`
#Списки файлов и исключений
LIST="/etc /usr/local/etc /var/named"
EXCLUDE_LIST="-not -path /etc/'*'shadow'*' \
-and -not -path /var/named/internal/slave/'*' \
-and -not -name '*'.pem \
-and -not -name '*'.key \
-and -not -name '*'.crt \
-and -not -path /etc/ssh_host_rsa_key \
-and -not -path /etc/ssh_host_dsa_key"

FILES="/home/pgsql/data/*.conf"
#Попробем определить пути к командам самостоятельно
SVN=`which svn`
SVNADMIN=`which svnadmin`
#Корневой каталог репозитория
SVNROOT="/usr/local/svnconfbackuproot"

* This source code was highlighted with Source Code Highlighter.


В переменной LIST содержится список каталогов, в которых find будет искать файлы, а в переменной FILES — дополнительный список файлов для резервного копирования. Этот файл настроек можно рассматривать как полноценный sh-скрипт. Напомню, что внутри одиночных, или строгих, кавычек ' ' любой специальный символ (за исключением одинарной кавычки '), интерпретируется как простой символ. То есть, в переменной EXCLUDE_LIST звёздочки останутся звёздочками. А в переменной FILES мы в итоге получим список файлов в директории /home/pgsql/data/ оканчивающихся на .conf, поскольку символ "*" в данном случае является шаблоном имени файла.
А содержимое, заключённое между обратными кавычками ` `, будет заменено на результат выполнения команды, т.е. на её консольный вывод. Таким образом, вместо `date +%s` мы получим количество секунд, прошедших с 00:00:00 1 янв 1970 г. (mktemp был отвергнут по причине разного поведения в Linux и FreeBSD)
Обратный слэш \ отменяет специальное значение символа перевода строки. Это делается на всякий случай.

Но вернёмся к скрипту. Он будет состоять из двух частей — инициализации репозитория Subversion и процедуры резервного копирования. Инициализацию необходимо выполнить вручную один раз, в самом начале. Само резервное копирование должно проходить без вмешательства пользователя.
Синтаксис команды:

svnbackupconfig init|update

Т.е. svnbackupconfig init запустит инициализацию репозитория, а svnbackupconfig update запустит процедуру резервного копирования, другими словами — обновления данных в репозитории.

Сначала необходимо подгрузить настройки и выполнить инициализацию локальных переменных

#!/bin/sh
. /usr/local/etc/svnconfbackup.conf

#Путь к репозиторию в формате URL
SVNROOTsvn="file://$SVNROOT"



Дальше обработаем параметр команды, переданный в из командной строки

case "$1" in
init)
  #Здесь будет процедура инициализации
  ;;
update)
  #Здесь будет процедура резервного копирования
esac


* This source code was highlighted with Source Code Highlighter.


Процедура инициализации

cd $TMPDIR
#Создать временный каталог
mkdir $DESTDIR
chmod 700 $DESTDIR
#Создать структуру репозитория
mkdir $DESTDIR/branch
mkdir $DESTDIR/tag
mkdir $DESTDIR/trunk
cd $DESTDIR
#Проверить существование корневой директории репозитория
#Создать при необходимости
if [ ! -d $SVNROOT ]; then
 $SVNADMIN create $SVNROOT
fi
#Импорт в репозиторий
$SVN import $SVNROOTsvn/$REPDIR -q -m "Initial repository layout"
#Убрать за собой
cd ../
rm -rf $DESTDIR


* This source code was highlighted with Source Code Highlighter.


Процедура резервного копирования не намного длиннее, однако хочу остановиться поподробнее на алгоритме. Чтобы скрипт был простым и понятным, я решил задачу по-индусски «в лоб».
  1. Загрузить предыдущий бэкап из репозитория во временный каталог.
  2. Скопировать туда все файлы, заданные в списках резервного копирования. Пусть Subversion сам разбирается, что изменилось.
  3. Добавить в репозиторий новые файлы, отсутствующие в предыдущем бэкапе.
  4. Проверить каждый файл из бэкапа. Если он отсутствует в системе, удалить его из репозитория
  5. Сохранить результат в репозиторий.


Это, без сомнений, ресурсоёмкий алгоритм. Однако, на типичной системе его выполнение займёт всего несколько минут.
Новые файлы (п.3) можно найти легко — в выводе svn status строки начинаются с символа "?":

$ svn status
? some.file


Для получения имён файлов будем использовать конструкцию

svn status|grep ^?|awk '{print $2}'

Это значит, что вывод команды svn status передаётся на ввод команды grep ?, которая вернёт строки с первым символом "?". Этот вывод, в свою очередь, передаётся на ввод команды awk '{print $2}', которая возвратит второй параметр, т.е. имя файла.

Собственно, процедура резервного копирования.

cd $TMPDIR
#Создать временный каталог
mkdir $DESTDIR
chmod 700 $DESTDIR
#Получить из репозитория последний бэкап
$SVN checkout -q $SVNROOTsvn/$REPDIR/trunk $DESTDIR
cd $DESTDIR
#Построить список файлов, которые надо забэкапить
list=`eval find $LIST $EXCLUDE_LIST -and -type f|sort`
#Копировать файлы
for p in ${list} $FILES ; do
 pax -rw $p . > /dev/null 2>&1
done;
#Построить список файлов, отсутствующих в предыдущем бэкапе
list=`eval $SVN status|grep ^?|awk '{print $2}'`
#Добавить эти файлы в репозиторий
for p in ${list} ; do
 $SVN add -q $p
done;
#Построить список всех файлов в бэкапе
#за исключением файлов в служебных каталогах .svn
list=`eval find . -name .svn -prune -or -print`
#Проверить существование каждого файла из бэкапа в системе
#При необходимости удалить из репозитория
for p in ${list} ; do
 if [ ! -e /$p ]; then
  $SVN delete -q $p --force
 fi
done;
#Напечатать список изменений
$SVN diff
#Загрузить изменения в репозиторий
$SVN commit -q -m "svnbackup automatic update"
#Убрать за собой
cd ../
rm -rf $DESTDIR


* This source code was highlighted with Source Code Highlighter.


Ссылка на архив svnconfbackup.googlecode.com/files/svnconfbackup.tar.gz

Использовать этот скрипт тоже просто. После распаковки архива поместите файл скрипта в /usr/local/bin, а файл настроек в /usr/local/etc. Настройки приведите в соответствии с вашей ОС. Теперь необходимо инициализировать репозиторий. Выполните команду

svnbackupconfig init

Теперь, при желании, можно первый бэкап сделать вручную.

svnbackupconfig update

Процесс займёт несколько минут и завершится выводом текста всех конфигурационных файлов на консоль, поскольку репозиторий ещё пуст. При дальнейшем использовании вывод будет содержать только изменения между версиями.
Настройка автоматического запуска будет несколько отличаться для Linux и FreeBSD.

Для Linux:

echo -e "/usr/local/bin/svnconfbackup update\n" > /etc/cron.daily/svnconfbackup<br>
chmod 755 /etc/cron.daily/svnconfbackup


Для FreeBSD:

echo "/usr/local/bin/svnconfbackup update\n" > /usr/local/etc/periodic/daily/999.svnbackup<br>
chmod 755 /usr/local/etc/periodic/daily/999.svnbackup


Теперь — о том, как пользоваться бэкапом. По большому счёту, ниже — очень краткое описание основных комманд svn.
Для определённости будем использовать настройки по умолчанию. Для получения последнего бэкапа выполните команду

svn checkout file:///usr/local/svnconfbackup/conf/trunk conf

В текущем каталоге будет создан каталог conf, в который и будет помещена копия последнего бэкапа. При восстановлении данных имейте в виду, что в каждом каталоге присутствуют служебные каталоги с именем .svn.

Для следующих операций необходимо перейти в каталог conf, который также называют рабочим каталогом svn.
Нам понадобятся всего две команды — update и diff. Обратите внимание, что команда update обновляет рабочий каталог svn, а не репозиторий. Таким образом, для отката на предыдущую версию нужно выполнить команду

svn update --revision PREV

Вообще, в качестве аргумента для ключа --revision или его короткой формы -r можно указать и номер ревизии и дату. Например, так:

svn update -r "{2010-03-31}"

В данном случае будет взят бэкап на 31 марта 2010 г. 00:00:00. Обратите внимание, что если у вас автоматический бэкап выполняется позже этого времени, например, в 4 часа утра, то в рабочем каталоге будет бэкап за 30 марта.

С помощью команды diff можно посмотреть изменения между двумя любыми версиями файлов. При этом можно в явном виде указать, версии каких файлов надо сравнивать. Например, команда

svn diff -r "{2010-01-01}:HEAD"

покажет, что изменилось с прошлого года. Кстати, ключ -r работает и с командой checkout! Подробнее о синтаксисе и ключах можно узнать из справки:

svn help <имя комманды>

На всякий случай оставлю ссылку на сайт отличной книги по Subversion.

Желаю удачи! И помните — администраторы делятся на два типа — одни данные уже потеряли, а другие ещё потеряют!

UPD Перенёс в тематический блог
Tags:
Hubs:
Total votes 10: ↑7 and ↓3+4
Comments2

Articles