The following script solves the task of replicating a remote, ldap based, user and group database to a local ldap server. This approach is better than on-line ldap replication in scenarios where the local ldap server is behind a slow and unstable internet connection. The script utilizes extensive error reporting and emergency backups to keep everything in order under unexpected circumstances.
#!/bin/bash # GPLv3 by erno@rigo.info # log file placement LOG=/tmp/ldapmigrate.log # ldap database dir to backup and restore on emergency LDAPDIR=/var/lib/ldap # source ldap server MASTERHOST=ldap.example.com MASTERDN=dc=example,dc=com MASTERBIND=cn=admin,$MASTERDN MASTERPASS=********* # destination ldap server SLAVEHOST=localhost SLAVEDN=$MASTERDN SLAVEBIND=$MASTERBIND SLAVEPASS=$MASTERPASS # organizational units USERSOU=users GROUPSOU=groups ################ # do not touch bellow this line echo "+ $0 "`date "+%Y-%m-%d %H:%M:%S"`" starting..." | tee $LOG echo "+ logfile is at $LOG" | tee -a $LOG MASTERCONN="-h $MASTERHOST -D $MASTERBIND -x -w $MASTERPASS" SLAVECONN="-h $SLAVEHOST -D $SLAVEBIND -x -w $SLAVEPASS" do_delete() { echo "+ removing $1 (class $2) at $SLAVEHOST" | tee -a $LOG tmpfile=`mktemp` ldapsearch $SLAVECONN -LLL -b ou=$1,$MASTERDN "(objectClass=$2)" 'dn' 2>>$LOG | egrep "^dn" | cut -f2 -d':' > $tmpfile || return $? if [ -s $tmpfile ]; then ldapdelete -v $SLAVECONN -f $tmpfile >> $LOG 2>&1 || return $? count=`cat $tmpfile | wc -l` echo "+ successfully removed $count entries" | tee -a $LOG else echo "+ (no entries)" | tee -a $LOG fi rm -f $tmpfile } do_copy() { echo "+ copying $1 (class $2) from $MASTERHOST to $SLAVEHOST" | tee -a $LOG tmpfile=`mktemp` ldapsearch $MASTERCONN -b ou=$1,$MASTERDN "(objectClass=$2)" > $tmpfile 2>>$LOG || return $? if [ -s $tmpfile ]; then ldapmodify $SLAVECONN -a -f $tmpfile >> $LOG 2>&1 || return $? count=`cat $tmpfile | egrep "^dn:" | wc -l` echo "+ successfully copied $count entries" | tee -a $LOG else echo "+ (no entries)" | tee -a $LOG fi rm -f $tmpfile } do_migrate() { do_delete $1 $2 || return $? do_copy $1 $2 || return $? } try_migrate() { ( do_migrate $USERSOU posixAccount && do_migrate $GROUPSOU posixGroup ) || return $? } BACKUPDIR=`mktemp -d` do_backup() { echo "+ stoping slapd" | tee -a $LOG /etc/init.d/slapd stop >> $LOG 2>&1 || return $? echo "+ creating backup in $BACKUPDIR from $LDAPDIR" | tee -a $LOG cp -r $LDAPDIR/* $BACKUPDIR/ >> $LOG 2>&1 || return $? echo "+ starting slapd" | tee -a $LOG /etc/init.d/slapd start >> $LOG 2>&1 || return $? } do_restore() { echo "+ stoping slapd" | tee -a $LOG /etc/init.d/slapd stop >> $LOG 2>&1 || return $? echo "+ restoring backup from $BACKUPDIR to $LDAPDIR" | tee -a $LOG rm -rfv $LDAPDIR/* >> $LOG 2>&1 cp -r $BACKUPDIR/* $LDAPDIR/ >> $LOG 2>&1 || return $? chown -R openldap.openldap $LDAPDIR >> $LOG 2>&1 || return $? echo "+ starting slapd" | tee -a $LOG /etc/init.d/slapd start >> $LOG 2>&1 || return $? } do_cleanup() { echo "+ cleaning up backup directory $BACKUPDIR" | tee -a $LOG rm -rf $BACKUPDIR >> $LOG 2>&1 || return $? } ( do_backup && try_migrate && do_cleanup && echo "+ done and finishing successfully at "`date "+%Y-%m-%d %H:%M:%S"` ) || ( do_restore ; echo "+ FAILED! see: $LOG" ; exit -1 )