Всё работает на операционной системе:
# 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
}