diff --git a/heartbeat/README b/heartbeat/README index aaaff3a9c..604295685 100644 --- a/heartbeat/README +++ b/heartbeat/README @@ -1,44 +1,46 @@ The OCF RA shared code directory If an RA is too big to be comfortably maintained, split it into several source files. Obviosuly, if two or more RAs share some code, move that code out to a file which can be shared. These files will be installed in $OCF_ROOT/lib/heartbeat with permissions 644. Naming practice Use names such as .sh or -check.sh or anything-else.sh where "anything-else" should be related to both the RA and the code it contains. By adding extension (.sh) it is going to be easier to notice that these files are not complete resource agents. For instance, oracle and oralsnr RA can both use code in ora-common.sh. Of course, if the RA is implemented in another programming language, use the appropriate extension. RA tracing 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 +output will be saved to OCF_TRACE_FILE, if set. If not, +then the trace would be saved to the OCF_RESKEY_trace_dir. +If it's also not defined, the log will be saved by default to $HA_VARLIB/trace_ra//.. e.g. $HA_VARLIB/trace_ra/oracle/db.start.2012-11-27.08:37:08 HA_VARLIB is typically set to /var/lib/heartbeat. OCF_TRACE_FILE can be set to a path or file descriptor: - 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. diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in index 1e83676a7..2956d1264 100644 --- a/heartbeat/ocf-shellfuncs.in +++ b/heartbeat/ocf-shellfuncs.in @@ -1,1047 +1,1048 @@ # # # 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: $Format:%H$ # 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] # -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 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" < 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//.. # 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=$HA_VARLIB/trace_ra/${OCF_RESOURCE_TYPE}/${OCF_RESOURCE_INSTANCE}.${__OCF_ACTION}.$ts + __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_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