Всё работает на операционной системе:
# cat /etc/redhat-release CentOS release 6.5 (Final)
LDAP-сервер:
# yum list installed | grep openldap openldap.x86_64 2.4.23-34.el6_5.1 openldap-clients.x86_64 2.4.23-34.el6_5.1 openldap-servers.x86_64 2.4.23-34.el6_5.1
Сервер сконфигурирован на использование файла конфигурации slapd.conf
, а не базы cn=config
. Это имеет значение только для функции dirdel ()
, в которой задаётся переменная $dirtodel
.
В скрипте используется функция getopts()
, о которой подробнее можно почитать в статье BASH: функция getopts — используем опции в скриптах.
Так же — формирование списков резервных копий и имеющихся на сервере DIT выполняется с использованием индексированного массива, подробнее —BASH: использование массивов.
В целом про резервное копирование OpenLDAP можно почитать в статье OpenLDAP: резервное копирование и восстановление — утилиты slapcat / slapadd и ldapsearch / ldapadd.
#!/bin/bash bklog="/var/log/ldap_backup.log" bkdir="/backup" PATH="$PATH:/usr/sbin/" curdate=`date +%Y-%M-%d-%H:%M:%S` ardate=`echo $curdate | sed -e 's/:/_/g' -e 's/-/_/g'` slapconf="/etc/openldap/slapd.conf" function answer () { while read response; do echo case $response in [yY][eE][sS]|[yY]) return 0 break ;; [nN][oO]|[nN]) return 1 break ;; *) printf "Please, enter Y(yes) or N(no)! " esac done } slapstatus () { service slapd status && { echo -e "nSlapd running!nCan't proceed.n"; exit 1; } # used after backup completed to delete all files older then 30 days clean () { find $bkdir -type f -mtime +30 -exec rm -f $v {} ; } # get list of used Root DN's on server getnames () { ldapsearch -x -b '' -s base '(&)' namingContexts -LLL | cut -d" " -f 2 | grep -v "dn:" } # used in backup function, $setnames variable given inside loop when starting backup arname_f () { echo $setnames | sed -e 's/=/_/g' -e 's/,/_/g' } backup () { local arname=$(arname_f) local filename="$2"/"$3"_"$arname".ldif slapcat $v -b "$1" -l $filename && echo -e "Saved to file $filename." || exit 1 } # used for restore option to determine DN for restore and dirdel() function to delete files from dnselect () { declare -a names a=1 for i in $(getnames); do echo -e "n$a"")" $i names[$a]=$i (( a++ )) done echo read -p "Please select DN to restore: " selection if [ ! -z $selection ]; then echo -e "nWill restore: ${names[$selection]}.n" dntorestore=${names[$selection]} else echo -e "nThere is no number $selection!" exit fi } # this will delete unccessary files from DN's directory exclude file DB_CONFIG dirdel () { service slapd stop service slapd status && { echo -e "nSlapd running!nCan't proceed.n"; exit 1; } dirtodel=`cat $slapconf | grep -A3 "$1" | grep directory | awk '{print $2}'` echo -e "nAs your choice is $1, I'll remove directory: $dirtodel.n" cd $dirtodel echo -e "Ready to delete DB files.nnChecking current directory $PWD...n" if [ $PWD != $dirtodel ]; then echo -e "nERROR: wrong directory!n" exit 1 else echo -e "OK, directory correct - will remove all in "$dirtodel".n" echo -en "Are you sure to proceed? If "No" selected - I'll just exit: " answer && ls -1 | grep -v "^DB_CONFIG" | xargs rm -fv || exit 1 fi } # select file from which will run slapadd bkpSelect () { declare -a bkpnames a=1 echo -e "nCurrent backup files: " for i in `ls -1 $bkdir`; do echo -e "n$a"")" $i bkpnames[$a]=$i (( a++ )) done echo read -p "Please select archive to restore from: " arSelection if [ ! -z $arSelection ]; then echo -e "nWill restore $dntorestore from ${bkpnames[$arSelection]}.n" echo -en "Proceed? If "No" selected - I'll just exit: " answer || exit 1 bakName=${bkpnames[$arSelection]} else echo -e "nThere is no number $arSelection!" exit fi } restore () { slapadd $v -b "$1" -l "$2" && resResult=0 || resResult=1 chown -R ldap:ldap $dirtodel if [ $resResult = 0 ]; then service slapd start echo -e "nResore complited sucsessfully at $curdate.n" else echo -e "nError while restoring!n" exit 1 fi } usage () { cat << EOF Usage: $0 [ options ] This script can create and restore LDAP Databases by specified DN. Available options are: -h | (help) Show this help and exit; -b | (backup) Create ldif-files with backup of all DN's; -r | (restore) Restore database from ldif-file; -v | (verbose) Enable verbose mode. ATTENTION: when restoring DN - script will delete all data in DN's directory! All output writing to log-file /var/log/ldap_backup.log. EOF } # reset control variables backuprun= restorerun= v= while getopts "hbrv" opt; do case $opt in h) usage && exit 1 ;; b) backuprun=1 ;; r) restorerun=1 ;; v) v="-v" ;; *) usage && exit 1 ;; esac done if [ -z $1 ]; then usage && exit fi { if [[ $backuprun ]]; then echo -e "nStarting backup process at $curdaten" slapstatus; for setnames in $(getnames); do echo -e "Creating backup for $setnames...n" backup $setnames $bkdir $ardate && echo -e "Donen" || echo -e "Something going wrong!n" done echo -e "Deleteing old archives..." clean && echo -e "Deleted.n" echo -e "Backup process finished at $curdate.n" fi } 2>&1 | tee -a "$bklog" { if [[ $restorerun ]]; then echo -e "nStarting restore process at $curdate.n" slapstatus; dnselect; dirdel $dntorestore; bkpSelect; echo -e "Runnig slapadd process:" restore $dntorestore "$bkdir/$bakName"; fi } 2>&1 | tee -a "$bklog"
Примеры использования
Создание копий всех баз и удаление копий старше 30-ти дней:
# ./ldap_backup.sh -b Starting backup process at 2014-39-04-15:39:54 slapd is stopped Slapd stopped. I can't proceed without it. If "No" selected - I'll exit. Start it? (y/n) y Starting slapd: [ OK ] Creating backup for ou=db_1,dc=com... Saved to file /backup/2014_39_04_15_39_54_ou_db_1_dc_com.ldif. Done Creating backup for ou=db_1,dc=com... Saved to file /backup/2014_39_04_15_39_54_ou_db_1_dc_com.ldif. Done Deleting old archives... Deleted. Backup process finished at 2014-39-04-15:39:54.
Восстановление db_2
— удаление старых файлов базы, загрузка данных из файла резервной копии 2014_39_04_15_39_54_ou_db_2_dc_com.ldif
:
# ./ldap_backup.sh -r Starting restore process at 2014-40-04-15:40:48. slapd (pid 24008) is running... 1) ou=db_1,dc=com 2) ou=db_2,dc=com Please select DN to restore: 2 Will restore: ou=db_2,dc=com. Stopping slapd: [ OK ] slapd is stopped As your choice is ou=db_2,dc=com, I'll remove directory: /var/lib/ldap/db_2. Ready to delete DB files. Checking current directory /var/lib/ldap/db_2... OK, directory correct - will remove all in /var/lib/ldap/db_2. Are you sure to proceed? If "No" selected - I'll just exit: y removed `alock' removed `__db.001' removed `__db.002' removed `__db.003' removed `__db.004' removed `__db.005' removed `__db.006' removed `dn2id.bdb' removed `id2entry.bdb' removed `log.0000000001' Current backup files: 1) 2014_39_04_15_39_54_ou_db_1_dc_com.ldif 2) 2014_39_04_15_39_54_ou_db_2_dc_com.ldif Please select archive to restore from: 2 Will restore ou=db_2,dc=com from 2014_39_04_15_39_54_ou_db_2_dc_com.ldif. Proceed? If "No" selected - I'll just exit: y Runnig slapadd process: Starting slapd: [ OK ] Resore complited sucsessfully at 2014-40-04-15:40:48.
Добавляем скрипт в cron
на выполнение каждый день в 06:30 утра:
# crontab -l 30 6 * * * /opt/ldap_backup.sh -b
Проверяем:
# ls -lh /backup/ total 20M -rw-r--r-- 1 root root 314K Mar 5 06:30 2014_30_05_06_30_01_dc_auto1.ldif -rw-r--r-- 1 root root 378 Mar 5 06:30 2014_30_05_06_30_01_dc_auto2.ldif -rw-r--r-- 1 root root 378 Mar 5 06:30 2014_30_05_06_30_01_dc_auto3.ldif -rw-r--r-- 1 root root 9.5M Mar 5 06:30 2014_30_05_06_30_01_dc_db_2.ldif
Что можно (и нужно) улучшить:
1) добавить поддержку cn=config
;
2) сжимать ldif
-файлы бекапов в bz2
-архивы.
UPD
Для использования скрипта с cn=config
— необходимо изменить функцию dirdel ()
:
dirdel () { dirtodel=`ldapsearch -x -LLL -D 'cn=root,cn=config' -w superpuperpassword -b 'cn=config' '(&(olcDbDirectory=*)(olcSuffix='${1}'))' olcDbDirectory | grep "olcDbDirectory" | cut -d":" -f 2` echo -e "nAs your choice is $1, I'll remove directory: $dirtodel.n" service slapd stop service slapd status && { echo -e "nSlapd running!nCan't proceed.n"; exit 1; } cd $dirtodel echo -e "Ready to delete DB files.nnChecking current directory $PWD...n" if [ $PWD != $dirtodel ]; then echo -e "nERROR: wrong directory!n" exit 1 else echo -e "OK, directory correct - will remove all in "$dirtodel".n" echo -en "Are you sure to proceed? If "No" selected - I'll just exit: " answer && ls -1 | grep -v "^DB_CONFIG" | xargs rm -fv || exit 1 fi }