Resolvemos problemas práticos no Zabbix usando JavaScript

Resolvemos problemas práticos no Zabbix usando JavaScript
Tikhon Uskov, Engenheiro da equipe de integração do Zabbix

O Zabbix é uma plataforma personalizável que é usada para monitorar qualquer tipo de dados. Desde as primeiras versões do Zabbix, os administradores de monitoramento têm a capacidade de executar vários scripts via Opções para verificações nos nós da rede de destino. Ao mesmo tempo, o lançamento de scripts trouxe uma série de dificuldades, incluindo a necessidade de suporte a scripts, sua entrega a nós de comunicação e proxies, bem como suporte para diferentes versões.

JavaScript para Zabbix

Em abril de 2019, o Zabbix 4.2 foi introduzido com pré-processamento de JavaScript. Muitas pessoas ficaram empolgadas com a ideia de abandonar a escrita de scripts que pegam os dados em algum lugar, digerem e disponibilizam em um formato que o Zabbix entenda, e fazem verificações simples que vão receber dados que não estão prontos para armazenamento e processamento pelo Zabbix, e em seguida, processe esse fluxo de dados usando as ferramentas Zabbix e JavaScript. Em conjunto com a descoberta de baixo nível e itens dependentes que apareceram no Zabbix 3.4, obtivemos um conceito bastante flexível para classificar e gerenciar os dados recebidos.

No Zabbix 4.4, como uma continuação lógica do pré-processamento em JavaScript, surgiu um novo método de notificação - Webhook, que pode ser usado para integrar facilmente as notificações do Zabbix com aplicativos de terceiros.

JavaScript e Duktapes

Por que JavaScript e Duktape foram escolhidos? Várias opções de idiomas e motores foram consideradas:

  • Lua - Lua 5.1
  • Lua - LuaJIT
  • Javascript - Duktape
  • JavaScript – JerryScript
  • Python embutido
  • Perl embutido

Os principais critérios de seleção foram prevalência, facilidade de integração do motor no produto, baixo consumo de recursos e desempenho geral do motor, e a segurança de introduzir o código nesta linguagem no monitoramento. Com base na combinação de indicadores, o JavaScript venceu no mecanismo Duktape.

Resolvemos problemas práticos no Zabbix usando JavaScript

Critérios de seleção e testes de desempenho

Características do Duktape:

- Padrão ECMAScript E5/E5.1
— Módulos Zabbix para Duktape:

  • Zabbix.log() - permite escrever mensagens com diferentes níveis de detalhamento diretamente no log do Zabbix Server, o que possibilita correlacionar erros, por exemplo, em um Webhook, com o estado do servidor.
  • CurlHttpRequest() - permite fazer solicitações HTTP à rede, nas quais se baseia o uso do Webhook.
  • atob() e btoa() - permite codificar e decodificar strings no formato Base64.

ПРИМЕЧАНИЕ. Duktape está em conformidade com os padrões ACME. O Zabbix usa a versão 2015 do script. As alterações subseqüentes são pequenas, portanto, podem ser ignoradas..

magia do JavaScript

Toda a magia do JavaScript está na digitação dinâmica e na conversão de tipos: string, numérico e booleano.

Isso significa que não é necessário declarar antecipadamente qual tipo a variável deve retornar um valor.

Nas operações matemáticas, os valores retornados pelos operadores de função são convertidos em números. A exceção a essas operações é a adição, porque se pelo menos um dos termos for uma string, a conversão de string será aplicada a todos os termos.

ПРИМЕЧАНИЕ. Os métodos responsáveis ​​por tais transformações são geralmente implementados nos protótipos pais do objeto, valor de и para sequenciar. valor de chamado durante a conversão numérica e sempre antes do método para sequenciar. Método valor de deve retornar valores primitivos, caso contrário seu resultado é ignorado.

Um método é chamado em um objeto valor de. Caso não seja encontrado ou não retorne um valor primitivo, o método é chamado para sequenciar. Se o método para sequenciar não encontrado, procurando valor de no protótipo do objeto, e tudo se repete até que o processamento do valor seja concluído e todos os valores na expressão sejam convertidos para o mesmo tipo. Se o objeto implementa um método para sequenciar, que retorna um valor primitivo, é ele que é usado para conversão de string. No entanto, o resultado da aplicação desse método não é necessariamente uma string.

Por exemplo, se for for objeto 'vol'método é definido para sequenciar,

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

método para sequenciar retorna exatamente uma string e, ao adicionar uma string com um número, obtemos uma string colada:

`obj + 1 // '2001'` 

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

Mas se você reescrever para sequenciar, de forma que o método retorne um número, ao somar o objeto será realizada uma operação matemática com conversão numérica e será obtido o resultado da adição matemática.

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

`obj + 1 // '2001'`

Nesse caso, se fizermos uma adição com uma string, uma conversão de string é realizada e obtemos uma string colada.

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

Esse é o motivo de um grande número de erros cometidos por usuários iniciantes de JavaScript.

O método para sequenciar você pode escrever uma função que aumentará o valor atual do objeto em 1.

Resolvemos problemas práticos no Zabbix usando JavaScript
Execução do script, desde que a variável seja igual a 3, e também igual a 4.

Quando comparado com um elenco (==), o método é executado cada vez para sequenciar com função de aumento de valor. Assim, a cada comparação subsequente, o valor aumenta. Isso pode ser evitado usando comparação não convertida (===).

Resolvemos problemas práticos no Zabbix usando JavaScript
Comparação sem fundição de tipo

ПРИМЕЧАНИЕ. Não use comparações de elenco desnecessariamente.

Para scripts complexos, como Webhooks com lógica complexa, que requerem comparação com conversão de tipo, é recomendável pré-escrever verificações para os valores que retornam variáveis ​​e tratam inconsistências e erros.

Mídia Webhook

No final de 2019 e início de 2020, a equipe de integração do Zabbix desenvolveu ativamente Webhooks e integrações prontas para uso que acompanham a distribuição do Zabbix.

Resolvemos problemas práticos no Zabbix usando JavaScript
Vincular a documentação

Pré-processando

  • O advento do pré-processamento em JavaScript possibilitou o abandono da maioria dos scripts externos e, atualmente, no Zabbix, você pode obter qualquer valor e convertê-lo em um valor completamente diferente.
  • O pré-processamento no Zabbix é implementado pelo código JavaScript, que, ao ser compilado em bytecode, é convertido em uma função que recebe um único valor como parâmetro valor como uma string (uma string pode conter um dígito e um número).
  • Como a saída é uma função, no final do script é obrigatório retorno.
  • É possível usar macros personalizadas no código.
  • Os recursos podem ser limitados não apenas no nível do sistema operacional, mas também programaticamente. A etapa de pré-processamento recebe no máximo 10 megabytes de RAM e um limite de tempo de execução de 10 segundos.

Resolvemos problemas práticos no Zabbix usando JavaScript

ПРИМЕЧАНИЕ. O valor de tempo limite de 10 segundos é bastante, porque a coleta condicional de milhares de itens de dados em 1 segundo de acordo com um cenário de pré-processamento bastante “pesado” pode desacelerar o Zabbix. Portanto, não é recomendado usar o pré-processamento para executar scripts JavaScript completos por meio dos chamados elementos de dados de sombra (itens fictícios), que são executados apenas para realizar o pré-processamento.

Você pode verificar seu código por meio do teste de pré-processamento ou usando o utilitário 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áticas

Tarefa 1

Substitua o item calculado pelo pré-processamento.

Condição: Obtenha a temperatura em Fahrenheit do sensor para armazenar em Celsius.

Anteriormente, criaríamos um item que coleta a temperatura em graus Fahrenheit. Depois disso, outro item de dados (calculado) que converteria Fahrenheit em Celsius usando uma fórmula.

Problemas:

  • É necessário duplicar os elementos de dados e armazenar todos os valores no banco de dados.
  • Você deve concordar com os intervalos para o item de dados "pai" que é calculado e usado na fórmula e para o item de dados calculado. Caso contrário, o item calculado pode entrar em um estado sem suporte ou calcular um valor anterior, o que afetará a confiabilidade dos resultados do monitoramento.

Uma solução foi mudar os intervalos de verificação flexíveis em favor de intervalos fixos para garantir que o item calculado seja avaliado após o item que recebe os dados (no nosso caso, a temperatura em graus Fahrenheit).

Mas se, por exemplo, usarmos o modelo para verificar um grande número de dispositivos e a verificação for realizada uma vez a cada 30 segundos, o Zabbix "hackeia" por 29 segundos e, no último segundo, começa a verificar e calcular. Isso cria uma fila e afeta o desempenho. Portanto, recomenda-se usar intervalos fixos apenas se for realmente necessário.

Neste problema, a solução ideal é um pré-processamento JavaScript de uma linha que converte graus Fahrenheit em graus Celsius:

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

É rápido e fácil, você não precisa criar itens de dados desnecessários e manter um histórico deles, e também pode usar intervalos flexíveis para verificações.

Resolvemos problemas práticos no Zabbix usando JavaScript

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

Mas, se em uma situação hipotética for necessário adicionar o elemento de dado recebido, por exemplo, com qualquer constante definida na macro, deve-se levar em consideração que o parâmetro valor expande em uma string. Em uma operação de adição de strings, duas strings são simplesmente combinadas em uma.

Resolvemos problemas práticos no Zabbix usando JavaScript

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

Para obter o resultado de uma operação matemática, é necessário converter os tipos dos valores obtidos para um formato numérico. Para isso você pode usar a função parseInt (), que produz um inteiro, uma função analisarFloat(), que produz um decimal, ou uma função número, que retorna um número inteiro ou decimal.

Tarefa 2

Obtenha o tempo em segundos até o final do certificado.

Condição: um serviço emite uma data de expiração de certificado no formato "12 de fevereiro 12:33:56 2022 GMT".

Em ECMAScript5 Date.parse () aceita uma data no formato ISO 8601 (AAAA-MM-DDTHH:mm:ss.sssZ). É necessário lançar uma string para ele no formato MMM DD AAAA HH:mm:ss ZZ

problema: o valor do mês é expresso como texto, não como número. Dados neste formato não são aceitos pela Duktape.

Exemplo de solução:

  • Em primeiro lugar, é declarada uma variável que recebe um valor (o script inteiro é uma declaração de variáveis ​​listadas separadas por vírgulas).

  • Na primeira linha obtemos a data no parâmetro valor e separe-o com espaços usando o método divisão. Assim, obtemos um array, onde cada elemento do array, começando no índice 0, corresponde a um elemento de data antes e depois de um espaço. dividir(0) - mês, dividir(1) - número, dividir(2) - uma string com hora, etc. Depois disso, cada elemento da data pode ser acessado por índice no array.

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

  • Cada mês (em ordem cronológica) corresponde ao índice de sua posição na matriz (de 0 a 11). Para converter um valor de texto em um valor numérico, um é adicionado ao índice do mês (porque os meses são numerados a partir de 1). Nesse caso, a expressão com a adição de um é tomada entre colchetes, pois, caso contrário, será obtida uma string, não um número. No final fazemos fatiar() - corte a matriz do final para deixar apenas dois caracteres (o que é importante para meses com um número de dois 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 uma string no formato ISO a partir dos valores obtidos pela adição usual de strings na ordem apropriada.

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

Os dados no formato resultante são o número de segundos de 1970 até algum ponto no futuro. É quase impossível usar dados no formato recebido em triggers, pois o Zabbix permite operar apenas com macros {Encontro} и {Tempo}, que retornam a data e a hora em um formato amigável.

  • Podemos então obter a data atual em JavaScript no formato Unix Timestamp e subtraí-la da data de expiração do certificado resultante para obter o número de milissegundos a partir de agora até que o certificado expire.

`now = Date.now();`

  • Dividimos o valor recebido por mil para obter os segundos no Zabbix.

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

No gatilho, você pode especificar a expressão 'durar' seguido de um conjunto de dígitos que corresponde ao número de segundos no período ao qual você deseja responder, por exemplo, em semanas. Assim, o gatilho notificará que o certificado expira em uma semana.

ПРИМЕЧАНИЕ. Preste atenção ao uso parseInt () em função retornopara converter o número fracionário resultante da divisão de milissegundos em um número inteiro. Você também pode usar analisarFloat() e armazenar dados fracionários.

Assistir relatório

Fonte: habr.com

Adicionar um comentário