Objetivo
Demonstrar como criar plugins de monitoramento para o OpMon.
Público-alvo
Administradores e usuários que desejam criar plugins de monitoração.
Pré-requisitos
- Conhecimento em programação;
- Ter realizado o treinamento básico do OpMon;
- Ter realizado o treinamento avançado do OpMon;
1 – Padrões de Escrita de código (Coding Style | Design Patterns)
1.1 – Padrões de Estilo de Capitalização de Texto
1.1.1 – Camel Case
É uma convenção utilizada para padronizar a escrita de identificadores variáveis, funções, classes e etc. O Camel Case propõe a seguinte regra para identificadores compostos:
A primeira letra do identificador é minúscula e a primeira letra de cada palavra concatenada subsequente deve ser escrita em maiúscula.
Obs.:esta regra não se aplica aos nomes de classes
Ex.: isValid (método/função), numberDaysWeek (variável), Customer (classe)
1.1.2 – Identificadores
A criação de identificadores concisos é o maior desafio do programador. O uso de nomes como A, B ou C é extremamente prejudicial a qualidade do código, pois acaba com a possibilidade de uma leitura ágil e impacta em sua manutenabilidade adicionando complexidade – desnecessária – ao mesmo tempo. Logo, os identificadores devem descrever exatamente o que este faz/armazena.
Exemplos de identificadores válidos para esta regra:getUptime, outputCommand, message, currentTime e etc.
1.1.3 – Constantes
O uso de constantes é muito recomendado para evitar o uso de caracteres que não significam muita coisa para um determinado contexto facilitando a compreensão de um determinado trecho de código. Por padrão todas as letras do identificador devem ser escritas em maiúscula – e separadas por underline (_) caso seja composto – para que sejam diferenciadas das variáveis. Ex.: PI, PATH.
Vejamos um exemplo onde o uso de constantes ajuda a entender qual o propósito de um determinado dado. Suponhamos que ao executar um comando este retorne a seguinte linha:
rootLine = root:x:0:0:root:/root:/bin/bash
Com a linha acima armazenada em um array (vetor) – criado utilizando ‘:’ como separador dos campos -, vamos pegar a informação referente a home do usuário root.
Abaixo serão demonstrados os exemplos errado e certo respectivamente, ambos tem o mesmo resultado, porém vamos primar pela legibilidade do código e não seu resultado.
# Código errado print rootLine[5] output: /root
# Código certo Constant HOME_FIELD = 5 print rootLine[ HOME_FIELD ] output: /root
Como podemos ver, apesar de termos um número maior de linhas, o código fica mais legível e indica claramente qual informação é importante para o contexto.
1.2 – Indentação de Código
Na maioria das linguagens de programação, a indentação é empregada com o objetivo de ressaltar a estrutura do algoritmo, aumentando assim a legibilidade do código. Em algumas linguagens, entretanto, a indentação é obrigatória. Python, Occam e Haskell, por exemplo, utilizam a mudança de indentação para definir a hierarquia dentre blocos de código. (Wikipédia).
A forma mais fácil de indentar o código é através da inserção de tabs no inicio da linha que será indentada, porém a tabulação é identificada de forma diferente entre os editores de texto sendo comum a aparição de erros ao visualizar o mesmo documento em editores diferentes. Afim de minimizarmos as chances de ocorrerem esses erros fica definido a substituição da tabulação por 4 espaços, conforme boas práticas de desenvolvimento descritas no site PEAR.
Configuração do vim para atender o item acima.
No editor, no modo comando, digite set smartindent tabstop=4 shiftwidth=4 softtabstop=4 expandtab[ENTER]
1.3 – O que evitar?
Nesta sessão é descrito o que o programador deve evitar para criar/manter seu código dito como “código de qualidade”.
- Evitar linhas de código com mais de 100 caracteres.Além de ser uma boa prática, utilizar 100 caracteres por linha possibilita uma fácil leitura do código, pois permite visualizá-lo em sua completude nos mais variados editores de texto e IDEs.
- Evitar métodos/funções que necessitem de mais de uma página para sua visualização, o chamado código macarrão.Assim como o item anterior, tem como finalidade facilitar a visualização e leitura do código sem a necessidade de utilizar barras de rolagem para isso.
- Evitar a inclusão de múltiplos níveis de estruturas de controle.Quanto maior a quantidade de estruturas de controle em um mesmo bloco de código maior será a complexidade e menor o entendimento.Segundo Robert C. Martin em seu livro intitulado Clean Code, o aninhamento superior a 3 estruturas de controle não é recomendado e deve ser repensado visando a qualidade do código.
- Identificadores com pouca diferença entre si. Nomes como getTime e getTime2 além não permitir identificar qual a diferença entre os dois ainda pode causar a inserção de bug em tempo de execução pelo uso acidental de uma no lugar da outra.
1.4 – Quebra de linha
Com a quebra de linha o programador pode agrupar em blocos os comandos utilizados para um mesmo fim ajudando na distinção de cada parte do programa.
Exemplos que devem ser seguidos:
1. Quebrar após vírgula
O uso de quebras de linhas após a vírgula ajuda a manter o padrão de 100 caracteres por linha e deve ser utilizado apenas quando este padrão for ferido.
chamarMetodo( param1, param2, param3, param4, param5, param6, param7 );
2. Quebrar antes de um operador
if (test && test && test && test && test) { ...... }
3. Quebra após bloco de códigos com mesmo fim
# Pegar conteúdo da pagina url = urlFactory(host, user, pass) page = getPage(url) # Outro bloco ... # Outro bloco ...
1.5 – Comentários
O uso de comentários é muito importante para entender/relembrar como o código funciona em um momento futuro, porém o excesso acaba prejudicando a leitura do código fonte. É importante evitar aqueles obvios, como o descrito no exemplo abaixo e que mais atrapalham do que ajudam na hora da manutenção do programa.
Ex.:
# Se o hash for gerado entra no if if (generateHash){ ... } else { // se não entra no else ... }
Abaixo podemos ver a estrutura padrão de comentários nos scripts. Todos os scripts que forem desenvolvidos/melhorados devem ser adequados a este.
#! ################################################################################## # Cabeçalho ################################################################################## # TICKET: # AUTOR: # CRIADO EM: 13/07/2013 14:01:12 # # REVISÕES: # -------------------------------------------------------------- # <versão> , # - <Descrição das modificações> # # ################################################################################## # Breve descrição do que o metodo/função faz respeitando o limite de 80 caracteres # @link # @param # @param # @return <descrição do retorno> ################################################################################## function getDiffTimeInSeconds(param1, param2) { ... codigo return } # vim: set smartindent tabstop=4 shiftwidth=4 softtabstop=4 expandtab #
Obs.: lembrando que o caracter de comentário pode variar conforme a linguagem utilizada
1.6 – Parâmetros
Como os plugins serão executados em sua maioria na console do OpMon, esses receberão as informações necessárias para a execução via parâmetro da linha de comando. No Nagios Plugins Development Guidelines podemos encontrar, na sessão Option Processing, algumas das nomenclaturas de parâmetros reservadas e que não devem ser utilizadas para outro fim senão o descrito no guia.
Visando facilitar o uso dos plugins desenvolvidos na OpServices, todos os plugins que forem desenvolvidos precisam, obrigatoriamente, possuir os seguintes parâmetros:
-v | –verbose => Possibilita o debug do código sem precisar lê-lo.
-h | –help => Exibe informações acerca dos parâmetros suportados, breve descrição do que o plugin faz, Site da empresa, e o usage.
-? | –usage => Deve exibir o usage (forma simples de uso) do plugin
-V | –version => Exibe a versão do plugin
–man => Exibe o manual completo do plugin.
–perfdata => Quando setado deve exibir os dados de performance (Quando aplicável)
Obs.: caso sejam determinado valores de warning e critical o plugin deve, obrigatoriamente, apresentar os dados de performance.
O manual do plugin deverá conter todas as informações relevantes quanto ao seu funcionamento. Essas informações devem responder as seguintes perguntas:
- Quais são as dependências? Como instalá-las?
- Como instalar o plugin? Caso necessário.
- De onde o plugin recebe os dados?
- Quais os retornos possíveis? (listar todos)
- Quais as formas possíveis de utilização? (listar todas)
1.7 – Estrutura básica
#!/bin/bash ####################################################################### # Cabeçalho ####################################################################### # TICKET: # AUTOR: # CRIADO EM: # # REVISÕES: # -------------------------------------------------------------- # <versão> , # - <Descrição das modificações> # <Modulos, caso exista> Constant VERSION 1.0 <Variáveis globais, caso exista> ####################################################################### # Exibir o manual do software ####################################################################### function getGuideLine { ... Manual do plugin escrito em português exit; } ####################################################################### # Seta os atributos da variável global $np ####################################################################### DESNECESSÁRIO EM LINGUAGENS QUE NÃO POSSUI API DO NAGIOS PLUGINS function setNagios { ... Codigo para definir as configurações do nagios } <Funções diversas para solucionar o problema> function main { ... } main
A seguir serão apresentados os templates para as linguagens PERL, PHP, SHELLSCRIPT, porém pode ser estendido para outras linguagens com a devida adaptação.
- Plugins escritos em PERL devem seguir os padrões do arquivo: template.pl
Dica: Plugins perl podem utilizar a biblioteca utils.pm, localizada no OpMon no diretório: /var/local/opmon/libexec/utils.pm - Plugins escritos em PHP devem seguir os padrões do arquivo: template.php
Dica: Plugins php podem utilizar a biblioteca Nagios_Plugins.php, localizada no OpMon no diretório: /var/local/opmon/libexec/php-nagios-plugins/Nagios_Plugin.php - Plugins escritos em SHELLSCRIPT devem seguir os padrões do arquivo: template.sh
2 – O desenvolvimento
- Aqui devemos ter as informações do autor, data de criação e revisões do plugin. Também criamos aqui as variáves do tipo read_only, que não sofrem alteração durante a execução do plugin.
- Função responsável por exibir o manual do plugin durante a sua execução na linha de comando:
- Função responsável por exibir as orientações de como deve-se passar os paramêtros para o plugin:
- Função responsável por gerar a versão do plugin e exibir dinamicamente o nome do plugin, quando o mesmo for executado por linha de comando:
- Aqui nesta função, são exibidos todos os parâmetros utilizados no plugin e o tipo de cada um (string, number, etc)
- Aqui as variáveis são definidas de acordo com os parâmetros informados para o plugin
- Aqui é onde a mágica acontece, bloco lógico responsável por gerar, capturar o valor que será exibido pelo plugin.
- Nesta parte do código, o número gerado na função getRandonNumber é comparado com os thresholds informados, gerando o exit_code que será informado para o OpMon.
- A rotina principal do programa, que é responsável por informar ao OpMon o número gerado e o exit_code.
3 – Exemplos de execução
- Exemplo do retorno do help do plugin:
- Exemplo de exbição do manual do plugin:
- Exemplo do resultado exibido pelo plugin, com a opção verbose: