diff options
Diffstat (limited to 'agents/alerts')
-rw-r--r-- | agents/alerts/Makefile.am | 15 | ||||
-rw-r--r-- | agents/alerts/alert_file.sh.sample | 122 | ||||
-rw-r--r-- | agents/alerts/alert_smtp.sh.sample | 118 | ||||
-rw-r--r-- | agents/alerts/alert_snmp.sh.sample | 193 |
4 files changed, 448 insertions, 0 deletions
diff --git a/agents/alerts/Makefile.am b/agents/alerts/Makefile.am new file mode 100644 index 0000000..fdb294f --- /dev/null +++ b/agents/alerts/Makefile.am @@ -0,0 +1,15 @@ +# +# Copyright 2016-2023 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. +# + +include $(top_srcdir)/mk/common.mk + +samplesdir = $(datadir)/$(PACKAGE)/alerts/ +dist_samples_DATA = alert_file.sh.sample \ + alert_smtp.sh.sample \ + alert_snmp.sh.sample diff --git a/agents/alerts/alert_file.sh.sample b/agents/alerts/alert_file.sh.sample new file mode 100644 index 0000000..f6c2211 --- /dev/null +++ b/agents/alerts/alert_file.sh.sample @@ -0,0 +1,122 @@ +#!/bin/sh +# +# Copyright 2015-2021 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. +# +############################################################################## +# Sample configuration (cib fragment in xml notation) +# ================================ +# <configuration> +# <alerts> +# <alert id="alert_sample" path="/path/to/alert_file.sh"> +# <instance_attributes id="config_for_alert_file"> +# <nvpair id="debug_option_1" name="debug_exec_order" value="false"/> +# </instance_attributes> +# <meta_attributes id="config_for_timestamp"> +# <nvpair id="ts_fmt" name="timestamp-format" value="%H:%M:%S.%06N"/> +# </meta_attributes> +# <recipient id="logfile_destination" value="/path/to/logfile"/> +# </alert> +# </alerts> +# </configuration> + +# Explicitly list all environment variables used, to make static analysis happy +: ${CRM_alert_version:=""} +: ${CRM_alert_recipient:=""} +: ${CRM_alert_node_sequence:=""} +: ${CRM_alert_timestamp:=""} +: ${CRM_alert_kind:=""} +: ${CRM_alert_node:=""} +: ${CRM_alert_desc:=""} +: ${CRM_alert_task:=""} +: ${CRM_alert_rsc:=""} +: ${CRM_alert_attribute_name:=""} +: ${CRM_alert_attribute_value:=""} + +# No one will probably ever see this echo, unless they run the script manually. +# An alternative would be to log to the system log, or similar. (We can't send +# this to the configured recipient, because that variable won't be defined in +# this case either.) +if [ -z $CRM_alert_version ]; then + echo "$0 must be run by Pacemaker version 1.1.15 or later" + exit 0 +fi + +# Alert agents must always handle the case where no recipients are defined, +# even if it's a no-op (a recipient might be added to the configuration later). +if [ -z "${CRM_alert_recipient}" ]; then + echo "$0 requires a recipient configured with a full filename path" + exit 0 +fi + +debug_exec_order_default="false" + +# Pacemaker passes instance attributes to alert agents as environment variables. +# It is completely up to the agent what instance attributes to support. +# Here, we define an instance attribute "debug_exec_order". +: ${debug_exec_order=${debug_exec_order_default}} + +if [ "${debug_exec_order}" = "true" ]; then + tstamp=`printf "%04d. " "$CRM_alert_node_sequence"` + if [ ! -z "$CRM_alert_timestamp" ]; then + tstamp="${tstamp} $CRM_alert_timestamp (`date "+%H:%M:%S.%06N"`): " + fi +else + if [ ! -z "$CRM_alert_timestamp" ]; then + tstamp="$CRM_alert_timestamp: " + fi +fi + +case $CRM_alert_kind in + node) + echo "${tstamp}Node '${CRM_alert_node}' is now '${CRM_alert_desc}'" >> "${CRM_alert_recipient}" + ;; + fencing) + # Other keys: + # + # CRM_alert_node + # CRM_alert_task + # CRM_alert_rc + # + echo "${tstamp}Fencing ${CRM_alert_desc}" >> "${CRM_alert_recipient}" + ;; + resource) + # Other keys: + # + # CRM_alert_target_rc + # CRM_alert_status + # CRM_alert_rc + # + if [ ${CRM_alert_interval} = "0" ]; then + CRM_alert_interval="" + else + CRM_alert_interval=" (${CRM_alert_interval})" + fi + + if [ ${CRM_alert_target_rc} = "0" ]; then + CRM_alert_target_rc="" + else + CRM_alert_target_rc=" (target: ${CRM_alert_target_rc})" + fi + + case ${CRM_alert_desc} in + Cancelled) ;; + *) + echo "${tstamp}Resource operation '${CRM_alert_task}${CRM_alert_interval}' for '${CRM_alert_rsc}' on '${CRM_alert_node}': ${CRM_alert_desc}${CRM_alert_target_rc}" >> "${CRM_alert_recipient}" + ;; + esac + ;; + attribute) + # + echo "${tstamp}Attribute '${CRM_alert_attribute_name}' on node '${CRM_alert_node}' was updated to '${CRM_alert_attribute_value}'" >> "${CRM_alert_recipient}" + ;; + + *) + echo "${tstamp}Unhandled $CRM_alert_kind alert" >> "${CRM_alert_recipient}" + env | grep CRM_alert >> "${CRM_alert_recipient}" + ;; +esac diff --git a/agents/alerts/alert_smtp.sh.sample b/agents/alerts/alert_smtp.sh.sample new file mode 100644 index 0000000..62bfc41 --- /dev/null +++ b/agents/alerts/alert_smtp.sh.sample @@ -0,0 +1,118 @@ +#!/bin/sh +# +# Copyright 2016-2021 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. +# +############################################################################## +# +# Sample configuration (cib fragment in xml notation) +# ================================ +# <configuration> +# <alerts> +# <alert id="smtp_alert" path="/path/to/alert_smtp"> +# <instance_attributes id="config_for_alert_smtp"> +# <nvpair id="cluster_name" name="cluster_name" value=""/> +# <nvpair id="email_client" name="email_client" value=""/> +# <nvpair id="email_sender" name="email_sender" value=""/> +# </instance_attributes> +# <recipient id="smtp_destination" value="admin@example.com"/> +# </alert> +# </alerts> +# </configuration> + +# Explicitly list all environment variables used, to make static analysis happy +: ${CRM_alert_version:=""} +: ${CRM_alert_recipient:=""} +: ${CRM_alert_timestamp:=""} +: ${CRM_alert_kind:=""} +: ${CRM_alert_node:=""} +: ${CRM_alert_desc:=""} +: ${CRM_alert_task:=""} +: ${CRM_alert_rsc:=""} +: ${CRM_alert_attribute_name:=""} +: ${CRM_alert_attribute_value:=""} + +email_client_default="sendmail" +email_sender_default="hacluster" +email_recipient_default="root" + +: ${email_client=${email_client_default}} +: ${email_sender=${email_sender_default}} +email_recipient="${CRM_alert_recipient-${email_recipient_default}}" + +node_name=`uname -n` +cluster_name=`crm_attribute --query -n cluster-name -q` +email_body=`env | grep CRM_alert_` + +if [ ! -z "${email_sender##*@*}" ]; then + email_sender="${email_sender}@${node_name}" +fi + +if [ ! -z "${email_recipient##*@*}" ]; then + email_recipient="${email_recipient}@${node_name}" +fi + +if [ -z ${CRM_alert_version} ]; then + email_subject="Pacemaker version 1.1.15 or later is required for alerts" +else + case ${CRM_alert_kind} in + node) + email_subject="${CRM_alert_timestamp} ${cluster_name}: Node '${CRM_alert_node}' is now '${CRM_alert_desc}'" + ;; + fencing) + email_subject="${CRM_alert_timestamp} ${cluster_name}: Fencing ${CRM_alert_desc}" + ;; + resource) + if [ ${CRM_alert_interval} = "0" ]; then + CRM_alert_interval="" + else + CRM_alert_interval=" (${CRM_alert_interval})" + fi + + if [ ${CRM_alert_target_rc} = "0" ]; then + CRM_alert_target_rc="" + else + CRM_alert_target_rc=" (target: ${CRM_alert_target_rc})" + fi + + case ${CRM_alert_desc} in + Cancelled) ;; + *) + email_subject="${CRM_alert_timestamp} ${cluster_name}: Resource operation '${CRM_alert_task}${CRM_alert_interval}' for '${CRM_alert_rsc}' on '${CRM_alert_node}': ${CRM_alert_desc}${CRM_alert_target_rc}" + ;; + esac + ;; + attribute) + # + email_subject="${CRM_alert_timestamp} ${cluster_name}: The '${CRM_alert_attribute_name}' attribute of the '${CRM_alert_node}' node was updated in '${CRM_alert_attribute_value}'" + ;; + *) + email_subject="${CRM_alert_timestamp} ${cluster_name}: Unhandled $CRM_alert_kind alert" + ;; + + esac +fi + +if [ ! -z "${email_subject}" ]; then + case $email_client in + # This sample script supports only sendmail for sending the email. + # Support for additional senders can easily be added by adding + # new cases here. + sendmail) + sendmail -t -r "${email_sender}" <<__EOF__ +From: ${email_sender} +To: ${email_recipient} +Return-Path: ${email_sender} +Subject: ${email_subject} + +${email_body} +__EOF__ + ;; + *) + ;; + esac +fi diff --git a/agents/alerts/alert_snmp.sh.sample b/agents/alerts/alert_snmp.sh.sample new file mode 100644 index 0000000..a140828 --- /dev/null +++ b/agents/alerts/alert_snmp.sh.sample @@ -0,0 +1,193 @@ +#!/bin/sh +# +# Copyright 2013 Florian CROUZAT <gentoo@floriancrouzat.net> +# Later changes copyright 2013-2023 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. +# +# Description: Manages a SNMP trap, provided by NTT OSSC as a +# script under Pacemaker control +# +############################################################################## +# This sample script assumes that only users who already have +# hacluster-equivalent access to the cluster nodes can edit the CIB. Otherwise, +# a malicious user could run commands as hacluster by inserting shell code into +# the trap_options or timestamp-format parameters. +# +# Sample configuration (cib fragment in xml notation) +# ================================ +# <configuration> +# <alerts> +# <alert id="snmp_alert" path="/path/to/alert_snmp.sh"> +# <instance_attributes id="config_for_alert_snmp"> +# <nvpair id="trap_node_states" name="trap_node_states" value="all"/> +# </instance_attributes> +# <meta_attributes id="config_for_timestamp"> +# <nvpair id="ts_fmt" name="timestamp-format" value="%Y-%m-%d,%H:%M:%S.%01N"/> +# </meta_attributes> +# <recipient id="snmp_destination" value="192.168.1.2"/> +# </alert> +# </alerts> +# </configuration> +# ================================ +# +# This uses the official Pacemaker MIB. +# 1.3.6.1.4.1.32723 has been assigned to the project by IANA: +# http://www.iana.org/assignments/enterprise-numbers + +# Defaults for user-configurable values +trap_binary_default="/usr/bin/snmptrap" +trap_version_default="2c" +trap_options_default="" +trap_community_default="public" +trap_node_states_default="all" +trap_fencing_tasks_default="all" +trap_resource_tasks_default="all" +trap_monitor_success_default="false" +trap_add_hires_timestamp_oid_default="true" +trap_snmp_persistent_dir_default="/var/lib/pacemaker/snmp" +trap_ignore_int32_default=2147483647 # maximum Integer32 value +trap_ignore_string_default="n/a" # doesn't conflict with valid XML IDs + +# Ensure all user-provided variables have values. +: ${trap_binary=${trap_binary_default}} +: ${trap_version=${trap_version_default}} +: ${trap_options=${trap_options_default}} +: ${trap_community=${trap_community_default}} +: ${trap_node_states=${trap_node_states_default}} +: ${trap_fencing_tasks=${trap_fencing_tasks_default}} +: ${trap_resource_tasks=${trap_resource_tasks_default}} +: ${trap_monitor_success=${trap_monitor_success_default}} +: ${trap_add_hires_timestamp_oid=${trap_add_hires_timestamp_oid_default}} +: ${trap_snmp_persistent_dir=${trap_snmp_persistent_dir_default}} +: ${trap_ignore_int32=${trap_ignore_int32_default}} +: ${trap_ignore_string=${trap_ignore_string_default}} + +# Ensure all cluster-provided variables have values, regardless of alert type. +: ${CRM_alert_node=${trap_ignore_string}} +: ${CRM_alert_rsc=${trap_ignore_string}} +: ${CRM_alert_task=${trap_ignore_string}} +: ${CRM_alert_desc=${trap_ignore_string}} +: ${CRM_alert_status=${trap_ignore_int32}} +: ${CRM_alert_rc=${trap_ignore_int32}} +: ${CRM_alert_target_rc=${trap_ignore_int32}} +: ${CRM_alert_attribute_name=${trap_ignore_string}} +: ${CRM_alert_attribute_value=${trap_ignore_string}} +: ${CRM_alert_version:=""} +: ${CRM_alert_recipient:=""} +: ${CRM_alert_kind:=""} + +if [ -z "$CRM_alert_version" ]; then + echo "$0 must be run by Pacemaker version 1.1.15 or later" + exit 0 +fi + +# SNMP v3 and above do not use community, which must be empty +case "$trap_version" in + 1|2c) ;; + *) trap_community="" ;; +esac + +if [ -z "$CRM_alert_recipient" ]; then + echo "$0 requires a recipient configured with the SNMP server IP address" + exit 0 +fi + +# Echo a high-resolution equivalent of the Pacemaker-provided time values +# using NetSNMP's DateAndTime specification ("%Y-%m-%d,%H:%M:%S.%01N"). +get_system_date() { + : ${CRM_alert_timestamp_epoch=$(date +%s)} + : ${CRM_alert_timestamp_usec=0} + + YMDHMS=$(date --date="@${CRM_alert_timestamp_epoch}" +"%Y-%m-%d,%H:%M:%S") + USEC=$(echo ${CRM_alert_timestamp_usec} | cut -b 1) + echo "${YMDHMS}.${USEC}" +} + +is_in_list() { + item_list=`echo "$1" | tr ',' ' '` + + if [ "${item_list}" = "all" ]; then + return 0 + else + for act in $item_list + do + act=`echo "$act" | tr A-Z a-z` + [ "$act" != "$2" ] && continue + return 0 + done + fi + return 1 +} + +send_pacemaker_trap() { + PREFIX="PACEMAKER-MIB::pacemakerNotification" + + OUTPUT=$("${trap_binary}" -v "${trap_version}" ${trap_options} \ + ${trap_community:+-c "${trap_community}"} \ + "${CRM_alert_recipient}" "" \ + "${PREFIX}Trap" \ + "${PREFIX}Node" s "${CRM_alert_node}" \ + "${PREFIX}Resource" s "${CRM_alert_rsc}" \ + "${PREFIX}Operation" s "${CRM_alert_task}" \ + "${PREFIX}Description" s "${CRM_alert_desc}" \ + "${PREFIX}Status" i "${CRM_alert_status}" \ + "${PREFIX}ReturnCode" i "${CRM_alert_rc}" \ + "${PREFIX}TargetReturnCode" i "${CRM_alert_target_rc}" \ + "${PREFIX}AttributeName" s "${CRM_alert_attribute_name}" \ + "${PREFIX}AttributeValue" s "${CRM_alert_attribute_value}" \ + ${hires_timestamp} 2>&1) + + if [ $? -ne 0 ]; then + echo "${trap_binary} returned error : rc=$? $OUTPUT" + fi +} + +if [ "${trap_add_hires_timestamp_oid}" = "true" ]; then + hires_timestamp="HOST-RESOURCES-MIB::hrSystemDate s $(get_system_date)" +fi + +if [ -z ${SNMP_PERSISTENT_DIR} ]; then + export SNMP_PERSISTENT_DIR="${trap_snmp_persistent_dir}" + # mkdir for snmp trap tools. + if [ ! -d ${SNMP_PERSISTENT_DIR} ]; then + mkdir -p ${SNMP_PERSISTENT_DIR} + fi +fi + +case "$CRM_alert_kind" in + node) + if is_in_list "${trap_node_states}" "${CRM_alert_desc}"; then + send_pacemaker_trap + fi + ;; + + fencing) + if is_in_list "${trap_fencing_tasks}" "${CRM_alert_task}"; then + send_pacemaker_trap + fi + ;; + + resource) + if is_in_list "${trap_resource_tasks}" "${CRM_alert_task}" && \ + [ "${CRM_alert_desc}" != "Cancelled" ] ; then + + if [ "${trap_monitor_success}" = "false" ] && \ + [ "${CRM_alert_rc}" = "${CRM_alert_target_rc}" ] && \ + [ "${CRM_alert_task}" = "monitor" ]; then + exit 0 + fi + send_pacemaker_trap + fi + ;; + + attribute) + send_pacemaker_trap + ;; + + *) + ;; +esac |