Как-то раз мы проспали проблему. Zabbix прислал пару SMS, но никто ночью не проснулся. А если бы zabbix позвонил, да ещё бы и рассказал о проблеме, то было бы проще всё упавшее поднимать. Учим zabbix звонить на телефон.
Как показывает практика, звонки через свою АТС могут быть дешевле, чем отправка SMS.
Что у нас есть:
- Zabbix сервер версии 3.4.15. Впрочем, версия не особо важна. Операционная система Ubuntu.
- Asterisk сервер.
Прежде чем приступить к реализации функционала я нашёл в сети Интернет с десяток статей. Где-то содрал куски кода и переписал их по-своему, где-то взял за основу теорию или практику. В итоге получилось что-то своё, со своими плюсами и минусами.
Теория
- При возникновении проблемы zabbix сервер должен выполнить bash скрипт, который нам и выполнит всю работу по совершению звонка. Весь необходимый функционал в zabbix уже есть, нам нужно только написать скрипт и всё настроить.
- Bash скрипт генерирует из текста ошибки звуковой WAV файл и CALL файл для Asterisk.
- Bash скрипт загружает по SCP на сервер Asterisk сгенерированные файлы, устанавливает им нужные права, помещает в нужные директории.
- Asterisk совершает звонок и проигрывает сообщение.
Дополнительные условия:
- Bash скрипт должен чистить за собой старые WAV файлы. Call файлы Asterisk почистит сам.
- Bash скрипт не должен звонить слишком часто при массовом сбое. Основная задача — разбудить админов, а не отправить максимальное количество звонков.
- Должны быть логи звонков.
- Должна быть поддержка русского языка.
- Должна быть возможность тонкой настройки для каждого пользователя, о каких триггерах уведомлять по телефону.
Подготовка серверов
WAV файл будем создавать на zabbix сервере, пример:
Создать WAV файл из текста в Ubuntu
Устанавливаем на zabbix сервере библиотеки:
apt-get install festival festvox-ru uuid
- festival — библиотека для генерации звукового файла из текста.
- festvox-ru — поддержка русского языка для festival.
- uuid — в bash скрипте я использую uuid для генерации уникального имени файла.
В скрипте я буду копировать WAV и CALL файлы на asterisk по SCP. Нужно настроить беспарольный вход по SSH от пользователя zabbix на zabbix сервере пользователю root на asterisk сервере. Вынес подробности в статью:
SCP — копируем файл без пароля
А если коротко, то на zabbix сервере под рутом:
ssh-keygen
На все вопросы жмём ввод, получаем пару ключей. Копируем публичный ключ на asterisk сервер (он у меня называется freepbx):
scp ~/.ssh/id_rsa.pub root@freepbx:~/.ssh/authorized_keys
Папку .ssh с ключами переношу в домашнюю директорию пользователя zabbix на zabbix сервере, потому что bash скрипт будет выполняться от его имени, и SCP тоже.
Bash скрипт
В настройках zabbix сервера /etc/zabbix/zabbix_server.conf смотрим что написано в параметре AlertScriptsPath:
AlertScriptsPath=/usr/lib/zabbix/alertscripts
Раскомментируйте параметр при необходимости.
У меня скрипт для уведомлений находятся по умолчанию в директории /usr/lib/zabbix/alertscripts. Создаю в ней пустой файл для логов /usr/lib/zabbix/alertscripts/freepbxgate.log, пользователь zabbix должен иметь права на чтение и запись. B создаю bash скрипт /usr/lib/zabbix/alertscripts/freepbxgate.sh. Пользователь zabbix должен иметь права на чтение и выполнение. Содержимое скрипта:
#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
# -----------------------------------
# настройки
# local zabbix server
workdir="/tmp"
logfile="/usr/lib/zabbix/alertscripts/freepbxgate.log"
prefix="zabbix1"
prefixname="Сообщ+ение от монит+оринга."
# remote asterisk сервер
aserver="root@freepbx.domain.local"
adir="/tmp"
asounds="/var/lib/asterisk/sounds/"
aout="/var/spool/asterisk/outgoing/"
# -----------------------------------
to=$1
subject=$2
phone=`echo $to | awk -F"/" '{ print $1}'`
tags=`echo $to | awk -F"/" '{ print $2}'`
#чистим subject
txt2wav=$(echo "$subject" | sed -r 's/[\.,\!\?]/ /g' | sed 's/(\([^)]*\))//g' | sed 's/[^0-9a-zA-Zа-яА-ЯёЁ ]//g' | tr -s " " | sed 's/^[ \t]*//;s/[ \t]*$//')
# функция генерации и отправки файлов на asterisk
callme(){
px=$1
#уникальное имя для wav и call файлов
uid=`uuid`
fp="${prefix}_${uid}_${phone}"
#генерация wav
wavfile="${workdir}/${fp}.wav"
command1="echo $prefixname $px $txt2wav | /usr/bin/text2wave -F 8000 -eval '(voice_msu_ru_nsh_clunits)' 2>/dev/null > ${wavfile}"
echo $command1 | /bin/bash
#генерация call
callfile="${workdir}/${fp}.call"
touch $callfile
echo "Channel: Local/$phone@from-internal" > $callfile
echo "MaxRetries: 3" >> $callfile
echo "RetryTime: 60" >> $callfile
echo "WaitTime: 60" >> $callfile
echo "Callerid: Wake Up Calls <*68>" >> $callfile
echo "Application: Playback" >> $callfile
echo "Data: $fp" >> $callfile
#Перенос файлов на asterisk
scp $wavfile $aserver:$adir
scp $callfile $aserver:$adir
rm $wavfile
rm $callfile
ssh $aserver "chown asterisk\: ${adir}/${fp}* && chmod 777 ${adir}/${fp}.wav && mv ${adir}/${fp}.wav ${asounds} && mv ${adir}/${fp}.call ${aout} && find ${asounds} -name '${prefix}*' -type f -mmin +10 -delete"
}
while IFS=',' read -ra item; do
for i in "${item[@]}"; do
if grep -q "$i" <<<$subject; then
date_now1=`date | awk -F":" '{print $1":"$2}'`
date_now2=`date | awk '{print $5,$6}'`
msg_count=`tail -n 5000 ${logfile} | grep "${date_now1}" | grep "${date_now2}" | grep "${phone}" | wc -l`
date_now=`date`
if [ $msg_count -gt 0 ]; then
if [ $msg_count -eq 1 ]; then
callme "+Очень мн+ого сообщ+ений, ч+асть звонк+ов проп+ущена!"
echo "$date_now $to $txt2wav" >> ${logfile}
else
echo "$date_now $to $txt2wav | не отправлено" >> ${logfile}
fi
else
callme
echo "$date_now $to $txt2wav" >> ${logfile}
fi
fi
done
done <<< "$tags"
На вход принимается два параметра:
- Получатель в формате "79990001122/(TAG1),(TAG2),(TAG3)"
- Заголовок триггера, например, "Всё сломалось! (TAG2) Срочно просыпайтесь!"
Получатель состоит из номера мобильного телефона и списка тегов через запятую, тегов может быть много. Тег — это кусок текста из заголовка триггера. Я, например, вставляю в названия триггеров теги вида (WIN) или (LINUX) или (SMS).
Заголовок — это название триггера.
Если у получателя есть тег, который присутствует в тексте заголовка, то получателю будет отправлен звонок на телефон. Если у получателя нет такого тега или тегов, то звонка не будет.
Параметры bash скрипта:
- workdir="/tmp" — директория на zabbix сервере, в которой будут генерироваться WAV и CALL файлы.
- logfile="/usr/lib/zabbix/alertscripts/freepbxgate.log" — лог файл на zabbix сервере.
- prefix="zabbix1" — префикс в названиях файлов. У меня несколько zabbix серверов, для каждого будет уникальный префикс.
- prefixname="Сообщ+ение от монит+оринга." — с этого текста начинается каждый звонок. Плюсы указывают на ударение в слове.
- aserver="root@freepbx.domain.local" — логин и имя сервера asterisk для передачи файлов SCP.
- adir="/tmp" — директория на asterisk сервере, в которую первоначально копируются файлы. В ней им настраиваются права и владелец.
- asounds="/var/lib/asterisk/sounds/" — директория на asterisk сервере, в которую копируются WAW файлы.
- aout="/var/spool/asterisk/outgoing/" — директория на asterisk сервере, в которую копируются CALL файлы.
Если за минуту поступит второй звонок, то в текст добавится "+Очень мн+ого сообщ+ений, ч+асть звонк+ов проп+ущена!", больше в эту минуту звонков не будет, хотя логи продолжат записываться. Думаю, потом я сделаю период звонков побольше.
Параметры CALL файла измените для своих нужд. Например, у меня в качестве Callerid используется существующий Wake Up Calls <*68>, который есть в freepbx для звонков будильника. Если сообщение нужно проиграть три раза, то замените строчку:
echo "Data: $fp" >> $callfile
на
echo "Data: $fp&$fp&$fp" >> $callfile
Настройка zabbix
Administration > Media types. Добавляем новый тип FreePBX Gate.
Настраиваем:
- Name: FreePBX Gate
- Type: Script
Configuration > Actions. Создаём Report problems to Zabbix administrators (FREEPBX).
Action — указываем нужные нам условия.
Operations. Здесь можно настроить Subject, именно он будет читаться в телефоне.
Добавляем операцию Send message to user groups: Zabbix administrators via FreePBX Gate.
Здесь нужно указать, что уведомление отправляем через FreePBX Gate.
В Recovery operations можно тоже добавить звонок о том, что проблема устранена, но я убрал эту возможность.
Acknowledgement operations мне тоже не нужно.
Теперь у себя в настройках смотрю раздел Media и добавляю FreePBX Gate 79990001122/(SMS AGENT),(PING),(SMS),(WEB),(VR),(HW),(1C),(WIN),(CRM) 1-7,00:00-24:00 NIWAHD, потом перенастрою на ночь.
Вот пример триггеров, на которые должен отреагировать скрипт:
Текст "(SMS AGENT)" есть в списке моих тегов, поэтому звонок пройдёт.