PDA

Просмотр полной версии : Bash скрипт для автоматизации процесса применения sql обновлений.


Astellar
31.05.2010, 00:07
Небольшое вступление. В силу ряда жизненных обстоятельств я отошел от конвейерного выпуска патчей для ядра. Однако за проектом следить не перестал и парочку полезных вещей могу предложить.

Как известно, адекватные обладатели серверов на базе *nix никогда графическую оболочку туда не воткнут. В итоге остаются они наедине с консолью, а обновлять базы временами приходится. Эти же адекватные владельцы стараются закрыть доступ к SQL серверу извне как можно сильнее. Отсюда нерадостная картина: очень хорошо, когда этих sql обновлений 2-3 штуки, но когда их переваливает за дюжину - хочется застрелиться, применяя их из консоли.

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

имя пользователя и пароль не хранятся в теле скрипта, что значительно повышает безопасность его использования;
для применения всех обновлений достаточно ввести логин и пароль только один раз;
нет необходимости в объединении отдельных sql файлов в один общий, порядок выполнения определяется именами файлов;
в скрипте нет жестко заданных имен баз данных, поэтому он подходит для обновления любых баз;
число обновляемых баз данных не имеет жесткого ограничения, т.е. при желании можно и десяток одной командой обновить;
есть возможность применения обновлений к базам, расположенным на удаленных узлах в сети (при условии, что пользователю разрешен туда доступ);
реализован достаточно полный контроль ошибок (пустое имя пользователя, пустой список баз для обновления, реакция на ошибки mysql);
примененные файлы обновлений перемещаются в отдельную подпапку. Это сделано для того, чтобы в случае остановки процесса из-за ошибки, повторный запуск не приводил к попытке еще раз применить успешные обновления. Также это защищает "от дурака", если в списке баз данных для обновления несколько раз одно и то же имя базы задать.

#!/bin/bash

UPDATE_ROOT_DIR="./Updates"
APPLIED_DIR="applied_"`eval date +%d_%m_%T`

read -p "Username: " LOGIN
[ "x$LOGIN" == "x" ] && { echo "Username can not be empty."; exit; }

read -s -p "Password: " PASSWORD
echo

read -p "Host (default is localhost): " DB_HOST
[ "x$DB_HOST" == "x" ] && { DB_HOST="localhost"; }

read -p "Databases to update (separate by spaces): " DB_LIST
[ "x$DB_LIST" == "x" ] && { echo "Empty list? I'm more clever than you think."; exit; }
echo

for DB in $DB_LIST; do
CURR_DIR=$UPDATE_ROOT_DIR/$DB
[ ! -d "$CURR_DIR" ] && {
echo "Directory \`$CURR_DIR\` not found. I try to read files to update database \`$DB\` from it.";
exit;
} || {
echo "Updating \`$DB\` database...";
for FILE in $CURR_DIR/*.sql; do
[ -f "$FILE" ] && {
echo " Applying \`$FILE\`.";
mysql -u $LOGIN --password="$PASSWORD" -h $DB_HOST $DB < $FILE;
[ $? -eq 1 ] && {
exit;
} || {
[ ! -d $CURR_DIR/$APPLIED_DIR ] && { mkdir $CURR_DIR/$APPLIED_DIR; };
mv $FILE $CURR_DIR/$APPLIED_DIR;
};
};
done;
echo "Done!";
}
done

В кратце, как оно работает (для тех, кто код не читает).

Сохраняете этот скрипт, допустим под именем update.sh. Не забываете дать ему права на выполнение (chmod +x). Далее создается в папке со скриптом папку Updates, в этой папке создаете подпапки, имена которых соответствуют именам баз данных, которые необходимо обновить (например: Updates/mangos, Updates/characters, Updates/realmd).

После этого запускаете скрипт (./updates.sh). Далее показан тестовый пример, из которого всем думаю понятно, что нужно вводить.
[astellar@laptop Development]$ ./update.sh
Username: root
Password:
Host (default is localhost):
Databases to update (separate by spaces): mangos characters realmd

Updating `mangos` database...
Applying `./Updates/mangos/540_MaNGOS_R9613_SD2_R1653_ACID_R304_RuDB_R37.4.sq l`.
Applying `./Updates/mangos/541_corepatch_mangos_9613_to_9651.sql`.
Applying `./Updates/mangos/541_mangos_FIX_(9651).sql`.
Applying `./Updates/mangos/542_corepatch_mangos_9651_to_9690.sql`.
Applying `./Updates/mangos/542_mangos_FIX_(9690).sql`.
Applying `./Updates/mangos/543_corepatch_mangos_9690_to_9748.sql`.
Applying `./Updates/mangos/543_mangos_FIX_(9748).sql`.
Applying `./Updates/mangos/544_corepatch_mangos_9748_to_9773.sql`.
Applying `./Updates/mangos/544_mangos_FIX_(9773).sql`.
Applying `./Updates/mangos/545_corepatch_mangos_9773_to_9799.sql`.
Applying `./Updates/mangos/545_mangos_FIX_(9799).sql`.
Applying `./Updates/mangos/546_corepatch_mangos_9799_to_9839.sql`.
Applying `./Updates/mangos/546_mangos_FIX_(9839).sql`.
Applying `./Updates/mangos/547_corepatch_mangos_9839_to_9884.sql`.
Applying `./Updates/mangos/547_mangos_FIX_(9884).sql`.
Applying `./Updates/mangos/548_corepatch_mangos_9884_to_9934.sql`.
Applying `./Updates/mangos/548_mangos_FIX_(9934).sql`.
Done!

Updating `characters` database...
Applying `./Updates/characters/01_characters.sql`.
Done!

Updating `realmd` database...
Applying `./Updates/realmd/01_realmd.sql`.
Done!Тестирование успешно было проведено на "живом" сервере, работающим под управлением Debian Lenny 5.0, а также на локальных машинах под управлением Ubuntu, Arch Linux, OpenSUSE. Авось кому пригодится.