terça-feira, 4 de novembro de 2014

LLD no Zabbix com Shell Script - Entendendo e utilizando esse recurso

Introdução

O recurso de LLD (Low Level Discovery) tem ganhado cada vez mais importância, uma vez que teoricamente é possível monitorar qualquer coisa utilizando esse recurso, apesar da documentação oficial, de artigos nacionais e internacionais, mensagens no fórum oficial, etc. O recurso continua desconhecido por muitos, eu queria compilar um pouco de tudo que encontrei, e da minha própria experiência e criar um artigo onde as pessoas entendessem a lógica do LLD e pudessem se basear para criar seus próprios LLDs.

Termos Técnicos

Antes de entrarmos na solução propriamente dita, precisamos entender alguns termos e soluções envolvidas nesse recurso.

LLD - Low Level Discovery: Função do Zabbix responsável por detectar determinadas características de um objeto, de forma dinâmica. Por exemplo, o Zabbix vai achar sozinho (dinamicamente) todas as partições da sua máquina (o objeto são as partições), e coletar dados como tamanho da partição, espaço livre, espaço utilizado (essas são as características do objeto).

JSON - JavaScript Object Notation: É uma formatação para intercâmbio de dados computacionais, que para seres humanos é fácil de ler e escrever e, para as máquinas é fácil de interpretar e gerar. Se você entende como um XML funciona, entende como um JSON funciona ;-)

PARSER: Em Português conhecemos como Análise Sintática, mas a maioria das pessoas usa o termo em inglês, de maneira simples, significa ler uma entrada de dados, nesse caso um arquivo JSON, e interpretar a sua estrutura gramatical. O software jq, no nosso caso, vai receber um arquivo texto com marcações específicas que ele sabe interpretar e extrair os dados.

Como funciona o LLD no Zabbix

O LLD no Zabbix de maneira muito resumida funciona da seguinte forma:
Você gera um arquivo no formato JSON com a entrada de dados utilizando o padrão de macros do Zabbix "{#VAR}", essas macros serão os objetos, por exemplo, a lista de placas de rede, a lista de partições, a lista de base de dados, a lista de tabelas de uma base de dados, a lista de antenas sem fio, etc. Isso é a Regra de Descoberta.
Em seguida você tem que dizer ao Zabbix o que coletar de cada um desses objetos da lista, isso é o Protótipo de itens. Por exemplo, para cada partição do sistema colete o tamanho da partição, o espaço livre e o espaço utilizado. Com esses itens gerados, podemos criar outros protótipos como Triggers e Gráficos.
Isso pode ser feito utilizando as Chaves suportadas pelo Zabbix, OIDs SNMP ou Scripts Personalizados.

Pré-requisitos

O único pré-requisito no Servidor Zabbix é a instalação do jq, que é um parser de JSON. No CentOS:
# yum -y install jq

Objetivo

Eu procurei criar a solução da maneira mais simples possível, para isso eu usei apenas Shell Script, nada de Perl, Python, Ruby, Awk, Expressões Regulares, apesar de tudo isso ser muito importante, eu queria que um administrador de redes iniciante tivesse condições de entender a solução, queria que pessoas que possuem ambientes críticos pudessem utilizar a solução tendo que realizar o mínimo possível de alterações no ambiente, apenas instalar o jq.

Arquivos envolvidos na solução

lld_passwd.sh: Script responsável por coletar os dados, neste exemplo, esses dados serão coletados do /etc/passwd, gerar o arquivo JSON com as macros que o Zabbix precisa e gerar um arquivo JSON comum de onde extrairemos os dados com o jq.
/tmp/lld_passwd.txt: Arquivo no formato JSON com as macros que o Zabbix necessita para interpretá-lo.
/tmp/lld_passwd_2.txt: Arquivo no formato JSON de onde extrairemos os dados para alimentar o Zabbix.

Estrutura da solução

O script coleta os dados do arquivo /etc/passwd e gera um aquivo JSON com as entradas "{#USER}", "{#NOME}", "{#HOME}" e "{#SHELL}" para cada um dos registros encontrados. No nosso exemplo, para o Zabbix só interessa a entrada "{#USER}", pois em cima da lista de usuários, solicitaremos os outros dados, o Nome do usuário "{#USER}", o Home do usuário "{#USER}", o Shell do usuário "{#USER}".

Você deve estar se perguntando: Se para o Zabbix só interessa a entrada "{#USER}" por que eu criei as outras entradas, certo? E também porque eu gerei o arquivo lld_passwd_2.txt se os dados já estão no /etc/passwd? Calma jovem gafanhoto...

O objetivo do artigo é ensinar a criar uma solução para qualquer tipo de dados, certo? Imagine que para coletar os dados que você precisa seja necessário executar um comando qualquer, nesse caso você precisaria executar o comando uma vez para montar o JSON, e depois executar o mesmo comando (ou outro) para coletar cada um dos dados referentes aos objetos do JSON, isso vai onerar o Servidor Zabbix e também o equipamento de onde os dados estão sendo coletados. Na solução aqui proposta nós vamos coletar todos os dados de uma única vez (podem ser necessários vários comandos para gerar o arquivo inteiro), e depois coletar os dados referentes aos objetos de um arquivo texto que está no próprio Servidor Zabbix, o que é muito menos custoso.

Variáveis do Script

O script foi projetado para receber as variáveis via passagem de parâmetros, porque o Zabbix vai passar esses parâmetros para ele.

Alguns detalhes devem ser observados nas variáveis do script:
Não podemos acrescentar " (aspas) ao arquivo JSON, a não ser as que ele espera encontrar e onde ele espera encontrar, então na variável $NOME, utilizei o comando tr -d \"`, para remover qualquer " (aspas) do arquivo /etc/passwd. Elas existem no user saslauth, como pode ser conferido abaixo:

# cat /etc/passwd | grep saslauth
saslauth:x:499:76:"Saslauthd user":/var/empty/saslauth:/sbin/nologin


Outro detalhe importante é referente às "/", elas precisam ser escapadas assim "\/", para isso usei o sed (eu sei que falei que não ia usar Expressões Regulares, mas é só um sed de nada..) nas variáveis $HOME e $SHELL.

A variável $LINHAS é utilizada para sabermos o número de entradas que serão geradas no arquivo JSON, isso porque todas as entradas acabam com uma ",", com exceção da última entrada. Por esse mesmo motivo o "for" foi configurado para ser executado até o "i<$LINHAS" e não "i<=$LINHAS".

Opções do Script

O script possui 4 opções, mas você pode adaptá-lo para ter quantas opções forem necessárias ao seu cenário. São elas:
discovery: Gera o arquivo lld_passwd.txt que será utilizado pela regra de descoberta do Zabbix.
Você pode (e deve) validar seus arquivos JSON no JSONLint.

user: Dado determinado usuário retorna o seu usuário, sim ela é inútil, foi apenas uma piadinha nerd para relaxar, qual será o user do user root?

nome: Dado determinado usuário retorna o nome do usuário.

home: Dado determinado usuário retorna o diretório home do usuário.

shell: Dado determinado usuário retorna o shell do usuário.

Arquivo lld_passwd_2.txt

Depois de montar o arquivo lld_passwd.txt, eu utilizo o sed para trocar todas as ocorrências de macros para itens normais de um arquivo JSON:
{#USER} -> user, {#NOME} -> nome, {#HOME} -> home e {#SHELL} -> shell.
E armazeno tudo nesse arquivo, quando eu realizo as operações user, nome, home e shell, o comando jq é invocado, entende o conteúdo do arquivo JSON e faz a extração dos dados que nos interessa.

Configuração no Zabbix Server

O script deve estar no seu diretório "ExternalScripts", se você estiver na dúvida, veja no arquivo /usr/local/etc/zabbix_server.conf  a localização do mesmo. Ele também deve possuir permissão para ser executado pelo usuário zabbix, que também deve ser capaz de criar os arquivos no /tmp.

Configuração na Interface Gráfica do Zabbix Server

 Crie um novo template com o nome LLD Passwd, depois na linha do nome do template clique em Autobusca // Criar regra de descoberta, preencha os dados da regra.
Regra de Descoberta

Na linha da regra clique em Protótipos de itens // Criar protótipo de item, preencha os dados dos protótipos.

Protótipo de Item Home

Protótipo de Item Nome

Protótipo de Item Shell

Protótipo de Item Usuário
 Clone o seu host Zabbix server com o nome de Zabbix server LLD.
Zabbix server LLD
 Vincule o template LLD Passwd no host.
Template LLD Passwd
Espere 5 minutos e acesse Configuração // Hosts, observe os itens criados automaticamente. Na figura abaixo eu usei um filtro para mostrar apenas os itens do usuário root.
Itens criados dinamicamente pelo LLD
Acesse Monitoramento // Dados recentes e visualize a leitura dos dados, neste exemplo eu filtrei apenas os itens do root.

Dados recentes

 

Conclusão

Com as explicações acima e os código disponíveis acredito que você seja capaz de entender o funcionamento do LLD no Zabbix, gerar seus próprios scripts e tirar o máximo proveito desse recurso fantástico.


Anexos

lld_passwd.sh
Template LLD_Passwd

 

Agradecimentos

Queria deixar aqui meus agradecimentos ao Ronei Xavier da Silva e Ederson Frasnelli Ribeiro que me deram uma força para entender o funcionamento do JSON!

Referências

Zabbix Manual
json.org
JSON Wikipedia
Análise Sintática Wikipedia
jsonlint.com
XModulo
JQ Manual
JQ FAQ

18 comentários:

Elton Ferreira disse...

Parabéns Déo!

André Déo disse...

Valeu Elton!

Abraços,

Unknown disse...

Muito boa as explicações. Técnica e sem rodeios.

Uma pergunta. Quando o LLD de dispositivo de rede termina é exibido o nome da interface: Broadcom BCM5708C NetXtreme II GigE (NDIS VBD Client) #2.

Existe a possibilidade de cortar um trexa da exibição do item? Tipo: Broadcom BCM5708C NetXtreme II GigE

Grato;

André Déo disse...

Fabio,

Você pode dar um:

| cut -d'(' -f1

Abraços,
Déo

Unknown disse...

Oi André, diante mão quero agradecer pelo seu retorno. talvez esse não seja o foco do seu blog, mas como o assunto é pertinente a sua postagem, pergunto: Onde entro com essa função que você explanou pra mim? Não consegui usar-la.

Abraços,

André Déo disse...

Fabio,

Você disse que o LLD retorna um dado como:
BCM5708C NetXtreme II GigE (NDIS VBD Client) #2.

E você quer que seja:
BCM5708C NetXtreme II GigE

O que eu quis dizer é que via script, você deve tratar a saída do dado para cortar a parte que te interessa, execute num terminal Linux:
# echo 'BCM5708C NetXtreme II GigE (NDIS VBD Client) #2.' | cut -d'(' -f1
BCM5708C NetXtreme II GigE

Mais sobre o cut aqui:
http://wiki.softwarelivre.org/TWikiBar/TWikiBarPapo003

Abraços,

Unknown disse...

André, me desculpe, mas eu sou novo nesse mundo zabbix.

Eu sei como o comando cut funciona no ambiente Linux e fiz os testes e realmente tenho o retorno que espero, porém, não sei como usa-lo no zabbix, não faço ideia de como realizar essa configuração via script no zabbix.

Abraço;

Unknown disse...

Você teria alguma leitura para me indicar. Leitura que possa me ajudar nesse entendimento?

Grato!

André Déo disse...

Fabio,

Não entendi sua pergunta, a leitura que te indico é o próprio post, nele tem passo a passo como fazer um LLD baseado em Shell e como configurar no Zabbix.

Se você tem os conhecimentos de script basta adaptar meu exemplo para a sua necessidade.

Abraços,

Unknown disse...

André, estou quebrando a cabeça mas ainda não consegui resolver, faço tudo conforme informou, mas quando vou no host, ele dá a seguinte informação na autobusca "Value should be a JSON object"

O que você acha?

André Déo disse...

Murilo,

Te chamei no Hangout, vamos ver se matamos isso ;-)

Abraços,

Unknown disse...

André, Consegui realizar a tratativa do nome da interface conforme você orientou.

Tenho mais uma pergunta sobre esse mesmo post. Existe a possibiliade de filtrar as interface que tem o paramentro ifOperStatus=down para não listar no host? Gostaria que só as placar UP fossem listadas para monitoramento. Faço a consulta utilizando SNMP.

Grato;

Element X disse...

Boa noite.
Estou começando a aprender o monitoramento pelo zabbix mas para monitorar os relógios de ponto.
Estou enfrentando alguns problemas mas mesmo assim estou vendo o futuro.
Achei maravilhoso a matéria sobre para este tipo de monitoramento e pós isso quero te fazer uma pergunta:

Tenho um sistema que gera um arquivo JSON com as informações do relógio que preciso. As informações ficam entre aspas e separadas por vírgulas e no sistema Windows.
Eu teria como usar este arquivo já pronto, que não posso alterar sua estrutura, para o zabbix o ler como na explicação da sua matéria? Fazendo as respectivas modificações?

Obrigado e grato desde já.

André Déo disse...

Fabio,

Tem sim, mas para isso você tem que alterar o script. Ou mesmo fazer um filtro via regex no Zabbix.

Abraços,

André Déo disse...

Element X,

Não entendi, se você não pode alterar o arquivo, como vai adaptá-lo para ficar igual ao meu??

Agora se sua dúvida é se você pegar esse seu JSON e colocar no formato que o Zabbix entende, se vai funcionar? Vai sim ;-)

Abraços,

diegaodoidao disse...

Ei andre
boa tarde
meu script esta executando corretamente
e me da o seguinte retorno

zabbix_agentd -t list_zumbi.discovery
list_zumbi.discovery [t|{
"data": [
{
"{#ZOMBIE}": "teste"
}
]
}]

mas no server eu tenho a mensagem
Value should be a JSON object.

pode me ajudar a resolver o problema.
Obrigado desde ja

Robson Américo disse...

Cara, sei que o post é antigo mas faço questão de comentar porque o artigo é foda e acabou de ser muito útil pra mim, parabéns por compartilhar a pesquisa

Sei que o Zabbix tem um timeout de 30 segundos para os itens checados via agent e/ou externalscripts (certo?), como você faria se um dos itens que você precisa checar fosse ultrapassar esse tempo? Quero checar o volume de dados de alguns diretórios gigantes no meu server, e um du -sh ultrapassará fácil esse timeout. Pensei em fazer o du via cron na madrugada, jogar o resultado num arquivo texto e o zabbix apenas consultar este arquivo, seria esta a melhor maneira?

Tiago disse...

Sempre que preciso usar LLD volto nessa postagem.
É excelente a explicação.