Перейти к основному содержанию
 

Zabbix — оповещение по телефону через Asterisk

Zabbix

Как-то раз мы проспали проблему. Zabbix прислал пару SMS, но никто ночью не проснулся. А если бы zabbix позвонил, да ещё бы и рассказал о проблеме, то было бы проще всё упавшее поднимать. Учим zabbix звонить на телефон.

Как показывает практика, звонки через свою АТС могут быть дешевле, чем отправка SMS.

Что у нас есть:

  • Zabbix сервер версии 3.4.15. Впрочем, версия не особо важна. Операционная система Ubuntu.
  • Asterisk сервер.

Прежде чем приступить к реализации функционала я нашёл в сети Интернет с десяток статей. Где-то содрал куски кода и переписал их по-своему, где-то взял за основу теорию или практику. В итоге получилось что-то своё, со своими плюсами и минусами.

Теория

  1. При возникновении проблемы zabbix сервер должен выполнить bash скрипт, который нам и выполнит всю работу по совершению звонка. Весь необходимый функционал в zabbix уже есть, нам нужно только написать скрипт и всё настроить.
  2. Bash скрипт генерирует из текста ошибки звуковой WAV файл и CALL файл для Asterisk.
  3. Bash скрипт загружает по SCP на сервер Asterisk сгенерированные файлы, устанавливает им нужные права, помещает в нужные директории.
  4. 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.

zabbix

Настраиваем:

  • Name: FreePBX Gate
  • Type: Script

zabbix

Configuration > Actions. Создаём Report problems to Zabbix administrators (FREEPBX).

zabbix

Action — указываем нужные нам условия.

zabbix

Operations. Здесь можно настроить Subject, именно он будет читаться в телефоне.

zabbix

Добавляем операцию Send message to user groups: Zabbix administrators via FreePBX Gate.

zabbix

Здесь нужно указать, что уведомление отправляем через FreePBX Gate.

В Recovery operations можно тоже добавить звонок о том, что проблема устранена, но я убрал эту возможность.

zabbix

Acknowledgement operations мне тоже не нужно.

zabbix

Теперь у себя в настройках смотрю раздел Media и добавляю FreePBX Gate 79990001122/(SMS AGENT),(PING),(SMS),(WEB),(VR),(HW),(1C),(WIN),(CRM) 1-7,00:00-24:00 NIWAHD, потом перенастрою на ночь.

zabbix

Вот пример триггеров, на которые должен отреагировать скрипт:

zabbix

Текст "(SMS AGENT)" есть в списке моих тегов, поэтому звонок пройдёт.

Теги