Подключаем производственный календарь в Zabbix

в 15:15, , рубрики: devops, zabbix, прозводственный календарь, системное администрирование

Как мы все знаем, рабочий процесс предприятия, в соответствии с официальными государственными и международными праздниками, зачастую требует изменения производственного процесса в части сдвига или замены рабочих и нерабочих дней. Во множестве организаций существуют внутренние производственные календари, на расписании которых работают технологические и бизнес-процессы. Системы мониторинга работающие автономно, довольно часто настроены на мониторинг бизнес-процессов в рамках обычной деятельности предприятия и имеют жёсткое фиксированное расписание по контролю информационных потоков и данных, сопровождающих бизнес процессы. В моменты изменения ежедневного рабочего расписания, администраторам требуются ручные действия по изменению логики мониторинга. Как заставить Zabbix использовать производственный календарь? Рассмотрим несколько вариантов поподробнее.

Введение

Все кто работал с Zabbix знают, что логика мониторинга тех или иных сервисов формируется при помощи шаблонов, подключаемых к серверам с контролируемыми сервисами. Изменение логики работы или расписания проверки сервисов является довольно трудоёмкой задачей, которая зависит от количества контролируемых элементов. Изменение рабочего расписания, когда вместо рабочего дня объявляется выходной, во избежание ошибочного срабатывания триггеров на события, заставляет администраторов отправлять контура мониторинга в режим обслуживания "Maintenance". В случае же рабочего дня в выходные, приходится руками включать множество сервисов мониторинга для контроля работы бизнес-процессов.

Официальной рекомендацией по гибкому изменению расписания работы триггеров мониторинга от Zabbix, является замена параметров циклов проверки на глобальные макросы
https://habr.com/ru/company/zabbix/blog/344492/.
Но данное решение не позволяет автоматизировать процесс включения/выключения проверки сервисов по расписанию в явном виде.

Zabbix сервер является автономной системой, которая чётко работает в рамках своей внутренней логики. Поэтому внешние воздействия на систему не рекомендуются.
Попробуем реализовать логику производственного календаря на базе внутренних механизмов Zabbix.
Сразу оговорюсь, что для тестирования производственного календаря в различных конфигурациях было перепробовано огромное количество вариантов. Ниже будут только рабочие примеры, которые прошли тщательное тестирование.
Шаблоны развёртывания доступны на github.com, ссылка в конце статьи.

Ограничения

В логике работы Zabbix сервера присутствуют следующие ограничения:

  • Вся логика работы Zabbix по контролю данных определённого узла сети ограничена только этим узлом сети
  • Пространство данных контролируемого узла не пересекается с пространством данных Zabbix сервера
  • Функциональное(вычисляемое) изменение элементов данных узла ограничено только целочисленными значениями
  • Зависимость триггеров ограничивается пространством хоста

Связность с системой Zabbix сервера

При работе Zabbix сервера допускаются следующие условности:

  • Узлы сети могут использовать локальные, глобальные и пользовательские макросы в работе
  • Вычисляемые значения элементов данных узла могут быть "виртуальными"

Условия работы системы

  • Для корректной работы всех описываемых механизмов, схема обслуживания в рамках производственного календаря не должна иметь ограничений работы сервисов/триггеров в выходные дни
  • Поставщик данных производственного календаря должен быть исключён из схемы работы через производственный календарь
  • Поставщик данных производственного календаря должен иметь свой механизм оповещения администраторов о его работе, независимый от производственного календаря
  • Поставщик данных производственного календаря доступен через HTTP/HTTPS

Значения по умолчанию

Адрес поставщика производственного календаря:

Условия развёртывания

  • Рекомендуется использовать подключение календаря в виде шаблона
  • На контролируемых хостах должен быть доступен Zabbix-agent. При недоступности Zabbix-agent необходимо изменение логики работы
  • Дата возвращаемая календарём обозначает дату выходного дня, если день рабочий, то возвращается любое цифровое значение

Метод №1

В качестве первого метода мы рассмотрим включение тихого режима при наступлении события.
В рамках шаблона необходимо определить макрос {$DATEURL} с адресом поставщика календаря. Создадим элемент с типом "HTTP agent" и именем "holiday.date.by.http".
Время обновления элемента рекомендуется выбирать в зависимости от возможной частоты изменения данных в календаре (для обеспечения гибкости лучше поставить 1м). Время хранения элемента 1день. Тренды не нужны.
Подключаем производственный календарь в Zabbix - 1
Элемент позволит получить значение даты от поставщика производственного календаря.
В закладке "Preprocessing" необходимо включить преобразование получаемых данных по формату "$.date".
Подключаем производственный календарь в Zabbix - 2

При обновлении элемента в заданный цикл проверки, в переменную шаблона "holiday.date.by.http" будет помещена дата полученная от поставщика производственного календаря.

Следующим шагом необходимо создать новый элемент с типом "Calculated" и именем "today.is.a.holiday"
Подключаем производственный календарь в Zabbix - 3

В качестве формулы используется строка:
last(holiday.date.by.http)=date(system.localtime)
Тип элемента "Numeric(Unsigned)"

Смысл элемента в том, чтобы преобразовать сравнение текущей даты и даты полученной от поставщика календаря в логический 0 или 1.

Заранее оговорим тот момент, что использование логического 0 или 1 в ответе от поставщика производственного календаря недопустимо. В случае недоступности календаря, может произойти "залипание" текущего статуса, что в свою очередь приведёт к некорректной работе всей системы. При использовании механизма с датами этого не произойдёт.

Итак, мы получили некое значение которое можно использовать двумя способами:

  • "Тихий режим"
  • "Проактивный режим" с оповещением

"Тихий режим"

Под "Тихим режимом" подразумевается механизм отключения срабатывания триггеров на любые события во время действия выходного дня. Для активации режима необходимо изменить существующие триггеры добавив в них еще одно условие.

Например начальное условие срабатывания триггера на количество пользователей в системе:

{Zabbix server:system.users.num.last()}>1

необходимо изменить на

{Zabbix server:system.users.num.last()}>1 and {Zabbix server:today.is.a.holiday.last()}=0

Это позволит отключить срабатывание триггера в выходной день.
Такая реализация не очень удобна на большом количестве триггеров и она не работает в шаблонах.

"Проактивный режим" с оповещением

Под проактивным режимом подразумевается перевод подчинённых триггеров в состояние "Обслуживание/Игнорирование".
Для активации данного режима необходимо для элемента "today.is.a.holiday" создать соответствующий триггер срабатывающий на изменение состояния режима выходного дня.
Подключаем производственный календарь в Zabbix - 4

После чего установить подчинённому триггеру зависимость от триггера выходного дня.
Подключаем производственный календарь в Zabbix - 5
Срабатывание высокоуровневого триггера выходного дня приведёт к игнорированию всех подчинённых триггеров.

Для отладки работы режима выходного дня использовались два тестовых подчинённых триггера. Первый основанный на количестве пользовательских сессий на сервере "{Zabbix server:system.users.num.last()}>1", срабатывающий когда количество пользователей в системе больше 1.
Второй основанный на количестве процессов "{Zabbix server:proc.num.last()}>20"
При срабатывании каждого из них мы видим по ним активность в панели "Проблемы"
Подключаем производственный календарь в Zabbix - 6
При включении режима выходного дня мы увидим единственное оповещение в панели проблем
Подключаем производственный календарь в Zabbix - 7
Такое же единственное оповещение придёт на систему оповещений(почта, TG, SMS).

С моментом активации режима выходного дня в рамках одного сервера скорее всего всё понятно. Но система мониторинга не ограничивается одним сервером. Хочется чтобы всё это работало глобально.

Метод №2

Как я уже писал ранее, у Zabbix сервера есть ограничения не позволяющие формировать зависимости триггеров между хостами. При создании нового триггера и смене набора элементов на другой сервер, триггер будет создан на выбранном сервере. Это не удобно с точки зрения развёртывания при помощи шаблонов.
Какой же выход ?

Вариант 1

Возможным вариантом является создание в рамках шаблона с бизнес-логикой своего элемента, который будет отвечать за получение даты выходного дня с источника производственного календаря и активировать локальный триггер.

Вариант 2

Перенести дату выходного дня в глобальный контекст доступный всем серверам, убрав лишний шаг получения даты от источника производственного календаря.

Варианты практически равноценны, за исключением глобализации настроек.
Для переноса даты выходного дня в глобальные переменные, лучше всего использовать глобальные макросы. Например создать макрос с именем {$HOLIDAY_DATE}. В случае, если вычисление текущей даты на контролируемом хосте невозможно, а такая ситуация возможна при отсутствии Zabbix-agent, то следует определить глобальный макрос {$CURRENT_DATE} содержащий текущую дату.

Разберём второй вариант на примере сервера InfluxDB. В рабочие дни туда поступает потоковая информация, которая разделена по дискретизации времени на два типа 1минута и 5 минут.

Пример шаблона для InfluxDB

Шаблон содержит элементы контролирующие состояние потоков данных, а также триггеры реагирующие на отставание потоков данных в рамках своих диапазонов. Функция fuzzytime сравнивает отставание значения элемента от времени сервера в указанном диапазоне. Выход значения за пределы диапазона вызывает срабатывание триггера оповещения.

Самым важным общим элементом данного шаблона является триггер выходного дня

                <item>
                    <name>Today is a holiday</name>
                    <type>CALCULATED</type>
                    <key>influxdb.holiday</key>
                    <history>1h</history>
                    <trends>0</trends>
                    <params>date(system.localtime)={$HOLIDAY_DATE}</params>
                    <applications>
                        <application>
                            <name>InfluxDB DataCheck</name>
                        </application>
                    </applications>
                    <triggers>
                        <trigger>
                            <expression>{last()}</expression>
                            <name>InfluxDB Holiday Activated</name>
                            <opdata>If Fired - all dependent triggers are disabled</opdata>
                            <priority>INFO</priority>
                            <description>Включен режим выходного дня для отключения проверки сервисов</description>
                        </trigger>
                    </triggers>
                </item>

Он проверяет совпадение текущей даты на контролируемом сервере с датой выходного дня.
Если получение текущей даты с сервера недоступно, то выражение следует изменить на следующее.

     <params>{$CURRENT_DATE}={$HOLIDAY_DATE}</params>

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

"ОК" скажете Вы, "А как дата выходного дня попадёт в макрос, если у Zabbix нет механизма замены значений макроса из функций?"

А для того, чтобы в макросе появилась дата, мы используем читерский метод обновления макроса. Zabbix умеет JSON RPC, который позволяет авторизованным пользователям менять настройки системы, в том числе глобальных макросов. Значит нам нужно создать новый элемент в пространстве Zabbix сервера, который будет заниматься заполнением даты выходного дня, либо заполнять дату извне. Метод конечно не сильно безопасен, но если не давать пользователям доступа в пространство редактирования параметров самого Zabbix сервера, то всё будет нормально.

Выглядит элемент следующим образом
Подключаем производственный календарь в Zabbix - 8
и содержит Preprocessing скрипт.
Подключаем производственный календарь в Zabbix - 9

Preprocessing Script

//Zabbix.Log(2, 'Date Update request value='+value);
var authtoken = '';
var globalmacroid = -1;

var req = new CurlHttpRequest();
req.AddHeader('Content-Type: application/json');
resp = req.Post("{$DATEURL}", '{}');
var holidaydate = JSON.parse(resp).date;

Zabbix.Log(2, 'Found new holiday date='+holidaydate);

resp = req.Post("{$JSONRPC}", '{"jsonrpc": "2.0","method": "user.login","params": {"user": "Calendar","password": "SomePassword"},"id": 1}');

// Получение токена авторизации

if (req.Status() == 200) {
    jv = JSON.parse(resp);
    if (jv.result)
       authtoken= jv.result;
    else
       return 0;
}
else
    return 0;

// Запрос списка глобальных макросов

var reqmacros = 
{
    "jsonrpc": "2.0",
    "method": "usermacro.get",
    "params": {
        "output": "extend",
        "globalmacro": true
    },
    "auth": authtoken,
    "id": 1
}

resp = req.Post("{$JSONRPC}", JSON.stringify(reqmacros));
if (req.Status() == 200) {
    var jv = JSON.parse(resp);
    for(item in jv.result) {
        if (jv.result[item].macro == '{$HOLIDAY_DATE}')
            {
                globalmacroid = jv.result[item].globalmacroid
                Zabbix.Log(2, 'Old Date value: '+jv.result[item].value)
            }
        }
    if (globalmacroid == -1)
        return 0;
}
else
{
    return 0;
}

// Изменение макроса с датой выходного дня

var changemacros = 
{   "jsonrpc": "2.0",
    "method": "usermacro.updateglobal",
    "params": {
        "globalmacroid": globalmacroid,
        "value": holidaydate
    },
    "auth": authtoken,
    "id": 1
}

resp = req.Post("{$JSONRPC}", JSON.stringify(changemacros));

if (req.Status() == 200) {
   jv = JSON.parse(resp);
   if (jv.result.globalmacroids.indexOf(globalmacroid) != -1)
        return 1
}
return 0;

Этот скрипт и сделает за нас всю работу по обновлению макроса "{$HOLIDAY_DATE}" и если необходимо "{$CURRENT_DATE}". Скрипт производит последовательный вызов методов по авторизации, получению списка макросов и изменению нужного макроса на дату полученную из источника производственного календаря. Как часто его вызывать данный элемент — решение за вами. Дата выходного дня может быть включена и выключена в любой момент.
По моему мнению, за счёт внешнего управления производственным календарём, данное решение позволяет помимо контроля рабочих/выходных дней, также управлять рабочим временем мониторинга бизнес-логики, так как включение/выключение режима происходит с момента изменения даты в глобальном макросе.

PS: При автоматизации получения значений производственного календаря, обязательно сделайте обвязку процесса получения через WEB сценарии, либо через элементы с типом "HTTP agent" с привязкой триггеров оповещения о проблемах получения даты.
Ссылка проекта на github.com

UPD: После первого вопроса решил немного скорректировать материал.
Я не зря в начале статьи упомянул ссылку на статью про использование макросов в "гибких интервалах". В документации к 4.X версии указано, что в полях периодичности опроса возможно использование глобальных макросов. Комбинация использования этого механизма с запросом информации из производственного календаря позволит сделать работу системы мониторинга намного гибче, чем она есть.

© Aborche 2020
Aborche

Автор: Человек с экрана телефона

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js