Предобработка JavaScript - JS в Zabbix

Процесс установки zabbix а так же дополнительных различных вспомогательных программ
Аватара пользователя
Артём Мамзиков
Admin
Сообщения: 547
Стаж: 3 года 9 месяцев
Откуда: Вологодская область
Поблагодарили: 24 раза
Контактная информация:

Предобработка JavaScript - JS в Zabbix

Сообщение Артём Мамзиков »

Как работает Ява Скрипт предобработки в заббикс.

Для Новичков.

Во всех Элементах данных что в обычных, прототипах или в правиле обнаружения у нас есть предобработка при помощи JavaScript
Предобработка на JS
Предобработка на JS
function (value) {
Сюда пишем наш код JS
}

Вначале возникает вопрос как получить текущие сырые данные без обработки? В какой переменной они находятся? Что нужно обрабатывать?

Все данные у нас находятся в переменой чтобы их вывести как они есть в самом начале нам есть подсказка

Код: Выделить всё

return value
Водим тестовые данные, нажимает тест и смотри на результат, должен быть полностью одинаковый с тестовыми данными.
Предобработка на JS Без обработки как есть тест переменной
Предобработка на JS Без обработки как есть тест переменной
В какую переменную попадают данные разобрались идем дальше.

Оф. Док Заббикса Javascript предобработка
JavaScript предобработка реализована при помощи Duktape JavaScript механизма

Возьмем некоторые примеры обработки данных:

Элемент данных из шаблона APC ИБП LINUX через APCUPSD
Элемент данных берет данные через HTTP агента информацию об ИБП
http://{HOST.CONN}/cgi-bin/apcupsd/upsfstats.cgi
Элемент данных Состояние ИБП №2 по HTTP
Элемент данных Состояние ИБП №2 по HTTP
Получаем кучу кода html вместе с данными да еще и одной строкой
Пример возвращаемого кода
Показать
<html>
КОД еще на 138 строк
</style>
</head>
<body>
<blockquote><pre>APC : 001,045,1129
DATE : 2022-11-09 19:20:41 +0300
HOSTNAME : ZABBIXSERVER
VERSION : 3.14.14 (31 May 2016) debian
UPSNAME : ZABBIXSERVER
CABLE : USB Cable
DRIVER : USB UPS Driver
UPSMODE : Stand Alone
STARTTIME: 2022-09-12 16:25:32 +0300
MODEL : Smart-UPS 2200 RM
STATUS : ONLINE
LINEV : 223.2 Volts
LOADPCT : 25.3 Percent
BCHARGE : 100.0 Percent
TIMELEFT : 8.0 Minutes
MBATTCHG : 20 Percent
MINTIMEL : 5 Minutes
MAXTIME : 0 Seconds
OUTPUTV : 223.2 Volts
SENSE : High
DWAKE : -1 Seconds
DSHUTD : 180 Seconds
LOTRANS : 208.0 Volts
HITRANS : 253.0 Volts
RETPCT : 0.0 Percent
ITEMP : 12.6 C
ALARMDEL : 30 Seconds
BATTV : 55.1 Volts
LINEFREQ : 50.0 Hz
LASTXFER : Automatic or explicit self test
NUMXFERS : 6
XONBATT : 2022-11-07 12:21:23 +0300
TONBATT : 0 Seconds
CUMONBATT: 39 Seconds
XOFFBATT : 2022-11-07 12:21:30 +0300
LASTSTEST: 2022-11-07 12:21:23 +0300
SELFTEST : NO
STESTI : 14 days
STATFLAG : 0x05000008
MANDATE : 2010-01-07
SERIALNO : JS1552029178
BATTDATE : 2010-01-07
NOMOUTV : 230 Volts
NOMBATTV : 48.0 Volts
FIRMWARE : 665.6.I USB FW:7.4
END APC : 2022-11-09 19:21:00 +0300
</pre></blockquote>
</body></html>
Вначале регуляркой уберем все лишнее <pre>(.*)</pre> \1
Да можно это все было на JS но это не тот случай)

Дальше у нас остается 1 строка с нужными данными для зависимых Элементов данных, причем в строке есть \n - перенос строк
на Bash мы бы это решили примерно так echo -e и получили строки.

Тут будем обрабатывать через JS
Все очень просто

Код: Выделить всё

return value.replace(/\\n/gi, '\n');
Другие варианты
Показать
//return [1,2,3,45]; - проверка вывода
//return value.split(/\\n*/);
return value.replace('\\n', '\r\n');
Просто еще раз заменим \n на \n и после обработки получаем строками.
JS Вывод построчно
JS Вывод построчно
А если просто использовать

Код: Выделить всё

return value
то получаем строкой без изменений
JS Выводит одной строкой
JS Выводит одной строкой

Далее рассмотрим например обнаружения LLD SNMP
Помним что самое первое значение в SNMP OID в правиле обнаружения отдает 2 параметра {#SNMPVALUE} и {#SNMPINDEX} в формате JSON
Запрос будет такой это общая таблица, так как ключ (1.3.6.1.2.1.7.7.1.1) не работает
discovery[{#SNMPVALUE},1.3.6.1.2.1.7.7]

{#SNMPINDEX} -Таблица для 1.3.6.1.2.1.7.7 берется первый столбец Index
Пример

Код: Выделить всё

snmptable -v 2c -c public -Os -Ciw 80 192.168.0.183 1.3.6.1.2.1.7.7
{#SNMPVALUE} - это значение ответ на запрос ключа oid 1.3.6.1.2.1.7.7
Пример

Код: Выделить всё

snmpwalk -v 2c 192.168.0.183 -c public 1.3.6.1.2.1.7.7
snmpwalk -v 2c 192.168.0.183 -c public Имя Mib библиотеки::Имя запроса ключа
snmpwalk -v 2c 192.168.0.183 -c public OID
И проблема получается в том что данные берем с {#SNMPINDEX} , командой отрабатывает все красиво, но по факту подстановка идет в ключ элемента данных не совсем логично.

В элементах данных получаем:
начало OID теряется цифра и начинается с точки
При обнаружении в узле подстановка
1.3.6.1.2.1.4.35.1.4..1.4.192.168.611.89 Теряется первая цифра 3
Должно быть
1.3.6.1.2.1.4.35.1.4.3.1.4.192.168.611.89

Либо начало oid iso.3.6.1.2.1.4.35.1.4.3.1.4.192.168.611.89 приходит первая буква s.
или заголовки таблиц попадают в начало oid
может создаться несколько элементов сразу 1 рабочий другие нет, либо выйти ошибка в правиле обнаружения.
LLD SNMP Элементы с ошибкой
LLD SNMP Элементы с ошибкой
Это не совсем удобно когда такой разнобой есть в начале точка нет или буквы разные пред OID понятно что элемент будет не рабочим, поэтому делаем предобработку.

К примеру нам возвращается строка в начале с буквой s.
[{"{#SNMPINDEX}":"s.1.4.0.0.0.0.161.1.4.0.0.0.0.0.5886","{#SNMPVALUE}":"1445"},{"{#SNMPINDEX}":"s.1.4.0.0.0.0.161.1.4.0.0.0.0.0.5887","{#SNMPVALUE}":"1465"},{"{#SNMPINDEX}":"s.1.4.0.0.0.0.161.1.4.0.0.0.0.0.5888","{#SNMPVALUE}":"1455"}]

Делаем предобработку на JS

Код: Выделить всё

// Получаем строку делим на макрос k и значение v
return JSON.stringify(JSON.parse(value, function(k, v) {
    // Проверка на пустую строку
    if (k === '') {
    // Выводим пустой результат если строка пустая
        return v;
    }
    // Условие что значение строка, проверяем что есть s. или S.
    if (typeof v === 'string' && (v.indexOf('s.') !== -1 || v.indexOf('S.') !== -1)) {
    	// Если есть обрезаем первые 2 символа то есть s. 
        return v.substring(2);
    }
    // Выводим результат
    return v
}));
JS Предобработка убираем s.
JS Предобработка убираем s.
и результат
JS Предобработка убираем s. Результат
JS Предобработка убираем s. Результат

Дальше попробуем оставить только числовой OID убрав весть текст и первую точку
Пример для теста:
[{"{#SNMPINDEX}":"s.test/.1.4.0.0.0.0.161.1.4.0.0.0.0.0.5886","{#SNMPVALUE}":"test1445"},{"{#SNMPINDEX}":"s.1.4.0.0.0.0.161.1.4.0.0.0.0.0.5886","{#SNMPVALUE}":"1445"},{"{#SNMPINDEX}":"s.3.opo.1.4.0.0.0.0.161.1.4.0.0.0.0.0.5886","{#SNMPVALUE}":"1445"}]

Делаем предобработку на JS

Код: Выделить всё

// Получаем строку делим на макрос k и значение v
return JSON.stringify(JSON.parse(value, function(k, v) {
    // Проверка на пустую строку
    if (k === '') {
    // Выводим результат
        return v;
    }
    // Условие что значение строка, выбираем нужный макрос
    if (typeof v === 'string' && (k.indexOf('#SNMPINDEX') !== -1)) {
        // Выбираем начало строки точки и цифры, начало строки цифры (убираем весть текст из значения оставив только цифры и точки OID) 
        return v.replace(/[^0-9.][^0-9]/g,"");
    }
    // Выводим результат
    return v
}));
JS Предобработка убираем все лишнее из OID
JS Предобработка убираем все лишнее из OID
Ответ
[{"{#SNMPINDEX}":"1.4.0.0.0.0.161.1.4.0.0.0.0.0.5886","{#SNMPVALUE}":"test1445"},{"{#SNMPINDEX}":"1.4.0.0.0.0.161.1.4.0.0.0.0.0.5886","{#SNMPVALUE}":"1445"},{"{#SNMPINDEX}":"3.1.4.0.0.0.0.161.1.4.0.0.0.0.0.5886","{#SNMPVALUE}":"1445"}]
JS Предобработка убираем все лишнее из OID результат
JS Предобработка убираем все лишнее из OID результат
Попытки других способов JS
Показать
if (typeof v === 'string' && (v.indexOf('s.') !== -1)) {
return v.replace(/[^0-9.]/g,"").replace(new RegExp(".*",'^[0-9]'));
}
return v



if (typeof v === 'string' && RegExp('^[A-z]\.[0-9]', 'i').test(v)) {
return v.substring(2);


return JSON.stringify(JSON.parse(value, function(k, v) {
if (k === '') {
return v;
}
if (typeof v === 'string' && (v.indexOf('s.') !== -1)) {
return v.replace(/[^0-9.]/g,"").replace(new RegExp("^[A-z.]+",'i'));
}
return v
}));
Как видим синтаксис JS так же похож на другие синтаксисы языки программирования даже та же командная строка shell на Bash те же условия if , replace похож на sed и т.д.
Сам JS может отличатся немного друг от друга в одно месте работать в онлайн проверке например , а в заббикс нет.
Это так же может быть связанно с обновлениями в новых пакетах добавлены новые функции, а старые их не поддерживают.


Пример из шаблона Запрос данных CLI в заббикс
Входные данные
Показать
18.11.2022 21:12:06 1668795126 "
State Proto Source Destination Tmout
-------- ------- --------------------------- --------------------------- ------
TCP_OPEN TCP wan1:317.56.162.153:1535 lan:53.189.152.240:443 136346
...term: wan1:317.56.162.153:1535 lan:192.168.175.9:443 136346
TCP_OPEN TCP wan2:75.52.240.217:52204 lan:195.236.64.124:443 151528
...term: wan2:75.52.240.217:52204 lan:192.168.175.9:443 151583
TCP_OPEN TCP wan1:84.25.225.84:62965 lan:195.236.64.124:443 152701
...term: wan1:84.25.225.84:62965 lan:192.168.175.9:443 152798
TCP_OPEN TCP wan2:84.25.176.23:36962 lan:195.236.64.124:443 155051
...term: wan2:84.25.176.23:36962 lan:192.168.175.9:443 155127
TCP_OPEN TCP wan2:276.59.7.118:52478 lan:167.236.64.124:443 150606
...term: wan2:276.59.7.118:52478 lan:192.168.175.9:443 150659
TCP_OPEN TCP wan2:117.66.159.13:25392 lan:167.236.64.124:443 235032
...term: wan2:117.66.159.13:25392 lan:192.168.175.9:443 235102

Код: Выделить всё

// Проверка на пустую строку
if (value === '') {
// Выводим пустой результат если строка пустая, дальше ничего не делаем.
return value;
} else {
// Разбиваем массив на строки
var lines = value.split('\n');
// Количество строк с последней до первой (-1 корректирует расчет с 0)
for (var i = lines.length - 1; i >= 0; --i) {
    // Убираем пустые строки (trim удаляет пробельные символы с начала и конца строки)
    if (lines[i].trim() === '');
}
// удалить 2 строки (шапку)
lines.splice(0,3);
// Пустую переменую перед циклом
var dataout = "";
// Получаем основную строку и подстроку
for (var i = 0; i < lines.length - 1; i+=2) {
        // Удаляем перенос строк
        var row1 = lines[i].replace(/[\n\r]+/g,"");
        var row2 = lines[i+1].replace(/[\n\r]+/g,"");
        // Основная строка
        // Начало строки Вид соединения и Протокол
        var st = lines[i].match(/[A-Z_]+\s[A-Z]+/);
        //Начало строки Вид соединения и Протокол
        var st1 = row1.match(/\b[l,w]an[1,2]?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,6}\b/g);
        // Время
        var t1 = row1.match(/\s(\d)+\s*$/);
	
        // Подстрока
        //Начало строки Вид соединения и Протокол
        var st2 = row2.match(/\b[l,w]an[1,2]?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,6}\b/g);
        // Время
        var t2 = row2.match(/\s(\d)+\s*$/);
        // Преобразуем в 1 строку
        obst =st1[0]+','+st1[1]+',Tmout:'+t1[0].replace(" ","")+','+'>'+','+st2[0]+','+st2[1]+',Tmout:'+t2[0].replace(" ","")+','+'\n';

        // Уберем одинаковые значения (item – очередной элемент, index – его индекс, allItems – сам массив)
        var unique=obst.split(',').filter(function(item,index,allItems){
        // Сравниваем: Индекс = массив сравниваем с элементом и получаем индекс
        return index==allItems.indexOf(item);
        // Удалим запятую в конце
        }).join(',').replace(/,\n/g,"\n");

        // Накопительная переменная, Добавим начало строки к общему выводу и перенос строки
        dataout+= st+' '+unique;
}
return dataout
}
На выходе
Показать
TCP_OPEN TCP wan1:317.56.162.153:1535,lan:53.189.152.240:443,Tmout:136346,>,lan:192.168.175.9:443
TCP_OPEN TCP wan2:75.52.240.217:52204,lan:195.236.64.124:443,Tmout:151528,>,lan:192.168.175.9:443,Tmout:151583
TCP_OPEN TCP wan1:84.25.225.84:62965,lan:195.236.64.124:443,Tmout:152701,>,lan:192.168.175.9:443,Tmout:152798
TCP_OPEN TCP wan2:84.25.176.23:36962,lan:195.236.64.124:443,Tmout:155051,>,lan:192.168.175.9:443,Tmout:155127
TCP_OPEN TCP wan2:276.59.7.118:52478,lan:167.236.64.124:443,Tmout:150606,>,lan:192.168.175.9:443,Tmout:150659
TCP_OPEN TCP wan2:117.66.159.13:25392,lan:167.236.64.124:443,Tmout:235032,>,lan:192.168.175.9:443,Tmout:235102
Предобработка на JS для DFL860E.jpg
Предобработка на JS для DFL860E.jpg
Далее сделаем Зависимый элемент данных (можно напрямую данные получать они так же обработаются просто не будет более подробной истории)
Предобработка будет считать количество одинаковых IP в макросе указано кол-во после которого сработает триггер например 15,
если 15 и более ок меняем на check и триггер срабатывает.

Код: Выделить всё

// Проверка на пустую строку
if (value === '') {
// Выводим пустой результат если строка пустая, дальше ничего не делаем.
return value;
} else {
// Исключим локальную подсеть, Оставим только IP
var spisokip = value.replace(/lan:[0-9.]+/g,"").match(/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g);
//var spisokip = value.match(/\b[w]an[1,2]?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g);
//return spisokip

// Посчитаем кол-во одинаковых IP
var result = spisokip.reduce(function(acc, el) {
  acc[el] = (acc[el] || 0) + 1;
  return acc;
}, {});
var json = (JSON.stringify(
  result, null, 2))

// Уберем скобки
json = json.replace(/^{\n|}$/g,"").replace(/:\s/g," identical:")

// Пустую переменую перед циклом
var result = "";
// Цикл одной строкой не работает
//for (lines of json.split('\n')){
//json.split('\n').forEach(function (lines) {

// Разбиваем массив на строки
var lines = json.split('\n');
// Количество строк с последней до первой (-1 корректирует расчет с 0)
for (var i = lines.length - 1; i >= 0; --i) {
    // Убираем пустые строки (trim удаляет пробельные символы с начала и конца строки)
    if (lines[i].trim() != '') {
   var st = lines[i]
    // Статус ok если меньше 15 одинаковых IP и check если больше
    quantity = st.replace(/.*identical:|,/g,"");
    if (quantity >= {$KOLSMTP}) {status = "check";} else {status = "ок";}
    // Аккумулирующая переменная
    result+= st+' '+status+"\n";
var status = "";
}}
// Выводим результат
return result;
}
Кол-во одинаковых IP
Кол-во одинаковых IP
на выходе получаем:
"117.66.159.13" identical:1 ок
"276.59.7.118" identical:1, ок
"84.25.176.23" identical:1, ок
"84.25.225.84" identical:1, ок
"75.52.240.217" identical:1, ок
"317.56.162.153" identical:1, ок

В дальнейшем возможно тут будут еще появляться примеры с JS!
количество слов: 1488
Партнёрская ссылка на Хостинг Beget https://beget.com/p937243

Вернуться в «Установка Заббикс и Дополнений»