В правилах LibreNMS нельзя штатными средствами запросить весь список устройств при срабатывании тревоги на одном из них, а это очень удобно для оперативного получения диагностической информации, особенно, при мониторинге Wi-Fi-устройств, т.к. зачастую, недоступными они становятся во время «шторма»1).
Нужно научить LibreNMS не только выбирать устройство, инициализировавшее тревогу, но и выбирать все устройства из той же группы вне зависимости от их статуса2). А при отсутствии таких устройств, должен возвращаться пустой ответ3).
Если кратко резюмировать все нижеприведенные этапы, то все сводится к главному – написать собственный запрос к базе данных, который будет учитывать мои потребности. Благо в LibreNMS это возможно без танцев с бубном! Но, по порядку.
Предполагается, что LibreNMS уже установлена и в нее добавлено некоторое количество устройств, для которых указано, как минимум, «Hostname / IP» и «Display Name».
Т.к. под мониторинг у меня попадают все устройства в LibreNMS, за исключением «устройств» для проверки доступности Интернета, логично, создать динамическую группу, откуда исключить последние.
Для этого создаем группу через «Devices» → «Manage Groups» → «New Device Group», где в качестве критерия выбираем «device_groups.id», «not equal» и, в моем случае, «9»4).
Добавляем новое правило через «Alerts» → «Alert Rules» → «Create new alert rule».
На закладке «Main» ничего интересного нет. Единственное, на что нужно обратить внимание, параметр «Delay», который, при использовании «быстрой проверки», нужно установить в «90s»5), дабы устранить подавляющее большинство ложных срабатываний – крайне актуально при мониторинге Wi-Fi-сети, особенно 4G (2.4Ghz) в загруженных локациях.
На закладке «Advanced», включаем «Override SQL» и добавляем следующий запрос:
SELECT * FROM devices WHERE devices.device_id IN ( SELECT device_group_device.device_id FROM device_group_device WHERE device_group_device.device_group_id = 10 ) AND EXISTS ( SELECT devices.status FROM devices WHERE devices.device_id = ? AND devices.status = 0 ) AND ( devices.disabled = 0 && devices.ignore = 0 ) = 1 ORDER BY devices.status ASC, devices.last_ping_timetaken DESC
Вот код в более читабельном виде.
SELECT * FROM devices WHERE #5 devices.device_id IN #6 ( SELECT #3 device_group_device.device_id FROM device_group_device WHERE device_group_device.device_group_id = 10 #2 ) AND EXISTS #1 ( SELECT devices.status FROM devices WHERE devices.device_id = ? #4 AND devices.status = 0 ) AND ( devices.disabled = 0 && devices.ignore = 0 #7 ) = 1 ORDER BY #8 devices.status ASC, devices.last_ping_timetaken DESC ;
Номер группы (#2) нужно указать вручную, т.к. метода автоматического извлечения этой информации я пока не придумал6).
Обратите внимание на заполнитель «?» (#4) – он обязателен, без него не будет работать правило! И он должен быть только один, иначе в отладке будет ошибка «SQLSTATE[HY093]: Invalid parameter number»!
Для отладки запроса нужно открыть консоль MySQL mysql -u root -p
, если надо, узнать название базы SHOW DATABASES;
и подключиться к базе use librenms
. Просмотр существующих таблиц – SHOW TABLES;
.
Если что-то не работает, то нужно зайти в одно из устройств, нажать на троеточие справа и выбрать «Capture», затем перейти на закладку «Poller» или «Alerts», нажать «Run» и изучать…
Теперь осталось только создать шаблон, перейдя в «Alerts» → «Alert Templates» и нажав «Create new alert template». После чего, назначить его созданному ранее правилу, выбрав в «Attach template to rules».
Template
The device "{{ $alert -> display }}" ({{ $alert -> hostname }}, id: {{ $alert -> device_id }}) is {{ $alert -> state ? 'DOWN' : 'UP' }} from {{ $alert -> timestamp }}! <br><br> @if ( $alert -> state == 0 )Approx. time elapsed: {{ $alert -> elapsed }}. <br><br> @endif @if ( $alert -> faults )Diagnostic information (ping in ms (last ping/poll, m ago): <br><br> @foreach ( $alert -> faults as $key => $value ) @if ( $key < 10 )0{{ $key }}@else{{ $key }}@endif) [{{ $value[ 'status' ] == 0 ? 'DN' : 'UP' }}] {{ $value[ 'display' ] }} - {{ $value[ 'last_ping_timetaken' ] == '0.00' ? '∞' : $value[ 'last_ping_timetaken' ] }} ({{ round( ( ( time() - strtotime( $value[ 'last_ping' ] ) ) / 60 ), 0 ) }}/{{ round( ( ( time() - strtotime( $value[ 'last_polled' ] ) ) / 60 ), 0 ) }}) <br> @endforeach @endif <br> Rule: @if ( $alert -> name ){{ $alert -> name }}@else{{ $alert -> rule }}@endif () (id: {{ $alert -> rule_id }}, severity: {{ $alert -> severity }}). <br><br> Unique-ID: {{ $alert -> uid }}.
Обратите внимание на пустые скобки «()» после «@endif» – они нужны, чтобы операторы не «съедали» то, что дальше. Так же нужно делать и с «@else»…
Alert title
{{ $alert -> name }} [{{ strtoupper( $alert -> severity ) }}]
Recovery title
{{ $alert -> name }} [OK]
Для тестирования шаблона и просмотра доступных значений и их заполнителей, нужно авторизоваться под пользователем «librenms»
sudo su - librenms
и выполнить команду
./scripts/test-template.php -t X -d -h HOST -r Y
где «X», это номер шаблона, а «Y» – номер правила. Обе цифры можно посмотреть в первой колонке соответствующего списка – списка шаблонов или списка правил. Естественно, «HOST» должен соответствовать значению, указанному в поле «Hostname or IP» соответствующего устройства.
Обсуждение