From 39906cee491a554e44575341e4103ded8206b1c5 Mon Sep 17 00:00:00 2001 From: Patrick Van der Veken Date: Fri, 15 Mar 2019 22:13:40 +0100 Subject: [PATCH] Added --older & --newer report options Various shellcheck fixes & other fixes --- sources/bin/check_health.sh | 49 ++++- sources/lib/core/display_csv.sh | 9 +- sources/lib/core/display_init.sh | 6 +- sources/lib/core/display_json.sh | 7 +- sources/lib/core/display_terse.sh | 9 +- sources/lib/core/display_zenoss.sh | 9 +- sources/lib/core/include_core.sh | 131 ++++++++++--- sources/lib/core/include_data.sh | 1 + sources/lib/core/include_os.sh | 3 + sources/lib/core/notify_mail.sh | 6 +- sources/lib/core/report_std.sh | 305 ++++++++++++++++++++--------- 11 files changed, 397 insertions(+), 138 deletions(-) diff --git a/sources/bin/check_health.sh b/sources/bin/check_health.sh index 7fc1f24..28798a4 100644 --- a/sources/bin/check_health.sh +++ b/sources/bin/check_health.sh @@ -38,7 +38,7 @@ # ------------------------- CONFIGURATION starts here ------------------------- # define the version (YYYY-MM-DD) -typeset -r SCRIPT_VERSION="2019-02-18" +typeset -r SCRIPT_VERSION="2019-03-16" # location of parent directory containing KSH functions/HC plugins typeset -r FPATH_PARENT="/opt/hc/lib" # location of custom HC configuration files @@ -52,6 +52,7 @@ typeset -r TMP_DIR="/var/tmp" # specify the UNIX user that needs to be used for executing the script typeset -r EXEC_USER="root" # ------------------------- CONFIGURATION ends here --------------------------- +typeset PATH=${PATH}:/sbin:/usr/bin:/usr/sbin:/usr/local/bin # read-only settings (but should not be changed) typeset -r SCRIPT_NAME=$(basename "$0" 2>/dev/null) typeset -r SCRIPT_DIR=$(dirname "$0" 2>/dev/null) @@ -76,7 +77,6 @@ typeset -r STATE_DIR="${LOG_DIR}/state" typeset -r STATE_PERM_DIR="${STATE_DIR}/persistent" typeset -r STATE_TEMP_DIR="${STATE_DIR}/temporary" # miscellaneous -typeset PATH=${PATH}:/sbin:/usr/bin:/usr/sbin:/usr/local/bin typeset CMD_LINE="" typeset CMD_PARAMETER="" typeset CHILD_ERROR=0 @@ -110,6 +110,7 @@ typeset DISABLE_RC=0 typeset ENABLE_RC=0 # shellcheck disable=SC2034 typeset FIX_FC=0 +typeset IS_PDKSH=0 typeset RUN_RC=0 typeset RUN_CONFIG_FILE="" typeset RUN_TIME_OUT=0 @@ -135,7 +136,9 @@ typeset ARG_LOCK=1 # lock for concurrent script executions is on by typeset ARG_LOG=1 # logging is on by default typeset ARG_LOG_HEALTHY=0 # logging of healthy health checks is off by default typeset ARG_MONITOR=1 # killing long running HC processes is on by default +typeset ARG_NEWER="" typeset ARG_NOTIFY="" # notification of problems is off by default +typeset ARG_OLDER="" typeset ARG_REVERSE=0 # show report in reverse date order is off by default typeset ARG_REPORT="" # report of HC events is off by default typeset ARG_TIME_OUT=0 # custom timeout is off by default @@ -304,7 +307,7 @@ then ARG_VERBOSE=0 warn "unable to acquire lock ${LOCK_DIR}" if [[ -f ${LOCK_DIR}/.pid ]] then - typeset LOCK_PID="$(cat ${LOCK_DIR}/.pid)" + typeset LOCK_PID="$(<${LOCK_DIR}/.pid)" print -u2 "ERROR: active health checker running on PID: ${LOCK_PID}" ARG_VERBOSE=0 warn "active health checker running on PID: ${LOCK_PID}. Exiting!" fi @@ -487,7 +490,7 @@ typeset WHOAMI="" # avoid sub-shell for mksh/pdksh # shellcheck disable=SC2046 -WHOAMI=$(IFS='()'; set -- $(id); print $2) +WHOAMI=$(IFS='()'; set -- $(id); print "${2}") if [[ "${WHOAMI}" != "${EXEC_USER}" ]] then print -u2 "ERROR: must be run as user '${EXEC_USER}'" @@ -508,6 +511,8 @@ function check_shell case "${KSH_VERSION}" in *MIRBSD*|*PD*|*LEGACY*) (( ARG_DEBUG > 0 )) && debug "running ksh: ${KSH_VERSION}" + # shellcheck disable=SC2034 + IS_PDKSH=1 ;; *) if [[ -z "${ERRNO}" ]] @@ -543,7 +548,7 @@ Syntax: ${SCRIPT_DIR}/${SCRIPT_NAME} [--help] | [--help-terse] | [--version] | (--check-host | ((--archive | --check | --enable | --disable | --run [--timeout=] | --show) --hc= [--config-file=] [hc-args="])) [--display=] ([--debug] [--debug-level=]) [--log-healthy] [--no-monitor] [--no-log] [--no-lock] [--flip-rc] [--notify=] [--mail-to=] [--sms-to= --sms-provider=] - [--report= ( ([--last] | [--today]) | ([--reverse] [--id= [--detail]] [--with-history]) ) ] + [--report= ( ([--last] | [--today]) | ([(--older|--newer)=] [--reverse] [--id= [--detail]] [--with-history]) ) ] EOT @@ -573,7 +578,7 @@ Parameters: --hc-args : extra arguments to be passed to an individual HC. Arguments must be comma-separated and enclosed in double quotes (example: --hc_args="arg1,arg2=value,arg3"). --id : value of a FAIL ID (must be specified as uninterrupted sequence of numbers) ---last : show the last events for each HC and their combined STC value +--last : show the last (failed) events for each HC and their combined STC value --list : show the available health checks. Use to search with wildcards. Following details are shown: - health check (plugin) name - state of the HC plugin (disabled/enabled) @@ -584,10 +589,12 @@ Parameters: --log-healthy : log/show also passed health checks. By default this is off when the plugin support this feature. (can be overridden by --no-log to disable all logging) --mail-to : list of e-mail address(es) to which an e-mail alert will be send to [requires mail core plugin] +--newer : show the (failed) events for each HC that are newer than the given date --no-lock : disable locking to allow concurrent script executions --no-log : do not log any messages to the script log file or health check results. --no-monitor : do not stop the execution of a HC after \$HC_TIME_OUT seconds --notify : notify upon HC failure(s). Multiple options may be specified if comma-separated (see --list-core for availble formats) +--older : show the (failed) events for each HC that are older than the given date --report : report on failed HC events (STDOUT is the default reporting method) --reverse : show the report in reverse date order (newest events first) --run : execute HC(s). @@ -596,7 +603,7 @@ Parameters: --sms-provider : name of a supported SMS provider (see \$SMS_PROVIDERS) [requires SMS core plugin] --sms-to : name of person or group to which a sms alert will be send to [requires SMS core plugin] --timeout : maximum runtime of a HC plugin in seconds (overrides \$HC_TIME_OUT) ---today : show today's events (HC and their combined STC value) +--today : show today's (failed) events (HC and their combined STC value) --version : show the timestamp of the script. --with-history : also include events that have been archived already (reporting) @@ -659,6 +666,7 @@ do if [[ ! -h "${FSYML}" ]] then ln -s "${FFILE##*/}" "${FSYML}" >/dev/null + # shellcheck disable=SC2181 (( $? == 0 )) && \ print -u2 "INFO: created symbolic link ${FFILE} -> ${FSYML}" fi @@ -676,6 +684,7 @@ do if [[ -h "${FDIR}/${FSYML}" ]] && [[ ! -f "${FDIR}/${FSYML}" ]] then rm -f "${FDIR}/${FSYML}" >/dev/null + # shellcheck disable=SC2181 (( $? == 0 )) && \ print -u2 "INFO: remove dead symbolic link ${FSYML}" fi @@ -925,6 +934,13 @@ do # shellcheck disable=SC2034 ARG_MAIL_TO="${CMD_PARAMETER#--mail-to=}" ;; + -newer=*) + ARG_NEWER="${CMD_PARAMETER#-newer=}" + ;; + --newer=*) + # shellcheck disable=SC2034 + ARG_NEWER="${CMD_PARAMETER#--newer=}" + ;; -notify=*) ARG_NOTIFY="${CMD_PARAMETER#-notify=}" ;; @@ -941,6 +957,13 @@ do -no-monitor|--no-monitor) ARG_MONITOR=0 ;; + -older=*) + ARG_OLDER="${CMD_PARAMETER#-older=}" + ;; + --older=*) + # shellcheck disable=SC2034 + ARG_OLDER="${CMD_PARAMETER#--older=}" + ;; -report|--report) # compatability support <2017-12-15 if (( ARG_ACTION > 0 )) then @@ -1108,6 +1131,7 @@ case ${ARG_ACTION} in # check for HC (function) exists_hc "${HC_CHECK}" && die "cannot find HC: ${HC_CHECK}" stat_hc "${HC_CHECK}" + # shellcheck disable=SC2181 if (( $? == 0 )) then log "HC ${HC_CHECK} is currently disabled" @@ -1115,6 +1139,7 @@ case ${ARG_ACTION} in log "HC ${HC_CHECK} is currently enabled" fi is_scheduled "${HC_CHECK}" + # shellcheck disable=SC2181 if (( $? == 0 )) then log "HC ${HC_CHECK} is currently not scheduled (cron)" @@ -1130,6 +1155,7 @@ case ${ARG_ACTION} in exists_hc "${HC_DISABLE}" && die "cannot find HC: ${HC_DISABLE}" log "disabling HC: ${HC_DISABLE}" touch "${STATE_PERM_DIR}/${HC_DISABLE}.disabled" >/dev/null 2>&1 + # shellcheck disable=SC2181 if (( $? == 0 )) then log "successfully disabled HC: ${HC_DISABLE}" @@ -1149,6 +1175,7 @@ case ${ARG_ACTION} in die "state directory does not exist, all HC(s) are enabled" stat_hc "${HC_ENABLE}" || die "HC is already enabled" rm -f "${STATE_PERM_DIR}/${HC_ENABLE}.disabled" >/dev/null 2>&1 + # shellcheck disable=SC2181 if (( $? == 0 )) then log "successfully enabled HC: ${HC_ENABLE}" @@ -1163,7 +1190,7 @@ case ${ARG_ACTION} in HC_NOW="$(date '+%Y-%m-%d %H:%M:%S' 2>/dev/null)" if [[ -z "${HC_FAIL_ID}" ]] then - HC_FAIL_ID="$(print ${HC_NOW} | tr -d '\-:[:space:]')" + HC_FAIL_ID="$(print "${HC_NOW}" | tr -d '\-:[:space:]')" fi # --check-host handling (( ARG_CHECK_HOST == 1 )) && init_check_host @@ -1174,12 +1201,14 @@ case ${ARG_ACTION} in # shellcheck disable=SC2034 HC_MSG_VAR="" : >${HC_MSG_FILE} 2>/dev/null + # shellcheck disable=SC2181 if (( $? > 0 )) then die "unable to reset the \${HC_MSG_FILE} file" fi # check for HC (function) exists_hc "${HC_RUN}" + # shellcheck disable=SC2181 if (( $? == 0 )) then # callback for display_init with extra code 'MISSING' @@ -1193,6 +1222,7 @@ case ${ARG_ACTION} in continue fi stat_hc "${HC_RUN}" + # shellcheck disable=SC2181 if (( $? == 0 )) then # call for display_init with extra code 'DISABLED' @@ -1209,11 +1239,13 @@ case ${ARG_ACTION} in HC_STDOUT_LOG="${TMP_DIR}/${HC_RUN}.stdout.log.$$" HC_STDERR_LOG="${TMP_DIR}/${HC_RUN}.stderr.log.$$" : >${HC_STDOUT_LOG} 2>/dev/null + # shellcheck disable=SC2181 if (( $? > 0 )) then die "unable to reset the \${HC_STDOUT_LOG} file" fi : >${HC_STDERR_LOG} 2>/dev/null + # shellcheck disable=SC2181 if (( $? > 0 )) then die "unable to reset the \${HC_STDERR_LOG} file" @@ -1317,6 +1349,7 @@ case ${ARG_ACTION} in ;; 5) # show info on HC (single) exists_hc "${ARG_HC}" + # shellcheck disable=SC2181 if (( $? == 0 )) then die "cannot find HC: ${ARG_HC}" diff --git a/sources/lib/core/display_csv.sh b/sources/lib/core/display_csv.sh index b6cbc9c..efc48f2 100644 --- a/sources/lib/core/display_csv.sh +++ b/sources/lib/core/display_csv.sh @@ -30,7 +30,7 @@ function display_csv { # ------------------------- CONFIGURATION starts here ------------------------- -typeset _VERSION="2018-10-28" # YYYY-MM-DD +typeset _VERSION="2019-03-16" # YYYY-MM-DD typeset _SUPPORTED_PLATFORMS="AIX,HP-UX,Linux" # uname -s match typeset _DISPLAY_SEP=";" # ------------------------- CONFIGURATION ends here --------------------------- @@ -52,16 +52,18 @@ typeset _ID_BIT="" # parse $HC_MSG_VAR if [[ -n "${HC_MSG_VAR}" ]] then + # shellcheck disable=SC1117 printf "%s${_DISPLAY_SEP}%s${_DISPLAY_SEP}%s${_DISPLAY_SEP}%s${_DISPLAY_SEP}%s${_DISPLAY_SEP}%s\n" "Health Check" "STC" "Message" "FAIL ID" \ "Current Value" "Expected Value" # shellcheck disable=SC2034 - print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read _DISPLAY_MSG_STC _DISPLAY_MSG_TIME _DISPLAY_MSG_TEXT _DISPLAY_MSG_CUR_VAL _DISPLAY_MSG_EXP_VAL + print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read -r _DISPLAY_MSG_STC _DISPLAY_MSG_TIME _DISPLAY_MSG_TEXT _DISPLAY_MSG_CUR_VAL _DISPLAY_MSG_EXP_VAL do # magically unquote if needed if [[ -n "${_DISPLAY_MSG_TEXT}" ]] then data_contains_string "${_DISPLAY_MSG_TEXT}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _DISPLAY_MSG_TEXT=$(data_magic_unquote "${_DISPLAY_MSG_TEXT}") @@ -70,6 +72,7 @@ then if [[ -n "${_DISPLAY_MSG_CUR_VAL}" ]] then data_contains_string "${_DISPLAY_MSG_CUR_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _DISPLAY_MSG_CUR_VAL=$(data_magic_unquote "${_DISPLAY_MSG_CUR_VAL}") @@ -78,6 +81,7 @@ then if [[ -n "${_DISPLAY_MSG_EXP_VAL}" ]] then data_contains_string "${_DISPLAY_MSG_EXP_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _DISPLAY_MSG_EXP_VAL=$(data_magic_unquote "${_DISPLAY_MSG_EXP_VAL}") @@ -94,6 +98,7 @@ then _DISPLAY_MSG_CUR_VAL=$(data_escape_csv "${_DISPLAY_MSG_CUR_VAL}") _DISPLAY_MSG_EXP_VAL=$(data_escape_csv "${_DISPLAY_MSG_EXP_VAL}") + # shellcheck disable=SC1117 printf "%s${_DISPLAY_SEP}%s${_DISPLAY_SEP}%s${_DISPLAY_SEP}%s${_DISPLAY_SEP}%s${_DISPLAY_SEP}%s\n" \ "${_DISPLAY_HC}" \ "${_DISPLAY_MSG_STC}" \ diff --git a/sources/lib/core/display_init.sh b/sources/lib/core/display_init.sh index 7a2f79c..97e3071 100644 --- a/sources/lib/core/display_init.sh +++ b/sources/lib/core/display_init.sh @@ -31,7 +31,7 @@ function display_init { # ------------------------- CONFIGURATION starts here ------------------------- -typeset _VERSION="2018-10-28" # YYYY-MM-DD +typeset _VERSION="2019-03-16" # YYYY-MM-DD typeset _SUPPORTED_PLATFORMS="AIX,HP-UX,Linux" # uname -s match # ------------------------- CONFIGURATION ends here --------------------------- @@ -93,7 +93,7 @@ then else if [[ -n "${HC_MSG_VAR}" ]] then - print "${HC_MSG_VAR}" | while read _HC_MSG_ENTRY + print "${HC_MSG_VAR}" | while read -r _HC_MSG_ENTRY do # determine _DISPLAY_MSG_STC (sum of all STCs) _DISPLAY_MSG_STC=$(print "${_HC_MSG_ENTRY}" | awk -F"${MSG_SEP}" 'BEGIN { stc = 0 } { for (i=1;i<=NF;i++) { stc = stc + $1 } } END { print stc }' 2>/dev/null) @@ -135,7 +135,7 @@ else fi # print status line (but also check for terminal support) - +# shellcheck disable=SC1117 printf "%-30s %50s\t[ %8s ]%s\n" \ "${_DISPLAY_HC}" \ "(${_DISPLAY_CFG})" \ diff --git a/sources/lib/core/display_json.sh b/sources/lib/core/display_json.sh index 4407f01..aaad0b6 100644 --- a/sources/lib/core/display_json.sh +++ b/sources/lib/core/display_json.sh @@ -30,7 +30,7 @@ function display_json { # ------------------------- CONFIGURATION starts here ------------------------- -typeset _VERSION="2018-10-28" # YYYY-MM-DD +typeset _VERSION="2019-03-16" # YYYY-MM-DD typeset _SUPPORTED_PLATFORMS="AIX,HP-UX,Linux" # uname -s match # ------------------------- CONFIGURATION ends here --------------------------- @@ -51,12 +51,13 @@ typeset _ID_BIT="" # parse $HC_MSG_VAR if [[ -n "${HC_MSG_VAR}" ]] then - print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read _DISPLAY_MSG_STC _DISPLAY_MSG_TIME _DISPLAY_MSG_TEXT _DISPLAY_MSG_CUR_VAL _DISPLAY_MSG_EXP_VAL + print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read -r _DISPLAY_MSG_STC _DISPLAY_MSG_TIME _DISPLAY_MSG_TEXT _DISPLAY_MSG_CUR_VAL _DISPLAY_MSG_EXP_VAL do # magically unquote if needed if [[ -n "${_DISPLAY_MSG_TEXT}" ]] then data_contains_string "${_DISPLAY_MSG_TEXT}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _DISPLAY_MSG_TEXT=$(data_magic_unquote "${_DISPLAY_MSG_TEXT}") @@ -65,6 +66,7 @@ then if [[ -n "${_DISPLAY_MSG_CUR_VAL}" ]] then data_contains_string "${_DISPLAY_MSG_CUR_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _DISPLAY_MSG_CUR_VAL=$(data_magic_unquote "${_DISPLAY_MSG_CUR_VAL}") @@ -73,6 +75,7 @@ then if [[ -n "${_DISPLAY_MSG_EXP_VAL}" ]] then data_contains_string "${_DISPLAY_MSG_EXP_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _DISPLAY_MSG_EXP_VAL=$(data_magic_unquote "${_DISPLAY_MSG_EXP_VAL}") diff --git a/sources/lib/core/display_terse.sh b/sources/lib/core/display_terse.sh index 7fe9a12..deb4088 100644 --- a/sources/lib/core/display_terse.sh +++ b/sources/lib/core/display_terse.sh @@ -30,7 +30,7 @@ function display_terse { # ------------------------- CONFIGURATION starts here ------------------------- -typeset _VERSION="2018-05-20" # YYYY-MM-DD +typeset _VERSION="2019-03-16" # YYYY-MM-DD typeset _SUPPORTED_PLATFORMS="AIX,HP-UX,Linux" # uname -s match # ------------------------- CONFIGURATION ends here --------------------------- @@ -51,15 +51,17 @@ typeset _ID_BIT="" # parse $HC_MSG_VAR if [[ -n "${HC_MSG_VAR}" ]] then + # shellcheck disable=SC1117 printf "%-30s\t%s\t%-16s\t%s\n" "HC" "STC" "FAIL ID" "Message" # shellcheck disable=SC2034 - print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read _DISPLAY_MSG_STC _DISPLAY_MSG_TIME _DISPLAY_MSG_TEXT _DISPLAY_MSG_CUR_VAL _DISPLAY_MSG_EXP_VAL + print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read -r _DISPLAY_MSG_STC _DISPLAY_MSG_TIME _DISPLAY_MSG_TEXT _DISPLAY_MSG_CUR_VAL _DISPLAY_MSG_EXP_VAL do # magically unquote if needed if [[ -n "${_DISPLAY_MSG_TEXT}" ]] then data_contains_string "${_DISPLAY_MSG_TEXT}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _DISPLAY_MSG_TEXT=$(data_magic_unquote "${_DISPLAY_MSG_TEXT}") @@ -68,6 +70,7 @@ then if [[ -n "${_DISPLAY_MSG_CUR_VAL}" ]] then data_contains_string "${_DISPLAY_MSG_CUR_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _DISPLAY_MSG_CUR_VAL=$(data_magic_unquote "${_DISPLAY_MSG_CUR_VAL}") @@ -76,6 +79,7 @@ then if [[ -n "${_DISPLAY_MSG_EXP_VAL}" ]] then data_contains_string "${_DISPLAY_MSG_EXP_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _DISPLAY_MSG_EXP_VAL=$(data_magic_unquote "${_DISPLAY_MSG_EXP_VAL}") @@ -87,6 +91,7 @@ then else _ID_BIT="" fi + # shellcheck disable=SC1117 printf "%-30s\t%s\t%-16s\t%s\n" \ "${_DISPLAY_HC}" \ "${_DISPLAY_MSG_STC}" \ diff --git a/sources/lib/core/display_zenoss.sh b/sources/lib/core/display_zenoss.sh index be31f2b..da805d4 100644 --- a/sources/lib/core/display_zenoss.sh +++ b/sources/lib/core/display_zenoss.sh @@ -32,7 +32,7 @@ function display_zenoss { # ------------------------- CONFIGURATION starts here ------------------------- -typeset _VERSION="2018-10-28" # YYYY-MM-DD +typeset _VERSION="2019-03-16" # YYYY-MM-DD typeset _SUPPORTED_PLATFORMS="AIX,HP-UX,Linux" # uname -s match # ------------------------- CONFIGURATION ends here --------------------------- @@ -53,12 +53,13 @@ typeset _DISPLAY_MSG_EXP_VAL="" if [[ -n "${HC_MSG_VAR}" ]] then # shellcheck disable=SC2034 - print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read _DISPLAY_MSG_STC _DISPLAY_MSG_TIME _DISPLAY_MSG_TEXT _DISPLAY_MSG_CUR_VAL _DISPLAY_MSG_EXP_VAL + print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read -r _DISPLAY_MSG_STC _DISPLAY_MSG_TIME _DISPLAY_MSG_TEXT _DISPLAY_MSG_CUR_VAL _DISPLAY_MSG_EXP_VAL do # magically unquote if needed if [[ -n "${_DISPLAY_MSG_TEXT}" ]] then data_contains_string "${_DISPLAY_MSG_TEXT}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _DISPLAY_MSG_TEXT=$(data_magic_unquote "${_DISPLAY_MSG_TEXT}") @@ -67,6 +68,7 @@ then if [[ -n "${_DISPLAY_MSG_CUR_VAL}" ]] then data_contains_string "${_DISPLAY_MSG_CUR_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _DISPLAY_MSG_CUR_VAL=$(data_magic_unquote "${_DISPLAY_MSG_CUR_VAL}") @@ -75,6 +77,7 @@ then if [[ -n "${_DISPLAY_MSG_EXP_VAL}" ]] then data_contains_string "${_DISPLAY_MSG_EXP_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _DISPLAY_MSG_EXP_VAL=$(data_magic_unquote "${_DISPLAY_MSG_EXP_VAL}") @@ -82,6 +85,7 @@ then fi if (( _DISPLAY_MSG_STC > 0 )) then + # shellcheck disable=SC1117 printf "NOK|data1=%s data2=%s data3=%s data4=\"%s\" data5=%s data6=%s\n" \ "${_DISPLAY_HC}" \ "${_DISPLAY_MSG_STC}" \ @@ -90,6 +94,7 @@ then "${_DISPLAY_MSG_CUR_VAL}" \ "${_DISPLAY_MSG_EXP_VAL}" else + # shellcheck disable=SC1117 printf "OK|data1=%s data2=%s data3=%s data4=\"%s\" data5=%s data6=%s\n" \ "${_DISPLAY_HC}" \ "${_DISPLAY_MSG_STC}" \ diff --git a/sources/lib/core/include_core.sh b/sources/lib/core/include_core.sh index c572287..0afde65 100644 --- a/sources/lib/core/include_core.sh +++ b/sources/lib/core/include_core.sh @@ -75,7 +75,7 @@ do return 2 } LOG_COUNT=$(wc -l ${ARCHIVE_FILE} 2>/dev/null | cut -f1 -d' ' 2>/dev/null) - log "# entries in ${ARCHIVE_FILE} now: ${LOG_COUNT}" + log "# of entries in ${ARCHIVE_FILE} now: ${LOG_COUNT}" # remove archived messages from the $HC_LOG (but create a backup first!) cp -p ${HC_LOG} ${SAVE_HC_LOG} 2>/dev/null @@ -315,6 +315,7 @@ do (( ARG_DEBUG > 0 )) && debug "notify_eif plugin is available" ;; *report_std.sh) + # shellcheck disable=SC2034 HAS_REPORT_STD=1 (( ARG_DEBUG > 0 )) && debug "report_std plugin is available" ;; @@ -522,7 +523,7 @@ if (( DO_NOTIFY_SMS > 0 )) && [[ -z "${ARG_SMS_PROVIDER}" ]] then die "you cannot specify '--notify=sms' without '--sms-provider'" fi -# --report/--detail/--id/--reverse/--last/--today/--with-history +# --report/--detail/--id/--reverse/--last/--today/--with-history/--older/--newer if (( DO_REPORT_STD > 0 )) then if (( ARG_DETAIL > 0 )) && [[ -z "${ARG_FAIL_ID}" ]] @@ -545,6 +546,14 @@ then then die "you cannot specify '--last' with '--id'" fi + if (( ARG_LAST > 0 )) && [[ -n "${ARG_OLDER}" ]] + then + die "you cannot specify '--last' with '--older'" + fi + if (( ARG_LAST > 0 )) && [[ -n "${ARG_NEWER}" ]] + then + die "you cannot specify '--last' with '--newer'" + fi if (( ARG_TODAY > 0 )) && (( ARG_DETAIL > 0 )) then die "you cannot specify '--today' with '--detail'" @@ -557,6 +566,26 @@ then then die "you cannot specify '--today' with '--id'" fi + if (( ARG_TODAY > 0 )) && [[ -n "${ARG_OLDER}" ]] + then + die "you cannot specify '--today' with '--older" + fi + if (( ARG_TODAY > 0 )) && [[ -n "${ARG_NEWER}" ]] + then + die "you cannot specify '--today' with '--newer'" + fi + if [[ -n "${ARG_OLDER}" ]] && [[ -n "${ARG_NEWER}" ]] + then + die "you cannot use '--older' with '--newer'" + fi + if [[ -n "${ARG_FAIL_ID}" ]] && [[ -n "${ARG_OLDER}" ]] + then + die "you cannot use '--id' with '--older'" + fi + if [[ -n "${ARG_FAIL_ID}" ]] && [[ -n "${ARG_NEWER}" ]] + then + die "you cannot use '--id' with '--newer'" + fi fi if (( DO_REPORT_STD == 0 )) && (( ARG_LAST > 0 )) then @@ -574,6 +603,14 @@ if (( DO_REPORT_STD == 0 )) && [[ -n "${ARG_FAIL_ID}" ]] then die "you cannot specify '--id' without '--report'" fi +if (( DO_REPORT_STD == 0 )) && [[ -n "${ARG_OLDER}" ]] +then + die "you cannot specify '--older' without '--report'" +fi +if (( DO_REPORT_STD == 0 )) && [[ -n "${ARG_NEWER}" ]] +then + die "you cannot specify '--newer' without '--report'" +fi return 0 } @@ -612,6 +649,7 @@ typeset EXISTS_RC=0 for FDIR in $(print "${FPATH}" | tr ':' ' ' 2>/dev/null) do data_contains_string "${FDIR}" "core" + # shellcheck disable=SC2181 if (( $? == 0 )) then ls "${FDIR}/${EXISTS_HC}" >/dev/null 2>&1 && EXISTS_RC=1 @@ -676,7 +714,7 @@ fi trap "[[ -f ${TMP_FILE} ]] && rm -f ${TMP_FILE} >/dev/null 2>&1; return 1" 1 2 3 15 # check and rewrite log file(s) -find ${LOG_STASH} -type f -print 2>/dev/null | while read FIX_FILE +find ${LOG_STASH} -type f -print 2>/dev/null | while read -r FIX_FILE do log "fixing log file ${FIX_FILE} ..." @@ -784,9 +822,11 @@ do # swap log file (but create a backup first!) cp -p ${FIX_FILE} ${SAVE_TMP_FILE} 2>/dev/null + # shellcheck disable=SC2181 if (( $? == 0 )) then mv ${TMP_FILE} ${FIX_FILE} 2>/dev/null + # shellcheck disable=SC2181 if (( $? > 0 )) then warn "failed to move/update log file, rolling back" @@ -850,8 +890,13 @@ then (( ARG_DEBUG > 0 )) && debug "HC all STC: ${ALL_MSG_STC}" data_is_numeric "${ALL_MSG_STC}" || die "HC all STC computes to a non-numeric value" else - # nothing to do - return 0 + # nothing to do, respect current EXIT_CODE + if (( EXIT_CODE > 0 )) + then + return ${EXIT_CODE} + else + return 0 + fi fi # display routines @@ -987,12 +1032,13 @@ then # default STDOUT if (( ARG_VERBOSE > 0 )) then - print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read ONE_MSG_STC ONE_MSG_TIME ONE_MSG_TEXT ONE_MSG_CUR_VAL ONE_MSG_EXP_VAL + print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read -r ONE_MSG_STC ONE_MSG_TIME ONE_MSG_TEXT ONE_MSG_CUR_VAL ONE_MSG_EXP_VAL do # magically unquote if needed if [[ -n "${ONE_MSG_TEXT}" ]] then data_contains_string "${ONE_MSG_TEXT}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then ONE_MSG_TEXT=$(data_magic_unquote "${ONE_MSG_TEXT}") @@ -1001,6 +1047,7 @@ then if [[ -n "${ONE_MSG_CUR_VAL}" ]] then data_contains_string "${ONE_MSG_CUR_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then ONE_MSG_CUR_VAL=$(data_magic_unquote "${ONE_MSG_CUR_VAL}") @@ -1009,6 +1056,7 @@ then if [[ -n "${ONE_MSG_EXP_VAL}" ]] then data_contains_string "${ONE_MSG_EXP_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then ONE_MSG_EXP_VAL=$(data_magic_unquote "${ONE_MSG_EXP_VAL}") @@ -1017,8 +1065,10 @@ then printf "%s" "INFO: ${HC_NAME} [STC=${ONE_MSG_STC}]: ${ONE_MSG_TEXT}" if (( ONE_MSG_STC > 0 )) then + # shellcheck disable=SC1117 printf " %s\n" "[FAIL_ID=${HC_FAIL_ID}]" else + # shellcheck disable=SC1117 printf "\n" fi done @@ -1030,12 +1080,13 @@ fi if (( ARG_LOG > 0 )) then # log routine (combined STC=0 or <>0) - print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read ONE_MSG_STC ONE_MSG_TIME ONE_MSG_TEXT ONE_MSG_CUR_VAL ONE_MSG_EXP_VAL + print "${HC_MSG_VAR}" | while IFS=${MSG_SEP} read -r ONE_MSG_STC ONE_MSG_TIME ONE_MSG_TEXT ONE_MSG_CUR_VAL ONE_MSG_EXP_VAL do # magically unquote if needed if [[ -n "${ONE_MSG_TEXT}" ]] then data_contains_string "${ONE_MSG_TEXT}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then ONE_MSG_TEXT=$(data_magic_unquote "${ONE_MSG_TEXT}") @@ -1044,6 +1095,7 @@ then if [[ -n "${ONE_MSG_CUR_VAL}" ]] then data_contains_string "${ONE_MSG_CUR_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then ONE_MSG_CUR_VAL=$(data_magic_unquote "${ONE_MSG_CUR_VAL}") @@ -1052,6 +1104,7 @@ then if [[ -n "${ONE_MSG_EXP_VAL}" ]] then data_contains_string "${ONE_MSG_EXP_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then ONE_MSG_EXP_VAL=$(data_magic_unquote "${ONE_MSG_EXP_VAL}") @@ -1064,9 +1117,11 @@ then "${ONE_MSG_TEXT}" >>${HC_LOG} if (( ONE_MSG_STC > 0 )) then + # shellcheck disable=SC1117 printf "%s${LOG_SEP}\n" "${HC_FAIL_ID}" >>${HC_LOG} HC_STC_RC=$(( HC_STC_RC + 1 )) else + # shellcheck disable=SC1117 printf "\n" >>${HC_LOG} fi done @@ -1136,8 +1191,11 @@ fi # --flip-rc: pass RC of HC plugin back if (( ARG_FLIP_RC == 0 )) then + # standard RC, error free return 0 else + # exit with max 255 + (( HC_STC_RC > 255 )) && HC_STC_RC=255 return ${HC_STC_RC} fi } @@ -1375,14 +1433,16 @@ typeset FVERSION="" typeset FCONFIG="" typeset FSTATE="enabled" # default typeset FFILE="" +typeset FSCRIPT="" typeset HAS_FCONFIG=0 typeset HC_VERSION="" # print header if [[ "${FACTION}" != "list" ]] then + # shellcheck disable=SC1117 printf "%-30s\t%-8s\t%s\t\t%s\n" "Core plugin" "State" "Version" "Config?" - # shellcheck disable=SC2183 + # shellcheck disable=SC2183,SC1117 printf "%80s\n" | tr ' ' - fi print "${FPATH}" | tr ':' '\n' | grep "core$" | sort 2>/dev/null | while read -r FDIR @@ -1391,14 +1451,18 @@ do # shellcheck disable=SC2010 ls -1 ${FDIR}/*.sh 2>/dev/null | grep -v "include_" | sort 2>/dev/null | while read -r FFILE do + # cache script contents in memory + FSCRIPT=$(<${FFILE}) + # reset state FSTATE="enabled" # find function name but skip helper functions in the plug-in file (function _name) - FNAME=$(grep -E -e "^function[[:space:]]+[^_]" "${FFILE}" 2>&1) + FNAME=$(print -R "${FSCRIPT}" | grep -E -e "^function[[:space:]]+[^_]" 2>/dev/null) # look for version string (cut off comments but don't use [:space:] in tr) - FVERSION=$(grep '^typeset _VERSION=' "${FFILE}" 2>&1 | tr -d '\"' | tr -d ' \t' | cut -f1 -d'#' | cut -f2 -d'=') + FVERSION=$(print -R "${FSCRIPT}" | grep '^typeset _VERSION=' 2>/dev/null |\ + awk 'match($0,/[0-9]+-[0-9]+-[0-9]+/){print substr($0, RSTART, RLENGTH)}' 2>/dev/null) # look for configuration file string - HAS_FCONFIG=$(grep -c '^typeset _CONFIG_FILE=' "${FFILE}" 2>&1) + HAS_FCONFIG=$(print -R "${FSCRIPT}" | grep -c '^typeset _CONFIG_FILE=' 2>/dev/null) if (( HAS_FCONFIG > 0 )) then FCONFIG="Yes" @@ -1411,12 +1475,14 @@ do # show results if [[ "${FACTION}" != "list" ]] then + # shellcheck disable=SC1117 printf "%-30s\t%-8s\t%s\t%s\n" \ "${FNAME#function *}" \ "${FSTATE}" \ "${FVERSION#typeset _VERSION=*}" \ "${FCONFIG}" else + # shellcheck disable=SC1117 printf "%s\n" "${FNAME#function *}" fi done @@ -1430,7 +1496,7 @@ then print "${FPATH}" | tr ':' '\n' | grep "core$" | while read -r FDIR do # do not use 'find -type l' here! - # shellcheck disable=SC2010 + # shellcheck disable=SC2010,SC1117 ls ${FDIR} 2>/dev/null | grep -v "\." | while read -r FFILE do if [[ -h "${FDIR}/${FFILE}" ]] && [[ ! -f "${FDIR}/${FFILE}" ]] @@ -1469,6 +1535,7 @@ typeset FSTATE="" typeset FFILE="" typeset FHEALTHY="" typeset FSCHEDULED=0 +typeset FSCRIPT="" typeset HAS_FCONFIG=0 typeset HAS_FHEALTHY="" typeset DISABLE_FFILE="" @@ -1485,20 +1552,26 @@ fi # print header if [[ "${FACTION}" != "list" ]] then + # shellcheck disable=SC1117 printf "%-40s\t%-8s\t%s\t\t%s\t%s\t%s\n" "Health Check" "State" "Version" "Config?" "Sched?" "H+?" - # shellcheck disable=SC2183 + # shellcheck disable=SC2183,SC1117 printf "%100s\n" | tr ' ' - fi -print "${FPATH}" | tr ':' '\n' | grep -v "core$" | sort 2>/dev/null | while read -r FDIR +print "${FPATH}" | tr ':' '\n' 2>/dev/null | grep -v "core$" 2>/dev/null | sort 2>/dev/null |\ + while read -r FDIR do ls -1 ${FDIR}/${FNEEDLE} 2>/dev/null | sort 2>/dev/null | while read -r FFILE do + # cache script contents in memory + FSCRIPT=$(<${FFILE}) + # find function name but skip helper functions in the plug-in file (function _name) - FNAME=$(grep -E -e "^function[[:space:]]+[^_]" "${FFILE}" 2>&1) + FNAME=$(print -R "${FSCRIPT}" | grep -E -e "^function[[:space:]]+[^_]" 2>/dev/null) # look for version string (cut off comments but don't use [:space:] in tr) - FVERSION=$(grep '^typeset _VERSION=' "${FFILE}" 2>&1 | tr -d '\"' | tr -d ' \t' | cut -f1 -d'#' | cut -f2 -d'=') + FVERSION=$(print -R "${FSCRIPT}" | grep '^typeset _VERSION=' 2>/dev/null |\ + awk 'match($0,/[0-9]+-[0-9]+-[0-9]+/){print substr($0, RSTART, RLENGTH)}' 2>/dev/null) # look for configuration file string - HAS_FCONFIG=$(grep -c '^typeset _CONFIG_FILE=' "${FFILE}" 2>&1) + HAS_FCONFIG=$(print -R "${FSCRIPT}" | grep -c '^typeset _CONFIG_FILE=' 2>/dev/null) if (( HAS_FCONFIG > 0 )) then FCONFIG="Yes" @@ -1539,7 +1612,7 @@ do esac fi # check for log_healthy support through --hc-args (plugin) - elif (( $(grep -c -E -e "_LOG_HEALTHY" "${FFILE}" 2>/dev/null) > 0 )) + elif (( $(print -R "${FSCRIPT}" | grep -c -E -e "_LOG_HEALTHY" 2>/dev/null) > 0 )) then FCONFIG="No" FHEALTHY="S" @@ -1559,6 +1632,7 @@ do [[ -h ${FFILE%%.*} ]] || FSTATE="unlinked" # check scheduling is_scheduled "${FNAME#function *}" + # shellcheck disable=SC2181 if (( $? == 0 )) then FSCHEDULED="No" @@ -1569,6 +1643,7 @@ do # show results if [[ "${FACTION}" != "list" ]] then + # shellcheck disable=SC1117 printf "%-40s\t%-8s\t%s\t%s\t%s\t%s\n" \ "${FNAME#function *}" \ "${FSTATE}" \ @@ -1577,6 +1652,7 @@ do "${FSCHEDULED}" \ "${FHEALTHY}" else + # shellcheck disable=SC1117 printf "%s\n" "${FNAME#function *}" fi done @@ -1590,7 +1666,7 @@ then print "${FPATH}" | tr ':' '\n' | grep -v "core" | while read -r FDIR do # do not use 'find -type l' here! - # shellcheck disable=SC2010 + # shellcheck disable=SC2010,SC1117 ls ${FDIR} 2>/dev/null | grep -v "\." | while read -r FFILE do if [[ -h "${FDIR}/${FFILE}" ]] && [[ ! -f "${FDIR}/${FFILE}" ]] @@ -1672,6 +1748,7 @@ typeset HC_MSG_EXP_VAL="" if [[ -n "${3}" ]] then data_contains_string "${3}" "${MSG_SEP}" + # shellcheck disable=SC2181 if (( $? > 0 )) then HC_MSG_TEXT=$(data_magic_quote "${3}") @@ -1682,6 +1759,7 @@ fi if [[ -n "${4}" ]] then data_contains_string "${4}" "${MSG_SEP}" + # shellcheck disable=SC2181 if (( $? > 0 )) then HC_MSG_CUR_VAL=$(data_magic_quote "${4}") @@ -1692,6 +1770,7 @@ fi if [[ -n "${5}" ]] then data_contains_string "${5}" "${MSG_SEP}" + # shellcheck disable=SC2181 if (( $? > 0 )) then HC_MSG_EXP_VAL=$(data_magic_quote "${5}") @@ -1749,9 +1828,9 @@ awk -F"${LOG_SEP}" '{ # empty hc variable means count of empty lines in log file if (hc != "") { printf ("\t%s:\n", hc) - printf ("\t\t# entries: %s\n", total_count[hc]) - printf ("\t\t# STC==0 : %s\n", ok_count[hc]) - printf ("\t\t# STC<>0 : %s\n", nok_count[hc]) + printf ("\t\t# entries: %d\n", total_count[hc]) + printf ("\t\t# STC==0 : %d\n", ok_count[hc]) + printf ("\t\t# STC<>0 : %d\n", nok_count[hc]) printf ("\t\tfirst : %s\n", first_entry[hc]) printf ("\t\tlast : %s\n", last_entry[hc]) } @@ -1763,7 +1842,7 @@ awk -F"${LOG_SEP}" '{ print; print print -R "--- ARCHIVED events --" print -find ${ARCHIVE_DIR} -type f -name "hc.*.log" 2>/dev/null | while read _ARCHIVE_FILE +find ${ARCHIVE_DIR} -type f -name "hc.*.log" 2>/dev/null | while read -r _ARCHIVE_FILE do print "${_ARCHIVE_FILE}:" awk -F"${LOG_SEP}" '{ @@ -1791,9 +1870,9 @@ do # empty hc variable means count of empty lines in log file if (hc != "") { printf ("\t%s:\n", hc) - printf ("\t\t# entries: %s\n", total_count[hc]) - printf ("\t\t# STC==0 : %s\n", ok_count[hc]) - printf ("\t\t# STC<>0 : %s\n", nok_count[hc]) + printf ("\t\t# entries: %d\n", total_count[hc]) + printf ("\t\t# STC==0 : %d\n", ok_count[hc]) + printf ("\t\t# STC<>0 : %d\n", nok_count[hc]) printf ("\t\tfirst : %s\n", first_entry[hc]) printf ("\t\tlast : %s\n", last_entry[hc]) } diff --git a/sources/lib/core/include_data.sh b/sources/lib/core/include_data.sh index f0924af..1c10c6d 100644 --- a/sources/lib/core/include_data.sh +++ b/sources/lib/core/include_data.sh @@ -814,6 +814,7 @@ typeset _CONVERT_DATE="" # try the GNU version of 'date -d' _CONVERT_DATE=$(date -d @"${_UNIX_EPOCH}" 2>/dev/null) +# shellcheck disable=SC2181 if (( $? > 0 )) then # try the perl way diff --git a/sources/lib/core/include_os.sh b/sources/lib/core/include_os.sh index ef6bd07..90ad57c 100644 --- a/sources/lib/core/include_os.sh +++ b/sources/lib/core/include_os.sh @@ -42,6 +42,7 @@ check_platform 'Linux' || { # try LSB first (good for Ubuntu & derivatives) if [[ -f /etc/lsb-release ]] then + # shellcheck disable=SC1091 . /etc/lsb-release LINUX_DISTRO="${DISTRIB_ID}" LINUX_RELEASE="${DISTRIB_RELEASE}" @@ -132,6 +133,7 @@ if [[ -x ${_CRM_BIN} && -n "${_CRM_BIN}" ]] then # check for active crm status >/dev/null 2>/dev/null + # shellcheck disable=SC2181 (( $? == 0 )) && _HAS_CRM=1 else (( ARG_DEBUG > 0 )) && debug "corosync (crm) is not active here" @@ -167,6 +169,7 @@ if [[ -x ${_DOCKER_BIN} && -n "${_DOCKER_BIN}" ]] then # check for active docker ps >/dev/null 2>/dev/null + # shellcheck disable=SC2181 (( $? == 0 )) && _HAS_DOCKER=1 else (( ARG_DEBUG > 0 )) && debug "docker is not active here" diff --git a/sources/lib/core/notify_mail.sh b/sources/lib/core/notify_mail.sh index 923ebd1..9d2f449 100644 --- a/sources/lib/core/notify_mail.sh +++ b/sources/lib/core/notify_mail.sh @@ -30,7 +30,7 @@ function notify_mail { # ------------------------- CONFIGURATION starts here ------------------------- -typeset _VERSION="2018-10-28" # YYYY-MM-DD +typeset _VERSION="2019-03-16" # YYYY-MM-DD typeset _SUPPORTED_PLATFORMS="AIX,HP-UX,Linux" # uname -s match # ------------------------- CONFIGURATION ends here --------------------------- @@ -138,6 +138,7 @@ do if [[ -n "${_MAIL_MSG_TEXT}" ]] then data_contains_string "${_MAIL_MSG_TEXT}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _MAIL_MSG_TEXT=$(data_magic_unquote "${_MAIL_MSG_TEXT}") @@ -146,6 +147,7 @@ do if [[ -n "${_MAIL_MSG_CUR_VAL}" ]] then data_contains_string "${_MAIL_MSG_CUR_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _MAIL_MSG_CUR_VAL=$(data_magic_unquote "${_MAIL_MSG_CUR_VAL}") @@ -154,6 +156,7 @@ do if [[ -n "${_MAIL_MSG_EXP_VAL}" ]] then data_contains_string "${_MAIL_MSG_EXP_VAL}" "${MAGIC_QUOTE}" + # shellcheck disable=SC2181 if (( $? > 0 )) then _MAIL_MSG_EXP_VAL=$(data_magic_unquote "${_MAIL_MSG_EXP_VAL}") @@ -161,6 +164,7 @@ do fi if (( _MAIL_MSG_STC > 0 )) then + # shellcheck disable=SC1117 _HC_BODY=$(printf "%s\n%s\n" "${_HC_BODY}" "${_MAIL_MSG_TEXT}") fi done diff --git a/sources/lib/core/report_std.sh b/sources/lib/core/report_std.sh index aa3140e..f0d6e64 100644 --- a/sources/lib/core/report_std.sh +++ b/sources/lib/core/report_std.sh @@ -20,7 +20,7 @@ # DOES: report HC events on STDOUT # EXPECTS: n/a # RETURNS: 0 -# REQUIRES: count_log_errors(), init_hc(), list_hc(), $EVENTS_DIR, $HC_LOG +# REQUIRES: count_log_errors(), die(), init_hc(), list_hc(), $EVENTS_DIR, $HC_LOG # # ----------------------------------------------------------------------------- # DO NOT CHANGE THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING! @@ -30,7 +30,7 @@ function report_std { # ------------------------- CONFIGURATION starts here ------------------------- -typeset _VERSION="2019-01-27" # YYYY-MM-DD +typeset _VERSION="2019-03-18" # YYYY-MM-DD typeset _SUPPORTED_PLATFORMS="AIX,HP-UX,Linux" # uname -s match # ------------------------- CONFIGURATION ends here --------------------------- @@ -39,7 +39,6 @@ typeset _SUPPORTED_PLATFORMS="AIX,HP-UX,Linux" # uname -s match init_hc "$0" "${_SUPPORTED_PLATFORMS}" "${_VERSION}" typeset _DIR_PREFIX="" -typeset _FAIL_COUNT=0 typeset _ERROR_COUNT=0 typeset _ERROR_TOTAL_COUNT=0 typeset _HC_LAST="" @@ -47,25 +46,102 @@ typeset _HC_LAST_TIME="" typeset _HC_LAST_STC=0 typeset _HC_LAST_FAIL_ID="-" typeset _ID_NEEDLE="" +typeset _IS_VALID_DATE="" +typeset _IS_VALID_ID="" typeset _CHECK_FILE="" +typeset _LOG_FILE="" +typeset _LOG_FILES="" typeset _LOG_STASH="" typeset _SORT_CMD="" +typeset _LOG_MONTH="" +typeset _LOG_YEAR="" +typeset _OLDER_MONTH="" +typeset _OLDER_YEAR="" +typeset _NEWER_MONTH="" +typeset _NEWER_YEAR="" -# which files do we need to examine -if (( ARG_HISTORY > 0 )) +# set archive log stash +if (( ARG_HISTORY > 0 )) || [[ -n "${ARG_OLDER}" ]] || [[ -n "${ARG_NEWER}" ]] then set +f # file globbing must be on - _LOG_STASH="${HC_LOG} ${ARCHIVE_DIR}/hc.*.log" -else - _LOG_STASH="${HC_LOG}" + _LOG_STASH="${ARCHIVE_DIR}/hc.*.log" fi +# apply --newer or --older to log stash by intelligently selecting archive log files +if [[ -n "${_LOG_STASH}" ]] +then + if [[ -n "${ARG_OLDER}" ]] || [[ -n "${ARG_NEWER}" ]] + then + (( ARG_DEBUG > 0 )) && debug "mangling archive log stash because we used --older/--newer" + if [[ -n "${ARG_OLDER}" ]] + then + # check datestamp (should be YYYYMMDD) + _IS_VALID_DATE=$(print "${ARG_OLDER}" | grep -c -E -e "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$" 2>/dev/null) + (( _IS_VALID_DATE > 0 )) || die "invalid date for '--older' specified" + # shellcheck disable=SC2003 + _OLDER_YEAR=$(expr substr "${ARG_OLDER}" 1 4 2>/dev/null) + # shellcheck disable=SC2003 + _OLDER_MONTH=$(expr substr "${ARG_OLDER}" 5 2 2>/dev/null) + (( ARG_DEBUG > 0 )) && debug "END date: ${_OLDER_YEAR}${_OLDER_MONTH}" + # expand curent log stash (use for/do ~f*cking mskh) + # shellcheck disable=SC2086 + _LOG_FILES=$(find ${_LOG_STASH} -type f 2>/dev/null | tr '\n' ' ' 2>/dev/null) + _LOG_STASH="" + for _LOG_FILE in ${_LOG_FILES} + do + # shellcheck disable=SC2003 + _LOG_YEAR=$(expr substr "$(basename ${_LOG_FILE} 2/dev/null)" 4 4 2>/dev/null) + # shellcheck disable=SC2003 + _LOG_MONTH=$(expr substr "$(basename ${_LOG_FILE} 2/dev/null)" 9 2 2>/dev/null) + (( ARG_DEBUG > 0 )) && debug "LOG date for ${_LOG_FILE}: ${_LOG_YEAR}${_LOG_MONTH}" + # add log file to stash if file date <= older date; force arithemetic on strings + if (( ${_LOG_YEAR}${_LOG_MONTH} <= ${_OLDER_YEAR}${_OLDER_MONTH} )) + then + (( ARG_DEBUG > 0 )) && debug "push ${_LOG_FILE} to archive log stash" + _LOG_STASH="${_LOG_STASH} ${_LOG_FILE}" + fi + done + fi + if [[ -n "${ARG_NEWER}" ]] + then + # check datestamp (should be YYYYMMDD) + _IS_VALID_DATE=$(print "${ARG_NEWER}" | grep -c -E -e "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$" 2>/dev/null) + (( _IS_VALID_DATE > 0 )) || die "invalid date for '--newer' specified" + # shellcheck disable=SC2003 + _NEWER_YEAR=$(expr substr "${ARG_NEWER}" 1 4) + # shellcheck disable=SC2003 + _NEWER_MONTH=$(expr substr "${ARG_NEWER}" 5 2) + (( ARG_DEBUG > 0 )) && debug "START date: ${_NEWER_YEAR}${_NEWER_MONTH}" + # expand curent log stash (use for/do ~f*cking mskh) + # shellcheck disable=SC2086 + _LOG_FILES=$(find ${_LOG_STASH} -type f 2>/dev/null | tr '\n' ' ' 2>/dev/null) + _LOG_STASH="" + for _LOG_FILE in ${_LOG_FILES} + do + # shellcheck disable=SC2003 + _LOG_YEAR=$(expr substr "$(basename ${_LOG_FILE} 2/dev/null)" 4 4) + # shellcheck disable=SC2003 + _LOG_MONTH=$(expr substr "$(basename ${_LOG_FILE} 2/dev/null)" 9 2) + (( ARG_DEBUG > 0 )) && debug "LOG date for ${_LOG_FILE}: ${_LOG_YEAR}${_LOG_MONTH}" + # add log file to stash if file date <= older date; force arithemetic on strings + if (( ${_LOG_YEAR}${_LOG_MONTH} >= ${_NEWER_YEAR}${_NEWER_MONTH} )) + then + (( ARG_DEBUG > 0 )) && debug "push ${_LOG_FILE} to archive log stash" + _LOG_STASH="${_LOG_STASH} ${_LOG_FILE}" + fi + done + fi + fi +fi +# add current log file to log stash +_LOG_STASH="${HC_LOG} ${_LOG_STASH}" # --last report if (( ARG_LAST > 0 )) then + # shellcheck disable=SC1117 printf "\n| %-40s | %-20s | %-14s | %-4s\n" "HC" "Timestamp" "FAIL ID" "STC (combined value)" - # shellcheck disable=SC2183 - printf "%100s\n" | tr ' ' - + # shellcheck disable=SC2183,SC1117 + printf "%120s\n" | tr ' ' - # loop over all HCs list_hc "list" | while read -r _HC_LAST do @@ -74,7 +150,8 @@ then _HC_LAST_FAIL_ID="-" # find last event or block of events (same timestamp) # (but unfortunately this is only accurate to events within the SAME second!) - _HC_LAST_TIME="$(grep -h ${_HC_LAST} ${_LOG_STASH} 2>/dev/null | sort -n | cut -f1 -d${LOG_SEP} | uniq | tail -1)" + # shellcheck disable=SC2086 + _HC_LAST_TIME="$(grep -h ${_HC_LAST} ${_LOG_STASH} 2>/dev/null | sort -n 2>/dev/null | cut -f1 -d${LOG_SEP} 2>/dev/null | uniq 2>/dev/null | tail -1 2>/dev/null)" if [[ -z "${_HC_LAST_TIME}" ]] then _HC_LAST_TIME="-" @@ -82,6 +159,7 @@ then else # use of cat is not useless here, makes sure END {} gets executed even # if $_LOG STASH contains non-existing files (because of * wildcard) + # shellcheck disable=SC2002,SC2086 cat ${_LOG_STASH} 2>/dev/null | awk -F "${LOG_SEP}" -v needle_time="${_HC_LAST_TIME}" -v needle_hc="${_HC_LAST}" \ ' BEGIN { @@ -99,9 +177,10 @@ then END { print last_fail_id, last_stc } - ' 2>/dev/null | read _HC_LAST_FAIL_ID _HC_LAST_STC + ' 2>/dev/null | read -r _HC_LAST_FAIL_ID _HC_LAST_STC fi # report on findings + # shellcheck disable=SC1117 printf "| %-40s | %-20s | %-14s | %-4s\n" \ "${_HC_LAST}" "${_HC_LAST_TIME}" "${_HC_LAST_FAIL_ID}" "${_HC_LAST_STC}" done @@ -112,89 +191,130 @@ then # other reports else _ID_NEEDLE="[0-9][0-9]*" - [[ -n "${ARG_FAIL_ID}" ]] && _ID_NEEDLE="${ARG_FAIL_ID}" + if [[ -n "${ARG_FAIL_ID}" ]] + then + # check FAIL_ID first (must be YYYYMMDDHHMMSS) + _IS_VALID_ID=$(print "${ARG_FAIL_ID}" | grep -c -E -e "^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])([0-1][0-9]|2[0-3])([0-5][0-9])([0-5][0-9])$" 2>/dev/null) + (( _IS_VALID_ID > 0 )) || die "invalid ID specified" + _ID_NEEDLE="${ARG_FAIL_ID}" + fi (( ARG_TODAY > 0 )) && _ID_NEEDLE="$(date '+%Y%m%d')" # refers to timestamp of HC FAIL_ID - # check fail count (look for unique IDs in the 5th field of the HC log) - _FAIL_COUNT=$(cut -f5 -d"${LOG_SEP}" ${_LOG_STASH} 2>/dev/null | grep -E -e "${_ID_NEEDLE}" | uniq | wc -l) - if (( _FAIL_COUNT > 0 )) + # reverse? + if (( ARG_REVERSE == 0 )) then - # check for detail or not? - if (( ARG_DETAIL > 0 )) && (( _FAIL_COUNT > 1 )) - then - ARG_LOG=1 die "you must specify a unique FAIL_ID value" - fi - # reverse? - if (( ARG_REVERSE == 0 )) - then - _SORT_CMD="sort -n" - else - _SORT_CMD="sort -rn" - fi - # global or detailed? - if (( ARG_DETAIL == 0 )) - then - printf "\n| %-20s | %-14s | %-40s | %-s\n" \ - "Timestamp" "FAIL ID" "HC" "Message" - # shellcheck disable=SC2183 - printf "%120s\n" | tr ' ' - - - # print failed events - # not a useless use of cat here - # (sort baulks if $_LOG STASH contains non-existing files (because of * wildcard)) - cat ${_LOG_STASH} 2>/dev/null | ${_SORT_CMD} 2>/dev/null | awk -F"${LOG_SEP}" -v id_needle="${_ID_NEEDLE}" \ - ' - { - if ($5 ~ id_needle && NF <= '"${NUM_LOG_FIELDS}"') { - printf ("| %-20s | %-14s | %-40s | %-s\n", $1, $5, $2, $4) - } - } - ' 2>/dev/null - printf "\n%-s\n" "SUMMARY: ${_FAIL_COUNT} failed HC event(s) found." - else - # print failed events (we may have multiple events for 1 FAIL ID) - # not a useless use of cat here - # (sort baulks if $_LOG STASH contains non-existing files (because of * wildcard)) - cat ${_LOG_STASH} 2>/dev/null | ${_SORT_CMD} 2>/dev/null | awk -F"${LOG_SEP}" -v id_needle="${_ID_NEEDLE}" \ - ' BEGIN { - event_count = 1 - dashes = sprintf("%36s",""); gsub (/ /, "-", dashes); - } - { - if ($5 ~ id_needle && NF <= '"${NUM_LOG_FIELDS}"') { - printf ("%36sMSG #%03d%36s", dashes, event_count, dashes) - printf ("\nTime : %-s\nHC : %-s\nDetail : %-s\n", $1, $2, $4) - event_count++ - } - } - ' 2>/dev/null - - _DIR_PREFIX="$(expr substr ${ARG_FAIL_ID} 1 4)-$(expr substr ${ARG_FAIL_ID} 5 2)" - # shellcheck disable=SC2183 - printf "%37sSTDOUT%37s\n" | tr ' ' -; - # display non-empty STDOUT file(s) - if [[ -n "$(du -a ${EVENTS_DIR}/${_DIR_PREFIX}/${ARG_FAIL_ID}/*.stdout.log 2>/dev/null | awk '$1*512 > 0 {print $2}')" ]] - then - cat ${EVENTS_DIR}/${_DIR_PREFIX}/${ARG_FAIL_ID}/*.stdout.log - else - printf "%-s\n" "No STDOUT found" - fi - - # shellcheck disable=SC2183 - printf "%37sSTDERR%37s\n" | tr ' ' -; - # display non-empty STDERR file(s) - if [[ -n "$(du -a ${EVENTS_DIR}/${_DIR_PREFIX}/${ARG_FAIL_ID}/*.stderr.log 2>/dev/null | awk '$1*512 > 0 {print $2}')" ]] - then - cat ${EVENTS_DIR}/${_DIR_PREFIX}/${ARG_FAIL_ID}/*.stderr.log - else - printf "%-s\n" "No STDERR found" - fi - - # shellcheck disable=SC2183 - printf "%80s\n" | tr ' ' - - fi + _SORT_CMD="sort -n" else - printf "\n%-s\n" "SUMMARY: 0 failed HC events found." + _SORT_CMD="sort -rn" + fi + # global or detailed? + if (( ARG_DETAIL == 0 )) + then + # print failed events + # not a useless use of cat here + # (sort baulks if $_LOG STASH contains non-existing files (because of * wildcard)) + # shellcheck disable=SC2002,SC2086 + cat ${_LOG_STASH} 2>/dev/null | ${_SORT_CMD} 2>/dev/null | awk -F"${LOG_SEP}" \ + -v id_needle="${_ID_NEEDLE}" \ + -v older="${ARG_OLDER}" \ + -v newer="${ARG_NEWER}" \ + ' + BEGIN { + event_count = 0 + if (older != "") { use_filter = 1; use_older = 1 } + if (newer != "") { use_filter = 1; use_newer = 1 } + } + + { + # apply --older/--newer filter? + if (use_filter > 0) { + # find log entries that are older than --older= + if (use_older > 0) { + log_date = substr($5, 1, 8); + if (log_date < older && $5 ~ id_needle && NF <= '"${NUM_LOG_FIELDS}"') { + events[event_count]=$0; + event_count++; + } + } + # find log entries that are newer than --older= + if (use_newer > 0) { + log_date = substr($5, 1, 8); + if (log_date > newer && $5 ~ id_needle && NF <= '"${NUM_LOG_FIELDS}"') { + events[event_count]=$0; + event_count++; + } + } + # no --older/--newer filter + } else { + if ($5 ~ id_needle && NF <= '"${NUM_LOG_FIELDS}"') { + events[event_count]=$0; + event_count++; + } + } + } + + END { + if (event_count > 0) { + printf ("\n| %-20s | %-14s | %-40s | %-s\n", "Timestamp", "FAIL ID", "HC", "Message"); + for (i=0; i<120; i++) { printf ("-"); } + # loop over array (sorted) + for (i=0; i/dev/null + else + # print failed events (we may have multiple events for 1 FAIL ID) + # not a useless use of cat here + # (sort baulks if $_LOG STASH contains non-existing files (because of * wildcard)) + # shellcheck disable=SC2002,SC2086 + cat ${_LOG_STASH} 2>/dev/null | ${_SORT_CMD} 2>/dev/null | awk -F"${LOG_SEP}" -v id_needle="${_ID_NEEDLE}" \ + ' BEGIN { + event_count = 1 + dashes = sprintf("%36s",""); gsub (/ /, "-", dashes); + } + { + if ($5 ~ id_needle && NF <= '"${NUM_LOG_FIELDS}"') { + printf ("%36sMSG #%03d%36s", dashes, event_count, dashes) + printf ("\nTime : %-s\nHC : %-s\nDetail : %-s\n", $1, $2, $4) + event_count++ + } + } + ' 2>/dev/null + + # shellcheck disable=SC2003,SC2086 + _DIR_PREFIX="$(expr substr ${ARG_FAIL_ID} 1 4 2>/dev/null)-$(expr substr ${ARG_FAIL_ID} 5 2 2>/dev/null)" + # shellcheck disable=SC2183,SC1117 + printf "%37sSTDOUT%37s\n" | tr ' ' -; + # display non-empty STDOUT file(s) + # shellcheck disable=SC2086 + if [[ -n "$(du -a ${EVENTS_DIR}/${_DIR_PREFIX}/${ARG_FAIL_ID}/*.stdout.log 2>/dev/null | awk '$1*512 > 0 {print $2}')" ]] + then + cat ${EVENTS_DIR}/${_DIR_PREFIX}/${ARG_FAIL_ID}/*.stdout.log + else + # shellcheck disable=SC1117 + printf "%-s\n" "No STDOUT found" + fi + + # shellcheck disable=SC2183,SC1117 + printf "%37sSTDERR%37s\n" | tr ' ' -; + # display non-empty STDERR file(s) + # shellcheck disable=SC2086 + if [[ -n "$(du -a ${EVENTS_DIR}/${_DIR_PREFIX}/${ARG_FAIL_ID}/*.stderr.log 2>/dev/null | awk '$1*512 > 0 {print $2}')" ]] + then + cat ${EVENTS_DIR}/${_DIR_PREFIX}/${ARG_FAIL_ID}/*.stderr.log + else + # shellcheck disable=SC1117 + printf "%-s\n" "No STDERR found" + fi + + # shellcheck disable=SC2183,SC1117 + printf "%80s\n" | tr ' ' - fi fi @@ -207,7 +327,8 @@ else fi # check consistency of log(s) -find ${_LOG_STASH} -type f -print 2>/dev/null | while read _CHECK_FILE +# shellcheck disable=SC2086 +find ${_LOG_STASH} -type f -print 2>/dev/null | while read -r _CHECK_FILE do _ERROR_COUNT=$(count_log_errors ${_CHECK_FILE}) if (( _ERROR_COUNT > 0 ))