diff options
Diffstat (limited to '')
-rwxr-xr-x | tools/crm_failcount.in | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/tools/crm_failcount.in b/tools/crm_failcount.in new file mode 100755 index 0000000..f70fe78 --- /dev/null +++ b/tools/crm_failcount.in @@ -0,0 +1,294 @@ +#!@BASH_PATH@ +# +# Copyright 2009-2018 the Pacemaker project contributors +# +# The version control history for this file may have further details. +# +# This source code is licensed under the GNU General Public License version 2 +# or later (GPLv2+) WITHOUT ANY WARRANTY. +# + +USAGE_TEXT="Usage: crm_failcount <command> [<options>] +Common options: + --help Display this text, then exit + --version Display version information, then exit + -V, --verbose Specify multiple times to increase debug output + -q, --quiet Print only the value (if querying) + +Commands: + -G, --query Query the current value of the resource's fail count + -D, --delete Delete resource's recorded failures + +Additional Options: + -r, --resource=value Name of the resource to use (required) + -n, --operation=value Name of operation to use (instead of all operations) + -I, --interval=value If operation is specified, its interval + -N, --node=value Use failcount on named node (instead of local node)" + + +HELP_TEXT="crm_failcount - Query or delete resource fail counts + +$USAGE_TEXT" + +# These constants must track crm_exit_t values +CRM_EX_OK=0 +CRM_EX_USAGE=64 +CRM_EX_NOSUCH=105 + +exit_usage() { + if [ $# -gt 0 ]; then + echo "error:" "$@" >&2 + fi + echo + echo "$USAGE_TEXT" + exit $CRM_EX_USAGE +} + +warn() { + echo "warning:" "$@" >&2 +} + +interval_re() { + echo "^[[:blank:]]*([0-9]+)[[:blank:]]*(${1})[[:blank:]]*$" +} + +# This function should follow crm_get_interval() as closely as possible +parse_interval() { + INT_S="$1" + + INT_8601RE="^P(([0-9]+)Y)?(([0-9]+)M)?(([0-9]+)D)?T?(([0-9]+)H)?(([0-9]+)M)?(([0-9]+)S)?$" + + if [[ $INT_S =~ $(interval_re "") ]]; then + echo $(( ${BASH_REMATCH[1]} * 1000 )) + + elif [[ $INT_S =~ $(interval_re "s|sec") ]]; then + echo $(( ${BASH_REMATCH[1]} * 1000 )) + + elif [[ $INT_S =~ $(interval_re "ms|msec") ]]; then + echo "${BASH_REMATCH[1]}" + + elif [[ $INT_S =~ $(interval_re "m|min") ]]; then + echo $(( ${BASH_REMATCH[1]} * 60000 )) + + elif [[ $INT_S =~ $(interval_re "h|hr") ]]; then + echo $(( ${BASH_REMATCH[1]} * 3600000 )) + + elif [[ $INT_S =~ $(interval_re "us|usec") ]]; then + echo $(( ${BASH_REMATCH[1]} / 1000 )) + + elif [[ $INT_S =~ ^P([0-9]+)W$ ]]; then + echo $(( ${BASH_REMATCH[1]} * 604800000 )) + + elif [[ $INT_S =~ $INT_8601RE ]]; then + echo $(( ( ${BASH_REMATCH[2]:-0} * 31536000000 ) \ + + ( ${BASH_REMATCH[4]:-0} * 2592000000 ) \ + + ( ${BASH_REMATCH[6]:-0} * 86400000 ) \ + + ( ${BASH_REMATCH[8]:-0} * 3600000 ) \ + + ( ${BASH_REMATCH[10]:-0} * 60000 ) \ + + ( ${BASH_REMATCH[12]:-0} * 1000 ) )) + + else + warn "Unrecognized interval, using 0" + echo "0" + fi +} + +query_single_attr() { + QSR_TARGET="$1" + QSR_ATTR="$2" + + crm_attribute $VERBOSE --quiet --query -t status -d 0 \ + -N "$QSR_TARGET" -n "$QSR_ATTR" +} + +query_attr_sum() { + QAS_TARGET="$1" + QAS_PREFIX="$2" + + # Build xpath to match all transient node attributes with prefix + QAS_XPATH="/cib/status/node_state[@uname='${QAS_TARGET}']" + QAS_XPATH="${QAS_XPATH}/transient_attributes/instance_attributes" + QAS_XPATH="${QAS_XPATH}/nvpair[starts-with(@name,'$QAS_PREFIX')]" + + # Query attributes that match xpath + # @TODO We ignore stderr because we don't want "no results" to look + # like an error, but that also makes $VERBOSE pointless. + QAS_ALL=$(cibadmin --query --sync-call --local \ + --xpath="$QAS_XPATH" 2>/dev/null) + QAS_EX=$? + + # "No results" is not an error + if [ $QAS_EX -ne $CRM_EX_OK ] && [ $QAS_EX -ne $CRM_EX_NOSUCH ]; then + echo "error: could not query CIB for fail counts" >&2 + exit $QAS_EX + fi + + # Extract the attribute values (one per line) from the output + QAS_VALUE=$(echo "$QAS_ALL" | sed -n -e \ + 's/.*<nvpair.*value="\([0-9][0-9]*\|INFINITY\)".*>.*/\1/p') + + # Sum the values + QAS_SUM=0 + for i in 0 $QAS_VALUE; do + if [ "$i" = "INFINITY" ]; then + QAS_SUM="INFINITY" + break + else + QAS_SUM=$(($QAS_SUM + $i)) + fi + done + if [ "$QAS_SUM" = "INFINITY" ]; then + echo $QAS_SUM + elif [ "$QAS_SUM" -ge 1000000 ]; then + echo "INFINITY" + else + echo $QAS_SUM + fi +} + +query_failcount() { + QF_TARGET="$1" + QF_RESOURCE="$2" + QF_OPERATION="$3" + QF_INTERVAL="$4" + + QF_ATTR_RSC="fail-count-${QF_RESOURCE}" + + if [ -n "$QF_OPERATION" ]; then + QF_ATTR_DISPLAY="${QF_ATTR_RSC}#${QF_OPERATION}_${QF_INTERVAL}" + QF_COUNT=$(query_single_attr "$QF_TARGET" "$QF_ATTR_DISPLAY") + else + QF_ATTR_DISPLAY="$QF_ATTR_RSC" + QF_COUNT=$(query_attr_sum "$QF_TARGET" "${QF_ATTR_RSC}#") + fi + + # @COMPAT attributes set < 1.1.17: + # If we didn't find any per-operation failcount, + # check whether there is a legacy per-resource failcount. + if [ "$QF_COUNT" = "0" ]; then + QF_COUNT=$(query_single_attr "$QF_TARGET" "$QF_ATTR_RSC") + if [ "$QF_COUNT" != "0" ]; then + QF_ATTR_DISPLAY="$QF_ATTR_RSC" + fi + fi + + # Echo result (comparable to crm_attribute, for backward compatibility) + if [ -n "$QUIET" ]; then + echo $QF_COUNT + else + echo "scope=status name=$QF_ATTR_DISPLAY value=$QF_COUNT" + fi +} + +clear_failcount() { + CF_TARGET="$1" + CF_RESOURCE="$2" + CF_OPERATION="$3" + CF_INTERVAL="$4" + + if [ -n "$CF_OPERATION" ]; then + CF_OPERATION="-n $CF_OPERATION -I ${CF_INTERVAL}ms" + fi + crm_resource $QUIET $VERBOSE --cleanup \ + -N "$CF_TARGET" -r "$CF_RESOURCE" $CF_OPERATION +} + +QUIET="" +VERBOSE="" + +command="" +resource="" +operation="" +interval="0" +target=$(crm_node -n 2>/dev/null) + +SHORTOPTS="qDGQVN:U:v:i:l:r:n:I:" + +LONGOPTS_COMMON="help,version,verbose,quiet" +LONGOPTS_COMMANDS="query,delete" +LONGOPTS_OTHER="resource:,node:,operation:,interval:" +LONGOPTS_COMPAT="delete-attr,get-value,resource-id:,uname:,lifetime:,attr-value:,attr-id:" + +LONGOPTS="$LONGOPTS_COMMON,$LONGOPTS_COMMANDS,$LONGOPTS_OTHER,$LONGOPTS_COMPAT" + +TEMP=$(@GETOPT_PATH@ -o $SHORTOPTS --long $LONGOPTS -n crm_failcount -- "$@") +if [ $? -ne 0 ]; then + exit_usage +fi +eval set -- "$TEMP" # Quotes around $TEMP are essential + +while true ; do + case "$1" in + --help) + echo "$HELP_TEXT" + exit $CRM_EX_OK + ;; + --version) + crm_attribute --version + exit $? + ;; + -q|-Q|--quiet) + QUIET="--quiet" + shift + ;; + -V|--verbose) + VERBOSE="$VERBOSE $1" + shift + ;; + -G|--query|--get-value) + command="--query" + shift + ;; + -D|--delete|--delete-attr) + command="--delete" + shift + ;; + -r|--resource|--resource-id) + resource="$2" + shift 2 + ;; + -n|--operation) + operation="$2" + shift 2 + ;; + -I|--interval) + interval="$2" + shift 2 + ;; + -N|--node|-U|--uname) + target="$2" + shift 2 + ;; + -v|--attr-value) + if [ "$2" = "0" ]; then + command="--delete" + else + warn "ignoring deprecated option '$1' with nonzero value" + fi + shift 2 + ;; + -i|--attr-id|-l|--lifetime) + warn "ignoring deprecated option '$1'" + shift 2 + ;; + --) + shift + break + ;; + *) + exit_usage "unknown option '$1'" + ;; + esac +done + +[ -n "$command" ] || exit_usage "must specify a command" +[ -n "$resource" ] || exit_usage "resource name required" +[ -n "$target" ] || exit_usage "node name required" + +interval=$(parse_interval $interval) + +if [ "$command" = "--query" ]; then + query_failcount "$target" "$resource" "$operation" "$interval" +else + clear_failcount "$target" "$resource" "$operation" "$interval" +fi |