#!/bin/bash # # Resource script for icinga/nagios daemon # # Description: Manages icinga/nagios daemon as an OCF resource in # an High Availability setup. # # Author: Lennart Betz # License: GNU General Public License (GPL) # Copyright: (C) NETWAYS GmbH # # Changelog: # # 2011-08-23 0.1 initial release # 2011-09-12 0.2 change parameter config to configfile # add parameter envfiles # 2012-12-20 0.3 add validation of lsof, pgrep, ... exist # # Include /etc/default|sysconfig/icinga|nagios for defaults. # # At this time only tested with debian. Check it on openSuSE, RedHat... # # # # usage: $0 {start|stop|status|monitor|validate-all|meta-data} # # The "start" arg starts icinga/nagios. # # The "stop" arg stops it. # # OCF parameters: # OCF_RESKEY_binary # OCF_RESKEY_configfile # OCF_RESKEY_pidfile # OCF_RESKEY_commandfile # OCF_RESKEY_envfiles # ########################################################################## # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ########################################################################## OCF_RESKEY_binary_default=/usr/local/icinga/bin/icinga OCF_RESKEY_configfile_default=/usr/local/icinga/etc/icinga.cfg OCF_RESKEY_pidfile_default=/usr/local/icinga/var/icinga.lock OCF_RESKEY_commandfile_default=/usr/local/icinga/var/rw/icinga.cmd # what commands are used and have to exist DEPENDENCIES="grep lsof pgrep" usage() { cat <<-! usage: $0 {start|stop|status|monitor|validate-all|meta-data} action: start start the ${DAEMON} daemon stop stop the ${DAEMON} daemon status return the status of the ${DAEMON} daemon, running or down methods return the set of commands we support monitor return TRUE if the ${DAEMON} daemon appears to be working. meta-data show meta data message validate-all validate the instance parameters ! exit $OCF_ERR_ARGS } meta_data() { cat < 1.0 This script manages the ${DAEMON} daemon OCF Resource Agent compliant ${DAEMON} daemon script. The ${DAEMON} binary path. Full path to the ${DAEMON} binary. The ${DAEMON} daemon configuration file name with full path. For example, "${OCF_RESKEY_configfile_default}" Configuration file name with full path The ${DAEMON} daemon pidfile name with full path. Isn't set, use "lock_file" from config file. For example, "${OCF_RESKEY_pidfile_default}" Pidfile name with full path. The ${DAEMON} commandfile with full path. Isn't set, use "command_file" from config file. For example, "${OCF_RESKEY_commandfile_default}" Commandfile with full path. Files (one or more) which contain extra environment variables. environment settings files END exit $OCF_SUCCESS } get_pids() { PIDS=( ) # Seek by pidfile PIDS[1]=$(awk '1{print $1}' $PIDFILE 2>/dev/null) if [ -n "${PIDS[1]}" ]; then typeset exe exe=$(ls -l "/proc/${PIDS[1]}/exe" 2>/dev/null) if [ $? = 0 ]; then exe=${exe##*-> } if ! [ "$exe" = ${OCF_RESKEY_binary} ]; then PIDS[1]="" fi else PIDS[1]="" fi fi # Seek by command file if [ $COMMANDFILE ]; then typeset pid for p in $(lsof -FpR $COMMANDFILE 2>/dev/null); do if [ "X$p" = "XR1" ]; then if [ -z ${PIDS[2]} ]; then PIDS[2]=$pid else PIDS[2]="$pid ${PIDS[2]}" fi fi pid=$(echo $p| sed 's/^p//g') done fi # Seek by pattern, parent 1 (init); for loop is need for forks for i in $(pgrep -P 1 -f "$PROCESS_PATTERN"); do if [ "X$i" == "X${PIDS[1]}" ]; then PIDS[0]=$i fi done } pids_sane() { if [ "${PIDS[1]}" = "${PIDS[2]}" ] && [ "${PIDS[1]}" = "${PIDS[0]}" ]; then return $OCF_SUCCESS else ocf_log err "$DAEMON: PID mismatch" return $OCF_ERR_GENERIC fi } is_dead() { if [ -z "${PIDS[0]}" ] & [ -z "${PIDS[2]}" ] then return 0 else return 1 fi } monitor() { get_pids #echo ps=${PIDS[0]} pidfile=${PIDS[1]} socket=${PIDS[2]} if ! pids_sane; then return $OCF_ERR_GENERIC fi if is_dead; then return $OCF_NOT_RUNNING fi return $OCF_SUCCESS } status() { monitor } start() { status retVal=$? if [ $retVal -eq $OCF_SUCCESS ]; then ocf_log info "${DAEMON} already running" exit $OCF_SUCCESS elif [ $retVal -ne $OCF_NOT_RUNNING ]; then ocf_log err "Error. Unknown status." exit $OCF_ERR_GENERIC fi $PROCESS_PATTERN if [ $? -ne 0 ]; then ocf_log err "Error. ${DAEMON} returned error $?." exit $OCF_ERR_GENERIC fi ocf_log info "Started ${DAEMON} daemon." exit $OCF_SUCCESS } stop() { pid=`cat $PIDFILE 2>/dev/null` if [ -n "$pid" ] ; then kill $pid if [ $? -ne 0 ]; then kill -SIGKILL $pid if [ $? -ne 0 ]; then ocf_log err "Error. Could not stop ${DAEMON}." return $OCF_ERR_GENERIC fi fi rm $PIDFILE 2>/dev/null fi kill -SIGKILL $(pgrep -f "$PROCESS_PATTERN") 2>/dev/null ocf_log info "Stopped ${DAEMON}." exit $OCF_SUCCESS } validate_all() { for file in $DEPENDENCIES; do if [ ! -x "$(which $file)" ]; then ocf_log err "$DAEMON $file could not be found or isn't executable." exit $OCF_ERR_INSTALLED fi done if [ ! -x $OCF_RESKEY_binary ]; then ocf_log err "$DAEMON binary $OCF_RESKEY_binary does not exist or is not executable." exit $OCF_ERR_INSTALLED fi if [ ! -f $OCF_RESKEY_configfile ]; then ocf_log err "Config $OCF_RESKEY_configfile does not exist." exit $OCF_ERR_CONFIGURED fi return $OCF_SUCCESS } # # Main # : ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}} DAEMON=$(basename ${OCF_RESKEY_binary}) if [ -z ${OCF_RESKEY_envfiles} ]; then if [ -f /etc/sysconfig/$DAEMON ]; then . /etc/sysconfig/$DAEMON fi if [ -f /etc/default/$DAEMON ]; then . /etc/default/$DAEMON fi else for i in ${OCF_RESKEY_envfiles}; do if [ -f $i ]; then . $i else ocf_log err "Error. Could not read $i, no such file or directory." exit $OCF_ERR_CONFIGURED fi done fi : ${OCF_RESKEY_configfile=${OCF_RESKEY_configfile_default}} : ${OCF_RESKEY_pidfile=${OCF_RESKEY_pidfile_default}} : ${OCF_RESKEY_socket=${OCF_RESKEY_commandfile_default}} # if config file is accessable, read pidfile and command file from config file if [ ! -z ${OCF_RESKEY_configfile} ] && [ -f ${OCF_RESKEY_configfile} ]; then # read pidfile from config file PIDFILE=$(grep -v "^#" ${OCF_RESKEY_configfile} |grep "^lock_file=" |cut -d "=" -f 2) if [ "X$PIDFILE" = "X" ]; then ocf_log err "Error. \"lock_file\" entry without whitespaces required in the $DAEMON config file by $DAEMON OCF RA." exit $OCF_ERR_GENERIC fi # read command file from config file COMMANDFILE=$(grep -v "^#" ${OCF_RESKEY_configfile} |grep "^command_file=" |cut -d "=" -f 2) if [ "X$COMMANDFILE" = "X" ]; then ocf_log err "Error. \"command_file\" entry without whitespaces required in the $DAEMON config file by $DAEMON OCF RA." exit $OCF_ERR_GENERIC fi else PIDFILE=${OCF_RESKEY_pidfile} COMMANDFILE=${OCF_RESKEY_commandfile} fi PROCESS_PATTERN="${OCF_RESKEY_binary} -d ${OCF_RESKEY_configfile}" case $1 in start) validate_all start ;; stop) validate_all stop ;; status) status ;; monitor) monitor ;; validate-all) validate_all ;; meta-data) meta_data ;; notify|promote|demote) exit $OCF_ERR_UNIMPLEMENTED ;; usage) usage exit $OCF_SUCCESS ;; *) usage exit $OCF_ERR_UNIMPLEMENTED ;; esac