#!/usr/local/bin/cbsd
#v11.0.6
MYARG=""
MYOPTARG="reload"
MYDESC="Daemon for executing nexttask"
CBSDMODULE="taskd"
EXTHELP="wf_taskd.html"

. ${subr}
. ${system}
. ${strings}

init $*

[ -z "${reload}" ] && reload=0

# reset hour for fwupdate
last_hour_fwupdate=0

shmux()
{
	local _mylock SSH_ARGS _locallockfile _locallock _remotelockfile _remotelock

	_locallockfile="${ftmpdir}/shmux_${_ip}.lock"
	_locallock="/usr/bin/lockf -s -t0 ${_locallockfile}"
	_remotelockfile="ftmp/from_${nodename}.lock"
	_remotelock="/usr/bin/lockf -s -t0 ${_remotelockfile}"

	. ${nodes}

	if [ -f "${_locallockfile}" ]; then
		if check_locktime ${_locallockfile} >/dev/null 2>&1; then
			cbsdsql nodes "UPDATE nodelist SET idle=datetime('now','localtime') WHERE ip=\"${_ip}\""
		fi
		return 0
	fi

	SSH_ARGS="-oControlPersist=30m -oBatchMode=yes -oStrictHostKeyChecking=no -oConnectTimeout=5 -q -oPort=${_port} -i ${_keyfile} -l ${cbsduser} ${_ip}"
	[ ! -f "${_locallockfile}" ] && ${miscdir}/daemon -u ${cbsduser} ${_locallock} /usr/bin/ssh ${SSH_ARGS} "${_remotelock} misc/cbsd_dot --file=var/db/local.sqlite" > ${tmpdir}/inv.${_ip}.updated 2>/dev/null
}

update_jaillock()
{
	local jname

	for jname in $( cbsdsql local SELECT jname FROM jails WHERE status=1 ); do
		jaillock="${jailsysdir}/${jname}/locked"
		/usr/sbin/daemon -f -u ${cbsduser} /usr/bin/lockf -s -t0 ${ftmpdir}/update_jaillock.lock /usr/bin/touch ${jaillock}
	done
}

update_fw_counters()
{
	local _curhour=$( /bin/date "+%H" )

	[ "${_curhour}" = "${last_hour_fwupdate}" ] && return 0
	last_hour_fwupdate="${_curhour}"
	/usr/sbin/daemon /usr/bin/lockf -s -t0 ${ftmpdir}/fwcounters.lock /usr/local/bin/cbsd fwcounters jname=alljails
}

# if $1 = "force" skip for cbsd_dot check
update_inventory()
{
	[ -z "${_ip}" ] && return 0
	if [ "${1}" != "force" ]; then
		[ ! -s "${tmpdir}/inv.${_ip}.updated" ] && return 0
		cbsdlogger NOTICE ${CBSD_APP}: update remote inventory for ${_ip}: new changes
	fi
	/usr/bin/truncate -s0 ${tmpdir}/inv.${_ip}.updated
	task mode=new exclusive=1 owner=cbsddsys jname=#retrinv_${nodename} /usr/local/bin/cbsd retrinv node=${_nodename} >/dev/null 2>&1
	/usr/sbin/daemon -f nexttask
}

readconf task.conf

[ ! -f "${dbdir}/cbsdtaskd.sqlite" ] && err 1 "No such ${dbdir}/cbsdtaskd.sqlite"
[ -z "${max_simul_jobs}" ] && max_simul_jobs="30"
[ -z "${loop_timeout}" ] && loop_timeout="30"

loop_per_retrinv=10	# one retrinv per 5 loop cycle's ( def: 10*30sec = once per <= 5 min )
retrinv_loop=0

# first of all, checks for orphaned tasks in status 1 (running) and back to status 0,
# due to next iteration take this job again

#store pid
echo $$ > /var/run/cbsdd.pid
trap "/bin/rm -f /var/run/cbsdd.pid" HUP INT QUIT ABRT KILL ALRM TERM BUS EXIT

cbsdsql cbsdtaskd 'UPDATE taskd SET status="0" WHERE status="1"' 2>/dev/null

# remove stale lock and trash files
/usr/bin/find -E ${ftmpdir} -depth 1 -maxdepth 1 \( -name shmux_\*.lock -or -name jstart\.\* -or -name jstop\.\* -or -name \*\.jconf \) -and -mtime +30m -delete > /dev/null 2>&1
/usr/bin/find ${tmpdir} -depth 1 -maxdepth 1 -name inv.\*.updated -delete > /dev/null 2>&1

# retrinv
[ ${sqlreplica} -eq 1 ] && /usr/sbin/daemon -f /usr/bin/lockf -s -t0 ${ftmpdir}/retrinv.lock /usr/local/bin/cbsd retrinv tryoffline=1

while [ 1 ]; do
	# internal tasks:
	update_jaillock
	[ ${ipfw_enable} -eq 1 ] && update_fw_counters

	unset ip port keyfile _ip _port _keyfile queue

	# make sshmux control master
	if [ ${sqlreplica} -eq 1 ]; then
		sqldelimer=" "
		cbsdsql nodes SELECT nodename,ip,port,keyfile FROM nodelist | while read _nodename _ip _port _keyfile; do
			[ -n "${_ip}" ] && shmux
			if [ ${retrinv_loop} -gt ${loop_per_retrinv} ]; then
				cbsdlogger NOTICE ${CBSD_APP}: update remote inventory for ${_ip} via loop_per_retrinv [${loop_per_retrinv}]
				update_inventory force
			else
				update_inventory
			fi
		done
		unset sqldelimer

		if [ ${retrinv_loop} -gt ${loop_per_retrinv} ]; then
			# reset loop
			retrinv_loop=0
		else
			retrinv_loop=$(( retrinv_loop + 1 ))
		fi
	fi

	cbsd_fwatch --file=${dbdir}/cbsdtaskd.sqlite --timeout=${loop_timeout} >/dev/null 2>&1
	_err=0
	queue=$( cbsdsql cbsdtaskd 'SELECT COUNT(id) FROM taskd WHERE status="0"' 2>/dev/null )

	[ -z "${queue}" ] && queue=0
	[ ${queue} -eq 0 ] && continue

	if [ ${queue} -gt ${max_simul_jobs} ]; then
		max=${max_simul_jobs}
	else
		max=${queue}
	fi

	for i in $( /usr/bin/seq 1 ${max} ); do
		cbsdlogger NOTICE ${CBSD_APP}: runtask ${i}/${max} [$max_simul_jobs max]
		/usr/sbin/daemon -f nexttask
		# wait for pid of daemon here!!!
		sleep 1
	done
done
