Resolvemos problemas prácticos en Zabbix usando JavaScript

Resolvemos problemas prácticos en Zabbix usando JavaScript
Tikhon Uskov, ingeniero del equipo de integración de Zabbix

Zabbix es una plataforma personalizable que se utiliza para monitorear cualquier tipo de datos. Desde las primeras versiones de Zabbix, los administradores de monitoreo han tenido la capacidad de ejecutar varios scripts a través de Acciones para verificaciones en los nodos de la red de destino. Al mismo tiempo, el lanzamiento de scripts generó una serie de dificultades, entre ellas, la necesidad de admitir scripts, su entrega a nodos de comunicación y proxies, así como el soporte para diferentes versiones.

JavaScript para Zabbix

En abril de 2019, se introdujo Zabbix 4.2 con preprocesamiento de JavaScript. Mucha gente se entusiasmó con la idea de abandonar la escritura de scripts que toman datos en alguna parte, los digieren y los proporcionan en un formato que Zabbix entiende, y realizan comprobaciones simples que recibirán datos que no están listos para el almacenamiento y procesamiento por parte de Zabbix, y luego procese este flujo de datos utilizando las herramientas de Zabbix y JavaScript. Junto con el descubrimiento de bajo nivel y los elementos dependientes que aparecieron en Zabbix 3.4, obtuvimos un concepto bastante flexible para clasificar y administrar los datos recibidos.

En Zabbix 4.4, como una continuación lógica del procesamiento previo en JavaScript, apareció un nuevo método de notificación: Webhook, que se puede usar para integrar fácilmente las notificaciones de Zabbix con aplicaciones de terceros.

JavaScript y Duktapes

¿Por qué se eligieron JavaScript y Duktape? Se consideraron varias opciones de idiomas y motores:

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

Los principales criterios de selección fueron la prevalencia, la facilidad de integración del motor en el producto, el bajo consumo de recursos y el rendimiento general del motor, y la seguridad de introducir código en este lenguaje en la monitorización. Basado en la combinación de indicadores, JavaScript ganó en el motor Duktape.

Resolvemos problemas prácticos en Zabbix usando JavaScript

Criterios de selección y pruebas de rendimiento

Características de Duktape:

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

  • Zabbix.log(): le permite escribir mensajes con diferentes niveles de detalle directamente en el registro del servidor Zabbix, lo que permite correlacionar errores, por ejemplo, en un Webhook, con el estado del servidor.
  • CurlHttpRequest(): le permite realizar solicitudes HTTP a la red, que se basa en el uso de Webhook.
  • atob() y btoa(): le permite codificar y decodificar cadenas en formato Base64.

NOTA. Duktape cumple con los estándares ACME. Zabbix usa la versión 2015 del script. Los cambios posteriores son menores, por lo que pueden ignorarse..

Magia JavaScript

Toda la magia de JavaScript radica en la escritura dinámica y la conversión de tipos: cadena, numérico y booleano.

Esto significa que no es necesario declarar de antemano de qué tipo la variable debe devolver un valor.

En las operaciones matemáticas, los valores devueltos por los operadores de funciones se convierten en números. La excepción a tales operaciones es la suma, porque si al menos uno de los términos es una cadena, la conversión de cadena se aplica a todos los términos.

NOTA. Los métodos responsables de tales transformaciones generalmente se implementan en los prototipos principales del objeto, valor de и Encadenar. valor de llamado durante la conversión numérica y siempre antes del método Encadenar. Método valor de debe devolver valores primitivos, de lo contrario se ignora su resultado.

Se llama a un método en un objeto. valor de. Si no se encuentra o no devuelve un valor primitivo, se llama al método Encadenar. Si el método Encadenar no encontrado, buscando valor de en el prototipo del objeto, y todo se repite hasta que se completa el procesamiento del valor y todos los valores en la expresión se convierten en el mismo tipo. Si el objeto implementa un método Encadenar, que devuelve un valor primitivo, entonces es el que se usa para la conversión de cadenas. Sin embargo, el resultado de aplicar este método no es necesariamente una cadena.

Por ejemplo, si for for object 'obj' el método está definido Encadenar,

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

метод Encadenar devuelve exactamente una cadena, y al agregar una cadena con un número, obtenemos una cadena pegada:

`obj + 1 // '2001'` 

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

Pero si reescribes Encadenar, para que el método devuelva un número, al momento de sumar el objeto se realizará una operación matemática con una conversión numérica y se obtendrá el resultado de la suma matemática.

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

`obj + 1 // '2001'`

En este caso, si realizamos la suma con una cadena, se realiza una conversión de cadena y obtenemos una cadena pegada.

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

Esta es la razón de una gran cantidad de errores por parte de los usuarios novatos de JavaScript.

El método Encadenar puede escribir una función que aumente el valor actual del objeto en 1.

Resolvemos problemas prácticos en Zabbix usando JavaScript
Ejecución del script, siempre que la variable sea igual a 3, y también sea igual a 4.

En comparación con un lanzamiento (==), el método se ejecuta cada vez Encadenar con función de aumento de valor. En consecuencia, con cada comparación posterior, el valor aumenta. Esto se puede evitar utilizando la comparación sin conversión (===).

Resolvemos problemas prácticos en Zabbix usando JavaScript
Comparación sin conversión de tipos

NOTA. No utilice la comparación de reparto innecesariamente.

Para secuencias de comandos complejas, como Webhooks con lógica compleja, que requieren una comparación con la conversión de tipos, se recomienda escribir previamente comprobaciones de los valores que devuelven variables y manejan incoherencias y errores.

Medios de webhook

A fines de 2019 y principios de 2020, el equipo de integración de Zabbix ha estado desarrollando activamente Webhooks e integraciones listas para usar que vienen con la distribución de Zabbix.

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

preprocesamiento

  • La llegada del preprocesamiento en JavaScript hizo posible abandonar la mayoría de los scripts externos y, actualmente, en Zabbix puede obtener cualquier valor y convertirlo en un valor completamente diferente.
  • El preprocesamiento en Zabbix se implementa mediante código JavaScript que, cuando se compila en código de bytes, se convierte en una función que toma un valor único como parámetro. propuesta de como una cadena (una cadena puede contener tanto un dígito como un número).
  • Dado que la salida es una función, al final del script se requiere volvemos.
  • Es posible utilizar macros personalizadas en el código.
  • Los recursos se pueden limitar no solo a nivel del sistema operativo, sino también mediante programación. Al paso de preprocesamiento se le asigna un máximo de 10 megabytes de RAM y un límite de tiempo de ejecución de 10 segundos.

Resolvemos problemas prácticos en Zabbix usando JavaScript

NOTA. El valor de tiempo de espera de 10 segundos es bastante, porque la recopilación condicional de miles de elementos de datos en 1 segundo de acuerdo con un escenario de preprocesamiento bastante "pesado" puede ralentizar a Zabbix. Por lo tanto, no se recomienda utilizar el preprocesamiento para ejecutar scripts de JavaScript completos a través de los llamados elementos de datos ocultos (elementos ficticios), que se ejecutan solo para realizar el preprocesamiento..

Puede verificar su código a través de la prueba de preprocesamiento o usando la utilidad 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`

Tareas prácticas

Tarea 1

Reemplace el elemento calculado con preprocesamiento.

Condicion: Obtenga la temperatura en Fahrenheit del sensor para almacenarla en Celsius.

Previamente, crearíamos un elemento que recopilara la temperatura en grados Fahrenheit. Después de eso, otro elemento de datos (calculado) que convertiría Fahrenheit a Celsius usando una fórmula.

Problemas:

  • Es necesario duplicar elementos de datos y almacenar todos los valores en la base de datos.
  • Debe acordar los intervalos para el elemento de datos "principal" que se calcula y utiliza en la fórmula y para el elemento de datos calculado. De lo contrario, el elemento calculado puede pasar a un estado no compatible o calcular un valor anterior, lo que afectará la confiabilidad de los resultados del monitoreo.

Una solución fue alejarse de los intervalos de verificación flexibles en favor de intervalos fijos para garantizar que el elemento calculado se evalúe después del elemento que recibe los datos (en nuestro caso, la temperatura en grados Fahrenheit).

Pero si, por ejemplo, usamos la plantilla para verificar una gran cantidad de dispositivos y la verificación se realiza una vez cada 30 segundos, Zabbix "hackea" durante 29 segundos y en el último segundo comienza a verificar y calcular. Esto crea una cola y afecta el rendimiento. Por lo tanto, se recomienda utilizar intervalos fijos solo si es realmente necesario.

En este problema, la solución óptima es un preprocesamiento de JavaScript de una línea que convierte grados Fahrenheit a grados Celsius:

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

Es rápido y fácil, no necesita crear elementos de datos innecesarios y mantener un historial sobre ellos, y también puede utilizar intervalos flexibles para las comprobaciones.

Resolvemos problemas prácticos en Zabbix usando JavaScript

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

Pero, si en una hipotética situación es necesario sumar el dato recibido, por ejemplo, con alguna constante definida en la macro, se debe tener en cuenta que el parámetro propuesta de se expande en una cadena. En una operación de suma de cadenas, dos cadenas simplemente se combinan en una.

Resolvemos problemas prácticos en Zabbix usando JavaScript

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

Para obtener el resultado de una operación matemática, es necesario convertir los tipos de los valores obtenidos a un formato numérico. Para esto puedes usar la función parseInt (), que produce un número entero, una función parseFloat (), que produce un decimal, o una función número, que devuelve un número entero o decimal.

Tarea 2

Obtenga el tiempo en segundos hasta el final del certificado.

Condicion: un servicio emite una fecha de vencimiento del certificado en el formato "12 de febrero 12:33:56 2022 GMT".

En ECMAScript5 Date.parse () acepta una fecha en formato ISO 8601 (AAAA-MM-DDTHH:mm:ss.sssZ). Es necesario emitirle una cadena en el formato MMM DD AAAA HH:mm:ss ZZ

problema: El valor del mes se expresa como texto, no como un número. Duktape no acepta datos en este formato.

Ejemplo de solución:

  • En primer lugar, se declara una variable que toma un valor (todo el script es una declaración de variables que se enumeran separadas por comas).

  • En la primera línea obtenemos la fecha en el parámetro propuesta de y sepárelo con espacios usando el método dividido. Por lo tanto, obtenemos una matriz, donde cada elemento de la matriz, comenzando en el índice 0, corresponde a un elemento de fecha antes y después de un espacio. dividir (0) - mes, dividir (1) - número, dividir (2) - una cadena con tiempo, etc. Después de eso, se puede acceder a cada elemento de la fecha por índice en la matriz.

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

  • Cada mes (en orden cronológico) corresponde al índice de su posición en la matriz (del 0 al 11). Para convertir un valor de texto en un valor numérico, se agrega uno al índice del mes (porque los meses se numeran a partir del 1). En este caso se toma entre paréntesis la expresión con la suma de uno, porque de lo contrario se obtendrá una cadena, no un número. Al final hacemos rebanada() - corte la matriz desde el final para dejar solo dos caracteres (lo cual es importante para los meses con un número de dos dígitos).

`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 una cadena en formato ISO a partir de los valores obtenidos mediante la adición habitual de cadenas en el orden apropiado.

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

Los datos en el formato resultante son la cantidad de segundos desde 1970 hasta algún momento en el futuro. Es casi imposible usar datos en el formato recibido en disparadores, porque Zabbix le permite operar solo con macros {Fecha} и {Tiempo}, que devuelven la fecha y la hora en un formato fácil de usar.

  • Luego podemos obtener la fecha actual en JavaScript en formato Unix Timestamp y restarla de la fecha de vencimiento del certificado resultante para obtener la cantidad de milisegundos desde ahora hasta que el certificado expire.

`now = Date.now();`

  • Dividimos el valor recibido por mil para obtener segundos en Zabbix.

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

En el activador, puede especificar la expresión 'último' seguido de un conjunto de dígitos que corresponde a la cantidad de segundos en el período al que desea responder, por ejemplo, en semanas. Así, el activador notificará que el certificado caduca en una semana.

NOTA. Presta atención al uso parseInt () en función volvemospara convertir el número fraccionario resultante de la división de milisegundos a un número entero. También puedes usar parseFloat () y almacenar datos fraccionarios.

Ver informe

Fuente: habr.com

Añadir un comentario