summaryrefslogtreecommitdiffstats
path: root/heartbeat/ocf-shellfuncs.in
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 07:52:36 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 07:52:36 +0000
commit7de03e4e519705301265c0415b3c0af85263a7ac (patch)
tree29d819c5227e3619d18a67d2a5dde963b3229dbe /heartbeat/ocf-shellfuncs.in
parentInitial commit. (diff)
downloadresource-agents-7de03e4e519705301265c0415b3c0af85263a7ac.tar.xz
resource-agents-7de03e4e519705301265c0415b3c0af85263a7ac.zip
Adding upstream version 1:4.13.0.upstream/1%4.13.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'heartbeat/ocf-shellfuncs.in')
-rw-r--r--heartbeat/ocf-shellfuncs.in1070
1 files changed, 1070 insertions, 0 deletions
diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in
new file mode 100644
index 0000000..6852163
--- /dev/null
+++ b/heartbeat/ocf-shellfuncs.in
@@ -0,0 +1,1070 @@
+#
+#
+# Common helper functions for the OCF Resource Agents supplied by
+# heartbeat.
+#
+# Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Brée
+# All Rights Reserved.
+#
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+# Build version: 204f146196774ded1581aed1b6acd0d562b4f958
+
+# TODO: Some of this should probably split out into a generic OCF
+# library for shell scripts, but for the time being, we'll just use it
+# ourselves...
+#
+
+# TODO wish-list:
+# - Generic function for evaluating version numbers
+# - Generic function(s) to extract stuff from our own meta-data
+# - Logging function which automatically adds resource identifier etc
+# prefixes
+# TODO: Move more common functionality for OCF RAs here.
+#
+
+# This was common throughout all legacy Heartbeat agents
+unset LC_ALL; export LC_ALL
+unset LANGUAGE; export LANGUAGE
+
+: ${HA_SBIN_DIR:=@sbindir@}
+
+__SCRIPT_NAME=`basename $0`
+
+if [ -z "$OCF_ROOT" ]; then
+ : ${OCF_ROOT=@OCF_ROOT_DIR@}
+fi
+
+if [ "$OCF_FUNCTIONS_DIR" = ${OCF_ROOT}/resource.d/heartbeat ]; then # old
+ unset OCF_FUNCTIONS_DIR
+fi
+
+: ${OCF_FUNCTIONS_DIR:=${OCF_ROOT}/lib/heartbeat}
+
+. ${OCF_FUNCTIONS_DIR}/ocf-binaries
+. ${OCF_FUNCTIONS_DIR}/ocf-returncodes
+. ${OCF_FUNCTIONS_DIR}/ocf-directories
+. ${OCF_FUNCTIONS_DIR}/ocf-rarun
+. ${OCF_FUNCTIONS_DIR}/ocf-distro
+
+# Define OCF_RESKEY_CRM_meta_interval in case it isn't already set,
+# to make sure that ocf_is_probe() always works
+: ${OCF_RESKEY_CRM_meta_interval=0}
+
+ocf_is_root() {
+ if [ X`id -u` = X0 ]; then
+ true
+ else
+ false
+ fi
+}
+
+ocf_maybe_random() {
+ if test -c /dev/urandom; then
+ od -An -N4 -tu4 /dev/urandom | tr -d '[:space:]'
+ else
+ awk -v pid=$$ 'BEGIN{srand(pid); print rand()}' | sed 's/^.*[.]//'
+ fi
+}
+
+# Portability comments:
+# o The following rely on Bourne "sh" pattern-matching, which is usually
+# that for filename generation (note: not regexp).
+# o The "*) true ;;" clause is probably unnecessary, but is included
+# here for completeness.
+# o The negation in the pattern uses "!". This seems to be common
+# across many OSes (whereas the alternative "^" fails on some).
+# o If an OS is encountered where this negation fails, then a possible
+# alternative would be to replace the function contents by (e.g.):
+# [ -z "`echo $1 | tr -d '[0-9]'`" ]
+#
+ocf_is_decimal() {
+ case "$1" in
+ ""|*[!0-9]*) # empty, or at least one non-decimal
+ false ;;
+ *)
+ true ;;
+ esac
+}
+
+ocf_is_true() {
+ case "$1" in
+ yes|true|1|YES|TRUE|True|ja|on|ON) true ;;
+ *) false ;;
+ esac
+}
+
+ocf_is_hex() {
+ case "$1" in
+ ""|*[!0-9a-fA-F]*) # empty, or at least one non-hex
+ false ;;
+ *)
+ true ;;
+ esac
+}
+
+ocf_is_octal() {
+ case "$1" in
+ ""|*[!0-7]*) # empty, or at least one non-octal
+ false ;;
+ *)
+ true ;;
+ esac
+}
+
+__ocf_set_defaults() {
+ __OCF_ACTION="$1"
+
+ # Return to sanity for the agents...
+ unset LANG
+ LC_ALL=C
+ export LC_ALL
+
+ # TODO: Review whether we really should source this. Or rewrite
+ # to match some emerging helper function syntax...? This imports
+ # things which no OCF RA should be using...
+
+ # Strip the OCF_RESKEY_ prefix from this particular parameter
+ if [ -z "$OCF_RESKEY_OCF_CHECK_LEVEL" ]; then
+ : ${OCF_CHECK_LEVEL:=0}
+ else
+ : ${OCF_CHECK_LEVEL:=$OCF_RESKEY_OCF_CHECK_LEVEL}
+ fi
+
+ if [ ! -d "$OCF_ROOT" ]; then
+ ha_log "ERROR: OCF_ROOT points to non-directory $OCF_ROOT."
+ exit $OCF_ERR_GENERIC
+ fi
+
+ if [ -z "$OCF_RESOURCE_TYPE" ]; then
+ : ${OCF_RESOURCE_TYPE:=$__SCRIPT_NAME}
+ fi
+
+ if [ "x$__OCF_ACTION" = "xmeta-data" ]; then
+ : ${OCF_RESOURCE_INSTANCE:="RESOURCE_ID"}
+ fi
+
+ if [ -z "$OCF_RA_VERSION_MAJOR" ]; then
+ : We are being invoked as an init script.
+ : Fill in some things with reasonable values.
+ : ${OCF_RESOURCE_INSTANCE:="default"}
+ return 0
+ fi
+
+ if [ -z "$OCF_RESOURCE_INSTANCE" ]; then
+ ha_log "ERROR: Need to tell us our resource instance name."
+ exit $OCF_ERR_ARGS
+ fi
+}
+
+hadate() {
+ date "+${HA_DATEFMT}"
+}
+
+set_logtag() {
+ if [ -z "$HA_LOGTAG" ]; then
+ if [ -n "$OCF_RESOURCE_INSTANCE" ]; then
+ HA_LOGTAG="$__SCRIPT_NAME($OCF_RESOURCE_INSTANCE)[$$]"
+ else
+ HA_LOGTAG="$__SCRIPT_NAME[$$]"
+ fi
+ fi
+}
+
+__ha_log() {
+ local ignore_stderr=false
+ local loglevel
+
+ [ "x$1" = "x--ignore-stderr" ] && ignore_stderr=true && shift
+
+ [ none = "$HA_LOGFACILITY" ] && HA_LOGFACILITY=""
+ # if we're connected to a tty, then output to stderr
+ if tty >/dev/null; then
+ if [ "x$HA_debug" = "x0" -a "x$loglevel" = xdebug ] ; then
+ return 0
+ elif [ "$ignore_stderr" = "true" ]; then
+ # something already printed this error to stderr, so ignore
+ return 0
+ fi
+ if [ "$HA_LOGTAG" ]; then
+ echo "$HA_LOGTAG: $*"
+ else
+ echo "$*"
+ fi >&2
+ return 0
+ fi
+
+ set_logtag
+
+ if [ "x${HA_LOGD}" = "xyes" ] ; then
+ ha_logger -t "${HA_LOGTAG}" "$@"
+ if [ "$?" -eq "0" ] ; then
+ return 0
+ fi
+ fi
+
+ if
+ [ -n "$HA_LOGFACILITY" ]
+ then
+ : logging through syslog
+ # loglevel is unknown, use 'notice' for now
+ loglevel=notice
+ case "${*}" in
+ *ERROR*) loglevel=err;;
+ *WARN*) loglevel=warning;;
+ *INFO*|info) loglevel=info;;
+ esac
+ logger -t "$HA_LOGTAG" -p ${HA_LOGFACILITY}.${loglevel} "${*}"
+ fi
+ if
+ [ -n "$HA_LOGFILE" ]
+ then
+ : appending to $HA_LOGFILE
+ echo `hadate`" $HA_LOGTAG: ${*}" >> $HA_LOGFILE
+ fi
+ if
+ [ -z "$HA_LOGFACILITY" -a -z "$HA_LOGFILE" ] && ! [ "$ignore_stderr" = "true" ]
+ then
+ : appending to stderr
+ echo `hadate`"${*}" >&2
+ fi
+ if
+ [ -n "$HA_DEBUGLOG" ]
+ then
+ : appending to $HA_DEBUGLOG
+ if [ "$HA_LOGFILE"x != "$HA_DEBUGLOG"x ]; then
+ echo "$HA_LOGTAG: "`hadate`"${*}" >> $HA_DEBUGLOG
+ fi
+ fi
+}
+
+ha_log()
+{
+ __ha_log "$@"
+}
+
+ha_debug() {
+
+ if [ "x${HA_debug}" = "x0" ] || [ -z "${HA_debug}" ] ; then
+ return 0
+ fi
+ if tty >/dev/null; then
+ if [ "$HA_LOGTAG" ]; then
+ echo "$HA_LOGTAG: $*"
+ else
+ echo "$*"
+ fi >&2
+ return 0
+ fi
+
+ set_logtag
+
+ if [ "x${HA_LOGD}" = "xyes" ] ; then
+ ha_logger -t "${HA_LOGTAG}" -D "ha-debug" "$@"
+ if [ "$?" -eq "0" ] ; then
+ return 0
+ fi
+ fi
+
+ [ none = "$HA_LOGFACILITY" ] && HA_LOGFACILITY=""
+
+ if
+ [ -n "$HA_LOGFACILITY" ]
+ then
+ : logging through syslog
+ logger -t "$HA_LOGTAG" -p "${HA_LOGFACILITY}.debug" "${*}"
+ fi
+ if
+ [ -n "$HA_DEBUGLOG" ]
+ then
+ : appending to $HA_DEBUGLOG
+ echo "$HA_LOGTAG: "`hadate`"${*}" >> $HA_DEBUGLOG
+ fi
+ if
+ [ -z "$HA_LOGFACILITY" -a -z "$HA_DEBUGLOG" ]
+ then
+ : appending to stderr
+ echo "$HA_LOGTAG: `hadate`${*}: ${HA_LOGFACILITY}" >&2
+ fi
+}
+
+ha_parameter() {
+ local VALUE
+ VALUE=`sed -e 's%[ ][ ]*% %' -e 's%^ %%' -e 's%#.*%%' $HA_CF | grep -i "^$1 " | sed 's%[^ ]* %%'`
+ if
+ [ "X$VALUE" = X ]
+ then
+
+ case $1 in
+ keepalive) VALUE=2;;
+ deadtime)
+ ka=`ha_parameter keepalive`
+ VALUE=`expr $ka '*' 2 '+' 1`;;
+ esac
+ fi
+ echo $VALUE
+}
+
+ocf_log() {
+ # TODO: Revisit and implement internally.
+ if
+ [ $# -lt 2 ]
+ then
+ ocf_log err "Not enough arguments [$#] to ocf_log."
+ fi
+ __OCF_PRIO="$1"
+ shift
+ __OCF_MSG="$*"
+
+ case "${__OCF_PRIO}" in
+ crit) __OCF_PRIO="CRIT";;
+ err) __OCF_PRIO="ERROR";;
+ warn) __OCF_PRIO="WARNING";;
+ info) __OCF_PRIO="INFO";;
+ debug)__OCF_PRIO="DEBUG";;
+ *) __OCF_PRIO=`echo ${__OCF_PRIO}| tr '[a-z]' '[A-Z]'`;;
+ esac
+
+ if [ "${__OCF_PRIO}" = "DEBUG" ]; then
+ ha_debug "${__OCF_PRIO}: $__OCF_MSG"
+ else
+ ha_log "${__OCF_PRIO}: $__OCF_MSG"
+ fi
+}
+
+#
+# ocf_exit_reason: print exit error string to stderr
+# Usage: Allows the OCF script to provide a string
+# describing why the exit code was returned.
+# Arguments: reason - required, The string that represents why the error
+# occured.
+#
+ocf_exit_reason()
+{
+ local cookie="$OCF_EXIT_REASON_PREFIX"
+ local fmt
+ local msg
+
+ # No argument is likely not intentional.
+ # Just one argument implies a printf format string of just "%s".
+ # "Least surprise" in case some interpolated string from variable
+ # expansion or other contains a percent sign.
+ # More than one argument: first argument is going to be the format string.
+ case $# in
+ 0) ocf_log err "Not enough arguments to ocf_log_exit_msg." ;;
+ 1) fmt="%s" ;;
+
+ *) fmt=$1
+ shift
+ case $fmt in
+ *%*) : ;; # ok, does look like a format string
+ *) ocf_log warn "Does not look like format string: [$fmt]" ;;
+ esac ;;
+ esac
+
+ if [ -z "$cookie" ]; then
+ # use a default prefix
+ cookie="ocf-exit-reason:"
+ fi
+
+ msg=$(printf "${fmt}" "$@")
+ printf >&2 "%s%s\n" "$cookie" "$msg"
+ __ha_log --ignore-stderr "ERROR: $msg"
+}
+
+#
+# ocf_deprecated: Log a deprecation warning
+# Usage: ocf_deprecated [param-name]
+# Arguments: param-name optional, name of a boolean resource
+# parameter that can be used to suppress
+# the warning (default
+# "ignore_deprecation")
+ocf_deprecated() {
+ local param
+ param=${1:-ignore_deprecation}
+ # don't use ${!param} here, it's a bashism
+ if ! ocf_is_true $(eval echo \$OCF_RESKEY_$param); then
+ ocf_log warn "This resource agent is deprecated" \
+ "and may be removed in a future release." \
+ "See the man page for details." \
+ "To suppress this warning, set the \"${param}\"" \
+ "resource parameter to true."
+ fi
+}
+
+#
+# Ocf_run: Run a script, and log its output.
+# Usage: ocf_run [-q] [-info|-warn|-err] <command>
+# -q: don't log the output of the command if it succeeds
+# -info|-warn|-err: log the output of the command at given
+# severity if it fails (defaults to err)
+#
+ocf_run() {
+ local rc
+ local output
+ local verbose=1
+ local loglevel=err
+ local var
+
+ for var in 1 2
+ do
+ case "$1" in
+ "-q")
+ verbose=""
+ shift 1;;
+ "-info"|"-warn"|"-err")
+ loglevel=`echo $1 | sed -e s/-//g`
+ shift 1;;
+ *)
+ ;;
+ esac
+ done
+
+ output=`"$@" 2>&1`
+ rc=$?
+ [ -n "$output" ] && output="$(echo "$output" | tr -s ' \t\r\n' ' ')"
+ if [ $rc -eq 0 ]; then
+ if [ "$verbose" -a ! -z "$output" ]; then
+ ocf_log info "$output"
+ fi
+ else
+ if [ ! -z "$output" ]; then
+ ocf_log $loglevel "$output"
+ else
+ ocf_log $loglevel "command failed: $*"
+ fi
+ fi
+
+ return $rc
+}
+
+ocf_pidfile_status() {
+ local pid pidfile="$1"
+ if [ ! -e "$pidfile" ]; then
+ # Not exists
+ return 2
+ fi
+ pid=$(cat "$pidfile")
+ kill -0 "$pid" > /dev/null 2>&1
+ if [ $? = 0 ]; then
+ return 0
+ fi
+
+ # Stale
+ return 1
+}
+
+# mkdir(1) based locking
+# first the directory is created with the name given as $1
+# then a file named "pid" is created within that directory with
+# the process PID
+# stale locks are handled carefully, the inode of a directory
+# needs to match before and after test if the process is running
+# empty directories are also handled appropriately
+# we relax (sleep) occasionally to allow for other processes to
+# finish managing the lock in case they are in the middle of the
+# business
+
+relax() { sleep 0.5; }
+ocf_get_stale_pid() {
+ local piddir pid dir_inode
+
+ piddir="$1"
+ [ -z "$piddir" ] && return 2
+ dir_inode="`ls -di $piddir 2>/dev/null`"
+ [ -z "$dir_inode" ] && return 1
+ pid=`cat $piddir/pid 2>/dev/null`
+ if [ -z "$pid" ]; then
+ # empty directory?
+ relax
+ if [ "$dir_inode" = "`ls -di $piddir 2>/dev/null`" ]; then
+ echo $dir_inode
+ else
+ return 1
+ fi
+ elif kill -0 $pid >/dev/null 2>&1; then
+ return 1
+ elif relax && [ -e "$piddir/pid" ] && [ "$dir_inode" = "`ls -di $piddir 2>/dev/null`" ]; then
+ echo $pid
+ else
+ return 1
+ fi
+}
+
+# There is a race when the following two functions to manage the
+# lock file (mk and rm) are invoked in parallel by different
+# instances. It is up to the caller to reduce probability of that
+# taking place (see ocf_take_lock() below).
+
+ocf_mk_pid() {
+ mkdir $1 2>/dev/null && echo $$ > $1/pid
+}
+ocf_rm_pid() {
+ rm -f $1/pid
+ rmdir $1 2>/dev/null
+}
+
+# Testing and subsequently removing a stale lock (containing the
+# process pid) is inherently difficult to do in such a way as to
+# prevent a race between creating a pid file and removing it and
+# its directory. We reduce the probability of that happening by
+# checking if the stale lock persists over a random period of
+# time.
+
+ocf_take_lock() {
+ local lockdir=$1
+ local rnd
+ local stale_pid
+
+ # we don't want it too short, so strip leading zeros
+ rnd=$(ocf_maybe_random | sed 's/^0*//')
+ stale_pid=`ocf_get_stale_pid $lockdir`
+ if [ -n "$stale_pid" ]; then
+ sleep 0.$rnd
+ # remove "stale pid" only if it persists
+ [ "$stale_pid" = "`ocf_get_stale_pid $lockdir`" ] &&
+ ocf_rm_pid $lockdir
+ fi
+ while ! ocf_mk_pid $lockdir; do
+ ocf_log info "Sleeping until $lockdir is released..."
+ sleep 0.$rnd
+ done
+}
+
+ocf_release_lock_on_exit() {
+ trap "ocf_rm_pid $1" EXIT
+}
+
+# returns true if the CRM is currently running a probe. A probe is
+# defined as a monitor operation with a monitoring interval of zero.
+ocf_is_probe() {
+ [ "$__OCF_ACTION" = "monitor" -a "$OCF_RESKEY_CRM_meta_interval" = 0 ]
+}
+
+# returns true if the resource is configured as a clone. This is
+# defined as a resource where the clone-max meta attribute is present.
+ocf_is_clone() {
+ [ ! -z "${OCF_RESKEY_CRM_meta_clone_max}" ]
+}
+
+# returns true if the resource is configured as a multistate
+# (master/slave) resource. This is defined as a resource where the
+# master-max meta attribute is present, and set to greater than zero.
+ocf_is_ms() {
+ [ "${OCF_RESKEY_CRM_meta_promotable}" = "true" ] || { [ ! -z "${OCF_RESKEY_CRM_meta_master_max}" ] && [ "${OCF_RESKEY_CRM_meta_master_max}" -gt 0 ]; }
+}
+
+# version check functions
+# allow . and - to delimit version numbers
+# max version number is 999
+#
+ocf_is_ver() {
+ echo $1 | grep '^[0-9][0-9.-]*[0-9A-Za-z.\+-]*$' >/dev/null 2>&1
+}
+
+# usage: ocf_version_cmp VER1 VER2
+# version strings can contain digits, dots, and dashes
+# must start and end with a digit
+# returns:
+# 0: VER1 smaller (older) than VER2
+# 1: versions equal
+# 2: VER1 greater (newer) than VER2
+# 3: bad format
+ocf_version_cmp() {
+ ocf_is_ver "$1" || return 3
+ ocf_is_ver "$2" || return 3
+ local v1=$1
+ local v2=$2
+
+ sort_version="sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n"
+ older=$( (echo "$v1"; echo "$v2") | $sort_version | head -1 )
+
+ if [ "$v1" = "$v2" ]; then
+ return 1
+ elif [ "$v1" = "$older" ]; then
+ return 0
+ else
+ return 2 # -1 would look funny in shell ;-)
+ fi
+}
+
+ocf_local_nodename() {
+ # use crm_node -n for pacemaker > 1.1.8
+ which pacemakerd > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ local version=$(pacemakerd -$ | grep "Pacemaker .*" | awk '{ print $2 }')
+ version=$(echo $version | awk -F- '{ print $1 }')
+ ocf_version_cmp "$version" "1.1.8"
+ if [ $? -eq 2 ]; then
+ which crm_node > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ crm_node -n
+ return
+ fi
+ fi
+ fi
+
+ # otherwise use uname -n
+ uname -n
+}
+
+# usage: dirname DIR
+dirname()
+{
+ local a
+ local b
+
+ [ $# = 1 ] || return 1
+ a="$1"
+ while [ 1 ]; do
+ b="${a%/}"
+ [ "$a" = "$b" ] && break
+ a="$b"
+ done
+ b=${a%/*}
+ [ -z "$b" -o "$a" = "$b" ] && b="."
+
+ echo "$b"
+ return 0
+}
+
+# usage: systemd_is_running
+# returns:
+# 0 PID 1 is systemd
+# 1 otherwise
+systemd_is_running()
+{
+ [ "$(cat /proc/1/comm 2>/dev/null)" = "systemd" ]
+}
+
+# usage: systemd_drop_in <name> <After|Before> <dependency.service>
+systemd_drop_in()
+{
+ local conf_file
+ if [ $# -ne 3 ]; then
+ ocf_log err "Incorrect number of arguments [$#] for systemd_drop_in."
+ fi
+
+ systemdrundir="/run/systemd/system/resource-agents-deps.target.d"
+ mkdir -p "$systemdrundir"
+ conf_file="$systemdrundir/$1.conf"
+ cat >"$conf_file" <<EOF
+[Unit]
+$2=$3
+EOF
+ # The information is accessible through systemd API and systemd would
+ # complain about improper permissions.
+ chmod o+r "$conf_file"
+ systemctl daemon-reload
+}
+
+# move process to root cgroup if realtime scheduling is enabled
+ocf_move_to_root_cgroup_if_rt_enabled()
+{
+ if [ -e "/sys/fs/cgroup/cpu/cpu.rt_runtime_us" ]; then
+ echo $$ >> /sys/fs/cgroup/cpu/tasks
+
+ if [ "$?" -ne "0" ]; then
+ ocf_log warn "Unable to move PID $$ to the root cgroup"
+ fi
+ fi
+}
+
+# usage: crm_mon_no_validation args...
+# run crm_mon without any cib schema validation
+# This is useful when an agent runs in a bundle to avoid potential
+# schema validation errors when host and bundle are not perfectly aligned
+# To be used, your shell must support on process substitution (e.g. bash)
+# returns:
+# <crm_mon error codes>
+crm_mon_no_validation()
+{
+ # The subshell prevents parsing error with incompatible shells
+ "$SHELL" -c "CIB_file=<(${HA_SBIN_DIR}/cibadmin -Q | sed 's/validate-with=\"[^\"]*\"/validate-with=\"none\"/') \
+ ${HA_SBIN_DIR}/crm_mon \$*" -- $*
+}
+
+#
+# pseudo_resource status tracking function...
+#
+# This allows pseudo resources to give correct status information. As we add
+# resource monitoring, and better resource tracking in general, this will
+# become essential.
+#
+# These scripts work because ${HA_RSCTMP} is cleaned on node reboot.
+#
+# We create "resource-string" tracking files under ${HA_RSCTMP} in a
+# very simple way:
+#
+# Existence of "${HA_RSCTMP}/resource-string" means that we consider
+# the resource named by "resource-string" to be running.
+#
+# Note that "resource-string" needs to be unique. Using the resource type
+# plus the resource instance arguments to make up the resource string
+# is probably sufficient...
+#
+# usage: ha_pseudo_resource resource-string op [tracking_file]
+# where op is {start|stop|monitor|status|restart|reload|print}
+# print is a special op which just prints the tracking file location
+# user can override our choice of the tracking file location by
+# specifying it as the third arg
+# Note that all operations are silent...
+#
+ha_pseudo_resource()
+{
+ local ha_resource_tracking_file="${3:-${HA_RSCTMP}/$1}"
+ case $2 in
+ start|restart|reload) touch "$ha_resource_tracking_file";;
+ stop) rm -f "$ha_resource_tracking_file";;
+ status|monitor)
+ if
+ [ -f "$ha_resource_tracking_file" ]
+ then
+ return 0
+ else
+ case $2 in
+ status) return 3;;
+ *) return 7;;
+ esac
+ fi;;
+ print) echo "$ha_resource_tracking_file";;
+ *) return 3;;
+ esac
+}
+
+# usage: rmtempdir TMPDIR
+rmtempdir()
+{
+ [ $# = 1 ] || return 1
+ if [ -e "$1" ]; then
+ rmdir "$1" || return 1
+ fi
+ return 0
+}
+
+# usage: maketempfile [-d]
+maketempfile()
+{
+ if [ $# = 1 -a "$1" = "-d" ]; then
+ mktemp -d
+ return 0
+ elif [ $# != 0 ]; then
+ return 1
+ fi
+
+ mktemp
+ return 0
+}
+
+# usage: rmtempfile TMPFILE
+rmtempfile ()
+{
+ [ $# = 1 ] || return 1
+ if [ -e "$1" ]; then
+ rm "$1" || return 1
+ fi
+ return 0
+}
+
+# echo the first lower supported check level
+# pass set of levels supported by the agent
+# (in increasing order, 0 is optional)
+ocf_check_level()
+{
+ local lvl prev
+ lvl=0
+ prev=0
+ if ocf_is_decimal "$OCF_CHECK_LEVEL"; then
+ # the level list should be very short
+ for lvl; do
+ if [ "$lvl" -eq "$OCF_CHECK_LEVEL" ]; then
+ break
+ elif [ "$lvl" -gt "$OCF_CHECK_LEVEL" ]; then
+ lvl=$prev # the previous one
+ break
+ fi
+ prev=$lvl
+ done
+ fi
+ echo $lvl
+}
+
+# usage: ocf_stop_processes SIGNALS WAIT_TIME PIDS
+#
+# we send signals (use quotes for more than one!) in the order
+# given; if one or more processes are still running we try KILL;
+# the wait_time is the _total_ time we'll spend in this function
+# this time may be slightly exceeded if the processes won't leave
+#
+# returns:
+# 0: all processes left
+# 1: some processes still running
+#
+# example:
+#
+# ocf_stop_processes TERM 5 $pids
+#
+ocf_stop_processes() {
+ local signals="$1"
+ local wait_time="$(($2/`echo $signals|wc -w`))"
+ shift 2
+ local pids="$*"
+ local sig i
+ test -z "$pids" &&
+ return 0
+ for sig in $signals KILL; do
+ kill -s $sig $pids 2>/dev/null
+ # try to leave early, and yet leave processes time to exit
+ sleep 0.2
+ for i in `seq $wait_time`; do
+ kill -s 0 $pids 2>/dev/null ||
+ return 0
+ sleep 1
+ done
+ done
+ return 1
+}
+
+#
+# create a given status directory
+# if the directory path doesn't start with $HA_VARRUN, then
+# we return with error (most of the calls would be with the user
+# supplied configuration, hence we need to do necessary
+# protection)
+# used mostly for PID files
+#
+# usage: ocf_mkstatedir owner permissions path
+#
+# owner: user.group
+# permissions: permissions
+# path: directory path
+#
+# example:
+# ocf_mkstatedir named 755 `dirname $pidfile`
+#
+ocf_mkstatedir()
+{
+ local owner
+ local perms
+ local path
+
+ owner=$1
+ perms=$2
+ path=$3
+
+ test -d $path && return 0
+ [ $(id -u) = 0 ] || return 1
+
+ case $path in
+ ${HA_VARRUN%/}/*) : this path is ok ;;
+ *) ocf_log err "cannot create $path (does not start with $HA_VARRUN)"
+ return 1
+ ;;
+ esac
+
+ mkdir -p $path &&
+ chown $owner $path &&
+ chmod $perms $path
+}
+
+#
+# create a unique status directory in $HA_VARRUN
+# used mostly for PID files
+# the directory is by default set to
+# $HA_VARRUN/$OCF_RESOURCE_INSTANCE
+# the directory name is printed to stdout
+#
+# usage: ocf_unique_rundir owner permissions name
+#
+# owner: user.group (default: "root")
+# permissions: permissions (default: "755")
+# name: some unique string (default: "$OCF_RESOURCE_INSTANCE")
+#
+# to use the default either don't set the parameter or set it to
+# empty string ("")
+# example:
+#
+# STATEDIR=`ocf_unique_rundir named "" myownstatedir`
+#
+ocf_unique_rundir()
+{
+ local path
+ local owner
+ local perms
+ local name
+
+ owner=${1:-"root"}
+ perms=${2:-"755"}
+ name=${3:-"$OCF_RESOURCE_INSTANCE"}
+ path=$HA_VARRUN/$name
+ if [ ! -d $path ]; then
+ [ $(id -u) = 0 ] || return 1
+ mkdir -p $path &&
+ chown $owner $path &&
+ chmod $perms $path || return 1
+ fi
+ echo $path
+}
+
+#
+# RA tracing may be turned on by setting OCF_TRACE_RA
+# the trace output will be saved to OCF_TRACE_FILE, if set, or
+# by default to
+# $HA_VARLIB/trace_ra/<type>/<id>.<action>.<timestamp>
+# e.g. $HA_VARLIB/trace_ra/oracle/db.start.2012-11-27.08:37:08
+#
+# OCF_TRACE_FILE:
+# - FD (small integer [3-9]) in that case it is up to the callers
+# to capture output; the FD _must_ be open for writing
+# - absolute path
+#
+# NB: FD 9 may be used for tracing with bash >= v4 in case
+# OCF_TRACE_FILE is set to a path.
+#
+ocf_bash_has_xtracefd() {
+ [ -n "$BASH_VERSION" ] && [ ${BASH_VERSINFO[0]} -ge 4 ]
+}
+# for backwards compatibility
+ocf_is_bash4() {
+ ocf_bash_has_xtracefd
+}
+ocf_trace_redirect_to_file() {
+ local dest=$1
+ if ocf_bash_has_xtracefd; then
+ exec 9>$dest
+ BASH_XTRACEFD=9
+ else
+ exec 2>$dest
+ fi
+}
+ocf_trace_redirect_to_fd() {
+ local fd=$1
+ if ocf_bash_has_xtracefd; then
+ BASH_XTRACEFD=$fd
+ else
+ exec 2>&$fd
+ fi
+}
+__ocf_test_trc_dest() {
+ local dest=$1
+ if ! touch $dest; then
+ ocf_log warn "$dest not writable, trace not going to happen"
+ __OCF_TRC_DEST=""
+ __OCF_TRC_MANAGE=""
+ return 1
+ fi
+ return 0
+}
+ocf_default_trace_dest() {
+ tty >/dev/null && return
+ if [ -n "$OCF_RESOURCE_TYPE" -a \
+ -n "$OCF_RESOURCE_INSTANCE" -a -n "$__OCF_ACTION" ]; then
+ local ts=`date +%F.%T`
+ __OCF_TRC_DEST=${OCF_RESKEY_trace_dir}/${OCF_RESOURCE_TYPE}/${OCF_RESOURCE_INSTANCE}.${__OCF_ACTION}.$ts
+ __OCF_TRC_MANAGE="1"
+ fi
+}
+
+ocf_start_trace() {
+ export __OCF_TRC_DEST="" __OCF_TRC_MANAGE=""
+ case "$OCF_TRACE_FILE" in
+ [3-9]) ocf_trace_redirect_to_fd "$OCF_TRACE_FILE" ;;
+ /*/*) __OCF_TRC_DEST=$OCF_TRACE_FILE ;;
+ "") ocf_default_trace_dest ;;
+ *)
+ ocf_log warn "OCF_TRACE_FILE must be set to either FD (open for writing) or absolute file path"
+ ocf_default_trace_dest
+ ;;
+ esac
+ if [ "$__OCF_TRC_DEST" ]; then
+ mkdir -p `dirname $__OCF_TRC_DEST`
+ __ocf_test_trc_dest $__OCF_TRC_DEST ||
+ return
+ ocf_trace_redirect_to_file "$__OCF_TRC_DEST"
+ fi
+ if [ -n "$BASH_VERSION" ]; then
+ PS4='+ `date +"%T"`: ${FUNCNAME[0]:+${FUNCNAME[0]}:}${LINENO}: '
+ fi
+ set -x
+ env=$( echo; printenv | sort )
+}
+ocf_stop_trace() {
+ set +x
+}
+
+# Helper functions to map from nodename/bundle-name and physical hostname
+# list_index_for_word "node0 node1 node2 node3 node4 node5" node4 --> 5
+# list_word_at_index "NA host1 host2 host3 host4 host5" 3 --> host2
+
+# list_index_for_word "node1 node2 node3 node4 node5" node7 --> ""
+# list_word_at_index "host1 host2 host3 host4 host5" 8 --> ""
+
+# attribute_target node1 --> host1
+list_index_for_word() {
+ echo $1 | tr ' ' '\n' | awk -v x="$2" '$0~x {print NR}'
+}
+
+list_word_at_index() {
+ echo $1 | tr ' ' '\n' | awk -v n="$2" 'n == NR'
+}
+
+ocf_attribute_target() {
+ if [ x$1 = x ]; then
+ if [ x$OCF_RESKEY_CRM_meta_container_attribute_target = xhost -a x$OCF_RESKEY_CRM_meta_physical_host != x ]; then
+ echo $OCF_RESKEY_CRM_meta_physical_host
+ else
+ if [ x$OCF_RESKEY_CRM_meta_on_node != x ]; then
+ echo $OCF_RESKEY_CRM_meta_on_node
+ else
+ ocf_local_nodename
+ fi
+ fi
+ return
+ elif [ x"$OCF_RESKEY_CRM_meta_notify_all_uname" != x ]; then
+ index=$(list_index_for_word "$OCF_RESKEY_CRM_meta_notify_all_uname" $1)
+ mapping=""
+ if [ x$index != x ]; then
+ mapping=$(list_word_at_index "$OCF_RESKEY_CRM_meta_notify_all_hosts" $index)
+ fi
+ if [ x$mapping != x -a x$mapping != xNA ]; then
+ echo $mapping
+ return
+ fi
+ fi
+ echo $1
+}
+
+ocf_promotion_score() {
+ ocf_version_cmp "$OCF_RESKEY_crm_feature_set" "3.10.0"
+ res=$?
+ if [ $res -eq 2 ] || [ $res -eq 1 ] || ! have_binary "crm_master"; then
+ ${HA_SBIN_DIR}/crm_attribute -p ${OCF_RESOURCE_INSTANCE} $@
+ else
+ ${HA_SBIN_DIR}/crm_master -l reboot $@
+ fi
+}
+
+__ocf_set_defaults "$@"
+
+: ${OCF_TRACE_RA:=$OCF_RESKEY_trace_ra}
+: ${OCF_RESKEY_trace_dir:="$HA_VARLIB/trace_ra"}
+ocf_is_true "$OCF_TRACE_RA" && ocf_start_trace
+
+# pacemaker sets HA_use_logd, some others use HA_LOGD :/
+if ocf_is_true "$HA_use_logd"; then
+ : ${HA_LOGD:=yes}
+fi