gitconf – хранение конфигов в git-репозитории

21 октября 2011 г.

Как известно, существует множество способов резервного копирования данных и системы. Все они отличаются по многим параметрам: масштабируемость, скорость восстановления, размер бэкапа и т.д. Для домашнего же пользователя и, по совместительству, администратора небольшого домашнего сервачка, самое главное — это удобство.

Поэтому я решил написать небольшой скрипт, который бы позволял хранить конфигурационные файлы в удаленном репозитории (в моем случае, на 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

Теги:
рубрика Интернет