
Tikhon Uskov, ingenjör för integrationsgruppen Zabbix
Zabbix Àr en anpassningsbar plattform som anvÀnds för att övervaka alla typer av data. FrÄn de tidigaste versionerna av Zabbix hade övervakningsadministratörer möjlighet att köra olika skript genom à tgÀrder för kontroller pÄ nÀtverkets mÄlknutpunkter. Att köra skript medförde dock en rad svÄrigheter, inklusive behovet av att stödja skript, leverera dem till anslutningspunkter och proxyer samt stödja olika versioner.
JavaScript för Zabbix
I april 2019 presenterades Zabbix 4.2 med funktionen för förbearbetning i JavaScript. MÄnga blev inspirerade av tanken att överge skrivandet av skript som hÀmtar data, bearbetar dem och presenterar dem i ett format som Zabbix förstÄr, och i stÀllet utföra enkla kontroller som fÄr oförberedd data för lagring och bearbetning i Zabbix, för att sedan bearbeta denna datastream med hjÀlp av Zabbix och JavaScript. Tillsammans med lÄg-nivÄ upptÀckter och beroende datakomponenter som introducerades i Zabbix 3.4, skapades ett tillrÀckligt flexibelt koncept för sortering och hantering av erhÄllen data.
I Zabbix 4.4, som en logisk fortsĂ€ttning pĂ„ förbearbetning i JavaScript, introducerades ett nytt varningssĂ€tt â Webhook, som kan anvĂ€ndas för enkel integration av Zabbix-varningar med tredjepartsapplikationer.
JavaScript och Duktape
Varför valdes just JavaScript och Duktape? Olika alternativ för sprÄk och motorer övervÀgdes:
- Lua â Lua 5.1
- Lua â LuaJIT
- JavaScript â Duktape
- JavaScript â JerryScript
- Embedded Python
- Embedded Perl
De huvudsakliga urvalskriterierna var spridning, enkelhet av motorens integration i produkten, lÄg resursförbrukning och den allmÀnna prestandan hos motorn, samt sÀkerheten av att integrera kod pÄ detta sprÄk i övervakningen. Baserat pÄ dessa kriterier vann JavaScript med Duktape-motorn.

Urvalskriterier och prestandatestning
Egenskaper hos Duktape:
â Standard
â Zabbix-moduler för Duktape:
- Zabbix.log() â gör att meddelanden med olika detaljeringsnivĂ„er kan skrivas direkt i Zabbix Server-loggen, vilket möjliggör jĂ€mförelse av fel, till exempel i Webhook, med serverstatus.
- CurlHttpRequest() â möjliggör HTTP-begĂ€rningar till nĂ€tverket, vilket utgör grunden för anvĂ€ndning av Webhook.
- atob() och btoa() â möjliggör kodning och avkodning av strĂ€ngar i Base64-format.
OBS. Duktape uppfyller ACME-standarder. I Zabbix anvÀnds skriptversionen frÄn 2015. Efterföljande Àndringar Àr obetydliga och kan dÀrför ignoreras..
Magin med JavaScript
All magi i JavaScript ligger i den dynamiska typningen och typkonverteringarna: strÀngar, nummer och logiska vÀrden.
Detta innebÀr att man inte behöver deklarera pÄ förhand vilken typ av variabel som ska returnera ett vÀrde.
Vid matematiska operationer konverteras vÀrden som returneras av operator-funktioner till siffror. Undantaget frÄn sÄdana operationer Àr addition, eftersom om minst en av summorna Àr en strÀng, tillÀmpas strÀngkonvertering pÄ alla summor.
OBS. Metoder som ansvarar för sÄdana konverteringar implementeras vanligtvis i förÀlderprototyper av objekt, valueOf och toString. valueOf anropas vid numerisk konvertering och kommer alltid före metoden toString. Metoden valueOf mÄste returnera primitiva vÀrden, annars ignoreras dess resultat.
För ett objekt anropas metoden valueOF. Om den inte hittas eller inte returnerar ett primitivt vĂ€rde, anropas metoden toString. Om metoden toString inte hittas, letas det i objektets prototyp, och allt upprepas tills vĂ€rdet har behandlats och alla vĂ€rden i uttrycket har konverterats till samma typ. valueOf Om ett objekt har en metod. , som returnerar ett primitivt vĂ€rde, anvĂ€nds den för strĂ€ngkonvertering. toStringResultatet av att anvĂ€nda denna metod behöver dock inte nödvĂ€ndigtvis vara en strĂ€ng. Till exempel, om ett objekt â
â definierar metodenobj`var obj = { toString() { return "200" }}` toString,
returnerar just en strÀng, och vid addition av strÀngen med ett nummer fÄr vi en sammansatt strÀng: metod toString `obj + 1 // '2001'``obj + 'a' // '200a'`
Men om vi skriver om, sÄ att metoden returnerar ett nummer, kommer additionen av objektet att utföra en matematisk operation med numerisk konvertering och resultatet blir resultatet av matematisk addition. toString`var obj = { toString() { return 200 }}``obj + 1 // '2001'`
Om vi dessutom utför addition med en strÀng, görs strÀngkonvertering, och vi fÄr en sammansatt strÀng.`obj + 'a' // '200a'`
Detta Àr anledningen till att nybörjare ofta fÄr mÄnga fel i JavaScript.Man kan skriva en funktion som ökar det aktuella vÀrdet i objektet med 1.
I metoden toString Körning av skriptet under förutsÀttning att variabeln Àr lika med 3, och den Àr ocksÄ lika med 4.

Kör skriptet under förutsÀttning att variabeln Àr lika med 3 och den ocksÄ Àr lika med 4.
Vid jÀmförelse med typkonvertering (==) anropas metoden varje gÄng toString med vÀrdeökande funktion. DÀrför ökar vÀrdet vid varje efterföljande jÀmförelse. Detta kan undvikas genom att anvÀnda jÀmförelse utan typkonvertering (===).

JÀmförelse utan typkonvertering
OBS. AnvÀnd inte typkonvertering vid jÀmförelse utan behov.
För komplexa skript, till exempel Webhook med komplex logik, dÀr jÀmförelse med typkonvertering Àr nödvÀndig, rekommenderas det att först skriva kontroller för vÀrdena som returneras av variabler och hantera avvikelser och fel.
Webhook Media
I slutet av 2019 och början av 2020 arbetade Zabbix integreringsteam aktivt med utveckling av Webhooks och

LĂ€nk till
Förbehandling
- FramvÀxten av förbehandling pÄ JavaScript har möjliggjort avskaffandet av de flesta externa skript, och just nu kan man i Zabbix fÄ vilket vÀrde som helst och omvandla det till ett annat vÀrde.
- Förbehandling i Zabbix implementeras med kod pÄ JavaScript, som vid kompilering till bytekod omvandlas till en funktion som tar ett enda vÀrde som parameter value i form av en strÀng (den kan innehÄlla bÄde siffror och tecken).
- Eftersom utdata Àr en funktion, Àr det obligatoriskt i slutet av skriptet ÄtervÀnda.
- AnvÀndning av anvÀndardefinierade makron i koden Àr möjlig.
- Resurser kan begrÀnsas inte bara pÄ operativsystemsnivÄ utan ocksÄ programmÀssigt. För steget förbehandling tilldelas maximalt 10 megabyte RAM och en exekveringstid pÄ 10 sekunder.

OBS. Timeout-vÀrdena pÄ 10 sekunder Àr ganska mycket, eftersom insamling av tusentals datainmatningar per sekund enligt ett ganska "tungt" förbehandlingssÀtt kan bromsa Zabbix. DÀrför rekommenderas det inte att anvÀnda förbehandling för att köra fullfjÀdrade skript pÄ JavaScript via sÄ kallade dummy-dataelement, som endast körs för att utföra förbehandling..
Du kan kontrollera din kod genom förbehandlingsrelaterad test eller med hjÀlp av verktyget 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`
Praktiska uppgifter
Uppgift 1
ErsÀtt den berÀknade datan med en förbehandling.
Villkor: vi fÄr temperaturen frÄn sensorn i Fahrenheit för att lagra den i Celsius.
Tidigare skulle vi ha skapat en datakomponent som samlar in temperaturen i Fahrenheit. Efter det â en annan datakomponent (berĂ€knad) som med en formel omvandlar grader Fahrenheit till grader Celsius.
Problem:
- Det Àr nödvÀndigt att duplicera datakomponenter och lagra alla vÀrden i databasen.
- Det Àr nödvÀndigt att samordna intervallen för den 'parent'-datakomponenten, som berÀknas och anvÀnds i formeln, med den berÀknade datakomponenten. Annars kan den berÀknade datakomponenten gÄ in i ett otillÄtet tillstÄnd eller rÀkna det föregÄende vÀrdet, vilket pÄverkar tillförlitligheten i övervakningsresultaten.
En av lösningarna var att överge flexibla kontrollintervall till förmĂ„n för fasta intervall, för att sĂ€kerstĂ€lla att den berĂ€knade datakomponenten berĂ€knas efter datakomponenten som fĂ„r data (i vĂ„rt fall â temperaturen i Fahrenheit).
Men om, till exempel, mallen vi anvÀnder för att kontrollera ett stort antal enheter, och kontrollen genomförs vart 30:e sekund, sÄ 'slappar' Zabbix i 29 sekunder, och börjar kontroller och berÀkningar under den sista sekunden. Detta leder till skapandet av en kö och pÄverkar prestandan. DÀrför rekommenderas fasta intervall endast om det verkligen Àr nödvÀndigt.
För denna uppgift Àr den optimala lösningen en förbehandling pÄ en rad i JavaScript som omvandlar grader Fahrenheit till grader Celsius:
`return (value - 32) * 5 / 9;`Det Àr snabbt och enkelt, det krÀvs inte att skapa onödiga datakomponenter och lagra historik för dem, och det kan ocksÄ anvÀndas för flexibla kontrollintervall.

`return (parseInt(value) + parseInt("{$EXAMPLE.MACRO}"));`Men om, i en hypotetisk situation, det Àr nödvÀndigt att summera den erhÄllna datakomponenten med, till exempel, en konstant definierad i makrot, mÄste vi ta hÀnsyn till att parametern value avtÀckes i en strÀng. Vid addition av strÀngar sammanfogas de helt enkelt till en strÀng.

`return (value + "{$EXAMPLE.MACRO}");`För att fÄ resultaten av en matematisk operation mÄste vÀrdenas typer konverteras till numeriskt format. För detta kan du anvÀnda funktionen parseInt(), som ger ett heltal, funktionen parseFloat(), som ger ett decimaltal, eller funktionen number, som ger antingen ett heltal eller ett decimaltal.
Uppgift 2
FÄ tiden i sekunder till certifikatets utgÄng.
Villkor: en viss tjÀnst ger certifikatets utgÄngsdatum i formatet "Feb 12 12:33:56 2022 GMT".
I ECMAScript5 Date.parse() tar emot datum i ISO 8601-format (YYYY-MM-DDTHH:mm:ss.sssZ). Det Àr nödvÀndigt att konvertera strÀngen till formatet MMM DD YYYY HH:mm:ss ZZ
Problemet: mÄnadens vÀrde uttrycks i textform och inte som ett nummer. Data i detta format godtas inte av Duktape.
Exempel pÄ lösning:
Först deklareras en variabel som fÄr ett vÀrde (hela skriptet bestÄr av deklarationer av variabler som anges med kommatecken).
I den första raden fĂ„r vi datumet i parametern value och delar den med mellanslag med metoden split. SĂ„ledes fĂ„r vi en array dĂ€r varje element, med början frĂ„n index 0, motsvarar ett datumselement före och efter mellanslaget. split(0) â mĂ„nad, split(1) â dag, split(2) â tidsstrĂ€ng osv. Efter detta kan varje datumselement nĂ„s via index i arrayen.
`var split = value.split(' '),`- Varje mĂ„nad (i kronologisk ordning) motsvarar index för dess position i arrayen (frĂ„n 0 till 11). För att konvertera textvĂ€rdet till ett numeriskt lĂ€ggs ett till mĂ„nadens index (eftersom mĂ„nadnumreringen börjar frĂ„n 1). Detta uttryck med tillĂ€gg av ett görs i parentes, eftersom det annars skulle ge en strĂ€ng istĂ€llet för ett nummer. I slutet utför vi slice() â en skĂ€rning av arrayen frĂ„n slutet för att behĂ„lla endast tvĂ„ tecken (vilket Ă€r viktigt för mĂ„nader med tvĂ„siffriga nummer).
`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),`- Vi formar en strÀng i ISO-format frÄn de erhÄllna vÀrdena genom att helt enkelt addera strÀngar i rÀtt ordning.
`ISOdate = split[3] + '-' + month_index + '-' + split[1] + 'T' + split[2],`Data i det erhÄllna formatet representerar antalet sekunder sedan 1970 till en viss tidpunkt i framtiden. Att anvÀnda data i det formatet i triggers Àr praktiskt taget omöjligt, eftersom Zabbix endast tillÄter att arbeta med makron {Date} och {Time}, som returnerar datum och tid i ett anvÀndarvÀnligt format.
- Efter detta kan vi fÄ det aktuella datumet i JavaScript i Unix Timestamp-format och subtrahera det frÄn det erhÄllna certifikatets slutdatum för att fÄ antal millisekunder frÄn nuvarande ögonblick till certifikatets utgÄngstid.
`now = Date.now();`- Vi delar det erhÄllna vÀrdet med tusen för att fÄ sekunder i Zabbix.
`return parseInt((Date.parse(ISOdate) - now) / 1000);`I triggern kan man ange uttrycket âlast<â och en uppsĂ€ttning siffror som motsvarar antalet sekunder i den period som ska reageras pĂ„, till exempel i veckor. PĂ„ sĂ„ sĂ€tt kommer triggern att meddela att certifikatets giltighetstid löper ut om en vecka.
OBS. Observera anvÀndningen av parseInt() i funktionen ÄtervÀnda, för att konvertera det decimala talet som erhÄllits som resultat av division med millisekunder till ett heltal. Det gÄr ocksÄ att anvÀnda parseFloat() och lagra decimala data.
KĂ€lla: habr.com
