Як подружити Zabbix з Asterisk «з коробки»

У попередній статті «Zabbix – розширюємо макро кордони» я розповів як отримувати сесію авторизації та підставляти її у локальний макрос хоста. У цій статті я розповім як подружити Zabbix з Asterisk без зовнішніх скриптів та ПЗ.

Ідея «подружити» ці дві системи народилася давно, причому без встановлення додаткового софту та скриптів. Швидке заглушування видавало безліч варіантів рішень, все зводилося до того, що закиньте скрипти (на пиху, баші, пітон і т. п.) на сервер, і буде вам щастя. Мені ж хотілося реалізувати моніторинг «з коробки» — без зовнішніх скриптів та встановлення додаткового софту на сервер із моніторингом та АТС.

Провозився я з цим у сумі 4 робочі дні, але результат коштував того. Робота через інтерфейс AMI, низькорівневе виявлення, тригери, а головне, на підключення АТС і решта налаштувань тепер йде хвилин 15.

В наявності заббікс 4.4, близько 100 штук Астерісків 13 версії. Якісь АТС йдуть з веб-інтерфейсом FreePBX, якісь із голою консоллю, купою хитрощів та інтеграцією через діалплан.

Отримуємо дані з АТС

Перший і основний момент, який потрібно вирішити - отримання даних про бенкетах і сип реєстраціях. Для цього в АТС існують інтерфейси AGI, AMI, ARI та SSH консоль. Додаткові модулі зі зрозумілих причин не розглядали.

Для початку треба розібратися, що собою представляють ці аги, амі, арі….

  • AGI – використання скриптів у діалплані. В основному використовується для керування викликами.
  • AMI – вміє віддавати всю необхідну інформацію, працює через порт 5038 за аналогією з Telnet. Нам підходить!
  • ARI - сучасно, модно, JSONно. Багато можливостей формат даних у зрозумілому вигляді для Zabbix, але для мене немає головного: не можна контролювати сип реєстрацію. Ще один мінус, для бенкетів є тільки два стани online/offline, хоча станів більше і враховувати їх корисно при діагностиці.
  • SSH може все, але іноді його не дають через «міркувань безпеки». Міркування можуть бути різними, розбирати їх не буду.

Проте при всіх своїх недоліках ARI закриває 90% усіх потреб моніторингу.

Zabbix і Telnet – моє розчарування

AMI знаю добре, свого часу реалізовував відстеження втрат у розмовах із розподілом по віддалених офісах, управління дзвінками тощо. З Telnet теж усе ясно: відкривай підключення, йшли команди і читай відповідь. Що я зробив, але результат мене розчарував.

Telnet у заббікса не такий як у консолі Linux, він трохи простіший і заточений під стандартну авторизацію типу логін/пароль. Якщо логіка авторизації інша, і немає запиту пари логін/пароль, вилітає помилка. Після марних спроб обійти вимогу авторизації поліз дивитись вихідники модуля Telnet.

Я зрозумів, що поки не буде традиційного запиту логіну з паролем, далі не просунуся. Заради інтересу, викинув із коду все, що стосується авторизації, перезбирав усе. Працює! Але ж під вимоги не підходить. Йдемо далі…

Повертаємося до пошуку

Перечитав ще раз документацію з ARI, провів додаткові тести - немає тут сип реєстрацій. Піри є, розмови є, бриджі є, реєстрацій немає. Якоїсь миті навіть задумався, чи так потрібні нам сип реєстрації?

За кумедним збігом обставин, у цей момент прилітає черговий запит від користувача з проблемою вихідних дзвінків. Проблема була в підвисанні сип реєстрації та вирішувалася звичайним перезавантаженням модуля.

asterisk -rx "sip reload"

Було б чудово по вебу звертатися до AMI: це вирішило б усі проблеми, подумав я. Починаю копати в цьому напрямку, і буквально перший рядок пошуку веде на офіційну документацію Asterisk, в якій йдеться про те, що для моїх завдань є опція webenabled у файлі /etc/asterisk/manager.conf, яку потрібно встановити значення YES, в секції [загальний]

Після цього, через звичайний веб запит виду http://ats:8089/mxml?action=SIPshowregistry отримуємо всю необхідну інформацію.

При використанні інтерфейсу FreePBX, через Інтернет не можна включити цю опцію, включати потрібно через консоль, вносячи правки до файлу manager.conf. FreePBX не стирає її при змінах конфігурації через Інтернет.

Скільки працював з різними інтеграціями Asterisk, ніколи не бачив, щоб десь згадувалася ця функція. Мене здивувало, що ніхто не описує цей метод взаємодії з АТС. Навіть спеціально поліз шукати інформацію на цю тему: практично нічого немає або використовувалося для зовсім інших завдань.

WEB AMI – що за звір?

Додавання опції webenabled у файл manager.conf відкривало повноцінний доступ до управління АТС через Інтернет. Всі команди, доступні через звичайний AMI, тепер є у Інтернеті, можна слухати події від АТС через сокет. Принцип роботи нічим не відрізняється від консольного AMI. Після активації цієї опції, до АТС можна звернутися за такими адресами:

https://ats:8089/manager — веб-сторінка з простим інтерфейсом, для тестів та ручної відправки запитів. Усі відповіді форматуються в читабельний HTML вигляд. Для моніторингу не дуже підходить.
https://ats:8089/rawman — лише текстовий висновок, формат аналогічний консольному AMI
https://ats:8089/mxml — лише текстовий висновок у форматі XML. Нам підходить!

Як подружити Zabbix з Asterisk «з коробки»

Тут я подумав: «Ось воно – рішення! Нині все буде готове! Ізі-пізі лемон сквізі», але радіти було поки що рано. Для отримання потрібної інформації достатньо використовувати GET запит з потрібними дією дію, що у відповідь повертає xml зі списком усіх реєстрацій та їх станом. Це все чудово, але потрібна авторизація із запам'ятовуванням сесії з cookie. Коли тестуєш у браузері, не замислюєшся про цей процес.

Процес авторизації

На початку ми звертаємось на адресу http://ats:8089/mxml?action=login&username=zabbix&secret=zabbixУ відповідь нам сервер надсилає куку з сесією авторизації. Ось так виглядає HTTP запит:

https://ats:8089/mxml?action=login&username=zabbix&secret=zabbix

Host: ats:8089
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:77.0) Gecko/20100101 Firefox/77.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1

Відповідь:

GET: HTTP/1.1 200 OK
Server: Asterisk/13.29.2
Date: Thu, 18 Jun 2020 17:41:19 GMT
Cache-Control: no-cache, no-store
Content-type: text/xml
Set-Cookie: mansession_id="6f5de42c"; Version=1; Max-Age=600
Pragma: SuppressEvents
Content-Length: 146

<ajax-response>
<response type="object" id="unknown">
<generic response="Success" message="Authentication accepted"/>
</response>
</ajax-response>

Для роботи там потрібно mansession_id="6f5de42c", тобто сама кука авторизації."
Контент потрібно лише перевірити наявність відповіді.Authentication accepted». Далі, при всіх зверненнях до сервера АТС, нам необхідно буде додавати в запит куку авторизації.

https://ats:8089/mxml?action=SIPpeers

Host: ats:8089
Connection: close
Cookie: mansession_id="6f5de42c"

Як отримувати куку авторизації та використовувати в інших запитах читайте тут: «Zabbix - розширюємо макро кордони»

Для створення елементів відстеження в заббіксі використовуватиму авто виявлення.

Авто виявлення

Для авто виявлення реєстрацій та відстеження станів бенкетів необхідно звертатися до адреси: https://ats:8089/mxml?action=SIPshowregistry або https://ats:8089/mxml?action=SIPpeers

У відповідь АТС повертає нам відповідь XML:

<ajax-response>
<response type="object" id="unknown">
<generic response="Success" eventlist="start" message="Registrations will follow"/>
</response>
...
<response type="object" id="unknown">
<generic event="RegistryEntry" host="login.mtt.ru" port="5060" username="111111" domain="login.mtt.ru" domainport="5060" refresh="105" state="Registered" registrationtime="1592502142"/>
</response>
<response type="object" id="unknown">
<generic event="RegistryEntry" host="voip.uiscom.ru" port="5060" username="222222" domain="voip.uiscom.ru" domainport="5060" refresh="105" state="Registered" registrationtime="1592502142"/>
</response>
<response type="object" id="unknown">
<generic event="RegistryEntry" host="voip.uiscom.ru" port="5060" username="333333" domain="voip.uiscom.ru" domainport="5060" refresh="105" state="Registered" registrationtime="1592502142"/>
</response>
...
</ajax-response>

У відповіді багато сміття, тому в препроцессингу ми його фільтруємо за шаблоном XPath: //response/generic[@host]
Далі починається найцікавіше. Щоб працювати з виявленням та динамічно створювати елементи, потрібно, щоб відповідь була у JSON форматі. XML під час виявлення не підтримується.

Для перетворення XML на JSON довелося трохи погратися з авто заміною, для чого я зробив скрипт на JS

Як подружити Zabbix з Asterisk «з коробки»

Цікавий момент, у відповіді АТС всі параметри обрамляються одинарними лапками, а після застосування шаблону //response/generic[@host] вони замінюються на подвійні.

Для створення елементів використовуємо змінні з XML відповіді (тепер JSON).

Як подружити Zabbix з Asterisk «з коробки»

SIP Registry

Для сип реєстрацій використовуємо три змінні: ім'я користувача, господар, порт. Мене влаштовувало назву елемента [захищено електронною поштою]: 5060, ситуацій, коли потрібно використовувати всі п'ять змінних я не знайшов.

Головний елемент, який отримує інформацію про всі реєстрації, Asterisk - AMI SIPshowregistry. Раз на хвилину він звертається до GET запитом до https://ats:8089/mxml?action=SIPshowregistry, після чого дані відповіді XML передаються всім залежним елементам для аналізу. Елемент з кожної реєстрації створюю залежними від нього. Це зручно, оскільки актуальну інформацію ми отримуємо за один запит, а не для кожного окремо. Ця реалізація має істотний мінус — навантаження на процесор.

При тестуванні до 100 залежних елементів навантаження не помітив, але при 1700 елементів це давало помітне 15 секундне навантаження на процесор. Майте це на увазі, якщо у вас велика кількість залежних елементів.

Як варіант для «розмазування» навантаження або встановлення різної частоти опитування елемента можна винести логіку обробки в кожен елемент окремо.

Отриману інформацію я не зберігаю у головному елементі. По-перше, не бачу в цьому необхідності, а по-друге, якщо відповідь більша за 64К, то заббікс її обрізає.

Оскільки для залежного елемента у нас використовується повна відповідь XML, нам потрібно в препроцессингу отримати значення даного елемента. Через XPath це робиться так:
string(//response/generic[@event=«RegistryEntry»]][@username="{#SIP_REGISTRY_USERNAME}"][@host="{#SIP_REGISTRY_HOST}"][@port="{#SIP_REGISTRY_PORT}"]/@ state)
Для статусів реєстрацій не став використовувати текстові статуси, а перевів їх у числовий вигляд за допомогою JavaScript:

switch(value) {
  case 'Registered':
    return 1;
  case 'Unregistered':
    return 0;
  default:
    return -1;
}

SIP Peers

За аналогією з сип реєстраціями, є головний елемент Asterisk - AMI SIPshowregistry, до якого додаються залежні.

Тут створюється два залежні елементи:

  • Статус бенкету в текстовому вигляді
  • Час відгуку пристрою - якщо статус ОК, то пишеться час відповіді пристрою, інакше "-1"

Сам шлях до елемента вже трохи простіше XPath:

string(//response/generic[@objectname="{#SIP_PEER_OBEJECTNAME}"]/@status)

Для другого елемента використав JavaScript, щоб відокремити час відгуку від статусу бенкету, оскільки вони зберігаються разом:

if(value.substring(0,2) == 'OK'){
	return value.match(/(d+)/gm);
}
else {
	return -1;
}

Висновок

Рішення "з коробки" може бути складним і не відразу зрозумілим. Зростає гнучкість та переносимість між різними системами

Усім приємною та легкою інтеграцією! Шаблон та інструкція з налаштування на GitHub.

Джерело: habr.com

Додати коментар або відгук