Resolvemos problemas prácticos en Zabbix usando JavaScript

Resolvemos problemas prácticos en Zabbix usando JavaScript
Tikhon Uskov, enxeñeiro do equipo de integración de Zabbix

Zabbix é unha plataforma personalizable que se usa para supervisar calquera tipo de datos. Desde as primeiras versións de Zabbix, os administradores de seguimento tiveron a capacidade de executar varios scripts a través de Accións para comprobacións nos nodos da rede de destino. Ao mesmo tempo, o lanzamento de scripts provocou unha serie de dificultades, entre elas a necesidade de admitir scripts, a súa entrega a nodos de comunicación e proxies, así como a compatibilidade con diferentes versións.

JavaScript para Zabbix

En abril de 2019, presentouse Zabbix 4.2 con preprocesamento de JavaScript. Moitas persoas entusiasmaron coa idea de abandonar a escritura de guións que levan datos nalgún lugar, os dixeran e fornecen nun formato que Zabbix entenda, e realizan comprobacións sinxelas que recibirán datos que non están listos para almacenar e procesar por Zabbix, e a continuación, procese este fluxo de datos usando as ferramentas Zabbix e JavaScript. Xunto co descubrimento de baixo nivel e os elementos dependentes que apareceron en Zabbix 3.4, obtivemos un concepto bastante flexible para ordenar e xestionar os datos recibidos.

En Zabbix 4.4, como continuación lóxica do procesamento previo en JavaScript, apareceu un novo método de notificación: Webhook, que se pode usar para integrar facilmente as notificacións de Zabbix con aplicacións de terceiros.

JavaScript e Duktapes

Por que se escolleu JavaScript e Duktape? Consideráronse varias opcións para idiomas e motores:

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

Os principais criterios de selección foron a prevalencia, a facilidade de integración do motor no produto, o baixo consumo de recursos e o rendemento global do motor e a seguridade de introducir código nesta linguaxe no seguimento. Baseándose na combinación de indicadores, JavaScript gañou no motor Duktape.

Resolvemos problemas prácticos en Zabbix usando JavaScript

Criterios de selección e probas de rendemento

Características de Duktape:

- Estándar ECMAScript E5/E5.1
- Módulos Zabbix para Duktape:

  • Zabbix.log() - permítelle escribir mensaxes con diferentes niveis de detalle directamente no rexistro do servidor de Zabbix, o que permite correlacionar erros, por exemplo, nun Webhook, co estado do servidor.
  • CurlHttpRequest() - permítelle facer solicitudes HTTP á rede, na que se basea o uso de Webhook.
  • atob() e btoa() - permítelle codificar e decodificar cadeas en formato Base64.

NOTA. Duktape cumpre cos estándares ACME. Zabbix usa a versión de 2015 do guión. Os cambios posteriores son menores, polo que se poden ignorar..

Maxia JavaScript

Toda a maxia de JavaScript reside na escritura dinámica e na emisión de tipos: cadea, numérico e booleano.

Isto significa que non é necesario declarar previamente que tipo de variable debe devolver un valor.

Nas operacións matemáticas, os valores devoltos polos operadores de funcións convértense en números. A excepción a tales operacións é a adición, porque se polo menos un dos termos é unha cadea, a conversión de cadea aplícase a todos os termos.

NOTA. Os métodos responsables de tales transformacións adoitan implementarse nos prototipos principais do obxecto, valorOf и toString. valorOf chamado durante a conversión numérica e sempre antes do método toString. Método valorOf debe devolver valores primitivos, se non, o seu resultado é ignorado.

Chámase un método nun obxecto valor de. Se non se atopa ou non devolve un valor primitivo, chámase ao método toString. Se o método toString non atopado, buscando valorOf no prototipo do obxecto, e todo repítese ata que se complete o procesamento do valor e todos os valores da expresión se emitan ao mesmo tipo. Se o obxecto implementa un método toString, que devolve un valor primitivo, entón é o que se usa para a conversión de cadeas. Non obstante, o resultado da aplicación deste método non é necesariamente unha cadea.

Por exemplo, se for for object 'obx' método está definido toString,

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

Método toString devolve exactamente unha cadea, e ao engadir unha cadea cun número, obtemos unha cadea pegada:

`obj + 1 // '2001'` 

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

Pero se reescribes toString, para que o método devolva un número, cando se engade o obxecto, realizarase unha operación matemática cunha conversión numérica e obterase o resultado da suma matemática.

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

`obj + 1 // '2001'`

Neste caso, se realizamos a suma cunha cadea, realízase unha conversión de cadea, e obtemos unha cadea pegada.

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

Este é o motivo dunha gran cantidade de erros por parte dos usuarios novatos de JavaScript.

O método toString pode escribir unha función que aumente o valor actual do obxecto en 1.

Resolvemos problemas prácticos en Zabbix usando JavaScript
Execución do script, sempre que a variable sexa igual a 3, e tamén sexa igual a 4.

Cando se compara cun reparto (==), o método execútase cada vez toString con función de aumento de valor. En consecuencia, con cada comparación posterior, o valor aumenta. Isto pódese evitar usando a comparación non emitida (===).

Resolvemos problemas prácticos en Zabbix usando JavaScript
Comparación sen tipo de fundición

NOTA. Non uses a comparación de emisións innecesariamente.

Para scripts complexos, como Webhooks con lóxica complexa, que requiren comparación co tipo casting, recoméndase escribir comprobacións previas para os valores que devolven variables e manexan inconsistencias e erros.

Webhook Media

A finais de 2019 e principios de 2020, o equipo de integración de Zabbix estivo desenvolvendo activamente Webhooks e integracións listas para usar coa distribución de Zabbix.

Resolvemos problemas prácticos en Zabbix usando JavaScript
Ligazón a documentación

Preprocesamento

  • A chegada do preprocesamento en JavaScript fixo posible abandonar a maioría dos scripts externos, e actualmente en Zabbix pode obter calquera valor e convertelo a un valor completamente diferente.
  • O preprocesamento en Zabbix está implementado por código JavaScript, que, cando se compila en bytecode, convértese nunha función que toma un único valor como parámetro valor como unha cadea (unha cadea pode conter tanto un díxito como un número).
  • Dado que a saída é unha función, é necesario ao final do script retorno.
  • É posible usar macros personalizadas no código.
  • Os recursos pódense limitar non só a nivel de sistema operativo, senón tamén programáticamente. Ao paso de preprocesamento asígnaselle un máximo de 10 megabytes de RAM e un límite de tempo de execución de 10 segundos.

Resolvemos problemas prácticos en Zabbix usando JavaScript

NOTA. O valor de tempo de espera de 10 segundos é bastante, porque recoller miles condicionais de elementos de datos en 1 segundo segundo un escenario de preprocesamento bastante "pesado" pode ralentizar Zabbix. Polo tanto, non se recomenda usar o preprocesamento para executar scripts JavaScript completos a través dos chamados elementos de datos sombra (elementos ficticios), que se executan só para realizar o preprocesamento..

Podes comprobar o teu código a través da proba de preprocesamento ou usando a utilidade 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`

Tarefas prácticas

Tarefa 1

Substitúe o elemento calculado por preprocesamento.

Condición: obtén a temperatura en Fahrenheit do sensor para almacenala en Celsius.

Anteriormente, creariamos un elemento que recolle a temperatura en graos Fahrenheit. Despois diso, outro elemento de datos (calculado) que convertería Fahrenheit en Celsius mediante unha fórmula.

Problemas:

  • É necesario duplicar elementos de datos e almacenar todos os valores na base de datos.
  • Debes acordar os intervalos para o elemento de datos "nai" que se calcula e usa na fórmula e para o elemento de datos calculado. En caso contrario, o elemento calculado pode pasar a un estado non compatible ou calcular un valor anterior, o que afectará á fiabilidade dos resultados do seguimento.

Unha solución foi afastarse dos intervalos de comprobación flexibles en favor de intervalos fixos para garantir que o elemento calculado se avalía despois do elemento que recibe os datos (no noso caso, a temperatura en graos Fahrenheit).

Pero se, por exemplo, usamos o modelo para comprobar un gran número de dispositivos, e a comprobación realízase unha vez cada 30 segundos, Zabbix "hackea" durante 29 segundos e no último segundo comeza a comprobar e calcular. Isto crea unha cola e afecta o rendemento. Polo tanto, recoméndase usar intervalos fixos só se é realmente necesario.

Neste problema, a solución óptima é un preprocesamento JavaScript dunha liña que converte graos Fahrenheit en graos Celsius:

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

É rápido e sinxelo, non necesitas crear elementos de datos innecesarios e manter un historial neles, e tamén podes utilizar intervalos flexibles para as comprobacións.

Resolvemos problemas prácticos en Zabbix usando JavaScript

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

Pero, se nunha situación hipotética é necesario engadir o elemento de datos recibido, por exemplo, con calquera constante definida na macro, hai que ter en conta que o parámetro valor se expande nunha cadea. Nunha operación de adición de cadeas, dúas cadeas simplemente combínanse nunha soa.

Resolvemos problemas prácticos en Zabbix usando JavaScript

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

Para obter o resultado dunha operación matemática, é necesario converter os tipos de valores obtidos a un formato numérico. Para iso podes usar a función parseInt(), que produce un número enteiro, unha función parseFloat(), que produce un decimal ou unha función número, que devolve un número enteiro ou decimal.

Tarefa 2

Obtén o tempo en segundos ata o final do certificado.

Condición: un servizo emite unha data de caducidade do certificado no formato "12 de febreiro 12:33:56 2022 GMT".

En ECMAScript5 data.parse() acepta unha data en formato ISO 8601 (AAAA-MM-DDTHH:mm:ss.sssZ). É necesario lanzarlle unha cadea no formato MMM DD AAAA HH:mm:ss ZZ

problema: o valor do mes exprésase como texto, non como número. Os datos neste formato non son aceptados por Duktape.

Exemplo de solución:

  • En primeiro lugar, declárase unha variable que toma un valor (todo o script é unha declaración de variables que aparecen separadas por comas).

  • Na primeira liña obtemos a data no parámetro valor e sepárao con espazos mediante o método división. Así, obtemos unha matriz, onde cada elemento da matriz, comezando no índice 0, corresponde a un elemento de data antes e despois dun espazo. dividir (0) - mes, dividir (1) - número, dividir (2) - unha cadea con tempo, etc. Despois diso, pódese acceder a cada elemento da data mediante un índice na matriz.

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

  • Cada mes (por orde cronolóxica) corresponde ao índice da súa posición na matriz (de 0 a 11). Para converter un valor de texto nun valor numérico, engádese un ao índice do mes (porque os meses están numerados a partir do 1). Neste caso, a expresión coa adición de un tómase entre parénteses, porque senón obterase unha cadea, non un número. Ao final facemos porción () - corta a matriz desde o final para deixar só dous caracteres (o que é importante durante meses cun número de dous díxitos).

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

  • Formamos unha cadea en formato ISO a partir dos valores obtidos mediante a adición habitual de cadeas na orde adecuada.

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

Os datos no formato resultante son o número de segundos desde 1970 ata algún momento no futuro. É case imposible usar os datos no formato recibido en disparadores, porque Zabbix permítelle operar só con macros {Data} и {Tempo}, que devolven a data e a hora nun formato sinxelo.

  • A continuación, podemos obter a data actual en JavaScript en formato Unix Timestamp e restala da data de caducidade do certificado resultante para obter o número de milisegundos desde agora ata que caduque o certificado.

`now = Date.now();`

  • Dividimos o valor recibido por mil para obter segundos en Zabbix.

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

No disparador, pode especificar a expresión 'último' seguido dun conxunto de díxitos que se corresponden co número de segundos do período ao que quere responder, por exemplo, en semanas. Así, o disparador notificará que o certificado caduca nunha semana.

NOTA. Preste atención ao uso parseInt() en función retornopara converter o número fraccionario resultante da división de milisegundos nun número enteiro. Tamén podes usar parseFloat() e almacenar datos fraccionarios.

Ver informe

Fonte: www.habr.com

Engadir un comentario