#!/bin/sh
#
#       OCF Resource Agent compliant resource script.
#
# Copyright (c) 2009 IN-telegence GmbH & Co. KG, Dominik Klein
#                    All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Further, this software is distributed without any warranty that it is
# free of the rightful claim of any third person regarding infringement
# or the like.  Any license provided herein, whether implied or
# otherwise, applies only to this software file.  Patent licenses, if
# any, provided herein do not apply to combinations of this program with
# other software, or any other product whatsoever.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.

# OCF instance parameters
#       OCF_RESKEY_binfile
#       OCF_RESKEY_cmdline_options
#	OCF_RESKEY_pidfile
#       OCF_RESKEY_logfile
#       OCF_RESKEY_errlogfile
#       OCF_RESKEY_user
#       OCF_RESKEY_monitor_hook
#
# This RA starts $binfile with $cmdline_options as $user and writes a $pidfile from that. 
# If you want it to, it logs:
# - stdout to $logfile, stderr to $errlogfile or 
# - stdout and stderr to $logfile
# - or to will be captured by lrmd if these options are omitted.
# Monitoring is done through $pidfile or your custom $monitor_hook script. 
# The RA expects the program to keep running "daemon-like" and
# not just quit and exit. So this is NOT (yet - feel free to
# enhance) a way to just run a single one-shot command which just
# does something and then exits.

# Initialization:
. ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs

getpid() { # make sure that the file contains a number
	# FIXME: pidfiles could contain spaces
	grep '^[0-9][0-9]*$' $1
}

anything_status() {
	# FIXME: This should use pidofproc
	# FIXME: pidfile w/o process means the process died, so should
	# be ERR_GENERIC
	if test -f "$pidfile" && pid=`getpid $pidfile` && kill -0 $pid
	then
		return $OCF_RUNNING
	else
		return $OCF_NOT_RUNNING
	fi
}

anything_start() {
	if ! anything_status
	# FIXME: use start_daemon
	# FIXME: What about daemons which can manage their own pidfiles?
	then
		if [ -n "$logfile" -a -n "$errlogfile" ]
		then
			# We have logfile and errlogfile, so redirect STDOUT und STDERR to different files
			cmd="su - $user -c \"nohup $binfile $cmdline_options >> $logfile 2>> $errlogfile & \"'echo \$!' "
		else if [ -n "$logfile" ]
			then
				# We only have logfile so redirect STDOUT and STDERR to the same file
				cmd="su - $user -c \"nohup $binfile $cmdline_options >> $logfile 2>&1 & \"'echo \$!' "
			else
				# We have neither logfile nor errlogfile, so we're not going to redirect anything
				cmd="su - $user -c \"nohup $binfile $cmdline_options & \"'echo \$!'"
			fi
		fi
		ocf_log debug "Starting $process: $cmd"
		# Execute the command as created above
		eval $cmd > $pidfile
		if anything_status
		then
			ocf_log debug "$process: $cmd started successfully"
			return $OCF_SUCCESS
		else 
			ocf_log err "$process: $cmd could not be started"
			return $OCF_ERR_GENERIC
		fi
	else
		# If already running, consider start successful
		ocf_log debug "$process: $cmd is already running"
		return $OCF_SUCCESS
	fi
}

anything_stop() {
	# FIXME: use killproc
	if anything_status
	then
		pid=`getpid $pidfile`
		kill $pid
		i=0
		# FIXME: escalate to kill -9 before timeout
		while sleep 1 
		do
			if ! anything_status
			then
				rm -f $pidfile > /dev/null 2>&1
				return $OCF_SUCCESS
			fi
			let "i++"
		done
	else
		# was not running, so stop can be considered successful
		rm -f $pidfile 
		return $OCF_SUCCESS
	fi
	# FIXME: Never reached.
	return $OCF_ERR_GENERIC
}

anything_monitor() {
	anything_status
	ret=$?
	if [ $ret -eq $OCF_SUCCESS ]
	then
		# implement your deeper monitor operation here
		if [ -n "$OCF_RESKEY_monitor_hook" ]; then
			eval "$OCF_RESKEY_monitor_hook"
			# FIXME: Implement a check that this doesn't
			# accidentially return NOT_RUNNING?
			return
		else
			true
		fi
	else
		return $ret
	fi
}

# FIXME: Attributes special meaning to the resource id
process="$OCF_RESOURCE_INSTANCE"
binfile="$OCF_RESKEY_binfile"
cmdline_options="$OCF_RESKEY_cmdline_options"
pidfile="$OCF_RESKEY_pidfile"
# FIXME: Why test for $binfile here?
[ -z "$pidfile" -a -n "$binfile" ] && pidfile=${HA_VARRUN}/anything_${process}.pid
logfile="$OCF_RESKEY_logfile"
errlogfile="$OCF_RESKEY_errlogfile"
user="$OCF_RESKEY_user"
[ -z "$user" ] && user=root

anything_validate() {
	# FIXME: Actually this needs to test from the point of view of
	# the user.
	if [ ! -x "$binfile" ]
	then
		ocf_log err "binfile $binfile does not exist or is not executable."
		exit $OCF_ERR_INSTALLED
	fi
	if ! getent passwd $user >/dev/null 2>&1
	then
		ocf_log err "user $user does not exist."
		exit $OCF_ERR_INSTALLED
	fi
	for logfilename in "$logfile" "$errlogfile"
	do
		if [ -n "$logfilename" ]; then
			mkdir -p `dirname $logfilename` || {
				ocf_log err "cannot create $(dirname $logfilename)"
				exit $OCF_ERR_INSTALLED
			}
		fi
	done
	return $OCF_SUCCESS
}

anything_meta() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="anything_ra">
<version>1.0</version>
<longdesc lang="en">
This is a generic OCF RA to manage almost anything.
</longdesc>
<shortdesc lang="en">anything</shortdesc>

<parameters>
<parameter name="binfile" required="1" unique="1">
<longdesc lang="en">
The full name of the binary to be executed. This is expected to keep running with the same pid and not just do something and exit.
</longdesc>
<shortdesc lang="en">Full path name of the binary to be executed</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="cmdline_options" required="0">
<longdesc lang="en">
Command line options to pass to the binary
</longdesc>
<shortdesc lang="en">Command line options</shortdesc>
<content type="string" />
</parameter>
<parameter name="pidfile">
<longdesc lang="en">
File to read/write the PID from/to.
</longdesc>
<shortdesc lang="en">File to write STDOUT to</shortdesc>
<content type="string" default="${HA_VARRUN}/anything_${process}.pid"/>
</parameter>
<parameter name="logfile" required="0">
<longdesc lang="en">
File to write STDOUT to
</longdesc>
<shortdesc lang="en">File to write STDOUT to</shortdesc>
<content type="string" />
</parameter>
<parameter name="errlogfile" required="0">
<longdesc lang="en">
File to write STDERR to
</longdesc>
<shortdesc lang="en">File to write STDERR to</shortdesc>
<content type="string" />
</parameter>
<parameter name="user" required="0">
<longdesc lang="en">
User to run the command as
</longdesc>
<shortdesc lang="en">User to run the command as</shortdesc>
<content type="string" default="root"/>
</parameter>
<parameter name="monitor_hook">
<longdesc lang="en">
Command to run in monitor operation
</longdesc>
<shortdesc lang="en">Command to run in monitor operation</shortdesc>
<content type="string"/>
</parameter>
</parameters>
<actions>
<action name="start"   timeout="90" />
<action name="stop"    timeout="100" />
<action name="monitor" depth="0"  timeout="20" interval="10" />
<action name="meta-data"  timeout="5" />
<action name="validate-all"  timeout="5" />
</actions>
</resource-agent>
END
exit 0
}

case "$1" in
	meta-data|metadata|meta_data)
		anything_meta
	;;
	start)
		anything_start
	;;
	stop)
		anything_stop
	;;
	monitor)
		anything_monitor
	;;
	validate-all)
		anything_validate
	;;
	*)
		ocf_log err "$0 was called with unsupported arguments: $*"
		exit $OCF_ERR_UNIMPLEMENTED
	;;
esac
