Инструменты пользователя

Инструменты сайта


nix:shell:nagios-check

Скрипты для системы мониторинга Nagios

Отправка СМС

В скрипте для отправки сообщений используется программа gnokii. С небольшими правками скрипта можно переделать на использование gammu. Описаний настройки gnokii/gammu не привожу, они выходят за рамки описания скрипта.

Для диагностических целей скрипт пишет свои действия в лог-файл /var/log/nagios4/sendsms.log

"set -o pipefail" в данном скрипте необязателен, но я почти всегда задаю опцию pipefail, которая указывает оболочке, что код завершения конвейера будет совпадать с первым ненулевым кодом завершения одной из команд конвейера или же нулю в случае, если все команды завершились корректно

Если отправка оповещений делается нескольким адресатам, то параллельное обращение к модему/телефону приведет к тому, что какие-то смс не будут доставлены. Чтобы этого избежать я делаю отправку в цикле, пока она не будет успешной (код возврата 0). Чтоб в случае постоянной ошибки скрипт не ушел в бесконечный цикл ограничиваю число попыток отправки (100 попыток думаю достаточно)

"LANG=ru_RU.UTF-8" перед выполнением программы gnokii нужно, чтоб кириллический текст в смс нормально отображался.

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

smssend.sh
#!/bin/bash
 
set -o pipefail
 
echo "$(date +%Y-%m-%dT%H:%M:%S) Send SMS to $2: $1"
echo "$(date +%Y-%m-%dT%H:%M:%S) Send SMS to $2: $1">>/var/log/nagios4/sendsms.log
 
retcode=1
try=1
while [[ $retcode -ne 0 |]]
do
echo "Try$try: LANG=ru_RU.UTF-8 echo \"$1\" | /usr/bin/gnokii --sendsms \"$2\" --smsc \"+79289900028\"">>/var/log/nagios4/sendsms.log 2>&1
LANG=ru_RU.UTF-8 echo "$1" | /usr/bin/gnokii --sendsms "$2" --smsc "+79289900028"
retcode=$?
try=$((try++))
if [[ $try -ge 100 |]]; then echo "Max try 100 exceeded"; break; fi
sleep 1
done
 
echo "$(date +%Y-%m-%dT%H:%M:%S) Send SMS to $2: $1 RetCode:$retcode">>/var/log/nagios4/sendsms.log 2>&1
echo "$(date +%Y-%m-%dT%H:%M:%S) Send SMS to $2: $1 RetCode:$retcode"
 
exit $retcode

Отправка оповещений в Telegram

Для работы скрипта в нем нужно задать правильные параметры телеграм-канала: TOKEN и CHAT_ID

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

tgsend.sh
#!/bin/bash
 
set -o pipefail
TOKEN="SpecifyYourTelegramToken"
CHAT_ID="SpecifyChatId"
APIURL="https://api.telegram.org/bot${TOKEN}/sendMessage"
 
if [[ -z "$1$2" ]]; then echo "Missing arguments" >&2; exit 2; fi
if [[ -z "$2" ]]
 then
  SUBJECT=""
  MESSAGE="$1"
 else
  SUBJECT="$1"
  MESSAGE="$2"
fi
 
curlres=$(curl -s --header 'Content-Type: application/json' --request 'POST' --data "{\"chat_id\":\"${CHAT_ID}\",\"text\":\"${SUBJECT}\n${MESSAGE}\"}" "${APIURL}")
curlerr="$?"
if [[ $curlerr -ne 0 ]]; then echo "Curl error:$curlerr" >&2; exit 2;fi
if [[ "$(echo "$curlres"jq ".ok")" != "true" ]]
 then
   echo "api.telegram error" >&2
   echo "cmd=curl -s --header 'Content-Type: application/json' --request 'POST' --data \"{\"chat_id\":\"${CHAT_ID}\",\"text\":\"${SUBJECT}\n${MESSAGE}\"}\" \"${APIURL}\"" >&2
   echo "ressult=$curlres" >&2
fi
 
exit 0

Проверка загрузки CPU

Для проверки загрузки процессора используется программа mpstat (входит в состав пакета sysstat)

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

check_cpu.sh
#!/bin/bash
 
E_OK=0;E_WARN=1;E_CRIT=2;E_UNKNOWN=3 #Коды возврата Nagios
 
WARN=20; CRIT=10 #Задаем пороги предупреждений и критического состояния по-умолчанию.
# Считываем пороги, если они заданы в командной строке
if [[ -n "$1" ]]; then WARN="$1";fi
if [[ -n "$2" ]]; then CRIT="$2";fi
 
res=$E_OK; res_txt="OK"
 
read check_time CPU usr nice sys iowait irq soft steal guest gnice idle <<<$(S_TIME_FORMAT=ISO mpstat --dec=0 1 1|tail -n2|head -n1)
 
if [[ $idle -le $WARN ]]; then res=$E_WARN; res_txt="WARN"; fi
if [[ $idle -le $CRIT ]]; then res=$E_CRIT; res_txt="CRIT"; fi
 
echo -n "$res_txt: Idle=$idle% usr=$usr% nice=$nice% sys=$sys% iowait=$iowait% irq=$irq% soft=$soft% steal=$steal% guest=$guest% gnice=$gnice%"
echo "|Idle=$idle%;$WARN;$CRIT;; usr=$usr%;;;; nice=$nice%;;;; sys=$sys%;;;; iowait=$iowait%;;;; irq=$irq%;;;; soft=$soft%;;;; steal=$steal%;;;; guest=$guest%;;;; gnice=$gnice%;;;;"
exit $res

Проверка состояния сетевого интерфейса

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

check_ip_link.sh
#!/bin/sh
 
# Exit-Codes:
STATE_OK=0;STATE_WARNING=1;STATE_CRITICAL=2;STATE_UNKNOWN=3
 
usage()
{
 cat <<EOF
 usage: $0 interface
 This script checks interface state
EOF
}
 
if [ -z "$1" ]; then usage; exit $STATE_UNKNOWN; fi
 
int="$1"
res=$STATE_OK; txt="OK"
 
lnk=$(ip link show $int|head -n1 |sed 's/\(.*)(state \w*)(.*\)/\2/') #'
 
if [ "$lnk" != "state UP" ]; then res=$STATE_CRITICAL; txt="CRITICAL"; fi
 
echo "$txt:Interface $int $lnk"
 
exit $res

Пинг большими нефрагментированными пакетами

Зачем? Ну например для проверки линков с включенным JumboFrame.

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

check_ping_big.sh
#!/bin/sh
 
E_OK=0;E_WARN=1;E_CRIT=2;E_UNKNOWN=3
 
#Defaults
WARN=100
CRIT=200
WARNPCT=10
CRITPCT=20
PKTCNT=5
PKTSIZE=6050
 
res=$E_OK;txt="OK"
 
usage()
{
cat <<EOF
usage: $0 -H host [OPTIONS]
This script checks ping to host and verifies packets loss and round trip time
OPTIONS:
   -h       Help
   -w wrtt  WARNING  RTT
   -c crtt  CRITICAL RTT
   -W wpct  WARNING  Packets loss %
   -C cpct  CRITICAL Packets loss %
   -p num   Number of packets
   -s size  Packet size
EOF
}
 
while getopts H:c:w:C:W:p:s: OPTION
do
     case $OPTION in
        H)
           CHECKHOST=`echo $OPTARG | grep -v "^-"`
           [ ! "$?" = 0 ] && echo "Error: missing or illegal option value" && exit $STATE_UNKNOWN;;
        c)
           CRIT=`echo $OPTARG | grep -v "^-"`
           [ ! "$?" = 0 ] && echo "Error: missing or illegal option value" && exit $STATE_UNKNOWN;;
        w)
           WARN=`echo $OPTARG | grep -v "^-"`
           [ ! "$?" = 0 ] && echo "Error: missing or illegal option value" && exit $STATE_UNKNOWN;;
        C)
           CRITPCT=`echo $OPTARG | grep -v "^-"`
           [ ! "$?" = 0 ] && echo "Error: missing or illegal option value" && exit $STATE_UNKNOWN;;
        W)
           WARNPCT=`echo $OPTARG | grep -v "^-"`
           [ ! "$?" = 0 ] && echo "Error: missing or illegal option value" && exit $STATE_UNKNOWN;;
        p)
           PKTCNT=`echo $OPTARG | grep -v "^-"`
           [ ! "$?" = 0 ] && echo "Error: missing or illegal option value" && exit $STATE_UNKNOWN;;
        s)
           PKTSIZE=`echo $OPTARG | grep -v "^-"`
           [ ! "$?" = 0 ] && echo "Error: missing or illegal option value" && exit $STATE_UNKNOWN;;
        ?)
           usage; exit $STATE_UNKNOWN;;
     esac
done
 
if [ -z "$CHECKHOST" ]; then usage; exit $STATE_UNKNOWN; fi
 
cmd_res="$(ping $CHECKHOST -c $PKTCNT -s $PKTSIZE -W 1 -M dont|tail -n2)"
 
PCT=$(echo "$cmd_res"|head -n1|awk '{print $6}'|tr -d '%')
 
TIME=$(echo "$cmd_res"|tail -n1|awk -F '/' '{print $5}')
if [ -z "$TIME" ]; then TIME=65565; fi
 
if [ $PCT -ge $WARNPCT ] && [ $res -lt $E_WARN ]
 then
   res=$E_WARN;txt="WARNING"
   if [ $PCT -ge $CRITPCT ] && [ $res -lt $E_CRIT ]
    then
      res=$E_CRIT;txt="CRITICAL"
   fi
fi
 
if [ $(echo "$TIME >= $WARN"|bc) -ne 0  ] && [ $res -lt $E_WARN ]
 then
   res=$E_WARN;txt="WARNING"
   if [ $(echo "$TIME >= $CRIT"|bc) -ne 0  ] && [ $res -lt $E_CRIT ]
    then
      res=$E_CRIT;txt="CRITICAL"
   fi
fi
 
echo "$txt: Host $CHECKHOST - $PCT% packet loss (warn:$WARNPCT,crit:$CRITPCT), AVG rtt $TIME (warn:$WARN,crit:$CRIT)|PacketLoss=$PCT%;$WARNPCT;$CRITPCT;0;100 RTT=${TIME}ms;$WARN;$CRIT;;"
exit $res

Сравнение локального файла с файлом на удаленной системе

Область применения - например проверка идентичности конфиг-файла на двух серверах.

Сравнение делается с помощью подключения по ssh. Для корректной работы скрипта требуется настроить ключи ssh для пользователя из под которого будет работать скрипт.

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

check_rdiff.sh
#!/bin/bash
 
E_OK=0;E_WARNING=1;E_CRITICAL=2;E_UNKNOWN=3
 
usage()
{
cat <<EOF
Usage: $0 remotehost filename
This script checks differecies of local and remote files
EOF
}
 
if [[ -z "$1" |]]; then usage; exit $E_UNKNOWN
 else  serv="$1"
fi
 
if [[ -z "$2" |]]; then usage; exit $E_UNKNOWN
 else fname="$2"
fi
 
difs="$(diff $fname <(ssh "$serv" "cat $fname"))"
 
if [[ "$?" -eq "1" |]]
 then
  echo "CRITICAL: File $fname. Local and on host $serv has differencies"
  echo "$difs"
  exit $E_CRITICAL
fi
 
echo "OK: File $fname. Local and on host $serv has no differencies"
exit $E_OK

Модифицированная версия. Может сравнивать несколько файлов заданных шаблоном (напр. /etc/application/*.conf)

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

check_rdiff.sh
#!/bin/bash
 
STATE_OK=0;STATE_WARNING=1;STATE_CRITICAL=2;STATE_UNKNOWN=3
 
usage()
{
cat << EOF
Usage: $0 remotehost filename
This script checks differecies of local and remote files
EOF
}
 
if [[ -z "$1" ]]; then usage; exit $STATE_UNKNOWN; else serv="$1"; fi
if [[ -z "$2" ]]; then usage; exit $STATE_UNKNOWN; else fname="$2"; fi
 
difs=""
ndifs=0
 
for f in $fname
do
 dif="$(ssh "$serv" "cat $f"|diff - $f)"
 if [[ $? -ne 0 ]]; then.
   ndifs=$(($ndifs + 1 ))
   difs="$difs$(echo $f):$dif"
 fi
done
 
if [[ $ndifs -eq 0 ]]
 then
  echo "OK: File $fname. Local and on host $serv has no differencies"; exit $STATE_OK
 else
  echo "CRITICAL: File $fname. Local and on host $serv has differencies"; echo "$difs"; exit $STATE_CRITICAL
fi

Проверка DNS-записей на соответствие заданным

В nagios-plugins есть check_dns, который позволяет (кроме другого функционала) проверить соответствуют ли записи о домене на днс-сервере желаемым. Однако check_dns не дружит с интернациональными доменами, даже если указать домен в punycode. Поэтому может потребоваться скрипт ниже.

Пример запуска скрипта

check_dns_recs.sh domain.com 1.1.1.1,2.2.2.2 8.8.8.8

В этом примере проверяется соответствуют ли записи домена domain.com на сервере 8.8.8.8 списку 1.1.1.1, 2.2.2.2

Адреса в списке можно указывать разделяя их между собой запятыми. Скрипт проверяет только А-записи (может позже это исправлю).

В основном действия в скрипте несложные. Немного описать имеет смысл следующую строку:

host -t $TYPE $DOMAIN $SERVER|grep "$DOMAIN has address "|grep -oE '[^ ]+$'|sort|tr '\n' ','|sed s/,$//
  • grep -oE '[^ ]+$' - эта команда удаляет из строк все кроме последнего слова, а в последнем слове содержатся требуемые адреса домена. Если разделителем слов будет не только пробел, но и другие разделители, то может понадобиться преобразовать регулярное выражение [^ ] к виду [^[:space:]]
  • sort - если не отсортировать вывод, то порядок запиесей может меняться и при сравнении один и тот же список адресов не совпадет с заданным шаблоном.
  • tr '\n' ','|sed s/,$// - зменяем все переводы строк запятыми (объединяем строки в одну с разделителем запятая) и удаляем лишнюю запятую в конце строки.

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

check_dns_recs.sh
#!/bin/bash
 
E_OK=0;E_WARN=1;E_CRIT=2;E_UNKNOWN=3 #Коды возврата Nagios
set -o pipefail
 
#Defaults
TYPE="A"
 
usage()
{
 cat <<EOF
 This script checks dns records corresponding to given list
 usage: $0 domain list [server]
      list - addresses list (separated by comma(,))
EOF
}
 
if [[ -n "$1" ]]; then DOMAIN="$1"; else usage; exit $E_UNKNOWN; fi
if [[ -n "$2" ]]; then LIST="$2"; else usage; exit $E_UNKNOWN; fi
if [[ -n "$3" ]]; then SERVER="$3"; fi
 
res=$E_OK; txt="OK"
 
dnsrecs="$(host -t $TYPE $DOMAIN $SERVER|grep "$DOMAIN has address "|grep -oE '[^ ]+$'|sort|tr '\n' ','|sed s/,$//)"
 
if [[ $? -ne 0 ]]; then echo "DNS lookup error for command: host -t $TYPE $DOMAIN $SERVER";exit $E_UNKNOWN; fi
 
if [[ "$dnsrecs" != "$LIST" ]]
 then res=$E_CRIT; txt="CRIT"; check_txt=" not equal to '$LIST'"
fi
 
echo "$txt:Records $TYPE for $DOMAIN: '$dnsrecs'$check_txt"
exit $res

Проверка является ли заданный сервер кластера PgPool-II primary-хостом

check_pgpool_node_is_primary.sh pg_master_host

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

check_pgpool_node_is_primary.sh
#!/bin/bash
 
E_OK=0;E_WARN=1;E_CRIT=2;E_UNKNOWN=3
 
if [[ -z "$1" ]]; then echo "Usage: $(basename $0) PostgresMasterHostname"; exit $E_UNKNOWN; fi
mastername="$1"
 
HOST="localhost"
#HOST="/var/run/postgresql"
 
res=$E_OK; res_txt="OK"; res_txt2="Host $mastername is Master"
 
strings="$(echo "node_id hname status role last_status_change")"
while IFS='|' read -r node_id hname port status lb_weight role select_cnt load_balance_node replication_delay replication_state replication_sync_state last_status_change
do
 strings="$strings\n$(echo "$node_id $hname $status $role $last_status_change")"
 if [[ "$hname" == "$mastername" && "$role" != "primary" ]]
  then
   res=$E_CRIT; res_txt="CRIT"; res_txt2="Host $hname is not Master"
 fi
 if [[ "$hname" != "$mastername" && "$role" == "primary" ]]
  then
   if [[ $res -lt $E_WARN ]]; then res=$E_WARN; res_txt="CRIT"; res_txt2="Host $hname is Master (myst be a slave)"; fi
 fi
done < <(psql -tA -h localhost -c "SHOW pool_nodes;" postgres postgres)
 
echo "$res_txt: $res_txt2"
echo -e "$strings"
exit $res

Проверка состояния streaming-репликации PostgreSQL-серверов через PgPool-II

Скрипт на пгпуле определяет который из серверов является мастером. Затем на мастере проверяется статистика по репликации.

Если позиции (LSN) в журналах различаются (не все отправлено на слейв, не все записано, не все подтверждено), то будет выдано предупреждение

Если состояние репликации будет не streaming, то будет выдано критическое состояние

В графики из получаемых данных ничего не запишешь, но все-таки я вывожу в них код завершения нагиос-скрипта. Это будет полезно для статистики. Коды возврата: E_OK=0;E_WARN=1;E_CRIT=2;E_UNKNOWN=3

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

check_pg_replication.sh
#!/bin/bash
 
E_OK=0;E_WARN=1;E_CRIT=2;E_UNKNOWN=3
 
#HOST="localhost"
HOST="/var/run/postgresql"
 
while IFS='|' read -r node_id hname port status lb_weight role select_cnt load_balance_node replication_delay replication_state replication_sync_state last_status_change
do
if [[ "$role" == "primary" ]]; then master=$hname; break; fi
done < <(psql -tA -h localhost -c "SHOW pool_nodes;" postgres postgres)
 
res=$E_OK; res_txt="OK"; res_txt2=""
 
IFS='|' read -r client_addr state sent_lsn write_lsn flush_lsn replay_lsn \
 <<< $(echo $(psql -tA -h $master -c 'select client_addr, state, sent_lsn, write_lsn,flush_lsn, replay_lsn from pg_stat_replication;' postgres postgres))
 
lsn_equal=1
for i in "$write_lsn" "$flush_lsn" "$replay_lsn"
do
 if [[ "$sent_lsn" != "$i" ]]; then lsn_equal=0;break; fi
done
if [[ $lsn_equal -ne 1 ]]; then res=$E_WARN; res_txt="WARN"; res_txt2="LSNs is not equal"; fi
 
 
if [[ "$state" != "streaming" ]]; then res=$E_CRIT; res_txt="CRIT"; res_txt2="state != streaming"; fi
 
echo -n "$res_txt: Master is $master. $res_txt2 "
echo "client_addr:$client_addr state:$state sent_lsn:$sent_lsn write_lsn:$write_lsn flush_lsn:$flush_lsn replay_lsn:$replay_lsn|result=$res"
exit $res
nix/shell/nagios-check.txt · Последнее изменение: 2022/06/20 17:31 — san

Если не указано иное, содержимое этой вики предоставляется на условиях следующей лицензии: Public Domain
Public Domain Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki