Vi löser praktiska problem i Zabbix med hjälp av JavaScript

Vi löser praktiska problem i Zabbix med hjälp av JavaScript
Tikhon Uskov, Zabbix integrationsteamingenjör

Zabbix är en anpassningsbar plattform som används för att övervaka alla typer av data. Sedan de tidigaste versionerna av Zabbix har övervakningsadministratörer haft möjlighet att köra olika skript via Handlingar för kontroller av målnätverksnoder. Samtidigt ledde lanseringen av skript till ett antal svårigheter, inklusive behovet av att stödja skript, deras leverans till kommunikationsnoder och proxyservrar, samt stöd för olika versioner.

JavaScript för Zabbix

I april 2019 introducerades Zabbix 4.2 med JavaScript-förbearbetning. Många människor blev entusiastiska över idén att överge att skriva skript som tar data någonstans, smälta den och tillhandahålla den i ett format som Zabbix förstår, och utföra enkla kontroller som kommer att ta emot data som inte är redo för lagring och bearbetning av Zabbix, och bearbeta sedan denna dataström med Zabbix- och JavaScript-verktyg. I samband med upptäckt på låg nivå och beroende objekt som dök upp i Zabbix 3.4 fick vi ett ganska flexibelt koncept för att sortera och hantera mottagen data.

I Zabbix 4.4, som en logisk fortsättning på förbearbetning i JavaScript, har en ny aviseringsmetod dykt upp - Webhook, som kan användas för att enkelt integrera Zabbix-aviseringar med tredjepartsapplikationer.

JavaScript och Duktapes

Varför valdes JavaScript och Duktape? Olika alternativ för språk och motorer övervägdes:

  • Lua - Lua 5.1
  • Lua - LuaJIT
  • Javascript - Duktape
  • Javascript - JerryScript
  • Inbäddad Python
  • Inbäddad Perl

De huvudsakliga urvalskriterierna var prevalens, enkel integrering av motorn i produkten, låg resursförbrukning och övergripande prestanda hos motorn, och säkerheten med att införa kod på detta språk i övervakningen. Baserat på kombinationen av indikatorer vann JavaScript på Duktape-motorn.

Vi löser praktiska problem i Zabbix med hjälp av JavaScript

Urvalskriterier och prestationstestning

Funktioner hos Duktape:

— Standard ECMAScript E5/E5.1
— Zabbix-moduler för Duktape:

  • Zabbix.log() - låter dig skriva meddelanden med olika detaljnivåer direkt in i Zabbix Server-loggen, vilket gör det möjligt att korrelera fel, till exempel i en Webhook, med serverns tillstånd.
  • CurlHttpRequest() - låter dig göra HTTP-förfrågningar till nätverket, på vilket användningen av Webhook är baserad.
  • atob() och btoa() - låter dig koda och avkoda strängar i Base64-format.

NOTERA. Duktape följer ACME-standarder. Zabbix använder 2015 års version av skriptet. Efterföljande ändringar är mindre, så de kan ignoreras..

JavaScript-magi

All magin med JavaScript ligger i dynamisk typning och typcasting: sträng, numerisk och boolesk.

Det betyder att det inte är nödvändigt att i förväg deklarera vilken typ av variabeln som ska returnera ett värde.

I matematiska operationer omvandlas värdena som returneras av funktionsoperatorer till siffror. Undantaget från sådana operationer är tillägg, eftersom om minst en av termerna är en sträng, tillämpas strängkonvertering på alla termer.

NOTERA. De metoder som är ansvariga för sådana transformationer implementeras vanligtvis i objektets överordnade prototyper, värdet av и att stränga. värdet av anropas under numerisk konvertering och alltid före metoden att stränga. Metod värdet av måste returnera primitiva värden, annars ignoreras dess resultat.

En metod anropas på ett objekt värdet av. Om den inte hittas eller inte returnerar ett primitivt värde, anropas metoden att stränga. Om metoden att stränga hittas inte, söker värdet av i prototypen av objektet, och allt upprepas tills bearbetningen av värdet är klar och alla värden i uttrycket gjuts till samma typ. Om objektet implementerar en metod att stränga, som returnerar ett primitivt värde, då är det det som används för strängkonvertering. Resultatet av att tillämpa denna metod är dock inte nödvändigtvis en sträng.

Till exempel, om för för objekt 'obj' metod definieras att stränga,

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

метод att stränga returnerar exakt en sträng, och när vi lägger till en sträng med ett nummer får vi en limmad sträng:

`obj + 1 // '2001'` 

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

Men om du skriver om att stränga, så att metoden returnerar ett tal, när objektet läggs till kommer en matematisk operation med en numerisk omvandling att utföras och resultatet av matematisk addition erhålls.

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

`obj + 1 // '2001'`

I det här fallet, om vi utför addition med en sträng, utförs en strängkonvertering, och vi får en limmad sträng.

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

Detta är anledningen till ett stort antal misstag av nybörjare JavaScript-användare.

Metoden att stränga du kan skriva en funktion som ökar objektets nuvarande värde med 1.

Vi löser praktiska problem i Zabbix med hjälp av JavaScript
Utförande av skriptet, förutsatt att variabeln är lika med 3, och den är också lika med 4.

Jämfört med en cast (==), exekveras metoden varje gång att stränga med värdeökningsfunktion. Följaktligen, med varje efterföljande jämförelse, ökar värdet. Detta kan undvikas genom att använda icke-cast jämförelse (===).

Vi löser praktiska problem i Zabbix med hjälp av JavaScript
Jämförelse utan typgjutning

NOTERA. Använd inte Cast Comparison i onödan.

För komplexa skript, som Webhooks med komplex logik, som kräver jämförelse med typcasting, rekommenderas det att förskriva kontroller för de värden som returnerar variabler och hanterar inkonsekvenser och fel.

Webhook Media

I slutet av 2019 och början av 2020 har Zabbix-integreringsteamet aktivt utvecklat Webhooks och färdiga integrationer som följer med Zabbix-distributionen.

Vi löser praktiska problem i Zabbix med hjälp av JavaScript
Länk till dokumentation

förbehandling

  • Tillkomsten av förbearbetning i JavaScript gjorde det möjligt att överge de flesta externa skript, och för närvarande i Zabbix kan du få vilket värde som helst och konvertera det till ett helt annat värde.
  • Förbearbetning i Zabbix implementeras av JavaScript-kod, som, när den kompileras till bytekod, omvandlas till en funktion som tar ett enda värde som en parameter värde som en sträng (en sträng kan innehålla både en siffra och ett tal).
  • Eftersom utdata är en funktion krävs i slutet av skriptet avkastning.
  • Det är möjligt att använda anpassade makron i koden.
  • Resurser kan begränsas inte bara på operativsystemnivå, utan också programmässigt. Förbehandlingssteget tilldelas maximalt 10 megabyte RAM och en körtidsgräns på 10 sekunder.

Vi löser praktiska problem i Zabbix med hjälp av JavaScript

NOTERA. Timeoutvärdet på 10 sekunder är ganska mycket, eftersom insamling av villkorliga tusentals dataobjekt på 1 sekund enligt ett ganska "tungt" förbearbetningsscenario kan sakta ner Zabbix. Därför rekommenderas det inte att använda förbearbetning för att exekvera fullfjädrade JavaScript-skript genom de så kallade skuggdataelementen (dummy-objekt), som endast körs för att utföra förbearbetning.

Du kan kontrollera din kod genom förbearbetningstestet 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 beräknad artikel med förbearbetning.

Skick: Hämta temperaturen i Fahrenheit från sensorn för att lagra i Celsius.

Tidigare skulle vi skapa ett föremål som samlar temperaturen i grader Fahrenheit. Efter det, en annan datapost (beräknad) som skulle konvertera Fahrenheit till Celsius med hjälp av en formel.

Problem:

  • Det är nödvändigt att duplicera dataelement och lagra alla värden i databasen.
  • Du måste komma överens om intervallen för den "överordnade" dataposten som beräknas och används i formeln, och för den beräknade dataposten. Annars kan det beräknade objektet gå in i ett tillstånd som inte stöds eller beräkna ett tidigare värde, vilket kommer att påverka övervakningsresultatens tillförlitlighet.

En lösning var att gå bort från flexibla kontrollintervall till förmån för fasta intervall för att säkerställa att det beräknade objektet utvärderas efter objektet som tar emot data (i vårt fall temperaturen i grader Fahrenheit).

Men om vi till exempel använder mallen för att kontrollera ett stort antal enheter, och kontrollen utförs en gång var 30:e sekund, "hacker" Zabbix i 29 sekunder, och i sista sekund börjar den kontrollera och beräkna. Detta skapar en kö och påverkar prestandan. Därför rekommenderas det att endast använda fasta intervaller om det verkligen är nödvändigt.

I det här problemet är den optimala lösningen en enrads JavaScript-förbearbetning som konverterar grader Fahrenheit till grader Celsius:

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

Det är snabbt och enkelt, du behöver inte skapa onödiga dataobjekt och ha en historik över dem, och du kan även använda flexibla intervall för kontroller.

Vi löser praktiska problem i Zabbix med hjälp av JavaScript

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

Men om det i en hypotetisk situation är nödvändigt att lägga till det mottagna dataelementet, till exempel med någon konstant definierad i makrot, måste det tas hänsyn till att parametern värde expanderar till en sträng. I en strängadditionsoperation kombineras två strängar helt enkelt till en.

Vi löser praktiska problem i Zabbix med hjälp av JavaScript

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

För att få resultatet av en matematisk operation är det nödvändigt att konvertera typerna av de erhållna värdena till ett numeriskt format. För detta kan du använda funktionen parseInt(), som producerar ett heltal, en funktion parseFloat(), som ger en decimal eller en funktion antal, som returnerar ett heltal eller decimal.

Uppgift 2

Få tiden i sekunder till slutet av certifikatet.

Skick: en tjänst utfärdar ett certifikats utgångsdatum i formatet "12 feb 12:33:56 2022 GMT".

I ECMAScript5 Date.parse () accepterar ett datum i ISO 8601-format (ÅÅÅÅ-MM-DDTHH:mm:ss.sssZ). Det är nödvändigt att casta en sträng till den i formatet MMM DD ÅÅÅÅ HH:mm:ss ZZ

problem: Månadsvärdet uttrycks som text, inte som ett tal. Data i detta format accepteras inte av Duktape.

Lösningsexempel:

  • Först och främst deklareras en variabel som tar ett värde (hela skriptet är en deklaration av variabler som är listade separerade med kommatecken).

  • På första raden får vi datumet i parametern värde och separera det med mellanslag med hjälp av metoden delas. Således får vi en array, där varje element i arrayen, med början vid index 0, motsvarar ett datumelement före och efter ett mellanslag. split(0) - månad, split(1) - siffra, split(2) - en sträng med tid, etc. Därefter kan varje element i datumet nås med index i arrayen.

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

  • Varje månad (i kronologisk ordning) motsvarar indexet för dess position i arrayen (från 0 till 11). För att konvertera ett textvärde till ett numeriskt värde, läggs ett till månadsindexet (eftersom månaderna är numrerade med början på 1). I det här fallet tas uttrycket med tillägg av en inom parentes, eftersom annars en sträng erhålls, inte ett nummer. På slutet gör vi det skiva() - Klipp ut arrayen från slutet för att bara lämna två tecken (vilket är viktigt för månader med ett tvåsiffrigt 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 bildar en sträng i ISO-format från de erhållna värdena genom det vanliga tillägget av strängar i lämplig ordning.

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

Data i det resulterande formatet är antalet sekunder från 1970 till någon tidpunkt i framtiden. Det är nästan omöjligt att använda data i det mottagna formatet i triggers, eftersom Zabbix låter dig arbeta endast med makron {Datum} и {Tid}, som returnerar datum och tid i ett användarvänligt format.

  • Vi kan sedan få det aktuella datumet i JavaScript i Unix Timestamp-format och subtrahera det från det resulterande certifikatets utgångsdatum för att få antalet millisekunder från nu tills certifikatet löper ut.

`now = Date.now();`

  • Vi delar det mottagna värdet med tusen för att få sekunder i Zabbix.

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

I utlösaren kan du ange uttrycket 'sista' följt av en uppsättning siffror som motsvarar antalet sekunder i perioden som du vill svara på, till exempel i veckor. Således kommer utlösaren att meddela att certifikatet löper ut om en vecka.

NOTERA. Var uppmärksam på användningen parseInt() i funktion avkastningför att konvertera bråktalet som blir resultatet av division av millisekunder till ett heltal. Du kan också använda parseFloat() och lagra fraktionerad data.

Se rapporten

Källa: will.com

Lägg en kommentar