diff --git a/CHANGELOG.md b/CHANGELOG.md index b9d77908..d601b50d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * Removed all "warn: False" args in command, shell and other modules as it's been deprecated and will give a hard fail in ansible-core 2.14.0. * webapps/nextcloud : Change default data directory to be outside web root * webapps/nextcloud : Small enhancement on the vhost template to lock out data dir +* nagios-nrpe : Rewrite check_vrrpd for a better check (check rp_filter, vrrpd and uvrrpd compatible, use arguments, …) ### Fixed diff --git a/nagios-nrpe/files/plugins/check_vrrpd b/nagios-nrpe/files/plugins/check_vrrpd index 9390aa6e..5cd50027 100755 --- a/nagios-nrpe/files/plugins/check_vrrpd +++ b/nagios-nrpe/files/plugins/check_vrrpd @@ -1,94 +1,190 @@ #!/bin/bash +# shellcheck disable=SC2207,SC2009,SC2076 -# README -# -# Variable to adjust : is_master and vrrpd_processes. -# vrrpd_processes is the number of vrrpd processes that should run on the server. -# is_master defines whether the vrrpd group should be master (1) or backup (0). -# -# If some instances have to be master and some other have to be backup, -# then the value of is_master is 2 and the states has to be precised in arguments. -# e.g. : ./check_vrrpd master backup master -# The order is defined by the output order of `ps auwx | grep vrrp` +usage() { +cat << EOL + Usage : -RC=0 -IFS=' -' + $0 --master X,Y --backup Z -is_master=2 # 1 if master ; 0 if backup ; 2 if mixed master and backup, in this case, it has to be precised in arguments -vrrpd_processes=3 # number of vrrpd processes that should be running -is_vrrpd_running=$(sudo /usr/lib/nagios//plugins/check_procs -C vrrpd -c $vrrpd_processes:$vrrpd_processes) -rc_is_vrrpd_running=$? -IP_vrrpd=($(for i in $(ps auwx | grep vrrpd | grep -v grep | grep -v check); do echo $i | awk '{print $--NF}'; done)) -INT_vrrpd=($(for i in $(ps auwx | grep vrrpd | grep -v grep | grep -v check); do echo $i | awk '{print $13}'; done)) -ID_vrrpd=($(for i in $(ps auwx | grep vrrpd | grep -v grep | grep -v check); do echo $i | awk '{print $19}'; done)) + -m|--master ID_MASTER # VRRP ID that should be master, separated by a comma "," + -b|--backup ID_BACKUP # VRRP ID that should be backup, separated by a comma "," + [--vrrpd] # Check for vrrpd daemon (default) + [--uvrrpd] # Check for uvrrpd daemon +EOL +} -if [[ $rc_is_vrrpd_running -ne 0 ]]; then - echo $is_vrrpd_running instead of $vrrpd_processes +unset ID_master +unset ID_backup +vrrpd_option="unset" +uvrrpd_option="unset" +unset critical_output +critical_state="unset" +unset warning_output +warning_state="unset" +unset ok_output +ok_state="unset" +exit_code=0 +used_daemon="vrrpd" +IFS=" +" + +# If no argument then show usage +if [ "$#" -eq 0 ]; then + usage exit 2 fi -for i in $(seq 0 $((${#ID_vrrpd[*]}-1))); do - ifconfig vrrp_${ID_vrrpd[$i]}_${INT_vrrpd[$i]} >/dev/null 2>&1 - # If has interface - if [[ $? -eq 0 ]]; then - # If has to be master : OK - if [[ $is_master -eq 1 ]]; then - echo OK - ${IP_vrrpd[$i]} exists and is master - # If has to be backup : KO - elif [[ $is_master -eq 0 ]]; then - echo CRITICAL - ${IP_vrrpd[$i]} exists whereas it should be backup - RC=2 - # We retrieve the state it should be from args - elif [[ $is_master -eq 2 ]]; then - arg=$(($i+1)) - state=${!arg} - # If has to be master : OK - if [[ $state = master ]]; then - echo OK - ${IP_vrrpd[$i]} exists and is master - # If has to be backup : KO - elif [[ $state = backup ]]; then - echo CRITICAL - ${IP_vrrpd[$i]} exists whereas it should be backup - RC=2 +while :; do + case $1 in + -h|-\?|--help) # Call a "usage" function to display a synopsis, then exit. + usage + exit + ;; + -m|--master) # Takes an option argument, ensuring it has been specified. + if [ -n "$2" ]; then + ID_master=($(echo "$2" | tr "," "\n")) # Make an array with values separated by "," + shift else - echo "CRITICAL - The arguments have to be master or backup. Exiting" + printf 'ERROR: "--master" requires a non-empty option argument.\n' >&2 exit 2 fi - # Unknown - else - RC=3 - fi - # If hasn't interface - elif [[ $? -ne 0 ]]; then - # If has to be master : KO - if [[ $is_master -eq 1 ]]; then - echo CRITICAL - ${IP_vrrpd[$i]} does not exist whereas it should be master - RC=2 - # If has to be backup : OK - elif [[ $is_master -eq 0 ]]; then - echo OK - ${IP_vrrpd[$i]} is backup - # We retrieve the state it should be from args - elif [[ $is_master -eq 2 ]]; then - arg=$(($i+1)) - state=${!arg} - # If has to be master : KO - if [[ $state = master ]]; then - echo CRITICAL - ${IP_vrrpd[$i]} does not exist whereas it should be master - RC=2 - # If has to be backup : OK - elif [[ $state = backup ]]; then - echo OK - ${IP_vrrpd[$i]} is backup + ;; + -b|--backup) # Takes an option argument, ensuring it has been specified. + if [ -n "$2" ]; then + ID_backup=($(echo "$2" | tr "," "\n")) # Make an array with values separated by "," + shift else - echo "CRITICAL - The arguments have to be master or backup. Exiting" + printf 'ERROR: "--backup" requires a non-empty option argument.\n' >&2 exit 2 fi - # Unknown - else - RC=3 - fi - # Unknown - else - RC=3 - fi + ;; + --vrrpd) + used_daemon="vrrpd" + vrrpd_option="set" + ;; + --uvrrpd) + used_daemon="uvrrpd" + uvrrpd_option="set" + ;; + -?*) + printf 'WARNING: Unknown option (ignored): %s\n' "$1" >&2 + ;; + *) # Default case: If no more options then break out of the loop. + break + esac + shift done -exit $RC + +# Make sure that each given ID is given once only +all_ID=("${ID_master[@]}" "${ID_backup[@]}") +uniqueNum=$(printf '%s\n' "${all_ID[@]}"|awk '!($0 in seen){seen[$0];c++} END {print c}') +if [ "$uniqueNum" != ${#all_ID[@]} ]; then + echo "ERROR : At least one VRRP ID is given multiple times" + exit 2 +fi + +# Make sure --vrrpd and --uvrrpd are not both set +if [ $vrrpd_option = "set" ] && [ $uvrrpd_option = "set" ]; then + echo "ERROR : You cannot set both parameters --vrrpd and --uvrrpd" + exit 2 +fi + +# Make sure no sysclt parameter "rp_filter" is set to 1 +if grep -q 1 /proc/sys/net/ipv4/conf/*/rp_filter; then + critical_output="${critical_output}CRITICAL - rp_filter is set to 1 at least for one interface\n" + critical_state="set" +fi + +vrrpd_processes_number=$((${#ID_master[@]}+${#ID_backup[@]})) # Number of vrrpd processes that should be running = length of arrays ID_master + ID_backup +regex_ipv4="((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])" +regex_ipv6="(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))" +vrrpd_processes=$(ps auwx | grep "$used_daemon" | grep -v -e grep -e check) +ID_running_vrrpd=($(for i in ${vrrpd_processes}; do echo "$i" | grep -Eo -- "-v [0-9]+" | awk '{print $2}'; done)) + +# Check the number of running vrrpd processes in comparison to the number of ID given +if ! sudo /usr/lib/nagios/plugins/check_procs -C "$used_daemon" -c $vrrpd_processes_number:$vrrpd_processes_number >/dev/null; then + critical_output="${critical_output}CRITICAL : $vrrpd_processes_number VRRP ID are given but $(ps auwx | grep "$used_daemon" | grep -v -e grep -e check -c) $used_daemon processes are running\n" + if pgrep uvrrp >/dev/null && [ $uvrrpd_option = "unset" ]; then + critical_output="${critical_output}It seems that uvrrpd is running. Use parameter --uvrrpd\n" + fi + critical_state="set" +fi + +IFS=" " + +# For each ID_master, make sure a process exist +if [ ${#ID_master[@]} -ne 0 ]; then + for i in "${ID_master[@]}"; do + # If array contains the current ID, then a process exist, and we have to make sure the corresponding interface exists + if [[ " ${ID_running_vrrpd[*]} " =~ " $i " ]]; then + vrrpd_current_proccess=$(echo "$vrrpd_processes" | grep -E -- "-v $i") + INT_current_vrrpd=$(echo "$vrrpd_current_proccess" | grep -Eo -- "-i \S+" | awk '{print $2}') + IP_current_vrrpd=$(echo "$vrrpd_current_proccess" | grep -Eo "${regex_ipv4}|${regex_ipv6}") + if [ "$used_daemon" = "vrrpd" ]; then + int_name="vrrp_${i}_${INT_current_vrrpd}" + elif [ "$used_daemon" = "uvrrpd" ]; then + int_name="${INT_current_vrrpd}_${i}" + fi + if /sbin/ifconfig "$int_name" 2> /dev/null | grep -q "$IP_current_vrrpd"; then + ok_output="${ok_output}OK - ID $i has a process and $IP_current_vrrpd is master\n" + ok_state="set" + else + warning_output="${warning_output}WARNING - The IP $IP_current_vrrpd for ID $i is backup while it should be master\n" + warning_state="set" + fi + else + critical_output="${critical_output}CRITICAL - No process is running for VRRP ID $i\n" + critical_state="set" + fi + done +fi + +# For each ID_backup, make sure a process exist +if [ ${#ID_backup[@]} -ne 0 ]; then + for i in "${ID_backup[@]}"; do + # If array contains the current ID, then a process exist, and we have to make sure the corresponding interface does not exist + if [[ " ${ID_running_vrrpd[*]} " =~ " $i " ]]; then + vrrpd_current_proccess=$(echo "$vrrpd_processes" | grep -E -- "-v $i") + INT_current_vrrpd=$(echo "$vrrpd_current_proccess" | grep -Eo -- "-i \S+" | awk '{print $2}') + IP_current_vrrpd=$(echo "$vrrpd_current_proccess" | grep -Eo "${regex_ipv4}|${regex_ipv6}") + if [ "$used_daemon" = "vrrpd" ]; then + int_name="vrrp_${i}_${INT_current_vrrpd}" + elif [ "$used_daemon" = "uvrrpd" ]; then + int_name="${INT_current_vrrpd}_${i}" + fi + if ! /sbin/ifconfig "$int_name" 2> /dev/null | grep -q "$IP_current_vrrpd"; then + ok_output="${ok_output}OK - ID $i has a process and $IP_current_vrrpd is backup\n" + ok_state="set" + else + warning_output="${warning_output}WARNING - The IP $IP_current_vrrpd for ID $i is master while it should be backup\n" + warning_state="set" + fi + else + critical_output="${critical_output}CRITICAL - No process is running for VRRP ID $i\n" + critical_state="set" + fi + done +fi + +# Make $exit_code the highest set +if [ "$critical_state" = "set" ]; then + exit_code=2 +elif [ "$warning_state" = "set" ]; then + exit_code=1 +elif [ "$ok_state" = "set" ]; then + exit_code=0 +fi + +# Echo most critical output first, least last +if [ -n "$critical_output" ]; then + echo -e "$critical_output" | grep -v "^$" +fi +if [ -n "$warning_output" ]; then + echo -e "$warning_output" | grep -v "^$" +fi +if [ -n "$ok_output" ]; then + echo -e "$ok_output" | grep -v "^$" +fi + +exit $exit_code