#!/bin/sh
#
# Functions and settings used for remote LRMS scenario
#

################################################################################
# Set DEBUG_FILES to a nonempty string to keep scratch and remote session dirs #
################################################################################
#DEBUG_FILES='1'

##########################################################
# Set up any environment variables we need at this point #
##########################################################

# Where to store temporary files
TMP_DIR=${TMP_DIR:-/tmp}
NORDUGRID_CONFIG=${NORDUGRID_CONFIG:-/etc/nordugrid.conf}
if [ -z $NORDUGRID_LOCATION ]; then
	LIBEXECDIR="/opt/nordugrid/libexec"
	SYSCONFDIR="/opt/nordugrid/etc"
else
	LIBEXECDIR="${NORDUGRID_LOCATION}/libexec"
	SYSCONFDIR="${NORDUGRID_LOCATION}/etc"
fi
GATEWAY_INC="${SYSCONFDIR}/remote-lrms.conf"
READ_CONF_VALUE="${LIBEXECDIR}/read-conf-value.pl"

#########################################
# Include log functions to allow output #
#########################################

LOG_FUNCTIONS="${LIBEXECDIR}/log-functions"
if [ -r ${LOG_FUNCTIONS} ]; then
	. ${LOG_FUNCTIONS}
else
	echo "$LOG_FUNCTIONS not readable!" 1>&2
	logger "$LOG_FUNCTIONS not readable!"
	exit 1
fi


####################
# System variables #
####################

# TODO: test availability at install or run time
# Path to important tools
TRUE='/bin/true'
FALSE='/bin/false'
SLEEP='/bin/sleep'
CP='/bin/cp'
MV='/bin/mv'
RM='/bin/rm'
PKILL='/usr/bin/pkill'
LS='/bin/ls'
FIND='/usr/bin/find'
CAT='/bin/cat'
EGREP='/bin/egrep'
SED='/bin/sed'
XARGS='/usr/bin/xargs'
PS='/bin/ps'
ENV='/usr/bin/env'
CHMOD='/bin/chmod'
CHOWN='/bin/chown'
BASENAME='/usr/bin/basename'
DIRNAME='/usr/bin/dirname'
MKTEMP='/bin/mktemp'

# Flags used with tools
FORCE='-f'
UPDATE='-u'
KEEP_PERMS='-p'
RECURSIVE='-r'
QUIET='-q'


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

function read_conf_value() {
	CONF_OPTION=$1
	CONF_VALUE=""

	if [ ! -x $READ_CONF_VALUE ]; then
		errormsg "${READ_CONF_VALUE} not executable"
		return 1
	fi
	
	CONF_VALUE=`$READ_CONF_VALUE $CONF_OPTION`
	if [ $? -ne '0' ]; then
		errormsg "${READ_CONF_VALUE} $CONF_OPTION failed!"
		return 1
	fi
	
	#debugmsg "found $CONF_VALUE associated with $CONF_OPTION in configuration"
	
	return 0
}

# TODO: perl'ify this?
function parse_gw_conf() {
	# Extract remote commands from supplied configuration file
	CONFIG=$1

	#debugmsg "parse_conf $CONFIG"

	# Defaults
	gateway_enabled=0
	gateway_lib=""
	gateway_conf=""
	remote_exec=""
	upload=""
	download=""
	upsync=""
	downsync=""


	if [ ! -r "$CONFIG" ]; then
		errormsg "Can not read $CONFIG"
		return 1
	fi

	section='resource_gateway'
	conf_string='gateway_conf'
	lib_string='gateway_lib'
	IN_SECTION='0'

	PURE_CONF=`$CAT $CONFIG | $EGREP -v "^\s*#"`

	for line in $PURE_CONF; do
		#echo "$line	($IN_SECTION)"
		if [ $IN_SECTION -eq '1' ]; then
			# Check if we found the next section
			echo $line|$EGREP -i "^\s*\[.*\]" >& /dev/null
			if [ $? -eq '0' ]; then
				#debugmsg "left section $section"
				IN_SECTION='0'
				continue
			fi
			echo $line|$EGREP -i "^\s*$conf_string" >& /dev/null
			if [ $? -eq '0' ]; then
				conf_line=$line
				#debugmsg "found $conf_string: $conf_line"
				continue
			fi
			echo $line|$EGREP -i "^\s*$lib_string" >& /dev/null
			if [ $? -eq '0' ]; then
				lib_line=$line
				#debugmsg "found $lib_string: $lib_line"
				continue
			fi
		else
			# Check if we found $section
			echo $line|$EGREP -i "^\s*\[$section\]" >& /dev/null
			if [ $? -eq '0' ]; then
				#debugmsg "entered section $section"
				gateway_enabled='1'
				IN_SECTION='1'
			fi
		fi
	done

	# Make sure lrms is actually set to "remote"
	read_conf_value "lrms"
	if [ "$CONF_VALUE" != "remote" ]; then
		gateway_enabled='0'
	fi
	#debugmsg "lrms set to $CONF_VALUE - gateway_enabled = $gateway_enabled"
	
	if [ "$gateway_enabled" -eq '1' -a -n "$conf_line" -a -n "$lib_line" ]; then
		#debugmsg "parsing relevant conf lines"
		gateway_conf=`echo $conf_line|$SED "s/^\s*${conf_string}\s*=\s*\"*\([^\t\ #\"]\+\)\"*\s*\(#.*\)*/\1/"`
		gateway_lib=`echo $lib_line|$SED "s/^\s*${lib_string}\s*=\s*\"*\([^\t\ #\"]\+\)\"*\s*\(#.*\)*/\1/"`
	else
		debugmsg "Disabling gateway - one or more of the required variables are not set"
		gateway_enabled=0
	fi

	if [ ! -d "$gateway_lib" ]; then
		debugmsg "Disabling gateway - gateway_lib ($gateway_lib) not set or is not a directory"
		gateway_enabled=0
	fi

	if [ ! -r "$gateway_conf" ]; then
		debugmsg "Disabling gateway - gateway_conf ($gateway_conf) not set or is not readable"
		gateway_enabled=0
	fi

	if [ "$gateway_enabled" -ne '0' ]; then
		remote_exec="${gateway_lib}/pywrat_execute"
		upload="${gateway_lib}/pywrat_upload"
		download="${gateway_lib}/pywrat_download"
		upsync="${gateway_lib}/pywrat_upsync"
		downsync="${gateway_lib}/pywrat_downsync"
	fi

	return 0
}

function read_gw_conf() {
	# Source preparsed gateway configuration if available and up2date
	# Please note that this will work even if the files are not available
	if [ -r ${GATEWAY_INC} -a ${GATEWAY_INC} -nt ${NORDUGRID_CONFIG} ] ; then
		#debugmsg "sourcing preparsed gateway configuration (${GATEWAY_INC})"
		. ${GATEWAY_INC}
	else
		debugmsg "No current preparsed gateway configuration (${GATEWAY_INC}) - manually parsing ${NORDUGRID_CONFIG}"

		parse_gw_conf ${NORDUGRID_CONFIG}
		write_gw_conf
		# Ignore write errors since configuration is available in memory
		debugmsg "write preparsed gateway configuration returned $?"
	fi

	# Now entire remote resource configuration is available
	if [ -z $gateway_enabled -o "$gateway_enabled" -ne '1' ]; then
		debugmsg "gateway disabled (source/parse returned $ret)"
		return 1
	fi

	#debugmsg "gateway enabled"
	return 0
}

function write_gw_conf() {
	# Write parsed configuration details to file for later inclusion
	# It may be used by non- and privileged users so we allow read here
	local OLD_UMASK=`umask`
	umask 022
	if [ -e ${GATEWAY_INC} -a ! -w ${GATEWAY_INC} ] ; then
		debugmsg "Can't write preparsed gateway configuration (${GATEWAY_INC})"
		ret='1'
	else
		debugmsg "Trying to write preparsed gateway configuration (${GATEWAY_INC})"
		echo "" >| ${GATEWAY_INC}

		echo "gateway_enabled=${gateway_enabled}" >> ${GATEWAY_INC}
		echo "gateway_conf=\"${gateway_conf}\"" >> ${GATEWAY_INC}
		echo "gateway_lib=\"${gateway_lib}\"" >> ${GATEWAY_INC}

                echo "remote_exec=\"${remote_exec}\"" >> ${GATEWAY_INC}
                echo "upload=\"${upload}\"" >> ${GATEWAY_INC}
                echo "download=\"${download}\"" >> ${GATEWAY_INC}
                echo "upsync=\"${upsync}\"" >> ${GATEWAY_INC}
                echo "downsync=\"${downsync}\"" >> ${GATEWAY_INC}
		ret=$?
	fi
	
	# Reset umask
	#debugmsg "Reset umask to $OLD_UMASK"
	umask $OLD_UMASK
	
	return $ret 
}


function remote_exec() {
	local cmd=$1 
	# Execute cmd at remote resource
	#debugmsg "execution of $cmd at remote resource"
	$remote_exec -c $gateway_conf "$cmd"
	return $?
}

function upload() {
	local lpath=$1 
	local rpath=$2
	# Transfer lpath to rpath at resource
	#debugmsg "upload $lpath to $rpath at remote resource"
	$upload -c $gateway_conf $lpath $rpath
	return $?
}

function download() {
	local lpath=$1 
	local rpath=$2
	# Transfer rpath from resource to local lpath
	#debugmsg "download $rpath to $lpath from remote resource"
	$download -c $gateway_conf $lpath $rpath
	return $?
}

function upsync() {
	local lpath=$1 
	local rpath=$2
	# Synchronize rpath at resource with local lpath
	#debugmsg "upsync $lpath to $rpath at remote resource"
	$upsync -c $gateway_conf $lpath $rpath
	return $?
}

function downsync() {
	local lpath=$1 
	local rpath=$2
	# Synchronize lpath with rpath from remote resource
	#debugmsg "downsync $rpath from remote resource to $lpath"
	$downsync -c $gateway_conf $lpath $rpath
	return $?
}


function upload_session_dir() {
	local session_dir=$1 
	# Transfer session directory to resource
	#debugmsg "upload session dir ($session_dir) to remote resource"
	session_base=`$DIRNAME $session_dir`
	upload $session_dir ${session_base}/
	return $?
}

function download_session_dir() {
	local session_dir=$1 
	# Transfer session directory to resource
	#debugmsg "download session dir ($session_dir) from remote resource"
	session_base=`$DIRNAME $session_dir`
	download ${session_base}/ $session_dir
	return $?
}

# Find and set global session_dir in the list of arguments
function find_session_dir() {
	session_dir=""
	# Read session dir path into CONF_VALUE variable
	read_conf_value "sessiondir"
	SESSION_PATH="$CONF_VALUE"
	if [ -z "$SESSION_PATH" ]; then
		SESSION_PATH="/scratch/grid"
		debugmsg "no sessiondir defined in $NORDUGRID_CONFIG - using default$SESSION_PATH"
	fi
	SESSION_STRING="$SESSION_PATH/[0-9]+"
	if [ $# -gt 0 ]; then
		for i in $@; do
			#debugmsg "arg is $i"
			echo $i | $EGREP "^${SESSION_STRING}$" >& /dev/null
			ret=$?
			if [ $ret -eq '0' ]; then
				session_dir=$i
				#debugmsg "found sessiondir $session_dir"
				break
			fi
		done
	fi
	return 0
}

# Find and set global control_dir from the configuration
function find_control_dir() {
	control_dir=""
	# Read control dir path into CONF_VALUE variable
	read_conf_value "controldir"
	control_dir="$CONF_VALUE"
	if [ -z "$control_dir" ]; then
		control_dir="/var/spool/nordugrid/jobstatus"
		debugmsg "no controldir defined in $NORDUGRID_CONFIG - using default$control_dir"
	fi
	return 0
}

# Build environment file to be sourced at the resource from current environment
function store_environment() {
	local ENV_FILE=$1
	
	# filter out these environment variables
	FILTER_REGEXP="(SHELL|TERM|USER|LS_COLORS|LS_OPTIONS|LD_LIBRARY_PATH|USER_NAME|MAIL|PATH|PWD|USER_ID|SHLVL|HOME|LOGNAME|_)"

	echo "" >| $ENV_FILE
	# We must enclose right hand side in apostrophes since variable 
	# 'HOSTNAME=/bin/hostname -f' will screw up otherwise
	$ENV | $EGREP -v "^${FILTER_REGEXP}=" | $SED 's/^\(.*\)=\(.*\)$/export \1="\2"/g' >> $ENV_FILE
	# For debugging we keep filtered variables but commented out
	$ENV | $EGREP "^${FILTER_REGEXP}=" | $SED 's/^\(.*\)=\(.*\)$/#export \1="\2"/g' >> $ENV_FILE
}
