Для Новичков.
Во всех Элементах данных что в обычных, прототипах или в правиле обнаружения у нас есть предобработка при помощи JavaScript function (value) {
Сюда пишем наш код JS
}
Вначале возникает вопрос как получить текущие сырые данные без обработки? В какой переменной они находятся? Что нужно обрабатывать?
Все данные у нас находятся в переменой
Код: Выделить всё
value
Код: Выделить всё
return value
Оф. Док Заббикса Javascript предобработка
JavaScript предобработка реализована при помощи Duktape JavaScript механизма
То есть это среда где выполняется код JS , например он может выполнятся в браузерах яндекс, опера, гугл и так далее.
В разных средах его написание может отличатся в одном браузере он будет работать, в другом нет.
Так же в Duktape заработает не каждый уже готовый скрипт!, плюс обновление синтаксиса новые функции зависят от версии Duktape.
Еще немного инфы про скобки
{} - объект (словарь), [] - массив.
В {фигурных} скобках хранятся данные вида "Ключ": "значение".
По умному это называется "Ассоциативный массив", в JS принято его называть просто "объект".
пример телефонная книга, имя: значение
Но часто бывает нужно делать объект с числовыми ключами, и что-то в нем перечислять.
Можно было ровно также писать ключи из чисел, но придумали короткий способ,
завернули его в [квадратные] скобки и назвали массивом (array), сверху добавили кучу полезных методов конкретно для массива
Возьмем некоторые примеры обработки данных:
Элемент данных из шаблона APC ИБП LINUX через APCUPSD
Элемент данных берет данные через HTTP агента информацию об ИБП
http://{HOST.CONN}/cgi-bin/apcupsd/upsfstats.cgi
Получаем кучу кода 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>
Да можно это все было на JS но это не тот случай)
Дальше у нас остается 1 строка с нужными данными для зависимых Элементов данных, причем в строке есть \n - перенос строк
на Bash мы бы это решили примерно так echo -e и получили строки.
Тут будем обрабатывать через JS
Все очень просто
Код: Выделить всё
return value.replace(/\\n/gi, '\n');
//return value.split(/\\n*/);
return value.replace('\\n', '\r\n');
Код: Выделить всё
return value
Далее рассмотрим например обнаружения 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
Пример
Код: Выделить всё
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
В элементах данных получаем:
начало 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 рабочий другие нет, либо выйти ошибка в правиле обнаружения. Это не совсем удобно когда такой разнобой есть в начале точка нет или буквы разные пред 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
}));
Дальше попробуем оставить только числовой 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
}));
[{"{#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"}]
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 может отличатся немного друг от друга в одно месте работать в онлайн проверке например , а в заббикс нет.
Это так же может быть связанно с обновлениями в новых пакетах добавлены новые функции, а старые их не поддерживают.
Пример из шаблона Запрос данных CLI в заббикс
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 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
Предобработка будет считать количество одинаковых 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;
}
"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, ок
Если необходимо вывести только превышающие вид будет таким
// Выводим результат
//return result;
// Выведем ip которые превышают порог
var spsip = result.match(/.*check\b/g);
var spsips ="["+ spsip +"]";
return spsips.replace(/check,/gi,'check\n').replace(/\[|\]/g,'')
}
Для Версии Zabbix 4.2 пришлось сделать скрипт на JS из формата XML в JSON для камер Hikvision
Запрашиваем XML (в 4.2 в http-агент еще нет авторизации diges по этому так)
shell.sh["curl -s -S -k --digest -u admin:Пароль http://192.168.ХХХ.ХХХ:80/ISAPI/System/status"]
Получаем следующие данные
<DeviceStatus version="1.0" xmlns="http://www.hikvision.com/ver20/XMLSchema">
<currentDeviceTime>2022-12-02T23:59:37+03:00</currentDeviceTime>
<deviceUpTime>5752186</deviceUpTime>
<CPUList>
<CPU>
<cpuDescription>2616.00</cpuDescription>
<cpuUtilization>3</cpuUtilization>
</CPU>
</CPUList>
<MemoryList>
<Memory>
<memoryDescription>DDR Memory</memoryDescription>
<memoryUsage>
240.308594</memoryUsage>
<memoryAvailable>
381.246094</memoryAvailable>
</Memory>
</MemoryList>
</DeviceStatus>
Код: Выделить всё
// Проверка на пустую строку
if (value === '') {
// Выводим пустой результат если строка пустая, дальше ничего не делаем.
return value;
} else {
// Удалим первые 1-2 строки в XML
//var stdl = value.replace(/\<\?xml(.+?)\?\>[\n\r]/g,"").replace(/\<Device.*version="[0-9.]+"\s+xmlns=.*\>[\n\r]/g,"");
var stdl = value.replace(/\<\?xml(.+?)\?\>[\n\r]/g,"").replace(/version="[0-9.]+"\s+xmlns=.*\"/g,"");
//var stdl = value.replace(/\<\?xml(.+?)\?\>[\n\r]/g,"");
// Преобразуем XML в JSON
var fromXML;!function(r){var t={"&":"&","<":"<",">":">","'":"'",""":'"'};function n(r){return r&&r.replace(/^\s+|\s+$/g,"")}function s(r){return r.replace(/(&(?:lt|gt|amp|apos|quot|#(?:\d{1,6}|x[0-9a-fA-F]{1,5}));)/g,(function(r){if("#"===r[1]){var n="x"===r[2]?parseInt(r.substr(3),16):parseInt(r.substr(2),10);if(n>-1)return String.fromCharCode(n)}return t[r]||r}))}function e(r,t){if("string"==typeof r)return r;var u=r.r;if(u)return u;var a,o=function(r,t){if(r.t){for(var e,u,a=r.t.split(/([^\s='"]+(?:\s*=\s*(?:'[\S\s]*?'|"[\S\s]*?"|[^\s'"]*))?)/),o=a.length,i=0;i<o;i++){var l=n(a[i]);if(l){e||(e={});var c=l.indexOf("=");if(c<0)l="@"+l,u=null;else{u=l.substr(c+1).replace(/^\s+/,""),l="@"+l.substr(0,c).replace(/\s+$/,"");var p=u[0];p!==u[u.length-1]||"'"!==p&&'"'!==p||(u=u.substr(1,u.length-2)),u=s(u)}t&&(u=t(l,u)),f(e,l,u)}}return e}}(r,t),i=r.f,l=i.length;if(o||l>1)a=o||{},i.forEach((function(r){"string"==typeof r?f(a,"#",r):f(a,r.n,e(r,t))}));else if(l){var c=i[0];if(a=e(c,t),c.n){var p={};p[c.n]=a,a=p}}else a=r.c?null:"";return t&&(a=t(r.n||"",a)),a}function f(r,t,n){if(void 0!==n){var s=r[t];s instanceof Array?s.push(n):r[t]=t in r?[s,n]:n}}r.fromXML=fromXML=function(r,t){return e(function(r){for(var t=String.prototype.split.call(r,/<([^!<>?](?:'[\S\s]*?'|"[\S\s]*?"|[^'"<>])*|!(?:--[\S\s]*?--|\[[^\[\]'"<>]+\[[\S\s]*?]]|DOCTYPE[^\[<>]*?\[[\S\s]*?]|(?:ENTITY[^"<>]*?"[\S\s]*?")?[\S\s]*?)|\?[\S\s]*?\?)>/),e=t.length,f={f:[]},u=f,a=[],o=0;o<e;){var i=t[o++];i&&v(i);var l=t[o++];l&&c(l)}return f;function c(r){var t=r.length,n=r[0];if("/"===n)for(var s=r.replace(/^\/|[\s\/].*$/g,"").toLowerCase();a.length;){var e=u.n&&u.n.toLowerCase();if(u=a.pop(),e===s)break}else if("?"===n)p({n:"?",r:r.substr(1,t-2)});else if("!"===n)"[CDATA["===r.substr(1,7)&&"]]"===r.substr(-2)?v(r.substr(8,t-10)):p({n:"!",r:r.substr(1)});else{var f=function(r){var t={f:[]},n=(r=r.replace(/\s*\/?$/,"")).search(/[\s='"\/]/);n<0?t.n=r:(t.n=r.substr(0,n),t.t=r.substr(n));return t}(r);p(f),"/"===r[t-1]?f.c=1:(a.push(u),u=f)}}function p(r){u.f.push(r)}function v(r){(r=n(r))&&p(s(r))}}(r),t)}}("object"==typeof exports&&exports||{});
// Преобразовываем и выводим результат
//return JSON.stringify(fromXML(stdl))
// Читаемый вид перенос строк
return JSON.stringify(fromXML(stdl)).replace(/\{/g,"{\n").replace(/\[/g,"[\n").replace(/\,/g,",\n").replace(/\"}/g,"\"\n}").replace(/\]/g,"\n]");
}
"DeviceStatus":{
"currentDeviceTime":"2022-12-05T20:42:19+03:00",
"deviceUpTime":"5999545",
"CPUList":{
"CPU":{
"cpuDescription":"2616.00",
"cpuUtilization":"3"
}},
"MemoryList":{
"Memory":{
"memoryDescription":"DDR Memory",
"memoryUsage":"240.761719",
"memoryAvailable":"380.792969"
}}}}
В дальнейшем возможно тут будут еще появляться примеры с JS!