* Added Clusterware (CRS) plugins (as a platform).

* Moved Serviceguard plugins to separate platform (+fixes)
* Other fixes
This commit is contained in:
Patrick Van der Veken
2019-04-24 14:19:02 +02:00
parent a4e1b4b954
commit 05dd91edc4
49 changed files with 1584 additions and 1126 deletions
@@ -0,0 +1,236 @@
#!/usr/bin/env ksh
#******************************************************************************
# @(#) check_clusterware_resource_config
#******************************************************************************
# @(#) Copyright (C) 2019 by KUDOS BVBA (info@kudos.be). All rights reserved.
#
# This program is a free software; you can redistribute it and/or modify
# it under the same terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details
#******************************************************************************
#
# DOCUMENTATION (MAIN)
# -----------------------------------------------------------------------------
# @(#) MAIN: check_clusterware_resource_config
# DOES: see _show_usage()
# EXPECTS: see _show_usage()
# REQUIRES: data_comma2space(), dump_logs(), init_hc(), log_hc(), warn()
#
# @(#) HISTORY:
# @(#) 2019-04-20: merged HP-UX+Linux version + fixes [Patrick Van der Veken]
# -----------------------------------------------------------------------------
# DO NOT CHANGE THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING!
#******************************************************************************
# -----------------------------------------------------------------------------
function check_clusterware_resource_config
{
# ------------------------- CONFIGURATION starts here -------------------------
typeset _CONFIG_FILE="${CONFIG_DIR}/$0.conf"
typeset _VERSION="2019-04-20" # YYYY-MM-DD
typeset _SUPPORTED_PLATFORMS="Linux" # uname -s match
typeset _MAX_LENGTH_VALUE_STRING=30
# ------------------------- CONFIGURATION ends here ---------------------------
# set defaults
(( ARG_DEBUG > 0 && ARG_DEBUG_LEVEL > 0 )) && set ${DEBUG_OPTS}
init_hc "$0" "${_SUPPORTED_PLATFORMS}" "${_VERSION}"
typeset _ARGS=$(data_comma2space "$*")
typeset _ARG=""
typeset _MSG=""
typeset _STC=0
typeset _CFG_HEALTHY=""
typeset _LOG_HEALTHY=0
typeset _CRSCTL_BIN=""
typeset _RES_RUN_FILE="${TMP_DIR}/.$0.res_run.$$"
typeset _RES_CFG_FILE="${TMP_DIR}/.$0.res_cfg.$$"
typeset _RES_INSTANCE=""
typeset _RES_INSTANCES=""
typeset _RES_CFG_ENTRY=""
typeset _RES_ENTRY=""
typeset _RES_MATCH=""
typeset _RES_PARAM=""
typeset _RES_VALUE=""
# handle arguments (originally comma-separated)
for _ARG in ${_ARGS}
do
case "${_ARG}" in
help)
_show_usage $0 ${_VERSION} ${_CONFIG_FILE} && return 0
;;
esac
done
# set local trap for cleanup
# shellcheck disable=SC2064
trap "rm -f ${_RES_RUN_FILE}.* ${_RES_CFG_FILE}.* >/dev/null 2>&1; return 1" 1 2 3 15
# handle configuration file
[[ -n "${ARG_CONFIG_FILE}" ]] && _CONFIG_FILE="${ARG_CONFIG_FILE}"
if [[ ! -r ${_CONFIG_FILE} ]]
then
warn "unable to read configuration file at ${_CONFIG_FILE}"
return 1
fi
_CFG_HEALTHY=$(_CONFIG_FILE="${_CONFIG_FILE}" data_get_lvalue_from_config 'log_healthy')
case "${_CFG_HEALTHY}" in
yes|YES|Yes)
_LOG_HEALTHY=1
;;
*)
# do not override hc_arg
(( _LOG_HEALTHY > 0 )) || _LOG_HEALTHY=0
;;
esac
# log_healthy
(( ARG_LOG_HEALTHY > 0 )) && _LOG_HEALTHY=1
if (( _LOG_HEALTHY > 0 ))
then
if (( ARG_LOG > 0 ))
then
log "logging/showing passed health checks"
else
log "showing passed health checks (but not logging)"
fi
else
log "not logging/showing passed health checks"
fi
# look for resource instance names
grep -E -e '^\[' ${_CONFIG_FILE} 2>/dev/null | cut -f1 -d']' 2>/dev/null | cut -f2 -d'[' 2>/dev/null |\
while read _RES_INSTANCE
do
_RES_INSTANCES="${_RES_INSTANCES} ${_RES_INSTANCE}"
done
if [[ -z "${_RES_INSTANCES}" ]]
then
warn "no resource information configured in ${_CONFIG_FILE}"
return 1
fi
# get resource information from crsctl
_CRSCTL_BIN="$(command -v crsctl 2>>${HC_STDERR_LOG})"
if [[ -z "${_CRSCTL_BIN}" || ! -x ${_CRSCTL_BIN} ]]
then
warn "CRS {crsctl} is not installed here"
return 1
else
for _RES_INSTANCE in ${_RES_INSTANCES}
do
crsctl status resource ${_RES_INSTANCE} -f 2>>${HC_STDERR_LOG} |\
tr -d ' \t' >${_RES_RUN_FILE}.${_RES_INSTANCE} 2>/dev/null
[[ -s ${_RES_RUN_FILE}.${_RES_INSTANCE} ]] || {
_MSG="unable to gather configuration cluster resource ${_RES_INSTANCE}"
log_hc "$0" 1 "${_MSG}"
# dump debug info
(( ARG_DEBUG > 0 && ARG_DEBUG_LEVEL > 0 )) && dump_logs
return 1
}
done
fi
# gather resource information from healthcheck configuration
for _RES_INSTANCE in ${_RES_INSTANCES}
do
awk -v resource="${_RES_INSTANCE}" '
# double escape []
BEGIN { found = 0; needle = "^\\["resource"\\]$" }
# skip blank lines
/^\s*$/ { next; }
# skip comment lines
/^#/ { next; }
# end marker
( $0 ~ /^\[.*\]$/ && found ) {
exit 1;
}
# start marker
$0 ~ needle {
found = 1;
};
# stanza body
( found && $0 !~ /^\[.*\]$/ ) {
# print non-compressed and compressed version
printf "%s|", $0;
gsub(" |\t", "", $0);
printf "%s\n", $0;
}' < ${_CONFIG_FILE} 2>>${HC_STDERR_LOG} >${_RES_CFG_FILE}.${_RES_INSTANCE}
done
# do resource configuration checks (using the compressed strings)
for _RES_INSTANCE in ${_RES_INSTANCES}
do
while read _RES_ENTRY
do
# split entry to get the compressed version
_RES_CFG_ENTRY=$(print "${_RES_ENTRY}" | cut -f2 -d'|' 2>/dev/null)
# get parameter name from non-compressed version
_RES_PARAM=$(print "${_RES_ENTRY}" | cut -f1 -d'|' 2>/dev/null | cut -f1 -d'=' 2>/dev/null)
# get parameter value from non-compressed version
_RES_VALUE=$(print "${_RES_ENTRY}" | cut -f1 -d'|' 2>/dev/null | cut -f2 -d'=' 2>/dev/null)
# is it present?
_RES_MATCH=$(grep -c "${_RES_CFG_ENTRY}" ${_RES_RUN_FILE}.${_RES_INSTANCE} 2>/dev/null)
# chop value if needed
if (( $(data_get_length_string "${_RES_VALUE}") > _MAX_LENGTH_VALUE_STRING ))
then
_RES_VALUE=$(data_get_substring "${_RES_VALUE}" ${_MAX_LENGTH_VALUE_STRING})
_RES_VALUE="${_RES_VALUE} ..."
fi
# find match between active and desired state?
if (( _RES_MATCH == 0 ))
then
# get parameter name from non-compressed version
_MSG="'${_RES_PARAM}' (${_RES_VALUE}) is not correctly configured for ${_RES_INSTANCE}"
_STC=1
else
_MSG="'${_RES_PARAM}' (${_RES_VALUE}) is configured for ${_RES_INSTANCE}"
fi
if (( _LOG_HEALTHY > 0 || _STC > 0 ))
then
log_hc "$0" ${_STC} "${_MSG}"
_STC=0
fi
done <${_RES_CFG_FILE}.${_RES_INSTANCE}
# add crsctl output to stdout log
print "==== {${_CRSCTL_BIN} status resource ${_RES_INSTANCE} -f} ====" >>${HC_STDOUT_LOG}
cat "${_RES_CFG_FILE}.${_RES_INSTANCE}" >>${HC_STDOUT_LOG}
done
# do cleanup
rm -f ${_RES_RUN_FILE}.* ${_RES_CFG_FILE}.* >/dev/null 2>&1
return 0
}
# -----------------------------------------------------------------------------
function _show_usage
{
cat <<- EOT
NAME : $1
VERSION : $2
CONFIG : $3 with parameters:
log_healthy=<yes|no>
and formatted stanzas for resource definitions
PURPOSE : Checks the configuration of Clusterware resources (parameters/values)
(comparing serialized strings from the HC configuration file to the
active cluster configuration)
EOT
return 0
}
#******************************************************************************
# END of script
#******************************************************************************
@@ -0,0 +1,217 @@
#!/usr/bin/env ksh
#******************************************************************************
# @(#) check_clusterware_resource_status
#******************************************************************************
# @(#) Copyright (C) 2019 by KUDOS BVBA (info@kudos.be). All rights reserved.
#
# This program is a free software; you can redistribute it and/or modify
# it under the same terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details
#******************************************************************************
#
# DOCUMENTATION (MAIN)
# -----------------------------------------------------------------------------
# @(#) MAIN: check_clusterware_resource_status
# DOES: see _show_usage()
# EXPECTS: see _show_usage()
# REQUIRES: data_comma2space(), data_contains_string(), data_uc(), dump_logs(),
# init_hc(), log_hc(), warn()
#
# @(#) HISTORY:
# @(#) 2019-04-20: merged HP-UX+Linux version [Patrick Van der Veken]
# -----------------------------------------------------------------------------
# DO NOT CHANGE THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING!
#******************************************************************************
# -----------------------------------------------------------------------------
function check_clusterware_resource_status
{
# ------------------------- CONFIGURATION starts here -------------------------
typeset _CONFIG_FILE="${CONFIG_DIR}/$0.conf"
typeset _VERSION="2019-04-20" # YYYY-MM-DD
typeset _SUPPORTED_PLATFORMS="Linux" # uname -s match
# ------------------------- CONFIGURATION ends here ---------------------------
# set defaults
(( ARG_DEBUG > 0 && ARG_DEBUG_LEVEL > 0 )) && set ${DEBUG_OPTS}
init_hc "$0" "${_SUPPORTED_PLATFORMS}" "${_VERSION}"
typeset _ARGS=$(data_comma2space "$*")
typeset _ARG=""
typeset _MSG=""
typeset _STC=0
typeset _CFG_HEALTHY=""
typeset _LOG_HEALTHY=0
typeset _CRS_HOST=""
typeset _CRS_NEEDLE=""
typeset _CRS_RESOURCE=""
typeset _CRS_STATES=""
typeset _CRS_STATE=""
typeset _CRS_STATES_ENTRY=""
typeset _CRS_STATE_ENTRY=""
typeset _CRSCTL_BIN=""
typeset _CRSCTL_STATUS=""
typeset _IS_ONLINE=0
typeset _MATCH_RC=0
# handle arguments (originally comma-separated)
for _ARG in ${_ARGS}
do
case "${_ARG}" in
help)
_show_usage $0 ${_VERSION} ${_CONFIG_FILE} && return 0
;;
esac
done
# handle configuration file
[[ -n "${ARG_CONFIG_FILE}" ]] && _CONFIG_FILE="${ARG_CONFIG_FILE}"
if [[ ! -r ${_CONFIG_FILE} ]]
then
warn "unable to read configuration file at ${_CONFIG_FILE}"
return 1
fi
_CFG_HEALTHY=$(_CONFIG_FILE="${_CONFIG_FILE}" data_get_lvalue_from_config 'log_healthy')
case "${_CFG_HEALTHY}" in
yes|YES|Yes)
_LOG_HEALTHY=1
;;
*)
# do not override hc_arg
(( _LOG_HEALTHY > 0 )) || _LOG_HEALTHY=0
;;
esac
# log_healthy
(( ARG_LOG_HEALTHY > 0 )) && _LOG_HEALTHY=1
if (( _LOG_HEALTHY > 0 ))
then
if (( ARG_LOG > 0 ))
then
log "logging/showing passed health checks"
else
log "showing passed health checks (but not logging)"
fi
else
log "not logging/showing passed health checks"
fi
# check for clusterware
_CRSCTL_BIN="$(command -v crsctl 2>>${HC_STDERR_LOG})"
if [[ -z "${_CRSCTL_BIN}" || ! -x ${_CRSCTL_BIN} ]]
then
warn "CRS {crsctl} is not installed here"
return 1
fi
# do resource status checks
grep -E -e "^crs:" ${_CONFIG_FILE} 2>/dev/null |\
while IFS=":" read -r _ _CRS_RESOURCE _CRS_STATES
do
# get actual resource info
(( ARG_DEBUG > 0 )) && debug "checking for resource: ${_CRS_RESOURCE}"
_CRSCTL_STATUS=$(crsctl status resource "${_CRS_RESOURCE}" 2>>${HC_STDERR_LOG})
if (( $? > 0 )) || [[ -z "${_CRSCTL_STATUS}" ]]
then
_MSG="unable to run command: {crsctl status resource ${_CRS_RESOURCE}}"
log_hc "$0" 1 "${_MSG}"
# dump debug info
(( ARG_DEBUG > 0 && ARG_DEBUG_LEVEL > 0 )) && dump_logs
return 1
fi
# loop over host/state entries
print "${_CRS_STATES}" | while IFS=',' read -rA _CRS_STATES_ENTRY
do
_IS_ONLINE=0
for _CRS_STATE_ENTRY in "${_CRS_STATES_ENTRY[@]}"
do
_CRS_HOST=$(print "${_CRS_STATE_ENTRY}" | cut -f1 -d'=' 2>/dev/null)
_CRS_STATE=$(print "${_CRS_STATE_ENTRY}" | cut -f2 -d'=' 2>/dev/null)
if [[ -z "${_CRS_HOST}" || -z "${_CRS_STATE}" ]]
then
warn "host/state value(s) for resource ${_CRS_RESOURCE} are/is incorrect in configuration file ${_CONFIG_FILE}"
continue
fi
(( ARG_DEBUG > 0 )) && debug "checking for host/state: ${_CRS_HOST}/${_CRS_STATE}"
# get actual resource state
CRS_STATE_LINE=$(print "${_CRSCTL_STATUS}" | grep -E -e "^STATE=" 2>/dev/null)
# set needle (wildcard or host check?)
if [[ "${_CRS_HOST}" = "*" ]]
then
_CRS_NEEDLE=$(data_uc "${_CRS_STATE}")
else
case "${_CRS_STATE}" in
ONLINE|online|Online)
_CRS_NEEDLE=$(data_uc "${_CRS_STATE}")
_CRS_NEEDLE="${_CRS_NEEDLE} on ${_CRS_HOST}"
;;
OFFLINE|offline|Offline)
_CRS_NEEDLE=$(data_uc "${_CRS_STATE}")
;;
esac
fi
# check for match
# if resource is online on at least one node, then CRS will not flag it offline
# on any other nodes in which case we just do a NOOP
# (ONLINE stanzas must preceed OFFLINE stanzas in the configuration file)
if (( _IS_ONLINE > 0 ))
then
_MATCH_RC=1
else
data_contains_string "${CRS_STATE_LINE}" "${_CRS_NEEDLE}"
_MATCH_RC=$?
fi
if (( _MATCH_RC >> 0 ))
then
_MSG="resource ${_CRS_RESOURCE} has a correct state [${_CRS_STATE}@${_CRS_HOST}]"
_STC=0
_IS_ONLINE=1
else
_MSG="resource ${_CRS_RESOURCE} has a wrong state [${_CRS_STATE}@${_CRS_HOST}]"
_STC=1
fi
if (( _LOG_HEALTHY > 0 || _STC > 0 ))
then
log_hc "$0" ${_STC} "${_MSG}"
fi
done
done
# add crsctl output to stdout log
print "==== {${_CRSCTL_BIN} status resource ${_CRS_RESOURCE}} ====" >>${HC_STDOUT_LOG}
print "${_CRSCTL_STATUS}" >>${HC_STDOUT_LOG}
done
return 0
}
# -----------------------------------------------------------------------------
function _show_usage
{
cat <<- EOT
NAME : $1
VERSION : $2
CONFIG : $3 with parameters:
log_healthy=<yes|no>
and formatted stanzas:
crs:<resource_name>:<*|node>=<ONLINE|OFFLINE>,<*|node>=<ONLINE|OFFLINE>,...
PURPOSE : Checks the STATE of CRS resource(s)
LOG HEALTHY : Supported
EOT
return 0
}
#******************************************************************************
# END of script
#******************************************************************************