summaryrefslogtreecommitdiffstats
path: root/tools/crm_failcount.in
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xtools/crm_failcount.in294
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