Rezolvăm probleme practice în Zabbix cu ajutorul JavaScript

Rezolvăm probleme practice în Zabbix cu ajutorul JavaScript
Tihon Uskov, inginer în echipa de integrare Zabbix

Zabbix este o platformă personalizabilă utilizată pentru monitorizarea oricăror date. Începând cu primele versiuni ale Zabbix, administratori de monitorizare au avut posibilitatea de a rula diverse scripturi prin Acțiuni pentru verificările pe nodurile țintă ale rețelei. Totuși, rularea scripturilor a generat o serie de dificultăți, inclusiv necesitatea de a susține scripturile, livrarea acestora pe noduri de comunicație și proxy-uri, precum și suportul pentru diferite versiuni.

JavaScript pentru Zabbix

În aprilie 2019, a fost lansat Zabbix 4.2 cu funcția de preprocesare în JavaScript. Mulți au fost inspirați de ideea de a abandona scrierea scripturilor care prelua date din alte surse, le procesau și le ofereau deja într-un format cunoscut pentru Zabbix, optând în schimb pentru verificări simple care să primească datele neprocesate pentru stocare și prelucrare în Zabbix și JavaScript. Corelate cu descoperirea de nivel înalt și elementele de date dependente introduse în Zabbix 3.4, s-a realizat o concepție suficient de flexibilă pentru sortarea și gestionarea datelor obținute.

În Zabbix 4.4, ca o continuare logică a preprocesării în JavaScript, a apărut un nou mod de notificare — Webhook, care poate fi utilizat pentru integrarea simplă a notificărilor Zabbix cu aplicații terțe.

JavaScript și Duktape

De ce au fost alese JavaScript și Duktape? Au fost luate în considerare diverse variante de limbaje și motoare:

  • Lua – Lua 5.1
  • Lua – LuaJIT
  • Javascript – Duktape
  • Javascript – JerryScript
  • Python încorporat
  • Perl încorporat

Principalele criterii de selecție au fost răspândirea, ușurința de integrare a motorului în produs, consumul scăzut de resurse și performanța generală a motorului, precum și securitatea implementării acestui limbaj în monitorizare. În urma analizei, JavaScript pe motorul Duktape a câștigat.

Rezolvăm probleme practice în Zabbix cu ajutorul JavaScript

Criterii de selecție și testare a performanței

Caracteristici Duktape:

— Standard ECMAScript E5/E5.1
— Module Zabbix pentru Duktape:

  • Zabbix.log() — permite scrierea direct în log-ul Zabbix Server a mesajelor cu diferite niveluri de detaliere, oferind posibilitatea de a corela erorile, de exemplu, în Webhook, cu starea serverului.
  • CurlHttpRequest() — permite efectuarea de cereri HTTP în rețea, pe baza cărora se bazează utilizarea Webhook.
  • atob() și btoa() — permit codarea și decodarea șirurilor în format Base64.

NOTĂ. Duktape respectă standardele ACME. În Zabbix este utilizată versiunea scriptului din 2015. Modificările ulterioare sunt minore, așa că pot fi ignorate..

Magia JavaScript

Toată magia JavaScript-ului constă în tipizarea dinamică și conversia tipurilor: șiruri, numerice și logice.

Aceasta înseamnă că nu trebuie declarat dinainte de ce tip trebuie să returneze valoarea o variabilă.

În operațiile matematice, valorile returnate de operatorii funcții sunt convertite în numere. O excepție de la aceste operații este adunarea, deoarece, dacă cel puțin unul dintre termeni este un șir, tuturor termenilor li se aplică conversia în șir.

NOTĂ. Metodele responsabile pentru astfel de conversii sunt, de obicei, implementate în prototipurile părinte ale obiectelor, valueOf și toString. valueOf este apelat în timpul conversiei numerice și întotdeauna înaintea metodei toString. Metoda valueOf trebuie să returneze valori primitive, altfel rezultatul său este ignorat.

Pentru un obiect, se apelează metoda valueOf. Dacă aceasta nu este găsită sau nu returnează o valoare primitivă, se apelează metoda toString. Dacă metoda toString nu este găsită, se caută valueOf în prototipul obiectului și totul se repetă până la finalizarea procesării valorii și conversia tuturor valorilor din expresie la un singur tip.. Dacă pentru obiect este implementată o metodă toString, care returnează o valoare primitivă, atunci aceasta este utilizată pentru conversia în șir. Rezultatul aplicării acestei metode nu este obligat să fie un șir.

De exemplu, dacă pentru obiectul ‘obj‘ este definită metoda toString,

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

metoda toString returnează exact un șir, iar la adunarea unui șir cu un număr obținem un șir concatenat:

`obj + 1 \/\/ '2001'` 

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

Dar dacă rescriem toString, astfel încât metoda să returneze un număr, la adunarea obiectului se va efectua operația matematică cu conversie numerică și se obține rezultatul adunării matematice.

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

`obj + 1 \/\/ '2001'`

În acest caz, dacă efectuăm adunarea cu un șir, se efectuează conversia în șir și obținem un șir concatenat.

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

Exact aceasta este cauza multor erori întâmpinate de utilizatorii începători ai JavaScript.

În metoda toString poți scrie o funcție care va crește valoarea curentă a obiectului cu 1.

Rezolvăm probleme practice în Zabbix cu ajutorul JavaScript
Executarea scriptului cu condiția că variabila este 3 și în același timp este 4.

Când compari folosind tipuri (==) se execută în fiecare dată metoda toString cu funcția de creștere a valorii. Prin urmare, la fiecare comparație ulterioară, valoarea crește. Acest lucru poate fi evitat prin utilizarea comparației fără conversia tipurilor (===).

Rezolvăm probleme practice în Zabbix cu ajutorul JavaScript
Comparația fără conversia tipurilor

NOTĂ. Nu utiliza comparația cu conversia tipurilor fără necesitate.

Pentru scripturi complexe, cum ar fi Webhook-uri cu logică sofisticată, în care este necesară comparația cu conversia tipurilor, se recomandă să scrii mai întâi verificări pentru valorile returnate de variabile și să gestionezi neconcordanțele și erorile.

Webhook Media

La sfârșitul anului 2019 și începutul anului 2020, echipa de integrare Zabbix a dezvoltat activ Webhooks și integrarea "din cutie", care sunt livrate cu distribuția Zabbix.

Rezolvăm probleme practice în Zabbix cu ajutorul JavaScript
Link către documentație

Preprocesare

  • Apariția preprocesării în JavaScript a permis renunțarea la majoritatea scripturilor externe, iar în prezent în Zabbix se poate obține orice valoare și o poate transforma în orice altă valoare complet diferită.
  • Preprocesarea în Zabbix este implementată prin cod JavaScript care, la compilare în bytecode, este transformat într-o funcție care primește o singură valoare ca parametru valoare sub forma unui șir (în șir poate fi și o cifră, și un număr).
  • Deoarece la ieșire se obține o funcție, la finalul scriptului este obligatoriu return.
  • Este permisă utilizarea macrocomenzilor personalizate în cod.
  • Resursele pot fi limitate nu doar la nivelul sistemului de operare, ci și programatic. Pentru etapa de preprocesare se alocă un maxim de 10 megabytes de memorie RAM și un limită de timp de execuție de 10 secunde.

Rezolvăm probleme practice în Zabbix cu ajutorul JavaScript

NOTĂ. Valorile timeout-ului de 10 secunde sunt suficiente, deoarece colectarea a unor mii de elemente de date într-o secundă printr-un scenariu destul de „greu” de preprocesare poate încetini funcționarea Zabbix. Prin urmare, nu se recomandă utilizarea preprocesării pentru executarea scripturilor complete în JavaScript prin așa-numitele elemente de date fantomă (dummy items), care sunt activate doar pentru a efectua preprocesarea..

Verificați-vă codul printr-un test de preprocesare sau utilizând un utilitar 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`

Sarcini practice

Sarcină 1

Înlocuiți elementul de date calculat cu preprocesarea.

Condiție: obținem de la senzor temperatura în grade Fahrenheit pentru a o păstra în grade Celsius.

În trecut, am creat un element de date care colecta temperatura în grade Fahrenheit. Apoi, un alt element de date (calculated), care printr-o formulă convertește gradele Fahrenheit în grade Celsius.

Probleme:

  • Este necesar să se dublieze elementele de date și să se păstreze toate valorile în bază.
  • Trebuie să se alinieze intervalele pentru elementul de date "părinte", care este calculat și folosit în formulă, și pentru elementul de date calculat. Altfel, elementul de date calculat poate trece într-o stare neacceptată sau poate calcula valoarea anterioară, ceea ce va afecta fiabilitatea rezultatelor de monitorizare.

Una dintre soluții a fost abandonarea intervalelor flexibile de verificare în favoarea intervalelor fixe, pentru a garanta calcularea elementului de date calculat după elementul de date care obține datele (în cazul nostru - temperatura în grade Fahrenheit).

Dar, de exemplu, dacă folosește un șablon pentru a verifica un număr mare de dispozitive, iar verificarea se efectuează la fiecare 30 de secunde, în ultimele 29 de secunde Zabbix "inactiv", iar în ultima secundă începe verificările și calculele. Acest lucru duce la crearea unei cozi și afectează performanța. Așadar, se recomandă utilizarea intervalelor fixe doar dacă este cu adevărat necesar.

În această sarcină, soluția optimă este un preprocesor dintr-un singur rând în JavaScript, care convertește gradele Fahrenheit în grade Celsius:

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

Este rapid și simplu, nu trebuie să creați elemente de date suplimentare și să păstrați istoricul pentru ele, de asemenea, poate fi folosit pentru intervale flexibile de verificare.

Rezolvăm probleme practice în Zabbix cu ajutorul JavaScript

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

Dar, dacă în situația ipotetică este necesar să adunăm elementul de date obținut, de exemplu, cu o constantă definită în macrou, trebuie avut în vedere că parametrul valoare se contopește într-un șir. Atunci când se efectuează operațiunea de adunare a șirurilor, cele două șiruri se combină pur și simplu într-unul singur.

Rezolvăm probleme practice în Zabbix cu ajutorul JavaScript

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

Pentru a obține rezultatul unei operații matematice, este necesar să convertim tipurile valorilor obținute în format numeric. Pentru aceasta, putem folosi funcția parseInt(), care returnează un număr întreg, funcția parseFloat(), care returnează un număr zecimal, sau funcția number, care returnează un număr întreg sau un număr zecimal.

Sarcina 2

Obțineți timpul în secunde până la expirarea certificatului.

Condiție: un anumit serviciu returnează data expirării certificatului în formatul "Feb 12 12:33:56 2022 GMT".

În ECMAScript5 Date.parse() acceptă date în format ISO 8601 (YYYY-MM-DDTHH:mm:ss.sssZ). Este necesar să convertiți un șir în formatul MMM DD YYYY HH:mm:ss ZZ

Problema: valoarea lunii este exprimată text, nu printr-un număr. Datele în acest format nu sunt acceptate de Duktape.

Exemplu de soluție:

  • Mai întâi se declară o variabilă, care primește o valoare (întreaga scriptare constă în declararea variabilelor, enumerate prin virgulă).

  • În prima linie obținem data în parametrul valoare și o împărțim prin spații folosind metoda split. Astfel, obținem un tablou, unde fiecărui element al tabloului, începând cu indexul 0, îi corespunde un element al datei înainte și după spațiu. split(0) — luna, split(1) — ziua, split(2) — un șir cu timpul etc. După aceasta, fiecare element al datei poate fi accesat prin index în tablou.

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

  • Fiecărei luni (în ordine cronologică) îi corespunde un index în tablou (de la 0 la 11). Pentru a converti valoarea textuală în numerică, la indexul lunii se adaugă unu (pentru că numerotarea lunilor începe de la 1). În acest context, expresia cu adăugarea unu este în paranteze, deoarece altfel va rezulta un șir, nu un număr. La final, executăm slice() — o tăiere a tabloului din spate, pentru a lăsa doar două caractere (ceea ce este important pentru lunile cu nume format din două cifre).

`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),`

  • Formăm din valorile obținute un șir în format ISO prin simpla concatenare a șirurilor într-o ordine corespunzătoare.

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

Datele în formatul primit reprezintă numărul de secunde din 1970 până la un anumit moment în viitor. Utilizarea datelor în acest format în declanșatoare este practic imposibilă, deoarece Zabbix permite doar operarea cu macrocomenzi. {Date} și {Time}, care returnează data și ora într-un format ușor de înțeles pentru utilizator.

  • După aceasta, putem obține în JavaScript data curentă în format Unix Timestamp și putem scădea aceasta din valoarea obținută a datei de expirare a certificatului pentru a calcula numărul de milisecunde de la momentul curent până la expirarea certificatului.

`now = Date.now();`

  • Împărțim valoarea obținută la o mie pentru a obține secunde în Zabbix.

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

În declanșator se poate specifica expresia ‘last<‘ și un set de cifre care corespunde numărului de secunde în perioada la care se dorește reacția, de exemplu, în săptămâni. Astfel, declanșatorul va avertiza că termenul de valabilitate a certificatului expiră în săptămâna următoare.

NOTĂ. Atenție la utilizarea parseInt() în funcția return, pentru a converti un număr zecimal obținut în urma împărțirii milisecundelor la un număr întreg. De asemenea, se pot utiliza parseFloat() și se pot păstra datele fracționate..

Vizionați prezentarea

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster