Вырашаем практычныя задачы ў Zabbix з дапамогай JavaScript

Вырашаем практычныя задачы ў Zabbix з дапамогай JavaScript
Ціхан Ускоў, інжынер каманды інтэграцыі Zabbix

Zabbix – кастамізаваная платформа, якая выкарыстоўваецца для маніторынгу любых дадзеных. З самых ранніх версій Zabbix у адміністратараў маніторынгу была магчымасць запускаць розныя скрыпты праз Дзеянні для праверак на мэтавых вузлах сеткі. Пры гэтым запуск скрыптоў прыводзіў да ўзнікнення шэрагу складанасцяў, у тым ліку такіх, як неабходнасць падтрымкі скрыптоў, іх дастаўкі на вузлы сувязі і проксі, а таксама падтрымкі розных версій.

JavaScript для Zabbix

У красавіку 2019 года быў прадстаўлены Zabbix 4.2 з функцыяй перадапрацоўкі на JavaScript. Шмат хто загарэўся ідэяй адмовіцца ад напісання скрыптоў, якія дзесьці забіраюць дадзеныя, пераварваюць іх і падаюць ужо ў зразумелым для Zabbix фармаце, а выконваць простыя праверкі, якія будуць атрымліваць негатовыя для захоўвання і апрацоўкі Zabbix дадзеныя, а потым апрацоўваць гэты струмень дадзеных з выкарыстаннем сродкаў Zabbix і JavaScript. У звязку з нізкаўзроўневым выяўленнем і залежнымі элементамі дадзеных, якія з'явіліся ў Zabbix 3.4, атрымалася дастаткова гнуткая канцэпцыя для сартавання і кіравання атрыманымі дадзенымі.

У Zabbix 4.4, як лагічны працяг перадапрацоўкі на JavaScript, з'явіўся новы спосаб абвесткі – Webhook, які можна выкарыстоўваць для простай інтэграцыі абвестак Zabbix са іншымі праграмамі.

JavaScript і Duktape

Чаму былі абраныя менавіта JavaScript і Duktape? Разглядаліся розныя варыянты моў і рухавічкоў:

  • Lua - Lua 5.1
  • Lua - LuaJIT
  • Javascript - Duktape
  • Javascript - JerryScript
  • Embedded Python
  • Embedded Perl

Асноўнымі крытэрамі выбару былі распаўсюджанасць, прастата інтэграцыі рухавічка ў прадукт, нізкае спажыванне рэсурсаў і агульная прадукцыйнасць рухавічка, і бяспеку ўкаранення кода на гэтай мове ў маніторынг. Па сукупнасці паказчыкаў перамог JavaScript на рухавічку Duktape.

Вырашаем практычныя задачы ў Zabbix з дапамогай JavaScript

Крытэрыі выбару і performance testing

Асаблівасці Duktape:

- Стандарт ECMAScript E5/E5.1
- Модулі Zabbix для Duktape:

  • Zabbix.log() - дазваляе ўпісаць непасрэдна ў лог Zabbix Server паведамлення з розным узровень дэталізацыі, што забяспечвае магчымасць супастаўляць памылкі, напрыклад, у Webhook са станам сервера.
  • CurlHttpRequest() - дазваляе рабіць HTTP-запыты ў сетку, на чым заснавана ўжыванне Webhook.
  • atob() і btoa() - дазваляе кадзіраваць і дэкадаваць радкі ў фармат Base64.

УВАГА. Duktape адпавядае стандартам ACME. У Zabbix выкарыстоўваецца версія скрыпту 2015 гады. Наступныя змены нязначныя, таму іх можна ігнараваць.

Магія JavaScript

Уся магія JavaScript заключана ў дынамічнай тыпізацыі і прывядзенні тыпаў: радковых, лікавых і лагічных.

Гэта азначае, што не трэба загадзя аб'яўляць якога тыпу зменная павінна вяртаць значэнне.

Пры матэматычных аперацыях значэння, якія вяртаюцца аператарамі-функцыямі, пераўтворацца ў лікі. Выключэнне з такіх аперацый - складанне, паколькі, калі хоць бы адно з складнікаў з'яўляецца радком, да ўсіх складнікаў ужываецца радковае пераўтварэнне.

УВАГА. Метады, якія адказваюць за такія пераўтварэнні, як правіла, рэалізаваны ў бацькоўскіх прататыпах аб'ектаў, значэнне и toString. значэнне выклікаецца пры лікавым пераўтварэнні і заўсёды перад метадам toString. Метад значэнне абавязаны вяртаць прымітыўныя значэнні, інакш яго вынік ігнаруецца.

Для аб'екта выклікаецца метад valueOF. Калі ён не знойдзены ці не вяртае прымітыўнае значэнне, выклікаецца метад toString. Калі метад toString не знойдзены, праводзіцца пошук значэнне у прататыпе аб'екта, і ўсё паўтараецца да завяршэння апрацоўкі значэння і прывядзення ўсіх значэнняў у выразе да аднаго тыпу. Калі для аб'екта рэалізаваны метад toString, Які вяртае прымітыўнае значэнне, то менавіта ён выкарыстоўваецца для радковага пераўтварэнні. Пры гэтым вынікам ужывання гэтага метаду не абавязкова з'яўляецца радок.

Напрыклад, калі для для аб'екта 'OBJ' вызначаецца метад toString,

`var obj = { toString() { return "200" }}` 

метад toString вяртае менавіта радок, і пры складанні радка з лікам мы атрымліваем злеплены радок:

`obj + 1 // '2001'` 

`obj + 'a' // ‘200a'`

Але калі перапісаць toString, Каб метад вяртаў лік, пры складанні аб'екта будзе выконвацца матэматычная аперацыя з лікавым пераўтварэннем і атрымліваецца вынік матэматычнага складання.

`var obj = { toString() { return 200 }}` 

`obj + 1 // '2001'`

Пры гэтым, калі мы выконваем складанне з радком, выконваецца радковае пераўтварэнне, і мы атрымліваем склеены радок.

`obj + 'a' // ‘200a'`

Менавіта ў гэтым крыецца чыннік вялікай колькасці памылак пачаткоўцаў карыстачоў JavaScript.

У метад toString можна ўпісаць функцыю, якая будзе павялічваць бягучае значэнне аб'екта на 1.

Вырашаем практычныя задачы ў Zabbix з дапамогай JavaScript
Выкананне скрыпту пры ўмове, што пераменная роўна 3, і яна ж роўна 4.

Пры параўнанні з прывядзеннем тыпаў (==) кожны раз выконваецца метад toString з функцыяй павелічэння значэння. Адпаведна, пры кожным наступным параўнанні значэнне павялічваецца. Гэтага можна пазбегнуць шляхам выкарыстання параўнання без прывядзення тыпаў (===).

Вырашаем практычныя задачы ў Zabbix з дапамогай JavaScript
Параўнанне без прывядзення тыпаў

УВАГА. Не выкарыстоўвайце параўнанне з прывядзеннем тыпаў без неабходнасці.

Для складаных скрыптоў, напрыклад, Webhook са складанай логікай, у якіх неабходна параўнанне з прывядзеннем тыпаў, рэкамендуецца папярэдне напісаць праверкі для значэнняў, якія вяртаюць зменныя і апрацаваць неадпаведнасці і памылкі.

Webhook Media

У канцы 2019 года і ў пачатку 2020 года каманда інтэграцыі Zabbix займалася актыўнай распрацоўкай Webhooks і інтэграцый "са скрынкі", якія пастаўляюцца ў дыстрыбутыве Zabbix.

Вырашаем практычныя задачы ў Zabbix з дапамогай JavaScript
Спасылка на дакументацыю

Папярэдняя апрацоўка

  • З'яўленне перадапрацоўкі на JavaScript дазволіла адмовіцца ад большасці вонкавых скрыптоў, і ў наш час у Zabbix можна атрымаць любое значэнне і пераўтварыць яго ў зусім іншае любое значэнне.
  • Прадапрацоўка ў Zabbix рэалізаваная кодам на JavaScript, які пры кампіляцыі ў байт-код пераўтворыцца ў функцыю, якая прымае адзінае значэнне ў выглядзе параметру значэнне у выглядзе радка (у радку можа быць і лічба, і лік).
  • Паколькі на выхадзе атрымліваецца функцыя, у канцы скрыпту абавязковы вяртаць.
  • Магчыма выкарыстанне карыстацкіх макрасаў у кодзе.
  • Рэсурсы можна абмежаваць не толькі на ўзроўні аперацыйнай сістэмы, але і праграмна. Для кроку перадапрацоўкі выдзяляецца максімум 10 мегабайт аператыўнай памяці і ліміт часу выканання ў 10 секунд.

Вырашаем практычныя задачы ў Zabbix з дапамогай JavaScript

УВАГА. Значэнні тайм-аўту ў 10 секунд досыць шмат, таму што збор умоўных тысяч элементаў дадзеных за 1 секунду па досыць "цяжкім" сцэнары перадапрацоўкі можа запаволіць працу Zabbix. Таму не рэкамендуецца выкарыстоўваць перадапрацоўку для выканання паўнавартасных скрыптоў на JavaScript праз так званыя ценявыя элементы дадзеных (dummy items), якія запускаюцца толькі для выканання перадапрацоўкі.

Праверыць свой код можна праз тэст перадапрацоўкі або з дапамогай утыліты zabbix_js:

`zabbix_js -s *script-file -p *input-param* [-l log-level] [-t timeout]`

`zabbix_js -s script-file -i input-file [-l log-level] [-t timeout]`

`zabbix_js -h`

`zabbix_js -V`

Практычныя задачы

Задача 1

Замяніць вылічаемы элемент дадзеных перадапрацоўкай.

ўмова: атрымліваем з датчыка тэмпературу ў градусах па Фарэнгейце для захоўвання ў градусах па Цэльсіі.

Раней мы стварылі б элемент дадзеных, які збірае тэмпературу ў градусах па Фарэнгейце. Пасля гэтага — яшчэ адзін элемент дадзеных (які вылічваецца), які па формуле пераўтвараў бы градусы па Фарэнгейце ў градусы па Цэльсіі.

Праблемы:

  • Неабходна дубляваць элементы дадзеных і захоўваць усе значэння ў базе.
  • Неабходна ўзгадніць інтэрвалы для «бацькоўскага» элемента дадзеных, які вылічаецца і выкарыстоўваецца ў формуле, і для вылічанага элемента дадзеных. У адваротным выпадку які вылічаецца элемент дадзеных можа перайсці ў непадтрымоўваны стан ці палічыць папярэдняе значэнне, што адаб'ецца на надзейнасці вынікаў маніторынгу.

Адным з рашэнняў была адмова ад гнуткіх інтэрвалаў праверак у карысць фіксаваных інтэрвалаў, каб гарантавана вылічваць вылічаемы элемент дадзеных пасля элемента дадзеных, які атрымлівае дадзеныя (у нашым выпадку - тэмпература ў градусах па Фарэнгейце).

Але калі, напрыклад, шаблон мы выкарыстоўваем для праверкі вялікай колькасці прылад, і праверка выконваецца раз у 30 секунд, 29 секунд Zabbix "халтурыт", а ў апошнюю секунду пачынае праверкі і вылічэнні. Гэта прыводзіць да стварэння чаргі і ўплывае на прадукцыйнасць. Таму рэкамендуецца выкарыстоўваць фіксаваныя інтэрвалы толькі калі гэта сапраўды неабходна.

У дадзенай задачы аптымальнае рашэнне - перадапрацоўка з аднаго радка на JavaScript, якая канвертуе градусы па Фарэнгейце ў градусы па Цэльсіі:

`return (value - 32) * 5 / 9;`

Гэта хутка і проста, не трэба ствараць лішніх элементаў даных і захоўваць па іх гісторыю, а таксама можна выкарыстоўваць для праверак гнуткія інтэрвалы.

Вырашаем практычныя задачы ў Zabbix з дапамогай JavaScript

`return (parseInt(value) + parseInt("{$EXAMPLE.MACRO}"));`

Але, калі ў гіпатэтычнай сітуацыі неабходна атрыманы элемент дадзеных скласці, напрыклад, з якой-небудзь канстантай, вызначанай у макрасе, неабходна ўлічваць, што параметр значэнне раскрываецца ў радок. Пры аперацыі складання радкоў, два радкі проста аб'ядноўваюцца ў адну.

Вырашаем практычныя задачы ў Zabbix з дапамогай JavaScript

`return (value + "{$EXAMPLE.MACRO}");`

Для атрымання выніку матэматычнага дзеяння неабходна прывесці тыпы атрыманых значэнняў у лічбавы фармат. Для гэтага можна выкарыстоўваць функцыю parseInt(), якая выдае цэлы лік, функцыю parseFloat(), якая выдае дзесятковы дроб, ці функцыю нумар, якая выдае цэлы лік або дзесятковы дроб.

задача 2

Атрымаць час у секундах да заканчэння сертыфіката.

ўмова: нейкі сэрвіс выдае дату заканчэння сертыфіката ў фармаце "Feb 12 12:33:56 2022 GMT".

У ECMAScript5 Date.parse() прымае дату ў фармаце ISO 8601 (YYYY-MM-DDTHH:mm:ss.sssZ). Неабходна прывесці да яго радок у фармаце MMM DD YYYY HH:mm:ss ZZ

праблема: значэнне месяца выражана тэкстам, а не лікам. Дадзеныя ў такім фармаце не прымаюцца Duktape.

Прыклад рашэння:

  • У першую чаргу аб'яўляецца пераменная, якая прымае значэнне (увесь скрыпт - аб'ява зменных, якія пералічаны праз коску).

  • У першым радку мы атрымліваем дату ў параметры значэнне і падзяляем яе прабеламі метадам раскол. Такім чынам, мы атрымліваем масіў, дзе кожнаму элементу масіва, пачынальна з азначніка 0, адпавядае адзін элемент даты да і пасля прабелу. split(0) - месяц, split(1) - Лік, split(2) - Радок з часам і т. д. Пасля гэтага да кожнага элемента даты можна звяртацца па індэксе ў масіве.

`var split = value.split(' '),`

  • Кожнаму месяцу (у храналагічным парадку) адпавядае індэкс яго становішча ў масіве (з 0 да 11). Каб сканвертаваць тэкставае значэнне ў лікавае, да азначніка месяца дадаецца адзінка (таму што нумарацыя месяцаў пачынаецца з 1). Пры гэтым выраз з прыбаўленнем адзінкі ўзята ў дужкі, таму што ў адваротным выпадку будзе атрыманы радок, а не лік. У канцы мы выконваем кавалачак () - зрэз масіва з канца, каб пакінуць толькі два сімвалы (што важна для месяцаў з двухзначным нумарам).

`MONTHS_LIST = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],`

`month_index = ('0' + (MONTHS_LIST.indexOf(split[0]) + 1)).slice(-2),`

  • Фарміруем з атрыманых значэнняў радок у фармаце ISO звычайным складаннем радкоў у адпаведным парадку.

`ISOdate = split[3] + '-' + month_index + '-' + split[1] + 'T' + split[2],`

Дадзеныя ў атрыманым фармаце - колькасць секунд з 1970 года да нейкага моманту ў будучыні. Выкарыстоўваць дадзеныя ў атрыманым фармаце ў трыгерах практычна немагчыма, таму што Zabbix дазваляе апераваць толькі макрасамі. {Дата} и {Time}, якія вяртаюць дату і час у зразумелым для карыстальніка фармаце.

  • Пасля гэтага мы можам атрымаць у JavaScript бягучую дату ў фармаце Unix Timestamp і адняць яе з атрыманага значэння даты заканчэння сертыфіката, каб атрымаць колькасць мілісекунд з бягучага моманту да моманту заканчэння сертыфіката.

`now = Date.now();`

  • Дзелім атрыманае значэнне на тысячу, каб атрымаць секунды ў Zabbix.

`return parseInt((Date.parse(ISOdate) - now) / 1000);`

У трыгеры можна паказаць выраз 'last' і набор лічбаў, які адпавядае колькасці секунд у перыядзе, на які неабходна адрэагаваць, напрыклад, у тыднях. Такім чынам, трыгер будзе апавяшчаць аб тым, што тэрмін дзеяння сертыфіката заканчваецца праз тыдзень.

УВАГА. Звярніце ўвагу на выкарыстанне parseInt() у функцыі вяртаць, Каб сканвертаваць дробавы лік, атрыманае ў выніку дзялення мілісекунд, у цэлы лік. Таксама можна выкарыстоўваць parseFloat() і захоўваць дробавыя дадзеныя.

Глядзець даклад

Крыніца: habr.com

Дадаць каментар