gitconf – хранение конфигов в git-репозитории
Как известно, существует множество способов резервного копирования данных и системы. Все они отличаются по многим параметрам: масштабируемость, скорость восстановления, размер бэкапа и т.д. Для домашнего же пользователя и, по совместительству, администратора небольшого домашнего сервачка, самое главное — это удобство.
Поэтому я решил написать небольшой скрипт, который бы позволял хранить конфигурационные файлы в удаленном репозитории (в моем случае, на github), и, что самое главное, при необходимости быстро их восстанавливать.
Принцип работы скрипта
Рассмотрим работу скрипта на примере:
gitconf.sh init
gitconf.sh add /etc/dhcpd.conf
gitconf.sh commit "Добавлен dhcpd.conf"
gitconf.sh push
Итак, по порядку:
1) Команда init инициализирует репозитории git и создает ссылку на удаленный репозиторий;
2) Команда add копирует файл в папку с репозиторием и добавляет его в репозиторий. Также в файл .files записывается полный путь добавляемого файла для последующего обновления или восстановления;
3) Команда commit создает коммит сделанных изменений с заданным комментарием;
4) Команда push отправляет изменения в удаленный репозиторий.
Как видно, синтаксис скрипта напоминает сильно упрощенный синтаксис программы git.
Разберем еще парочку примеров
sudo vim /etc/dhcpd.conf
gitconf.sh update dhcpd.conf
gitconf.sh commit "Изменен dhcpd.conf"
gitconf.sh push
Здесь мы изменяем конфиг dhcp-сервера, а затем с помощью команды update обновляем его в репозитории. Затем также создаем коммит и отправляем их на сервер.
sudo vim /etc/dhcpd.conf
gitconf restore dhcpd.conf
Здесь мы случайно портим конфиг, и затем восстанавливаем его, т.е. заменяем на версию из репозитория с помощью команды restore. Важный момент: если полный путь к скрипту не начинается с /home/, скрипт вызовет sudo.
Другие возможности использования
В принципе, данный скрипт лишь автоматизирует работу с git, так что все возможности git (создание отдельных веток, патчей и т.д.) могут быть применены и к конфигам. Отдельно хочется сказать про команды update all и restore all. Первая обновляет все файлы, перечисленные в .files, а вторая, соответственно, восстанавливает.
Заключение
Само собой, данный скрипт не претендует на оригинальность. Но, я думаю, что он сможет пригодится администраторам небольших сетей и домашним пользователям. Возможность восстановления позволяет без лишних проблем переставить систему с нуля без необходимости делать образ корневого раздела. Также данный скрипт поможет уберечь от поломки рабочей системы. Ну, и в конце концов, всегда приятно иметь набор 100% рабочих конфигов в качестве шаблонов для настройки нового сервера или локальной машины. Всем удачного использования.
Код скрипта
#!/bin/bash
GIT_PATH="/home/magist3r/code/conf_backup"
GIT_REMOTE="git@github.com:magist3r/conf_backup.git"
CURDIR="$(pwd)"
usage(){
echo "Использование: $0 <команда> [файлы]
Команды:
init - инициализировать репозиторий;
add [файлы] - добавить файлы в репозиторий;
rm [файлы] - удалить файлы из репозитория;
commit [comment] - закоммитить изменения в репозиторий;
update [файлы] - обновить указанные файлы в репозитории;
update all - обновить все файлы в репозитории;
push - отправить коммиты в удаленный репозиторий;
restore [файлы] - восстановить указанные файлы из репозитория;
restore all - восстановить все файлы из репозитория;
usage - вывести эту справку."
}
init(){
if [ ! -d "$GIT_PATH/.git" ]; then
cd "$GIT_PATH" && git init && git remote add origin "$GIT_REMOTE"
fi
}
add(){
if [ "$#" = 0 ]; then
echo "Не указаны файлы для добавления"
usage
exit 1
fi
cd "$GIT_PATH"
if [ ! -f "$GIT_PATH/.files" ]; then
touch "$GIT_PATH/.files"
cd "$GIT_PATH" && git add .files
fi
while (( "$#" > 0 )); do
FNAME="$(readlink -f "$1")"
if [ -f "$FNAME" ]; then # Проверка существования файла
grep "$FNAME" "$GIT_PATH/.files" > /dev/null
if [[ "$?" = 1 ]]; then # Проверка существования файла в репозитории
cp "$1" "$GIT_PATH" # Копируем файл в каталог с репозиторием
echo "$FNAME" >> "$GIT_PATH/.files" # Добавляем полный путь к файлу в .files
git add "$(basename "$FNAME")"
else
update $FNAME
fi
else
echo "Файл $FNAME не найден."
usage
exit 1
fi
shift
done
}
remove(){
if [ "$#" = 0 ]; then
echo "Не указаны файлы для удаления"
usage
exit 1
fi
cd "$GIT_PATH"
while (( "$#" > 0 )); do
NAME="$(basename "$1")"
if [ -f "$GIT_PATH/$NAME" ]; then
git rm "$GIT_PATH/$NAME"
sed -i "/$NAME/d" "$GIT_PATH/.files"
else
echo "Нет такого файла в репозитории"
exit 1
fi
shift
done
}
update(){
if [ "$#" = 0 ]; then
echo "Не указаны файлы для обновления. Для обновления всех файлов используйте gitconf update all"
exit 1
fi
cd "$GIT_PATH"
if [ "$1" = "all" ]; then
while read line; do
NAME=$(basename "$line")
diff "$NAME" "$line" > /dev/null
if [[ "$?" = 1 ]]; then
cp -a "$line" "$GIT_PATH"
fi
done < <(cat "$GIT_PATH/.files")
else
while (( "$#" > 0 )); do
FNAME="$(grep "$1" "$GIT_PATH/.files")"
NAME="$(basename "$FNAME")"
if [ ! -z "$NAME" ]; then
diff "$NAME" "$FNAME" > /dev/null
if [[ "$?" = 1 ]]; then
cp -a "$FNAME" "$GIT_PATH"
fi
fi
shift
done
fi
}
commit(){
cd "$GIT_PATH"
if [ ! -z "$1" ]; then
git commit -a -m "$1"
else
git commit -a
fi
}
push(){
cd "$GIT_PATH"
git push origin
}
restore(){
if [ "$#" = 0 ]; then
echo "Не указаны файлы для восстановления. Для восстановления всех файлов используйте gitconf revert all"
exit 1
fi
cd "$GIT_PATH"
if [ "$1" = "all" ]; then
while read line; do
NAME=$(basename "$line")
if [ "${line:0:6}" != "/home/" ]; then
sudo cp -a "$GIT_PATH/$NAME" "$line"
else
cp -a "$GIT_PATH/$NAME" "$line"
fi
done < <(cat "$GIT_PATH/.files")
else
while (( "$#" > 0 )); do
FNAME="$(grep "$1" "$GIT_PATH/.files")"
NAME="$(basename "$FNAME")"
if [ ! -z "$NAME" ]; then
if [ "${FNAME:0:6}" != "/home/" ]; then
sudo cp -a "$GIT_PATH/$NAME" "$FNAME"
else
cp -a "$GIT_PATH/$NAME" "$FNAME"
fi
else
echo "Файла $FNAME нет в репозитории"
fi
shift
done
fi
}
if [[ "$#" = 0 ]]; then
usage
else
case "$1" in
"init")
shift
init
;;
"add")
shift
add "$@"
;;
"rm")
shift
remove "$@"
;;
"commit")
shift
commit "$@"
;;
"push")
push
;;
"update")
shift
update "$@"
;;
"restore")
shift
restore "$@"
;;
*)
usage
exit 1
;;
esac
fi
exit 0
Ссылки
Топик, откуда были почерпнуты основные идеи
Отличное руководство с примерами по работе с git