Недавно появилось некоторое чувство дискомфорта когда я приступаю к работе. Чувство было не то чтобы сильным, но сосредоточиться мешало. Думал, лень. Оказалось, что все чуть сложнее :) Ноуту, за которым я работаю, уже почти 3 года; стоит на нем Mac OS X 10.6.1, но яблок на нем нигде не нарисовано, и система периодического резервного копирования на нем отсутствует как класс. В общем, не было ощущения стабильности и надежности, так что я занялся этим вопросом вплотную. Собственно, далее я опишу результат, который мое подсознание удовлетворил :) Может быть, кому-то что-нибудь будет полезно.
У меня, конечно, временами и фотографии появляются, которые хотелось бы сохранить, и прочие бинарники, но вопроса их резервного копирования мы касаться не будем, потому что надежного места, куда можно скриптами запихнуть больше 10 Гб у меня нет, да и чаще чем раз в месяц они не изменяются обычно.
Возможно, в ближайшем будущем этот список расширится, а пока, как мне кажется, этого более-менее достаточно.
Гугл по моим запросам ничего путного и удовлетворяющего моим запросам не выдал, поэтому пришлось писать самому. Заодно потрогал что есть Python, давно искал подходящий повод.
Вариант «копировать все» не проходит из-за нехватки места. К тому же, как-то кажется глупым держать кучу резервных копий ненужных файлов (объектников, логов сборки и т.п.). В итоге, так сказать, техзадание получилось следующим:
Скрипт копирования написан на Python и занимает чуть меньше 200 строк (с учетом отступов, комментариев и т.п.). Дополнительно использует один нагугленный модуль для преобразования абсолютных путей в относительные и наоборот.
Использование:
Ограничения:
Пример списка (с базовым каталогом ~):
Исходники (наверное, удобнее когда на файлохостинге лежат, чем когда те самые 200 строк засоряют текст):
sn-backup.py (посмотреть на dumpz.org)
relpath.py (посмотреть на dumpz.org)
relpath.py был взят отсюда, из первого коммента, и чуть подправлен.
Сжатие и шифрование требуют по одной строчке, так что как-то странно было бы их писать на Python. Чем сжимать – дело вкуса. Я предпочитаю 7-zip. Командная строка тут, соответственно, будет простой (имя архива – backup.7z, имя папки – .backup):
Для шифрования выбрал openssl, так как, в теории, почти везде есть и работает из коробки, без необходимости генерации чего бы то ни было. Команда выглядит так:
Соответственно, имя исходного файла backup.7z, имя выходного файла backup.aes256cbc (на случай, если вдруг забуду как зовется алгоритм шифрования). Пароль хранится в файле и может иметь произвольную длину. Лучше, все же, не менее 32 символов.
Отправку, из-за потенциального разнообразия способов, сначала хотелось сделать тоже через очень настраиваемый Python-скрипт, но потом я решил, что копировать на небольшое число хостов гораздо проще вручную, а копировать на большое число хостов попахивает паранойей. Поэтому отправка реализована в sh-скрипте. Команда копирования на Dropbox при установленном клиенте интереса не представляет, так что рассмотрим только команду отправки на почту (она хоть чуть реже встречается):
Внимание: чтобы эта команда работала, необходимо настроить на локальной машине SMTP-сервер. У меня провайдер его предоставляет Команда прикрепляет зашифрованный архив к сообщению с темой «[BACKUP] <текущая дата и время>» и отправляет сообщение на <адрес>. У меня эта команда лежит в скрипте sn-upload.sh, который в качестве единственного аргумента принимает имя файла зашифрованного архива.
Все вместе собирается скриптом backup.sh, который выглядит примерно так:
На досуге, возможно, сделаю такие доработки:
Я не исключаю возможности, что я изобрел велосипед. Но я потратил на это не так много времени, и получил немного опыта. Хочу отметить, что прежде всего в, кхм, дизайн этой системы закладывалась простота. Я знаю какие файлы и откуда мне надо скопировать. Я знаю что с ними потом делать. Мне нужен скрипт только для того, чтобы все это делалось на автомате. На мой взгляд, свои задачи он выполняет полностью.
Благодарю за внимание!
Задача
Что бекапим
- Каталоги с разнообразными исходниками. Некоторые проекты являются Git-репозиториями, соответственно, хочется сохранить репозиторий, а не просто последнюю версию исходников. NB: выполнять make clean или аналоги в конце дня я как-то не привык, так что добавляем требование, что бинарники не копируются.
- Каталоги с конфигами и параметрами.
- Каталоги с TeX-исходниками. На самом деле, можно было бы добавить к первому пункту.
У меня, конечно, временами и фотографии появляются, которые хотелось бы сохранить, и прочие бинарники, но вопроса их резервного копирования мы касаться не будем, потому что надежного места, куда можно скриптами запихнуть больше 10 Гб у меня нет, да и чаще чем раз в месяц они не изменяются обычно.
Куда бекапим
- Собственно, файлохранилища. Был выбран бесплатный аккаунт на Dropbox, ибо копировать командой cp – просто и удобно.
- Почта на Gmail. Все равно 7 гигов не используются, да и в надежности пока не было поводов сомневаться.
Возможно, в ближайшем будущем этот список расширится, а пока, как мне кажется, этого более-менее достаточно.
Какие фичи
- Простота. Основная фича :) Не нужно сложных и больших программ, я сам в состоянии решить какие файлы откуда мне нужно копировать. Проще быть уверенным в корректности работы небольшой программы.
- История изменений. Первая фича, которую хочется – это история изменений, чтобы не ругаться на тему «чем же этот файл мне мешал!»
- Сжатие. Git, конечно, жмет, но т.к. хранить бекапы все равно удобнее в одном файле, так что пускай его дожмет кто-нибудь еще.
- Шифрование Я не сомневаюсь в честности и секъюрности провайдеров интернета и провайдеров хранилищ. Тем не менее, не хочу, чтобы то, что я делаю, передавалось и лежало непонятно где в открытом виде.
Решение
Гугл по моим запросам ничего путного и удовлетворяющего моим запросам не выдал, поэтому пришлось писать самому. Заодно потрогал что есть Python, давно искал подходящий повод.
Копирование
Вариант «копировать все» не проходит из-за нехватки места. К тому же, как-то кажется глупым держать кучу резервных копий ненужных файлов (объектников, логов сборки и т.п.). В итоге, так сказать, техзадание получилось следующим:
- Список каталогов и файлов для копирования хранится в отдельном файле.
- Для каждого каталога можно указать маски файлов, которые из него нужно копировать. Если маска не указана, копировать все.
- Сохраняется исходная структура каталогов.
- Скрипт копирует (и только копирует) файлы в указанную папку.
- Если в целевой папке файл уже существует, копировать только в случае, если время модификации исходного файла больше.
Скрипт копирования написан на Python и занимает чуть меньше 200 строк (с учетом отступов, комментариев и т.п.). Дополнительно использует один нагугленный модуль для преобразования абсолютных путей в относительные и наоборот.
Использование:
sn-backup.py <файл со списком> <базовый каталог> <каталог для резервного копирования>
Ограничения:
- Строгий формат файла со списком. Формат строки:
<путь относительно базового каталога>[\t<маски через запятую>]
Более одного знака табуляции не допускается. Маски идут через запятую без пробелов. - Практически не реализована защита от дурака.
Пример списка (с базовым каталогом ~):
.emacs Documents/Programming *.c,*.h,*.cpp,*.pro,*.py,.git Scripts
Исходники (наверное, удобнее когда на файлохостинге лежат, чем когда те самые 200 строк засоряют текст):
sn-backup.py (посмотреть на dumpz.org)
relpath.py (посмотреть на dumpz.org)
relpath.py был взят отсюда, из первого коммента, и чуть подправлен.
Сжатие и шифрование
Сжатие и шифрование требуют по одной строчке, так что как-то странно было бы их писать на Python. Чем сжимать – дело вкуса. Я предпочитаю 7-zip. Командная строка тут, соответственно, будет простой (имя архива – backup.7z, имя папки – .backup):
7za a -mx7 backup.7z .backup
Для шифрования выбрал openssl, так как, в теории, почти везде есть и работает из коробки, без необходимости генерации чего бы то ни было. Команда выглядит так:
openssl enc -aes-256-cbc -salt -in backup.7z -out backup.aes256cbc -pass file:<pass path>
Соответственно, имя исходного файла backup.7z, имя выходного файла backup.aes256cbc (на случай, если вдруг забуду как зовется алгоритм шифрования). Пароль хранится в файле и может иметь произвольную длину. Лучше, все же, не менее 32 символов.
Отправка
Отправку, из-за потенциального разнообразия способов, сначала хотелось сделать тоже через очень настраиваемый Python-скрипт, но потом я решил, что копировать на небольшое число хостов гораздо проще вручную, а копировать на большое число хостов попахивает паранойей. Поэтому отправка реализована в sh-скрипте. Команда копирования на Dropbox при установленном клиенте интереса не представляет, так что рассмотрим только команду отправки на почту (она хоть чуть реже встречается):
uuencode <путь к зашифрованному архиву> $(basename <путь к зашифрованному архиву>) | mail -s "[BACKUP] $(date)" <адрес>
Внимание: чтобы эта команда работала, необходимо настроить на локальной машине SMTP-сервер. У меня провайдер его предоставляет Команда прикрепляет зашифрованный архив к сообщению с темой «[BACKUP] <текущая дата и время>» и отправляет сообщение на <адрес>. У меня эта команда лежит в скрипте sn-upload.sh, который в качестве единственного аргумента принимает имя файла зашифрованного архива.
Все вместе
Все вместе собирается скриптом backup.sh, который выглядит примерно так:
# ~/.backup - каталог, в который и происходит резервное копирование.
# Предварительно в нем должен быть инициализирован .git-репозиторий.
cd ~/.backup
# Список удобно держать там же.
~/Scripts/sn-backup.py ./list ~ .
# Скопировали, теперь коммитим в git.
git add .
git commit -m "Backup at $(date)"
# Возвращаемся назад и архивируем.
cd ..
7za a -mx7 backup.7z .backup > /dev/null
# Шифруем.
openssl enc -aes-256-cbc -salt -in backup.7z -out backup.aes256cbc -pass file:///${SECRET_PATH}/.password
# Отправляем.
~/Scripts/sn-upload.sh ./backup.aes256cbc
# ???
rm backup.7z
# PROFIT!
Направления для дальнейшего развития
На досуге, возможно, сделаю такие доработки:
- Перевести все bash-скрипты на Python.
- Возможно, переключиться на pylzma и встроенную криптографию Python (для кроссплатформенности).
- Сделать формат файла-списка помягче и поприличнее.
Заключение
Я не исключаю возможности, что я изобрел велосипед. Но я потратил на это не так много времени, и получил немного опыта. Хочу отметить, что прежде всего в, кхм, дизайн этой системы закладывалась простота. Я знаю какие файлы и откуда мне надо скопировать. Я знаю что с ними потом делать. Мне нужен скрипт только для того, чтобы все это делалось на автомате. На мой взгляд, свои задачи он выполняет полностью.
Благодарю за внимание!