У Oracle для его баз данных имеется замечательный инструмент Flashback. Его задача – восстанавливать базу до определённого состояния.
Подобное потребовалось сделать и для LDAP-баз при выполнении автотестов.
Решение очень простое, в основном потому, что:
а) имена DIT совпадают с определёнными переменными, которые присвоены каждому из BuildAgent-ов TeamCIty;
б) пароли для доступа к базам – такие же, как и имена баз, так что не о какой безопасности речи нет (всё работает в ограниченной сети).
Список DIT-ов выглядит так:
namingContexts: dc=autobuild1 namingContexts: dc=autobuild2 namingContexts: dc=autobuild3
И в каждом каталоге – две ветки:
dn: ou=Users,dc=autobuild1 dn: ou=Groups,dc=autobuild1
В которых соответственно находятся записи «нижнего» уровня:
dn: uid=0,ou=Users,dc=autobuild1 dn: uid=1,ou=Users,dc=autobuild1
Собственно – сам скрипт:
#!/bin/bash curdate=`date +%Y-%M-%d-%H:%M:%S` log="/var/log/ldap_rollback.log" { # обработка результатов команд в функциях resOk () { echo -e "$1" } resEr () { echo -e "$1" exit 1 } # проверяем наличие 1-го аргумента скрипту при вызове [[ $1 ]] || resEr "nERROR! Must be call with ENV variables as argument.n" # список допустимых аргументов, что бы не затереть "левую" базу names="AUTOBUILD1, AUTOBUILD2, AUTOBUILD3" checknames () { echo "$names" | grep "$1" } # если переданный скрипту аргумент не найден - пишем об ошибке и выходим checknames $1 2>&1 > /dev/null || resEr "nERROR! I don't know what environment is "$1". Exit.n" # переменная ENV на билд-агентах задаётся ЗАГЛАВНЫМИ, поэтому - переводим её в строчные dn="dc=${1,,}" # формируем пароль, вырезая dc= и оставляя только имя переменной строчными буквами pw=`echo $dn | cut -d"=" -f 2` # userfile и groupfile - файлы-шаблоны для баз userfile="/home/auto/ldifs/Users.ldif" groupfile="/home/auto/ldifs/Groups.ldif" # а это временные файлы, которые создаются функцией chNames t_userfile="/tmp/Users_$dn.ldif" t_groupfile="/tmp/Groups_$dn.ldif" # проверяем наличие файлов-шаблонов if [ ! -e $userfile ] && [ ! -e $groupfile ]; then echo -e "nERROR: there is no file $userfile or $groupfile!n" exit 1 fi echo -e "nStarting rollback at $curdate with DN $dnn" # в файлах-шаблонах dc=CHANGEME, меняем его на переменную $dn полученную из аргумента самому скрипту chNames () { echo -e "nPreparing temporary files...n" sed 's/dc=CHANGEME/'${1}'/g' $userfile > $t_userfile && resOk "File $t_userfile ready..." || resEr "nCan't create file $t_userfile!n" sed 's/dc=CHANGEME/'${1}'/g' $groupfile > $t_groupfile && resOk "File $t_groupfile ready..." || resEr "nCan't create file $t_groupfile!n" } chNames $dn # удаляем старые записи из базы delEntries () { echo -e "nDeleting old entries in $dn...n" ldapdelete -v -D "cn=root,$1" -w$pw -r "ou=Users,$1" && resOk "nou=Users,$1 deleted;" || resEr "nCan't delete ou=Users,$1!n" ldapdelete -v -D "cn=root,$1" -w$pw -r "ou=Groups,$1" && resOk "nou=Groups,$1 deleted;" || resEr "nCan't delete ou=Groups,$1!n" } delEntries $dn # заполняем базу из временных файлов addEntries () { echo -e "nAdding new entries...n" ldapadd -x -D "cn=root,$1" -w$pw -f $t_userfile && resOk "nUsers added.n" || resEr "nCan't add ou=Users,$1!n" ldapadd -x -D "cn=root,$1" -w$pw -f $t_groupfile && resOk "Groups added.n" || resEr "nCan't add ou=Groups,$1!n" } addEntries $dn # удаляем временные файлы echo -e "Deleting temporary files..." rm $t_userfile && echo -e "n$t_userfile deleted;" || echo -e "nCan't delete $t_userfile!n" rm $t_groupfile && echo -e "n$t_groupfile deleted.n" || echo -e "nCan't delete $t_groupfile!n" echo -e "Roll-back finihsed at $curdate.n" # и пишем всё в лог-файл для истории } | 2>&1 tee -a $log
Далее, в проекте билда на TeamCity добавляется задача на запуск batch
-скритпа с BuildAgent-а (или можно его выполнять задачей из Maven) с одной строкой:
plink -batch -agent -l auto ldapserver.com ". /home/auto/ldap/ldap_rollback.sh %ENV%"
При этом plink
подключается с помощью ключа авторизации, загруженного в Pageant (см. Putty: настройка авторизации SSH по ключу).