#! /bin/sh
# Copyright (c) 2007, Novell Inc.
#
# Author: adrian@suse.de
#
# /etc/init.d/obsworker
#   and its symbolic  link
# /usr/sbin/rcobsworker
#
### BEGIN INIT INFO
# Provides:          obsworker
# Required-Start:    $time $network $syslog
# Required-Stop:     $time $network $syslog
# Should-Start:      $remote_fs
# Default-Start:     3 5
# Default-Stop:      0 1 2 4 6
# Description:       openSUSE build service worker
### END INIT INFO

. /etc/rc.status

. /etc/sysconfig/obs-worker

# Determine the base and follow a runlevel link name.
base=${0##*/}
link=${base#*[SK][0-9][0-9]}

if [ -z "$OBS_RUN_DIR" ]; then
	OBS_RUN_DIR="/var/run/obs"
fi
if [ -z "$OBS_LOG_DIR" ]; then
	OBS_LOG_DIR="/var/log/obs"
fi
if [ -z "$OBS_REPO_SERVERS" ]; then
	OBS_REPO_SERVERS="localhost:6262"
fi
if [ -z "$OBS_SRC_SERVER" ]; then
	OBS_SRC_SERVER="localhost:6362"
fi

if [ -n "$OBS_USE_SLP" ]; then
	OBS_SRC_PARM=`slptool findsrvs service:obs.source_server | sed -n 's/service:obs.source_server:\([^,]*\),.*/--srcserver \1/p' | head -n 1`
	for i in `slptool findsrvs service:obs.repo_server | sed -n 's/service:obs.repo_server:\([^,]*\),.*/\1/p'`; do
           OBS_REPO_PARM="$OBS_REPO_PARM --reposerver $i"
        done
fi
if [ -n "$OBS_WORKER_TEST_MODE" ]; then
       OBS_TEST="--test"
fi
if [ -n "$OBS_WORKER_JOBS" ]; then
       OBS_JOBS="--jobs $OBS_WORKER_JOBS"
fi

if [ -z "$OBS_SRC_PARM" ]; then
       OBS_SRC_PARM="--srcserver http://$OBS_SRC_SERVER"
fi
if [ -z "$OBS_REPO_PARM" ]; then
	for i in $OBS_REPO_SERVERS; do
           if [ -z "$OBS_WORKER_PARM" ]; then
                 OBS_WORKER_PARM="http://$i"
           fi
           OBS_REPO_PARM="$OBS_REPO_PARM --reposerver http://$i"
        done
fi

obsrundir="$OBS_RUN_DIR"
workerdir="$obsrundir"/worker
workerbootdir="$workerdir"/boot
screenrc="$workerdir"/boot/screenrc
obsopt=""
OBS_WORKER_OPT=""

if [ -n "$OBS_CACHE_DIR" ]; then
   OBS_WORKER_OPT="--cachedir $OBS_CACHE_DIR"
fi

if [ -n "$OBS_CACHE_SIZE" ]; then
   if [ -z "$OBS_CACHE_DIR" ]; then
        OBS_CACHE_DIR="/tmp/workercache"
        OBS_WORKER_OPT="--cachedir $OBS_CACHE_DIR"
   fi
   mkdir -p $OBS_CACHE_DIR
   OBS_WORKER_OPT="$OBS_WORKER_OPT --cachesize $OBS_CACHE_SIZE "
fi

if [ -z "$OBS_WORKER_USE_LVM" ]; then
	OBS_WORKER_USE_LVM="no"
fi

if [ -f /etc/buildhost.config ];then
	. /etc/buildhost.config
	obsopt=--xen
fi

if [ -f /etc/kvmbuildhost.config ]; then
	. /etc/kvmbuildhost.config
	obsopt=--kvm
fi

rc_reset
case "$1" in
    start)
		# reset screenrc
                mkdir -p "$obsrundir"
                chown obsrun:obsrun "$obsrundir"
		rm -rf "$workerdir"
		mkdir -p "$workerbootdir"
		#echo "zombie on"       > $screenrc
		echo "caption always" >> $screenrc

		if [ "$OBS_WORKER_INSTANCES" -gt 0 ]; then
			NUM="$OBS_WORKER_INSTANCES"
		else
			# define hostsystem memory
			case "$(lsb_release -r | awk '{print $NF}')" in
				11)
					HOSTMEM=1572864
				;;
				12.3)
					HOSTMEM=1835008
				;;
				13.1)
					HOSTMEM=2097152
				;;
				*)
					HOSTMEM=2097152
				;;
			esac
			# start one build backend per CPU
			NUM=`grep ^processor /proc/cpuinfo  | wc -l`
			# get total system memory and check if there is enough space for running
			# CPUCOUNT * XENMEM + RAMDDISK Workers
			MEM=$(cat /proc/meminfo | grep ^MemTotal: | awk -v NUM=${NUM} -v XENMEM=${XEN_MEMX} -v HM=${HOSTMEM} '{print $2 - (XENMEM * 1024*NUM+HM) }')
			if [ -n "${MEM}" ] ; then
				until [ ${MEM} -gt 0 ] ; do
					NUM=`expr ${NUM} - 1`
					MEM=$(cat /proc/meminfo | grep ^MemTotal: | awk -v NUM=${NUM} -v XENMEM=${XEN_MEMX} -v HM=${HOSTMEM} '{print $2 - (XENMEM * 1024*NUM+HM) }')
				done
			fi
			#if [ "${NUM}" -gt 1 ] ; then
			#	NUM=`echo ${NUM} | awk '{print $1 * 1.5 }'`
			#fi
		fi
		I=0
		ROOT="/tmp"
		[ -d /BUILD ] && ROOT="/BUILD"
		[ -d /abuild ] && ROOT="/abuild"
		[ -n "$OBS_WORKER_DIRECTORY" ] && ROOT="$OBS_WORKER_DIRECTORY"
		echo "Run $NUM obsworker using $ROOT"

                pvs=( `vgdisplay -v abuild 2>/dev/null | grep "PV Name" | awk '{ print $3 }'` )
                pv_idx=0                                                                       
                pv_count=${#pvs[@]}                                                            
                pv_count=$(( ($pv_count / 2) * 2 )) # be sure that we have an equal number     
                o1=0                                                                           
                o2=1

		# fetch worker sources from server
		pushd "$workerbootdir"
		curl -q "${OBS_WORKER_PARM}"/getworkercode | cpio --extract
		ln -s . XML 
		chmod 755 bs_worker
		popd
		
		# cleanup stale LVs / loops and setup cache/base volumes
		if [ "$OBS_WORKER_USE_LVM" == "yes" ] ; then
			lvremove -f abuild
			OBS_CACHE_LV_SIZE=$((${OBS_CACHE_SIZE} + 500))
			lvm lvcreate -n cache -L ${OBS_CACHE_LV_SIZE}M abuild
			OBS_BASE_LV_SIZE=$((((${OBS_CACHE_SIZE} + 500)) * 2))
			lvm lvcreate -n base -L ${OBS_BASE_LV_SIZE}M abuild

			if [ -n "`grep ^xfs /proc/modules`" ] ; then
				mkfs.xfs -q -f /dev/abuild/cache
				mkdir -p ${OBS_CACHE_DIR}
				mount -t xfs /dev/abuild/cache ${OBS_CACHE_DIR}

				mkfs.xfs -q -f /dev/abuild/base
				mkdir -p ${OBS_WORKER_DIRECTORY}
				mount -t xfs /dev/abuild/base ${OBS_WORKER_DIRECTORY}
			elif [ -n "`grep ^ext4 /proc/modules`" ] ; then
				mkfs.ext4 -q /dev/abuild/cache
				mkdir -p ${OBS_CACHE_DIR}
				mount -t ext4 /dev/abuild/cache ${OBS_CACHE_DIR}

				mkfs.ext4 -q /dev/abuild/base
				mkdir -p ${OBS_WORKER_DIRECTORY}
				mount -t ext4 /dev/abuild/base ${OBS_WORKER_DIRECTORY}
			else
				mkfs.ext3 -q /dev/abuild/cache
                                mkdir -p ${OBS_CACHE_DIR}
                                mount -t ext3 /dev/abuild/cache ${OBS_CACHE_DIR}

                                mkfs.ext3 -q /dev/abuild/base
                                mkdir -p ${OBS_WORKER_DIRECTORY}
                                mount -t ext3 /dev/abuild/base ${OBS_WORKER_DIRECTORY}
			fi

		else
			for a in `losetup -a|awk -F: '{print $1}'` ; do losetup -d $a ; done
		fi
		# create initrd for xen guests
		if [ ! -f /boot/initrd ] ; then
			mkinitrd -d /
			if [ "$obsopt" == "--xen" ] ; then
			ln -sf /boot/initrd-xen /boot/initrd
			fi
			if [ "$obsopt" == "--kvm" ] ; then
			ln -sf /boot/initrd-`uname -r` /boot/initrd
			fi
		fi
		while test "$NUM" -gt "$I"; do
			if [ "$OBS_WORKER_PORTBASE" -gt 0 ]; then
				port="--port $((OBS_WORKER_PORTBASE + I))"
			else
				port=""
			fi
			I=$(( $I + 1 ))
			title="$HOSTNAME/$I"
                        mkdir $workerdir/$I
			# prepare xen build setup...
			# requires the file /etc/buildhost.config which contains
			# the following variables:
			# ---
			# XEN_ROOT=[n]
			# XEN_SWAP=[n]
			# XEN_MEMX=[n]
			# ---
			if [ -d $ROOT/root_$I ];then
				rm -rf $ROOT/root_$I
			else
				mkdir -p $ROOT/root_$I
			fi
			if [ ! -z $obsopt ];then
				if [ "$OBS_WORKER_USE_LVM" == "yes" ] ; then
					xen_opts="--device /dev/abuild/${I}_root --swap /dev/abuild/${I}_swap --vm-memory $XEN_MEMX"
					lvdisplay abuild >& /dev/null || exit
					lvm lvcreate -n ${I}_root -L ${XEN_ROOT}M abuild ${pvs[$(( $pv_idx + $o1 ))]} || exit
					lvm lvcreate -n ${I}_swap -L ${XEN_SWAP}M abuild ${pvs[$(( $pv_idx + $o2 ))]} || exit
					pv_idx=$(( $pv_idx + 2 ))
					if [ $pv_idx -ge $pv_count ]; then
						pv_idx=0
						# swap offset, so that swap and root partitions are not on same device
						a=$o1
						o1=$o2
						o2=$a
					fi
				else
					xen_opts="--device $ROOT/root_$I/root --swap $ROOT/root_$I/swap --vm-memory $XEN_MEMX"
					dd if=/dev/zero of=$ROOT/root_$I/root bs=1M seek=$XEN_ROOT count=1
					dd if=/dev/zero of=$ROOT/root_$I/swap bs=1M seek=$XEN_SWAP count=1
					echo $XEN_MEMX > $ROOT/root_$I/memory
				fi
			fi
			kernelparam=""
			if [ -f /.build.initrd.kvm ] ; then
				kernelparam="$kernelparam --vm-initrd /.build.initrd.kvm"
			fi
			if [ -f /.build.kernel.kvm ] ; then
				kernelparam="$kernelparam --vm-kernel /.build.kernel.kvm"
			fi
			# prepare obsworker startup in screen...
			echo "screen -t $title ./bs_worker $kernelparam $obsopt $xen_opts $port --root $ROOT/root_$I" \
				"--statedir $workerdir/$I --id $HOSTNAME/$I $OBS_REPO_PARM" \
				"$OBS_JOBS $OBS_TEST $OBS_SRC_PARM $OBS_WORKER_OPT" \
				>> $screenrc
		done
		pushd "$workerbootdir"
		screen -m -d -c $screenrc
		popd
	;;
	stop)
		echo -n "Shutting down obsworker"
		ps axu|grep obsworker|grep -i screen| awk '{print "kill -9 "$2}'|sh
		killall bs_worker
		umount ${OBS_CACHE_DIR}
		umount ${OBS_WORKER_DIRECTORY} 
		rc_status -v
	;;
	restart)
		## If first returns OK call the second, if first or
		## second command fails, set echo return value.
		$0 stop &&  $0 start
		rc_status
	;;
	try-restart)
		$0 status
		if test $? = 0; then
			$0 restart
		else
			rc_reset        # Not running is not a failure.
		fi
		# Remember status and be quiet
		rc_status
	;;
	reload)
	;;
	status)
		echo -n "Checking for obsworker: "
		checkproc bs_worker
		rc_status -v
	;;
	*)
		echo "Usage: $0 {start|stop|status|try-restart|restart|reload}"
		exit 1
	;;
esac
rc_exit
