#!/bin/bash
#
# Univention LDAP
#  test script
#
# Copyright 2004-2021 Univention GmbH
#
# https://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <https://www.gnu.org/licenses/>.

. /usr/share/univention-lib/base.sh

cat << End
Possible Tests:

 1  backup listener test
 2  primary notifier test
 3  direct ldap modification on backup
 4  listener-kill test
 5  notifier-kill test
 6  replica ldap/backup test
 7  univention-directory-replication-resync test
 8  ldapmodrdn-test
 9  replica listener backup slapd restart test

End

echo -e "Please enter all test you want to run [12345678]"
read choice
if [ -z "$choice" ]
then
	choice="12345678"
fi
n_tests=${#choice}

echo -e "\vHow many objects do you want me to create in each test [1]:"
read LIMIT
if [ -z "$LIMIT" ]
then
	LIMIT=1
fi

echo -e "\vname or ip of Backup Directory Node:"
read backup

echo -e "\vname or ip of Replica Directory Node:"
read replica

echo -e "\vroot password:"
stty -echo
read dc_pw
stty echo

let "total = $LIMIT * 6"
let "total = $total * $n_tests"
echo -e "\v##############################################################"
echo "# Note: Each test creates $LIMIT objects of each used module "
echo "#       Total number of objects = $total"
echo "#       The modules are:"
echo "#       users/user groups/group computers/ipmanagedclient"
echo "#       networks/network shares/printer shares/share"
echo "##############################################################"

# Last chance to exit
echo -e "\vWanna start now? (Ctrl+C to exit)"
read answer
echo "Starting ..."

# Setting variables and deleting old results
eval "$(univention-config-registry shell)"
echo $dc_pw > pw.tmp
cat /dev/null > result.txt
primary=$hostname
pw="pw.tmp"
pre=`date -u +%s`
suf=0
let "sync_time=$LIMIT * 6"
pause=`expr 30 + $sync_time`


#############  Functions ########################################
#
#

random_string ()
{
string1="`makepasswd --minchars=4 --maxchars=12 --string=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\"`"
string2="`makepasswd --minchars=4 --maxchars=12 --string=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\"`"
}



random_name () # create objectnames
{
	rand1="Object$pre$suf"
	suf=`expr $suf + 1`
	rand2=$rand1"#sub"
}

user () # create a users/user object
{
	groups_default_domainusers=$(custom_groupname "Domain Users")
	univention-admin "$module" create --set username="$rand1" --set lastname="$rand2" --set password=univention --set unixhome="/home/$rand1" --set primaryGroup="cn=$groups_default_domainusers,cn=groups,$ldap_base" --position="cn=users,$ldap_base"
}

group () # create a groups/group object
{
	univention-admin "$module" create --set name="$rand1" --position="cn=groups,$ldap_base"
}

computer () # create a computers/ipmanagedclient object
{
	univention-admin "$module" create --set name="$rand1" --set unixhome=/dev/null --set primaryGroup="cn=Computers,cn=groups,$ldap_base" --position="cn=computers,$ldap_base"
}

network () # create a networks/network object
{
	univention-admin "$module" create --set name="$rand1" --set network=192.168.0.0 --set netmask=255.255.255.0 --position="cn=networks,$ldap_base"
}

printer () # create a shares/printer object
{
	univention-admin "$module" create --set name="$rand1" --set spoolHost="$cups_server" --set uri="lp0://$rand1/" --set model="$rand2" --position="cn=printers,$ldap_base"
}

share () # create a shares/share object
{
	univention-admin "$module" create --set name="$rand1" --set host="$hostname.$domainname" --set path="/home/groups/$rand1/" --position="cn=shares,$ldap_base"
}


modrdn_objects ()
{
for module in "users/user" "groups/group" "computers/ipmanagedclient" "networks/network" "shares/printer" "shares/share"
do
	case "$module" in
		users/user) cn="users" ;;
		groups/group) cn="groups" ;;
		computers/ipmanagedclient) cn="computers" ;;
		networks/network) cn="networks" ;;
		shares/printer) cn="printers" ;;
		shares/share) cn="shares" ;;
		*);;
	esac
	count=0
	for dn in $(ldapsearch -x -ZZ -D "$ldap_hostdn" -y /etc/machine.secret -b cn="$cn,$ldap_base" -s one | sed -ne '/Object/s/^dn: //p')
	do
		rdn=`echo $dn |awk -F , '{print $1}' |awk -F = '{print $1}'`
		random_string
		echo "Changing $dn to $rdn=Object$string1"
		ldapmodrdn -x -D "cn=admin,$ldap_base" -w "$(cat /etc/ldap.secret)" "$dn" "$rdn=Object$string1"
		echo "Changing $rdn=Object$string1 to $rdn=Objectxxx$string2 (using argument -r )"
		ldapmodrdn -x -D "cn=admin,$ldap_base" -w "$(cat /etc/ldap.secret)" -r "$rdn=Object$string1,cn=$cn,$ldap_base" "$rdn=Objectxxx$string2"
		count=`expr $count + 1`
		if [ "$count" -eq "$LIMIT" ]
		then
			break
		fi
	done
done
}


create_objects () # create $LIMIT of every function above
{
echo -e "\v===> create $LIMIT objects of each module"
echo "===> users/user groups/group computers/ipmanagedclient networks/network shares/printer shares/share"
for module in "users/user" "groups/group" "computers/ipmanagedclient" "networks/network" "shares/printer" "shares/share"
do
	for ((a=1; a <= LIMIT ; a++))
	do
		random_name
		echo -e "\n-->Adding $module ($a of $LIMIT)..."
		case "$module" in
			users/user) user ;;
			groups/group) group ;;
			computers/ipmanagedclient) computer ;;
			networks/network) network ;;
			shares/printer) printer ;;
			shares/share) share ;;
			*) echo "Module $module not defined in TestScript..." ;;
		esac
	done
done
}

create_ldif () # creates a ldif-file and the same objects on primary
{
touch backup.ldif
touch primary.tmp
echo -e "\v===> create ldif-file for backup-manipulation"
for dn in $(ldapsearch -x -ZZ -D "$ldap_hostdn" -y /etc/machine.secret -b "cn=users,$ldap_base" -s one | sed -ne '/Object/s/^dn: //p')
do
	echo -e "dn: $dn\nchangetype: modify\nreplace: homeDirectory\nhomeDirectory: /dev/null\n" >> backup.ldif
	echo -e "$dn" >> primary.tmp
done
}

compare () # compares two ldap_dump-files using diff
{
echo -e "\v===> comparing $rmhost and $rmhost2"
if [ "$rmhost" == "$replica" ]
then
	univention-scp -timeout 60 "$pw" /etc/ldap.secret "root@$rmhost:/etc/"
elif [ "$rmhost2" == "$replica" ]
then
	univention-scp -timeout 60 "$pw" /etc/ldap.secret "root@$rmhost2:/etc/"
fi

cmd="for module in users/user groups/group computers/ipmanagedclient networks/network shares/printer shares/share; do univention-admin "$module" list >> /tmp/ldap_dump_$rmhost.tmp; done"
#cmd="ldapsearch -x -b $ldap_base > /tmp/ldap_dump_$rmhost.tmp"
univention-ssh -timeout 60 "$pw" "root@$rmhost" $cmd
univention-scp -timeout 60 "$pw" "root@$rmhost:/tmp/ldap_dump_$rmhost.tmp" /tmp/

cmd="for module in users/user groups/group computers/ipmanagedclient networks/network shares/printer shares/share; do univention-admin "$module" list >> /tmp/ldap_dump_$rmhost2.tmp; done"
#cmd="ldapsearch -x -b $ldap_base > /tmp/ldap_dump_$rmhost2.tmp"
univention-ssh -timeout 60 "$pw" "root@$rmhost2" $cmd
univention-scp -timeout 60 "$pw" "root@$rmhost2:/tmp/ldap_dump_$rmhost2.tmp" /tmp/
echo -e "\v ###### $test " >> result.txt
echo -e "diff /tmp/ldap_dump_$rmhost.tmp /tmp/ldap_dump_$rmhost2.tmp :\v" >> result.txt
diff "/tmp/ldap_dump_$rmhost.tmp" "/tmp/ldap_dump_$rmhost2.tmp" >> result.txt
cmd="rm /tmp/ldap_dump*"
echo -e "\v===> deleting temp-files"
univention-ssh -timeout 60 "$pw" "root@$rmhost" $cmd &> /dev/null
univention-ssh -timeout 60 "$pw" "root@$rmhost2" $cmd &> /dev/null

if [ "$rmhost" == "$replica" ]
then
	univention-ssh -timeout 60 "$pw" "root@$rmhost" "rm /etc/ldap.secret"
elif [ "$rmhost2" == "$replica" ]
then
	univention-ssh -timeout 60 "$pw" "root@$rmhost2" "rm /etc/ldap.secret"
fi

}

wait_for () # beautiful sleep-output-function ;o)
{
echo -e "\v===> waiting for $pause seconds"
for ((a=1; a <= pause; a++))
do
printf "\b\b\b\b\b\b\b $a"
sleep 1
done
printf "\b\b\b\b\b\b\b       \n"

}

stop () # stopping daemon on remote host using init-script
{
echo -e "\v===> stopping $what on $where"
cmd="/etc/init.d/$what stop"
univention-ssh -timeout 60 "$pw" "root@$where" $cmd
}

start () # starting daemon on remote host using init-script
{
echo -e "\v===> starting $what on $where"
cmd="/etc/init.d/$what start"
univention-ssh -timeout 60 "$pw" "root@$where" $cmd
}

reset ()
{
echo -e "\v ------ resetting all needed daemon  ------"

cmd="systemctl start univention-directory-listener"
echo -e "\v===>primary:"
univention-ssh -timeout 60 "$pw" "root@$primary" $cmd
echo -e "\v===>backup:"
univention-ssh -timeout 60 "$pw" "root@$backup" $cmd
echo -e "\v===>replica:"
univention-ssh -timeout 60 "$pw" "root@$replica" $cmd

cmd="systemctl start univention-directory-notifier"
echo -e "\v===>primary:"
univention-ssh -timeout 60 "$pw" "root@$primary" $cmd
echo -e "\v===>backup:"
univention-ssh -timeout 60 "$pw" "root@$backup" $cmd

cmd="/etc/init.d/slapd start"
echo -e "\v===>primary"
univention-ssh -timeout 60 "$pw" "root@$primary" $cmd
echo -e "\v===>backup"
univention-ssh -timeout 60 "$pw" "root@$backup" $cmd
echo -e "\v===>replica"
univention-ssh -timeout 60 "$pw" "root@$replica" $cmd
}

check_failed () # check for replication failed.ldif
{
echo -e "------ checking for failed.ldiff ------"
cmd="/usr/bin/test -e /var/lib/univention-directory-replication/failed.ldif"
univention-scp -timeout 60 "$pw" "root@$where:/var/lib/univention-directory-replication/failed.ldif" . >/dev/null 2>&1

if [ -e failed.ldif ] ; then
	echo "failed.ldif exists on $where"
	echo "failed.ldif exists on $where" >> result.txt
	rm failed.ldif
fi

}

get_id () # get notifier id
{
echo -e "------ getting notifier id from $where ------"
cmd="cat /var/lib/univention-directory-listener/notifier_id"
notifier_id=$(univention-ssh -timeout 60 "$pw" "root@where" $cmd)
echo "notifier_id: $notifier_id"
}

compare_ids ()
{
	if [ $last_id != $notifier_id ] ; then
		check_failed
	 else
		get_id
		pause=5
		wait_for
		compare_ids
	fi
}

config_replicalistener () # config listener to connect first on $con_to
{
	eval "$(univention-config-registry shell)"

	replica="$where"
	replica_hostdn=$(univention-admin computers/domaincontroller_slave list --filter cn="$replica" | sed -ne 's/^DN: //p')

	backup="$con_to.$domainname"
	echo '#!/bin/sh -e' > /tmp/listener-run0
	echo "" >> /tmp/listener-run0
	echo "exec /usr/sbin/univention-directory-listener -h '$backup' -F -b '$ldap_base' -m '/usr/lib/univention-directory-listener/system' -c '/var/lib/univention-directory-listener' -o -x -ZZ -D '$replica_hostdn' -y /etc/machine.secret >>/var/log/univention/listener.log 2>&1" >> /tmp/listener-run0

	univention-scp -timeout 60 "$pw" /tmp/listener-run0 "root@$where:/etc/runit/univention-directory-listener/run"
	rm /tmp/listener-run0
}

defconfig_replicalistener ()
{
	cmd="univention-config-registry commit /etc/runit/univention-directory-listener/run"
	univention-ssh -timeout 60 "$pw" "root@$where" $cmd
}

#####################  Tests ###############################
#
#

reset

#test="compare primary and backup before starting test "
#rmhost=$backup
#rmhost2=$primary
#compare

#test="compare primary and backup before starting test "
#rmhost=$replica
#rmhost2=$primary
#compare

run=`echo $choice |grep 1`
if [ -n "$run" ]
then
test="**********  backup listener test **********"
echo -e "\v$test"
###################################################################
#
# stop backup-listener / create objects / start backup-listener /
# compare ldap_dump
#
###################################################################
	rmhost=$backup
	rmhost2=$primary

	what="univention-directory-listener"
	where=$backup
	stop

	create_objects

	start

	wait_for

	compare


	# reset
fi

run=`echo $choice |grep 2`
if [ -n "$run" ]
then
test="**********  primary notifier test **********"
	echo -e "\v$test"
###################################################################
#
# stop primary-notifier / create objects / start primary-notifier /
# compare ldap_dump
#
###################################################################
	rmhost=$backup
	rmhost2=$primary

	what="univention-directory-notifier"
	where=$primary
	stop

	create_objects

	start

	wait_for

	compare

	# reset
fi

run=`echo $choice |grep 3`
if [ -n "$run" ]
then
test="**********  direct ldap modification on backup **********"
echo -e "\v$test"
###################################################################
#
# stop backup-listener / change objects using ldapadd on backup /
# change same on primary / start backup-listener / compare ldap_dump
#
###################################################################
	rmhost=$backup
	rmhost2=$primary

	create_objects

	what="univention-directory-listener"
	where=$rmhost
	stop

	create_ldif

	echo -e "\v===> copy ldif to $rmhost"
	univention-scp -timeout 60 "$pw" backup.ldif "root@$rmhost:~/"

	echo -e "\v===> get ldap-rootpw from $rmhost"
	univention-scp -timeout 60 "$pw" "root@$rmhost:/etc/ldap/rootpw.conf" .
	rootpw=`cat rootpw.conf |awk '{print $2}' |perl -pi -e 's/\"/ /g'`
	echo -e "===> sounds like: $rootpw"
	rm rootpw.conf

	echo -e "\v===> using ldif on $rmhost"
	cmd="ldapmodify -x -D 'cn=update,$ldap_base' -w '$rootpw' -f backup.ldif"
	univention-ssh -timeout 60 "$pw" "root@$rmhost" $cmd

	echo -e "\v===> using ldif on primary"
	for dn in `cat primary.tmp`
	do
		univention-admin users/user modify --dn "$dn" --set unixhome=/home/groups
	done

	start

	wait_for

	compare

	# reset
fi

run=`echo $choice |grep 4`
if [ -n "$run" ]
then
test="**********  listener-kill test **********"
echo -e "\v$test"
###################################################################
#
# kill listener / create objects / start killing/create-loop /
# compare ldap_dump
#
###################################################################
	rmhost=$backup
	rmhost2=$primary

	echo -e "\v===> killing backup listener"
	cmd="killall -9 univention-directory-listener"
	univention-ssh -timeout 60 "$pw" "root@$backup" $cmd

	create_objects

	echo -e "\v\v===> starting killing-loop"
	for module in "users/user" "groups/group" "computers/ipmanagedclient" "networks/network" "shares/printer" "shares/share"
	do
		for ((a=1; a <= LIMIT; a++))
		do
			random_name
			echo -e "\v\v===> killing primary listener"
			cmd="killall -9 univention-directory-listener"
			univention-ssh -timeout 60 "$pw" "root@$backup" $cmd 2> /dev/null
			case "$module" in
				users/user)user;;
				groups/group)group;;
				computers/ipmanagedclient)computer;;
				networks/network)network;;
				shares/printer)printer;;
				shares/share)share;;
				*);;
			esac
		done
	done

	wait_for

	compare

	# reset
fi

run=`echo $choice |grep 5`
if [ -n "$run" ]
then
test="**********  notifier-kill test **********"
echo -e "\v$test"
###################################################################
#
# kill primary-notifier / create objects / start killing/create-loop /
# compare ldap_dump
#
###################################################################
	rmhost=$backup
	rmhost2=$primary

	echo -e "\v===> killing backup listener"
	cmd="killall -9 univention-directory-listener"
	univention-ssh -timeout 60 "$pw" "root@$backup" $cmd

	create_objects

	echo -e "\v\v===> starting killing-loop"
	for module in "users/user" "groups/group" "computers/ipmanagedclient" "networks/network" "shares/printer" "shares/share"
	do
		for ((a=1; a <= LIMIT; a++))
		do
			random_name
			echo -e "\v\v===> killing primary notifier"
			cmd="killall -9 univention-directory-notifier"
			univention-ssh -timeout 60 "$pw" "root@$primary" $cmd 2> /dev/null
			case "$module" in
				users/user)user;;
				groups/group)group;;
				computers/ipmanagedclient)computer;;
				networks/network)network;;
				shares/printer)printer;;
				shares/share)share;;
				*);;
			esac
		done
	done
	wait_for
	compare

	# reset
fi

run=`echo $choice |grep 6`
if [ -n "$run" ]
then
test="**********  replica ldap/backup test **********"
echo -e "\v$test"
###################################################################
#
# stop replica-listener / create objects / stop primary-notifier /
# start replica-listener / compare ldap_dump / stop replica-listener /
# start primary-notifier / create objects / stop backup-notifier /
# start replica-listener / compare ldap_dump / start backup-notifier
#
###################################################################
	what=univention-directory-listener
	where=$replica
	stop

	create_objects

	what=univention-directory-notifier
	where=$primary
	stop

	what=univention-directory-listener
	where=$replica
	start

	wait_for

	rmhost=$replica
	rmhost2=$primary
	compare

	stop

	what=univention-directory-notifier
	where=$primary
	start

	create_objects

	what=univention-directory-notifier
	where=$backup
	stop

	what=univention-directory-listener
	where=$replica
	start

	wait_for

	rmhost=$replica
	rmhost2=$primary
	compare

	what=univention-directory-notifier
	where=$backup
	start


	# reset

fi

run=`echo $choice |grep 7`
if [ -n "$run" ]
then
test="**********  univention-directory-replication-resync test **********"
echo -e "\v$test"
###################################################################
#
# stop backup-slapd / create objects / start backup-slapd /
# execute univention-directory-replication / compare ldap_dump
#
###################################################################
	what=slapd
	where=$backup
	stop

	wait_for

	create_objects

	what=slapd
	where=$backup
	start

	pause=10
	wait_for

	echo -e "\v===> execute univention-directory-replication-resync on backup"
	cmd="univention-directory-replication-resync /var/lib/univention-directory-replication/failed.ldif"
	univention-ssh -timeout 360 "$pw" "root@$replica" $cmd

	pause=`expr 30 + $sync_time`
	wait_for

	rmhost=$backup
	rmhost2=$primary
	compare

	# reset
fi


run=`echo $choice |grep 8`
if [ -n "$run" ]
then
test="**********  ldapmodrdn test **********"
echo -e "\v$test"
###################################################################
#
# stop backup-listener / change objects using ldapmodrdn /
# start backup-listener / compare ldap_dump
#
###################################################################
        what=univention-directory-listener
        where=$backup
        stop

	create_objects

	modrdn_objects

	start

        pause=`expr 30 + $sync_time`
        wait_for

        rmhost=$backup
        rmhost2=$primary
        compare

        # reset
fi

run=`echo $choice |grep 9`
if [ -n "$run" ]
then
test="********** replica listener backup slapd restart test  **********"
echo -e "\v$test"
echo -e "\v ###### $test " >> result.txt
###################################################################
#
# stop replica listener / create objects / start replica listener/
# restart backup slapd / check for failed.ldiff
#
###################################################################
		what=univention-directory-listener
		where=$replica
		stop
		con_to=$backup
		config_replicalistener
		create_objects
		start

		what=slapd
		where=$backup
		stop
		start

		where=$replica
		compare_ids
		what=univention-directory-listener
		where=$replica
		stop
		defconfig_replicalistener
		start
fi

echo -e "\v\v**********  The Results **********"
#cat result.txt
echo -e "\v Results saved in result.txt"

echo -e "\v**********  removing temp-files **********"
cmd="if [ -e backup.ldif ] ; then rm backup.ldif ; fi"
univention-ssh -timeout 60 "$pw" "root@$backup" $cmd
if [ -e "backup.ldif" ] ; then rm backup.ldif ; fi
if [ -e "primary.tmp" ] ; then rm primary.tmp ; fi
if [ -e "pw.tmp" ] ; then rm pw.tmp ; fi
#if [ -e "modrdn.tmp" ] ; then rm modrdn.tmp ; fi

echo -e "\v\v**********  Remove created objects **********"
echo -e "\vDo you want to delete all $total created objects? [Crt-C for \"No\"]"
read answer
echo "Removing all created objects..."
for module in "users/user" "groups/group" "computers/ipmanagedclient" "networks/network" "shares/printer" "shares/share"
do
	case "$module" in
		users/user)cn="cn=users";;
		groups/group)cn="cn=groups";;
		computers/ipmanagedclient)cn="cn=computers";;
		networks/network)cn="cn=networks";;
		shares/printer)cn="cn=printers";;
		shares/share)cn="cn=shares";;
		*)cn="cn=NotValidCN$pre";;
	esac

	for dn in $(ldapsearch -x -ZZ -D "$ldap_hostdn" -y /etc/machine.secret -b "$cn,$ldap_base" -s one | sed -ne '/Object/s/^dn: //p')
	do
		univention-admin "$module" remove --dn "$dn"
	done
done

echo -e "\v\v********** FINISH **********\v"
exit 0
