Affrontiamo problemi pratici in Zabbix utilizzando JavaScript

Affrontiamo problemi pratici in Zabbix utilizzando JavaScript
Tikhon Uskov, ingegnere del team di integrazione Zabbix

Zabbix è una piattaforma personalizzabile utilizzata per monitorare qualsiasi tipo di dato. Sin dalle prime versioni, gli amministratori di monitoraggio hanno avuto la possibilità di eseguire vari script tramite Azioni per controlli su nodi target della rete. Tuttavia, l'esecuzione degli script ha comportato diverse difficoltà, come la necessità di supportare gli script, la loro distribuzione sui nodi di rete e proxy, e la compatibilità con diverse versioni.

JavaScript per Zabbix

Ad aprile 2019 è stata lanciata la versione 4.2 di Zabbix con funzionalità di preelaborazione in JavaScript. Molti si sono appassionati all'idea di abbandonare la scrittura di script che estraevano dati da vari luoghi, li elaboravano e li presentavano in un formato comprensibile per Zabbix. Al contrario, è possibile eseguire controlli semplici per raccogliere dati non pronti per la memorizzazione e l'elaborazione da Zabbix, per poi gestire questo flusso di dati utilizzando le capacità di Zabbix e JavaScript. Insieme al rilevamento a basso livello e agli elementi di dati dipendenti introdotti in Zabbix 3.4, è emersa una concezione sufficientemente flessibile per la classificazione e la gestione dei dati ricevuti.

In Zabbix 4.4, come evoluzione logica della preelaborazione in JavaScript, è stato introdotto un nuovo metodo di notifica: il Webhook, utilizzabile per una semplice integrazione delle notifiche di Zabbix con applicazioni di terze parti.

JavaScript e Duktape

Perché sono stati scelti JavaScript e Duktape? Sono stati considerati diversi linguaggi e motori:

  • Lua – Lua 5.1
  • Lua – LuaJIT
  • JavaScript – Duktape
  • JavaScript – JerryScript
  • Python incorporato
  • Perl incorporato

I criteri principali di scelta erano la diffusione, la facilità di integrazione del motore nel prodotto, il basso consumo di risorse, le prestazioni generali del motore e la sicurezza nell'inserimento del codice in questo linguaggio nel monitoraggio. In base a questi indicatori, ha prevalso JavaScript con il motore Duktape.

Affrontiamo problemi pratici in Zabbix utilizzando JavaScript

Criteri di selezione e performance testing

Caratteristiche di Duktape:

— Standard ECMAScript E5/E5.1
— Moduli Zabbix per Duktape:

  • Zabbix.log() — consente di scrivere direttamente nel log del Zabbix Server messaggi con diversi livelli di dettaglio, permettendo di correlare gli errori, ad esempio, nel Webhook con lo stato del server.
  • CurlHttpRequest() — permette di effettuare richieste HTTP alla rete, su cui si basa l'utilizzo del Webhook.
  • atob() e btoa() — consentono di codificare e decodificare stringhe nel formato Base64.

NOTA. Duktape è conforme agli standard ACME. In Zabbix viene utilizzata la versione dello script del 2015. Le modifiche successive sono lievi, quindi possono essere ignorate..

La magia di JavaScript

Tutta la magia di JavaScript risiede nella tipizzazione dinamica e nella conversione dei tipi: stringhe, numeri e logici.

Ciò significa che non è necessario dichiarare in anticipo di che tipo deve essere la variabile per restituire un valore.

Nelle operazioni matematiche, i valori restituiti dai funzionali degli operatori vengono convertiti in numeri. L'eccezione a queste operazioni è l'addizione, poiché se almeno uno degli addendi è una stringa, viene applicata la conversione in stringa a tutti gli addendi.

NOTA. I metodi responsabili di tali conversioni sono generalmente implementati nei prototipi genitori degli oggetti. valueOf e toString. valueOf viene invocato durante la conversione numerica e viene sempre eseguito prima del metodo toString. Il metodo valueOf deve restituire valori primitivi, altrimenti il suo risultato viene ignorato.

Per l'oggetto viene invocato il metodo valueOF. Se non viene trovato o non restituisce un valore primitivo, viene invocato il metodo toString. Se il metodo toString non viene trovato, viene effettuata una ricerca valueOf nel prototipo dell'oggetto, e tutto si ripete fino a quando non viene completato il trattamento del valore e la conversione di tutti i valori nell'espressione a un unico tipo. Se per l'oggetto è implementato un metodo toString, che restituisce un valore primitivo, questo viene utilizzato per la conversione in stringa. In questo caso, il risultato dell'applicazione di questo metodo non è necessariamente una stringa.

Ad esempio, se per l'oggetto ‘obj‘ è definito un metodo toString,

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

metodo toString restituisce una stringa, e quando sommiamo una stringa con un numero otteniamo una stringa concatenata:

`obj + 1 // '2001'` 

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

Ma se riscriviamo toString, in modo che il metodo restituisca un numero, quando sommiamo l'oggetto verrà eseguita un'operazione matematica con la conversione in numero, ottenendo così il risultato di una somma matematica.

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

`obj + 1 // '2001'`

In questo caso, se eseguiamo la somma con una stringa, verrà effettuata una conversione in stringa e otterremo una stringa concatenata.

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

È proprio questa la causa di un gran numero di errori da parte dei principianti in JavaScript.

Nel metodo toString può essere scritta una funzione che incrementa l'attuale valore dell'oggetto di 1.

Affrontiamo problemi pratici in Zabbix utilizzando JavaScript
Esecuzione dello script a condizione che la variabile sia uguale a 3, e sia uguale anche a 4.

Quando si confronta con la conversione dei tipi (==) viene eseguito ogni volta il metodo toString con la funzione che incrementa il valore. Pertanto, ad ogni confronto successivo il valore aumenta. Questo può essere evitato usando un confronto senza conversione dei tipi (===).

Affrontiamo problemi pratici in Zabbix utilizzando JavaScript
Confronto senza conversione dei tipi

NOTA. Non utilizzare il confronto con la conversione dei tipi senza necessità.

Per script complessi, come i Webhook con logiche intricate, in cui è necessario il confronto con la conversione dei tipi, si consiglia di scrivere in anticipo controlli per i valori restituiti dalle variabili e gestire le discrepanze e gli errori.

Webhook Media

Alla fine del 2019 e all'inizio del 2020, il team di integrazione di Zabbix ha lavorato attivamente allo sviluppo di Webhook e integrazioni 'pronte all'uso', che sono inclusi nella distribuzione di Zabbix.

Affrontiamo problemi pratici in Zabbix utilizzando JavaScript
Link a documentazione

Preprocessing

  • L'introduzione della preelaborazione in JavaScript ha permesso di eliminare la maggior parte degli script esterni, e attualmente in Zabbix è possibile ottenere qualsiasi valore e trasformarlo in un altro valore completamente diverso.
  • La preelaborazione in Zabbix è realizzata con codice JavaScript, che, durante la compilazione in bytecode, viene trasformato in una funzione che accetta un singolo valore come parametro value come stringa (nella stringa può essere presente sia un numero che una cifra).
  • Poiché il risultato finale è una funzione, alla fine dello script è obbligatorio return.
  • È possibile utilizzare macro personalizzate nel codice.
  • Le risorse possono essere limitate non solo a livello di sistema operativo, ma anche programmaticamente. Per il passo di preelaborazione, viene riservato un massimo di 10 megabyte di memoria RAM e un limite di tempo di esecuzione di 10 secondi.

Affrontiamo problemi pratici in Zabbix utilizzando JavaScript

NOTA. Valori di timeout di 10 secondi sono piuttosto elevati, perché raccogliere migliaia di elementi di dati in 1 secondo in uno scenario di preelaborazione piuttosto "pesante" può rallentare Zabbix. Pertanto, non è consigliabile utilizzare la preelaborazione per eseguire script completi in JavaScript attraverso quelli che vengono chiamati elementi di dati dummy, che vengono eseguiti solo per completare la preelaborazione..

Puoi verificare il tuo codice attraverso il test di preelaborazione o utilizzando l'utilità 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`

Compiti pratici

Compito 1

Sostituire l'elemento di dati calcolato con la preelaborazione.

Condizione: otteniamo dal sensore la temperatura in gradi Fahrenheit da memorizzare in gradi Celsius.

In passato avremmo creato un elemento dati per raccogliere la temperatura in gradi Fahrenheit. Successivamente, un altro elemento dati (calcolato) avrebbe trasformato i gradi Fahrenheit in gradi Celsius attraverso una formula.

Problemi:

  • È necessario duplicare gli elementi dati e memorizzare tutti i valori nel database.
  • È fondamentale concordare gli intervalli per l'elemento dati "genitore", che viene calcolato e utilizzato nella formula, e per l'elemento dati calcolato. In caso contrario, l'elemento dati calcolato potrebbe entrare in uno stato non supportato o calcolare il valore precedente, compromettendo l'affidabilità dei risultati di monitoraggio.

Una delle soluzioni è stata rinunciare agli intervalli di controllo flessibili a favore di intervalli fissi, per garantire che l'elemento dati calcolato venga sempre calcolato dopo l'elemento dati che riceve i dati (in questo caso, la temperatura in gradi Fahrenheit).

Tuttavia, se ad esempio il modello viene utilizzato per controllare un gran numero di dispositivi, e il controllo viene eseguito ogni 30 secondi, per 29 secondi Zabbix "deriva" e all'ultimo secondo inizia i controlli e i calcoli. Questo porta alla creazione di una coda e influisce sulle prestazioni. Pertanto, si raccomanda di utilizzare intervalli fissi solo se è realmente necessario.

In questo problema, la soluzione ottimale è una pre-elaborazione in una riga in JavaScript, che converte i gradi Fahrenheit in gradi Celsius:

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

È veloce e semplice, non è necessario creare elementi di dati aggiuntivi e conservarne la cronologia, inoltre può essere utilizzato per verifiche a intervalli flessibili.

Affrontiamo problemi pratici in Zabbix utilizzando JavaScript

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

Tuttavia, se in una situazione ipotetica è necessario sommare l'elemento di dati ottenuto, ad esempio con una costante definita nel macro, è importante considerare che il parametro value viene espanso in una stringa. Durante l'operazione di somma di stringhe, le due stringhe vengono semplicemente concatenate in una sola.

Affrontiamo problemi pratici in Zabbix utilizzando JavaScript

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

Per ottenere il risultato di un'operazione matematica, è necessario convertire i tipi di valori ottenuti in formato numerico. A tal fine, è possibile utilizzare la funzione parseInt(), che restituisce un numero intero, la funzione parseFloat(), che restituisce un numero decimale, oppure la funzione number, che restituisce un numero intero o decimale.

Compito 2

Ottenere il tempo in secondi fino alla scadenza del certificato.

Condizione: un certo servizio restituisce la data di scadenza del certificato nel formato "Feb 12 12:33:56 2022 GMT".

In ECMAScript5 Date.parse() accetta date nel formato ISO 8601 (YYYY-MM-DDTHH:mm:ss.sssZ). È necessario convertire la stringa nel formato MMM DD YYYY HH:mm:ss ZZ

Problema: il valore del mese è espresso in testo, anziché in numero. I dati in questo formato non sono accettati da Duktape.

Esempio di soluzione:

  • Prima di tutto, viene dichiarata una variabile che riceve un valore (l'intero script consiste in dichiarazioni di variabili, elencate tramite virgole).

  • Nella prima riga otteniamo la data nel parametro value e la separiamo con spazi usando il metodo split. In questo modo, otteniamo un array, in cui ogni elemento dell'array, a partire dall'indice 0, corrisponde a un elemento della data prima e dopo lo spazio. split(0) — mese, split(1) — giorno, split(2) — una stringa con l'orario e così via. Dopo, ogni elemento della data può essere accessibile tramite l'indice nell'array.

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

  • A ciascun mese (in ordine cronologico) corrisponde un indice della sua posizione nell'array (da 0 a 11). Per convertire il valore testuale in numerico, si aggiunge uno all'indice del mese (poiché la numerazione dei mesi inizia da 1). L'espressione con l'aggiunta di uno è racchiusa tra parentesi, perché altrimenti si otterrebbe una stringa, non un numero. Alla fine eseguiamo slice() — un taglio dell'array dalla fine, per mantenere solo due caratteri (importante per i mesi con numero a due 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),`

  • Formiamo una stringa dal formato ISO dai valori ottenuti, semplicemente sommando le stringhe nell'ordine corrispondente.

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

I dati nel formato ottenuto rappresentano il numero di secondi dal 1970 fino a un certo momento nel futuro. Utilizzare i dati in questo formato nei trigger è praticamente impossibile, perché Zabbix consente solo di operare con le variabili {Date} e {Time}, che restituiscono data e ora in un formato comprensibile per l'utente.

  • Dopo di che possiamo ottenere in JavaScript la data corrente nel formato Unix Timestamp e sottrarla dal valore ottenuto della data di scadenza del certificato, per ottenere il numero di millisecondi dall'ora attuale fino alla scadenza del certificato.

`now = Date.now();`

  • Dividiamo il valore ottenuto per mille, per ottenere i secondi in Zabbix.

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

Nella regola si può specificare l'espressione 'last<' e un insieme di cifre che corrisponde al numero di secondi nel periodo al quale si deve reagire, ad esempio, in settimane. In questo modo, la regola avviserà che la validità del certificato scade fra una settimana.

NOTA. Si prega di notare l'uso di parseInt() nella funzione return, per convertire un numero decimale, ottenuto dividendo i millisecondi, in un intero. È anche possibile utilizzare parseFloat() e memorizzare dati decimali.

Guarda la relazione

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster