Compare commits
4 Commits
825f42d951
...
c61ea544aa
| Author | SHA1 | Date |
|---|---|---|
|
|
c61ea544aa | |
|
|
033347b005 | |
|
|
be2867ecd6 | |
|
|
b4a56ed604 |
|
|
@ -1,457 +0,0 @@
|
|||
Arquitetura Técnica e Engenharia de Templates Zabbix 7.0 via YAML
|
||||
1. Introdução: A Mudança de Paradigma para Configuração como Código
|
||||
A evolução das plataformas de observabilidade de nível empresarial atingiu um ponto de inflexão com o lançamento do Zabbix 7.0 LTS. Esta versão não representa apenas um incremento funcional, mas consolida uma mudança fundamental na gestão de configurações: a transição de uma administração baseada em interface gráfica (GUI) e banco de dados para uma metodologia de "Monitoramento como Código" (MaC). Central para essa transição é a padronização do formato YAML (Yet Another Markup Language) como o meio primário para definição, exportação e versionamento de templates.1
|
||||
Historicamente, a engenharia de monitoramento no Zabbix dependia de arquivos XML verbosos ou manipulação direta via frontend, métodos que dificultavam a integração com pipelines modernos de CI/CD e práticas de GitOps. O XML, embora estruturado, carecia de legibilidade humana e facilidade de edição manual, tornando a revisão de código e a detecção de diferenças (diffs) processos árduos. Com o Zabbix 7.0, a estrutura YAML atinge um nível de maturidade que permite aos arquitetos de sistemas e engenheiros de DevOps escrever templates complexos "do zero", dissociando a lógica de monitoramento da instância do servidor.3
|
||||
Este relatório técnico oferece uma análise exaustiva da engenharia de templates Zabbix 7.0 em YAML. Exploraremos não apenas a sintaxe, mas as implicações arquiteturais da gestão de UUIDs, a mecânica intrínseca da coleta nativa do Zabbix Agent 2, os fundamentos matemáticos dos triggers preditivos e a integração de camadas de visualização diretamente no código do template. O domínio destes elementos é essencial para construir pipelines de observabilidade resilientes, portáveis e escaláveis.
|
||||
________________
|
||||
2. Fundamentos Arquiteturais do Schema YAML no Zabbix 7.0
|
||||
A construção de um template YAML válido exige uma compreensão profunda do schema que o rege. Diferente de formatos de configuração livres, o Zabbix impõe uma hierarquia estrita que deve ser respeitada para garantir a integridade referencial durante a importação.
|
||||
2.1 A Estrutura Raiz e Controle de Versionamento
|
||||
O documento YAML começa com o nó raiz zabbix_export, que atua como o namespace global para o arquivo. Imediatamente subordinado a ele, encontra-se o parâmetro version. Para o Zabbix 7.0, este valor deve ser explicitamente declarado como 7.0. O parser de importação do Zabbix utiliza este campo para determinar quais conversores de banco de dados aplicar. Embora o servidor Zabbix possua compatibilidade retroativa (permitindo a importação de templates 6.0, por exemplo), a criação de um template novo deve aderir estritamente à versão 7.0 para desbloquear recursos modernos como widgets avançados e novos tipos de item.1
|
||||
Uma distinção crítica introduzida nas versões recentes e solidificada na 7.0 é a separação entre grupos de templates e grupos de hosts. Anteriormente, ambos compartilhavam a entidade groups. No schema 7.0, é obrigatório definir template_groups na raiz para a organização lógica dos templates. Falhar em distinguir isso pode resultar em erros de validação ou na criação de templates "órfãos" no frontend.
|
||||
Estrutura Raiz Canônica:
|
||||
|
||||
|
||||
YAML
|
||||
|
||||
|
||||
|
||||
|
||||
zabbix_export:
|
||||
version: '7.0'
|
||||
template_groups:
|
||||
- uuid: a571c0d144b14fd4a87a9d9b2aa9fcd6
|
||||
name: Templates/Applications
|
||||
templates:
|
||||
- uuid:...
|
||||
|
||||
A indentação e a estrutura de lista (hífen -) são cruciais. O Zabbix utiliza um parser YAML estrito; erros de indentação ou mistura de tabs e espaços invalidarão o arquivo inteiro.3
|
||||
2.2 O Imperativo do UUID: Estabilidade em GitOps
|
||||
Um dos desafios mais profundos na criação manual de templates é a gestão de Identificadores Únicos Universais (UUIDs). No banco de dados relacional do Zabbix (seja PostgreSQL ou MySQL), as entidades são ligadas por IDs inteiros sequenciais (itemid, triggerid). No entanto, esses IDs são efêmeros e específicos da instância. Ao exportar um template, o Zabbix substitui essas chaves primárias por UUIDs de 32 caracteres hexadecimais para garantir a portabilidade.5
|
||||
Quando um engenheiro assume a autoria do YAML, ele se torna responsável pela geração e manutenção desses identificadores. A regra cardinal do desenvolvimento de templates em YAML é: A persistência do UUID é sagrada.
|
||||
2.2.1 Consequências da Instabilidade do UUID
|
||||
Considere um cenário de fluxo de trabalho GitOps:
|
||||
1. Um item "Carga de CPU" é criado no YAML com um UUID aleatório ($UUID_A$).
|
||||
2. O template é importado para o Zabbix, que cria o registro no banco de dados e começa a coletar dados históricos vinculados a esse item.
|
||||
3. O engenheiro edita o YAML para ajustar o intervalo de coleta, mas, por descuido ou uso de um gerador automático, altera o UUID para ($UUID_B$).
|
||||
4. Ao reimportar, o Zabbix interpreta a mudança não como uma atualização, mas como duas operações atômicas: a exclusão do item associado a $UUID_A$ (e consequente perda de todo o histórico de dados) e a criação de um novo item associado a $UUID_B$.
|
||||
Esta "rotatividade" de UUIDs destrói a continuidade dos dados, inviabilizando análises de tendência de longo prazo (SLA). Portanto, ao criar templates do zero, deve-se gerar UUIDs criptograficamente seguros uma única vez e mantê-los estáticos durante todo o ciclo de vida do template.5
|
||||
2.2.2 Algoritmos de Geração e Prevenção de Colisão
|
||||
O Zabbix espera uma string hexadecimal de 32 caracteres. Embora o formato padrão UUID v4 inclua hifens (ex: 550e8400-e29b-41d4-a716-446655440000), o schema de exportação do Zabbix frequentemente os remove ou normaliza. Para máxima compatibilidade e adesão ao padrão visual dos templates oficiais, recomenda-se o uso de strings de 32 caracteres minúsculas.
|
||||
Metodologia de Geração para Autores:
|
||||
Engenheiros não devem tentar "inventar" UUIDs manualmente (ex: 111111...), pois isso aumenta o risco de colisões globais, especialmente se o template for compartilhado publicamente ou importado em ambientes com múltiplos servidores. Deve-se utilizar ferramentas de linha de comando ou scripts para gerar blocos de identificadores:
|
||||
|
||||
|
||||
Bash
|
||||
|
||||
|
||||
|
||||
|
||||
# Exemplo de geração segura em shell UNIX
|
||||
uuidgen | tr -d '-' | tr '[:upper:]' '[:lower:]'
|
||||
|
||||
No arquivo YAML, o campo uuid é obrigatório para o objeto template principal e crítico para todas as subentidades (itens, triggers, regras de descoberta) para permitir diffs precisos e atualizações idempotentes.5
|
||||
________________
|
||||
3. Estratégia de Aquisição de Dados: O Poder dos Itens Nativos
|
||||
A eficiência de uma plataforma de monitoramento é definida pela razão entre a utilidade da informação coletada e o custo computacional de sua coleta. O Zabbix 7.0 suporta múltiplos tipos de itens, mas a ênfase em itens nativos ("baked-in") do Zabbix Agent e Agent 2 é fundamental para desempenho e segurança. Itens nativos são executados diretamente pelo binário do agente, sem a sobrecarga de criar novos processos (forking), invocar shells ou interpretar scripts externos, o que é comum em UserParameters ou system.run.7
|
||||
3.1 O Namespace system: Telemetria do Sistema Operacional
|
||||
O namespace system fornece as métricas fundacionais de saúde do SO. No YAML, a definição precisa destes itens exige atenção aos tipos de dados e unidades.
|
||||
3.1.1 Discrepâncias de CPU: Carga vs. Utilização
|
||||
Um template robusto deve distinguir claramente entre system.cpu.load e system.cpu.util.
|
||||
* system.cpu.load[all,avg1]: Mede o tamanho da fila de execução do processador. É um valor adimensional e ilimitado. Em sistemas Linux, este valor inclui processos em estado "uninterruptible sleep" (geralmente aguardando I/O de disco). Portanto, uma alta carga de CPU pode, na verdade, diagnosticar um gargalo de armazenamento.
|
||||
* system.cpu.util[all,user,avg1]: Mede a porcentagem de tempo que a CPU gastou em contextos específicos.
|
||||
Implementação YAML Exemplar:
|
||||
|
||||
|
||||
YAML
|
||||
|
||||
|
||||
|
||||
|
||||
- uuid: 73e56303244c41499553641753755375
|
||||
name: 'CPU I/O Wait time'
|
||||
type: ZABBIX_ACTIVE
|
||||
key: 'system.cpu.util[all,iowait,avg1]'
|
||||
history: 7d
|
||||
value_type: FLOAT
|
||||
units: '%'
|
||||
description: 'Tempo gasto pela CPU aguardando a conclusão de operações de I/O.'
|
||||
tags:
|
||||
- tag: component
|
||||
value: cpu
|
||||
|
||||
Observe o uso de ZABBIX_ACTIVE. Em ambientes modernos de nuvem e contêineres, agentes ativos são preferíveis pois iniciam a conexão com o servidor (ou proxy), facilitando a configuração de firewalls e NATs, além de permitir o buffer de dados em caso de desconexão.8
|
||||
3.1.2 Memória: A Hierarquia vm.memory
|
||||
A chave vm.memory.size é polimórfica.
|
||||
* vm.memory.size[available]: Esta é a métrica crítica para alertas. No Linux, ela não é apenas a memória livre, mas uma estimativa da memória disponível para iniciar novas aplicações sem swapping (calculada aproximadamente como free + buffers + cached).
|
||||
* vm.memory.size[total]: Dado estático, útil para inventário e cálculos de porcentagem.
|
||||
Não é necessário armazenar a porcentagem de memória como um item coletado se você já coleta available e total. O Zabbix pode calcular isso dinamicamente em gráficos ou triggers. No entanto, para relatórios de longo prazo (SLA), um Item Calculado (discutido na Seção 4) pode ser criado no template para armazenar o valor percentual explicitamente.9
|
||||
3.2 O Namespace vfs: Engenharia de Sistemas de Arquivos
|
||||
O monitoramento de armazenamento evoluiu. Verificar apenas o espaço livre é insuficiente em sistemas com filesystems virtuais, montagens bind e contêineres.
|
||||
3.2.1 Descoberta Dinâmica: vfs.fs.discovery
|
||||
Definições estáticas de partições (como / ou /home) são obsoletas e frágeis. O uso da chave vfs.fs.discovery é mandatório para templates portáveis. Esta chave retorna um JSON contendo macros LLD como {#FSNAME} e {#FSTYPE}.
|
||||
Estratégia de Filtragem no YAML:
|
||||
O YAML deve definir filtros rigorosos na regra de descoberta para evitar o monitoramento de pseudo-filesystems (tmpfs, overlay, sysfs), que geram ruído e alertas falsos.
|
||||
|
||||
|
||||
YAML
|
||||
|
||||
|
||||
|
||||
|
||||
discovery_rules:
|
||||
- uuid: 88746067727448849764761405822606
|
||||
name: 'Descoberta de Sistemas de Arquivos'
|
||||
key: vfs.fs.discovery
|
||||
delay: 1h
|
||||
filter:
|
||||
evaltype: AND
|
||||
conditions:
|
||||
- macro: '{#FSTYPE}'
|
||||
value: 'ext|xfs|btrfs|zfs'
|
||||
operator: MATCHES_REGEX
|
||||
item_prototypes:
|
||||
- uuid: 5b4c4091572c4146a896684784918491
|
||||
name: 'Espaço livre em {#FSNAME}'
|
||||
key: 'vfs.fs.size'
|
||||
|
||||
3.2.2 Esgotamento de Inodes
|
||||
Um cenário comum de falha catastrófica é o esgotamento de inodes (muitos arquivos pequenos) enquanto o espaço em disco permanece abundante. A chave vfs.fs.inode deve ser pareada com cada verificação de espaço em disco nos protótipos de itens.9
|
||||
3.3 O Namespace net: Telemetria de Interface
|
||||
A chave net.if.discovery alimenta o monitoramento de interfaces de rede.
|
||||
* Tráfego: net.if.in[{#IFNAME}] e net.if.out[{#IFNAME}].
|
||||
* Preprocessing para Contadores: Contadores de rede são monotonicamente crescentes. O servidor Zabbix deve calcular o delta entre as coletas. No YAML, o passo de pré-processamento "Change per second" é obrigatório aqui. O Zabbix Agent 2 lida automaticamente com o overflow de contadores (32-bit vs 64-bit), mas a configuração correta do pré-processamento no template garante que resets de contadores (reboot do switch/servidor) sejam tratados sem gerar picos de dados absurdos (spikes).10
|
||||
3.4 Zabbix Agent 2: Plugins Nativos e Coleta Assíncrona
|
||||
O Zabbix Agent 2, escrito em Go, introduz uma arquitetura de plugins que permite a coleta de métricas complexas que anteriormente exigiam scripts externos ou binários adicionais. Ao criar templates para o Agent 2, o engenheiro pode utilizar chaves exclusivas que se comunicam diretamente com APIs ou sockets.8
|
||||
3.4.1 Docker Nativo (docker.*)
|
||||
Anteriormente, monitorar Docker exigia adicionar o usuário zabbix ao grupo docker e scripts Python/Bash. O Agent 2 possui um plugin Docker nativo que fala diretamente com o socket do Docker API.
|
||||
Exemplo de Chaves Nativas no YAML:
|
||||
* docker.container_info[{#NAME}]: Retorna JSON com estado detalhado.
|
||||
* docker.container_stats[{#NAME}]: Estatísticas de recursos em tempo real.
|
||||
|
||||
|
||||
YAML
|
||||
|
||||
|
||||
|
||||
|
||||
- uuid: <UUID>
|
||||
name: 'Docker: Quantidade de containers rodando'
|
||||
key: 'docker.containers[,,running]'
|
||||
type: ZABBIX_ACTIVE
|
||||
|
||||
O uso destas chaves reduz a latência de coleta e elimina dependências de scripts no host monitorado.11
|
||||
3.4.2 Certificados Web (web.certificate)
|
||||
Outro recurso poderoso "baked-in" do Agent 2 é a capacidade de verificar datas de validade de certificados SSL/TLS sem invocar o OpenSSL via shell.
|
||||
* Chave: web.certificate.get[<website>,<port>,<ip>]
|
||||
* Retorno: Um JSON contendo x509, datas de expiração, emissor, etc.
|
||||
Isso permite criar um item dependente com pré-processamento JSONPath para extrair a data de expiração e um trigger preditivo para alertar 15 dias antes.13
|
||||
________________
|
||||
4. A Camada de Transformação: Pré-processamento e Itens Calculados
|
||||
A "inteligência" de um template moderno reside na sua capacidade de transformar dados brutos em informação acionável antes mesmo de serem gravados no banco de dados.
|
||||
4.1 Pré-processamento: O Pipeline ETL do Zabbix
|
||||
O pré-processamento permite a aplicação de lógica de transformação sequencial. No schema YAML, isso é definido como uma lista de objetos preprocessing.
|
||||
4.1.1 Descarte de Dados Inalterados (Throttling)
|
||||
Para itens de configuração ou inventário (ex: system.uname, system.sw.os, números de série), gravar o mesmo valor string a cada minuto é um desperdício massivo de I/O de banco de dados e armazenamento.
|
||||
Estratégia YAML:
|
||||
Utilize DISCARD_UNCHANGED_HEARTBEAT. Isso instrui o servidor a descartar o valor se ele for idêntico ao anterior, mas gravar forçadamente uma vez a cada período (heartbeat) para confirmar que o item ainda está ativo.
|
||||
|
||||
|
||||
YAML
|
||||
|
||||
|
||||
|
||||
|
||||
preprocessing:
|
||||
- type: DISCARD_UNCHANGED_HEARTBEAT
|
||||
parameters:
|
||||
- 1d # Grava pelo menos uma vez por dia
|
||||
|
||||
Isso reduz a tabela de histórico em ordens de magnitude para métricas estáticas.10
|
||||
4.1.2 Multiplicadores Personalizados e Conversão de Unidades
|
||||
O Zabbix opera nativamente em unidades base (Bytes, Segundos). Se um dispositivo ou API retorna valores em Kilobytes (KB) ou Milissegundos (ms), eles devem ser normalizados no pré-processamento.
|
||||
* Exemplo: Memória retornada em KB.
|
||||
* YAML:
|
||||
YAML
|
||||
preprocessing:
|
||||
- type: MULTIPLIER
|
||||
parameters:
|
||||
- '1024' # Converte KB para Bytes
|
||||
|
||||
Isso garante que os sufixos automáticos do frontend (MB, GB, TB) funcionem corretamente.10
|
||||
4.1.3 Expressões Regulares (Regex) para Extração
|
||||
Para extrair versões de software de strings complexas, o pré-processamento REGEX é vital.
|
||||
* Tipo: REGEX
|
||||
* Parâmetros: padrão, saída.
|
||||
* Uso: Extrair "7.0.5" de "Zabbix Agent 7.0.5 (revision 123)".
|
||||
|
||||
|
||||
YAML
|
||||
|
||||
|
||||
|
||||
|
||||
preprocessing:
|
||||
- type: REGEX
|
||||
parameters:
|
||||
- '([0-9]+\.[0-9]+\.[0-9]+)'
|
||||
- '\1'
|
||||
|
||||
Isso limpa os dados para relatórios de inventário.14
|
||||
4.2 Itens Dependentes: Otimização de Polling
|
||||
Para extrair múltiplas métricas de uma única fonte rica (como um JSON de status do Apache ou a saída de docker.info), não se deve consultar a fonte múltiplas vezes. A arquitetura correta utiliza um Item Mestre e Itens Dependentes.
|
||||
Fluxo de Configuração no YAML:
|
||||
1. Item Mestre: Coleta o JSON bruto.
|
||||
* type: ZABBIX_AGENT (ou HTTP_AGENT).
|
||||
* history: 0 (Se o JSON bruto for muito grande e não for necessário armazená-lo, apenas processá-lo).
|
||||
2. Item Dependente:
|
||||
* type: DEPENDENT.
|
||||
* master_item: Referencia a chave do item mestre.
|
||||
* preprocessing: Usa JSONPATH para extrair o campo específico.
|
||||
Exemplo Prático (Conexões Nginx):
|
||||
Item Mestre coleta http://localhost/status. Item Dependente "Active Connections" usa JSONPath $.active. Isso reduz a carga HTTP no serviço monitorado de N requisições para 1 requisição por ciclo.3
|
||||
4.3 Itens Calculados: Métricas Virtuais
|
||||
Itens calculados derivam valores de outros itens existentes, executando a lógica no Zabbix Server. Eles são essenciais para agregar dados ou normalizar percentuais quando o dispositivo não fornece essa métrica diretamente.
|
||||
Sintaxe da Fórmula no YAML:
|
||||
A fórmula utiliza a sintaxe funcional func(/host/key, param). No contexto de templates, o host é frequentemente omitido (//key) para indicar "o host atual onde o template está aplicado".
|
||||
Tabela de Funções Comuns para Itens Calculados:
|
||||
Função
|
||||
Descrição
|
||||
Exemplo de Fórmula
|
||||
last
|
||||
Último valor coletado
|
||||
100 * (last(//vm.memory.size[used]) / last(//vm.memory.size[total]))
|
||||
avg
|
||||
Média em um período
|
||||
avg(//net.if.in[eth0], 1h)
|
||||
sum
|
||||
Soma de múltiplos itens
|
||||
last(//net.if.in[eth0]) + last(//net.if.out[eth0])
|
||||
Implementação YAML:
|
||||
|
||||
|
||||
YAML
|
||||
|
||||
|
||||
|
||||
|
||||
- uuid: <UUID>
|
||||
name: 'Utilização Total de Memória (%)'
|
||||
type: CALCULATED
|
||||
key: 'vm.memory.utilization_calc'
|
||||
params: '100 * last(//vm.memory.size[used]) / last(//vm.memory.size[total])'
|
||||
units: '%'
|
||||
value_type: FLOAT
|
||||
|
||||
Nota: O campo params no YAML armazena a fórmula matemática.16
|
||||
________________
|
||||
5. Engenharia de Eventos Avançada: Triggers e Predição
|
||||
O motor de triggers do Zabbix 7.0 transcende a simples verificação de limiares (last() > N). Com funções de tendência e preditivas, é possível criar alertas que avisam antes que o problema ocorra ou que analisam anomalias baseadas em comportamento histórico.
|
||||
5.1 Funções de Tendência (Trend functions)
|
||||
O Zabbix mantém duas tabelas principais de dados: history (dados brutos, retidos por curto prazo, ex: 7 dias) e trends (médias/máximos/mínimos horários, retidos por longo prazo, ex: 1 ano).
|
||||
Funções normais como avg(1M) tentariam ler milhões de linhas da tabela history, o que é performaticamente inviável. As funções de tendência (trendavg, trendmax, trendmin) acessam a tabela trends, permitindo cálculos leves sobre períodos longos.17
|
||||
Cenário de Uso: Detecção de Anomalia de Linha de Base.
|
||||
"Alertar se a carga de CPU atual for 50% maior que a média da mesma hora na semana passada."
|
||||
Expressão no YAML:
|
||||
|
||||
|
||||
YAML
|
||||
|
||||
|
||||
|
||||
|
||||
expression: 'last(/host/system.cpu.load) > 1.5 * trendavg(/host/system.cpu.load, 1h:now-1w)'
|
||||
|
||||
* 1h:now-1w: Esta sintaxe de deslocamento temporal (time shift) instrui o Zabbix a olhar para uma janela de 1 hora, mas deslocada 1 semana para o passado.
|
||||
* Insight de Segunda Ordem: O uso de funções de tendência é ideal para monitoramento de capacidade e desvios de padrão (SLA), mas elas são avaliadas com menos frequência (geralmente a cada hora, coincidindo com a geração da tendência) ou quando o item recebe dados, dependendo da configuração. Elas não substituem alertas de tempo real.17
|
||||
5.2 Funções Preditivas: timeleft e forecast
|
||||
Estas funções aplicam modelos matemáticos (regressão linear ou polinomial) aos dados históricos para projetar valores futuros.
|
||||
5.2.1 timeleft: O Cronômetro para a Falha
|
||||
A função timeleft(/host/key, period, threshold) calcula quantos segundos restam até que o item atinja o threshold, baseando-se na taxa de variação durante o period.
|
||||
Aplicação Crítica: Planejamento de Capacidade de Disco.
|
||||
Em vez de alertar quando o disco está 95% cheio (o que pode ser tarde demais se a taxa de gravação for alta), alertamos quando o tempo restante para 0% livre for menor que um intervalo de segurança.
|
||||
Expressão YAML e Tratamento de Erros:
|
||||
|
||||
|
||||
YAML
|
||||
|
||||
|
||||
|
||||
|
||||
expression: 'timeleft(/host/vfs.fs.size[/,free],1h,0) < 3h'
|
||||
|
||||
* O Problema do -1: Se o disco estiver sendo esvaziado ou estiver estático, a regressão linear nunca interceptará o zero no futuro. Nesses casos, a função retorna números extremamente grandes (indicando infinito) ou códigos de erro específicos dependendo da versão (1.79E+308 no Zabbix 7.0 para "sem intersecção").
|
||||
* Robustez: A expressão deve ser composta para evitar falsos positivos se a previsão for irrelevante. No entanto, para alertas de "falta de espaço iminente", a condição simples < 3h é geralmente segura porque valores de erro/infinito serão maiores que 3h (10800 segundos).18
|
||||
5.2.2 forecast: Previsão de Valor
|
||||
A função forecast(/host/key, period, time) retorna qual será o valor do item daqui a time segundos.
|
||||
Cenário: A temperatura do servidor atingirá níveis críticos na próxima hora?
|
||||
Expressão: forecast(/host/sensor.temp, 30m, 1h) > 80
|
||||
Isso permite ações preventivas (como ligar ventilação auxiliar) antes que o incidente de superaquecimento ocorra.
|
||||
Sintaxe e Escaping no YAML:
|
||||
Ao escrever expressões de trigger complexas no YAML, cuidado especial deve ser tomado com as aspas. Se a chave do item contém colchetes e aspas (ex: tags LLD), a string inteira da expressão deve ser encapsulada corretamente.
|
||||
|
||||
|
||||
YAML
|
||||
|
||||
|
||||
|
||||
|
||||
triggers:
|
||||
- uuid: <UUID>
|
||||
expression: 'timeleft(/host/vfs.fs.size,1h,0)<1h'
|
||||
name: 'O disco {#FSNAME} ficará cheio em menos de 1 hora'
|
||||
priority: HIGH
|
||||
|
||||
________________
|
||||
6. Visualização como Código: Dashboards em Templates
|
||||
O Zabbix 7.0 permite que dashboards sejam definidos dentro do próprio template. Quando o template é vinculado a um host, o dashboard torna-se disponível no contexto desse host, preenchido automaticamente com os dados dele. Isso é um recurso poderoso para padronização visual.7
|
||||
6.1 Estrutura do Objeto Dashboard no YAML
|
||||
O elemento dashboards reside na raiz do objeto template. A estrutura é hierárquica: Dashboard -> Pages -> Widgets -> Fields.
|
||||
Desafio de Mapeamento de Campos:
|
||||
A configuração de widgets no YAML não usa nomes de parâmetros amigáveis, mas uma estrutura genérica de fields contendo pares nome-valor.
|
||||
Exemplo de Configuração de Widget Gráfico:
|
||||
|
||||
|
||||
YAML
|
||||
|
||||
|
||||
|
||||
|
||||
dashboards:
|
||||
- uuid: <UUID>
|
||||
name: 'Performance do Sistema'
|
||||
pages:
|
||||
- widgets:
|
||||
- type: graph
|
||||
name: 'Carga de CPU'
|
||||
width: 12
|
||||
height: 5
|
||||
fields:
|
||||
- type: GRAPH
|
||||
name: graphid
|
||||
value: 0 # 0 indica criação dinâmica ou referência interna
|
||||
- type: ITEM
|
||||
name: itemid
|
||||
value: 'system.cpu.load[all,avg1]' # Referência pela CHAVE
|
||||
|
||||
Nota Crítica sobre Referências:
|
||||
Em um dashboard global exportado, o campo value para um itemid seria um número inteiro (o ID do banco de dados). Em um Template Dashboard, a referência deve ser feita pela CHAVE do item (key), pois o ID do item ainda não existe no momento da importação em um novo host. O Zabbix resolve essa referência dinamicamente.20
|
||||
6.2 Novos Widgets do Zabbix 7.0
|
||||
O Zabbix 7.0 introduz widgets modernos como o Honeycomb e o Gauge, que oferecem visualizações mais densas e interativas.
|
||||
* Honeycomb (Favo de Mel): Ideal para visualizar grupos de itens (como todos os núcleos de CPU ou todos os filesystems descobertos via LLD) com mudança de cor baseada em limiares. No YAML, sua configuração envolve definir os item_patterns e as regras de thresholds.
|
||||
* Gauge (Manômetro): Perfeito para itens percentuais únicos (ex: vm.memory.utilization).
|
||||
Incluir esses widgets no template YAML garante que, ao implantar o monitoramento, a equipe de operações tenha visualização imediata sem configuração manual extra.
|
||||
________________
|
||||
7. Taxonomia e Governança: Tags e Alertas
|
||||
O sistema de Tags (etiquetas) no Zabbix 7.0 substitui completamente o antigo conceito de "Applications". As tags são pares chave-valor que permitem uma categorização multidimensional, essencial para filtragem de alertas, correlação de eventos e relatórios gerenciais.3
|
||||
7.1 Estratégia de Tagging para Relatórios Úteis
|
||||
Para que os relatórios (SLA, Top 100 Triggers) sejam úteis, as tags devem seguir uma taxonomia rigorosa definida no template.
|
||||
Níveis de Tagging no YAML:
|
||||
1. Tags de Template: Aplicadas a todos os hosts que usam o template.
|
||||
* target: os, class: linux.
|
||||
2. Tags de Item: Classificam a métrica.
|
||||
* component: cpu, component: memory, layer: hardware.
|
||||
3. Tags de Trigger: Classificam o incidente.
|
||||
* scope: availability, scope: performance, security: cve.
|
||||
Integração com Alertas (Actions):
|
||||
As "Ações" do Zabbix podem ser configuradas para rotear alertas com base nessas tags.
|
||||
* Regra de Ação: "Se Tag component igual a database E Tag severity igual a High -> Enviar para Equipe de DBA".
|
||||
* Benefício: Ao definir essas tags no Template YAML, você garante que qualquer novo host monitorado já nasça integrado corretamente às políticas de roteamento de incidentes da empresa, sem configuração manual na ação.
|
||||
Exemplo YAML de Trigger com Tags:
|
||||
|
||||
|
||||
YAML
|
||||
|
||||
|
||||
|
||||
|
||||
tags:
|
||||
- tag: scope
|
||||
value: capacity
|
||||
- tag: service
|
||||
value: storage
|
||||
|
||||
________________
|
||||
8. Guia Passo a Passo: Construindo o Template Mestre
|
||||
Sintetizando os conceitos, apresentamos o fluxo lógico para a construção do arquivo.
|
||||
8.1 Passo 1: O Cabeçalho e Grupos
|
||||
Defina o arquivo UTF-8. Declare version: '7.0'. Crie o template_group obrigatório (ex: Templates/Operating Systems).
|
||||
8.2 Passo 2: Definição dos Itens Nativos
|
||||
Liste os itens do Agent 2 (docker, system). Aplique UUIDs gerados externamente. Configure o preprocessing para conversão de unidades (Multiplier) e descarte de duplicatas (Discard unchanged).
|
||||
8.3 Passo 3: Regras de Descoberta (LLD)
|
||||
Configure vfs.fs.discovery e net.if.discovery. Crie os item_prototypes e, crucialmente, os trigger_prototypes preditivos (timeleft) para cada entidade descoberta. Utilize tags dinâmicas nos protótipos (ex: filesystem: {#FSNAME}).
|
||||
8.4 Passo 4: Dashboards e Visualização
|
||||
Insira o bloco dashboards referenciando as chaves dos itens criados. Configure um widget Honeycomb para exibir o status de todos os filesystems descobertos.
|
||||
8.5 Exemplo de Artefato YAML (Trecho Consolidado)
|
||||
|
||||
|
||||
YAML
|
||||
|
||||
|
||||
|
||||
|
||||
zabbix_export:
|
||||
version: '7.0'
|
||||
template_groups:
|
||||
- uuid: 576c953372c8427aa214271822762276
|
||||
name: 'Templates/OS'
|
||||
templates:
|
||||
- uuid: 91409940733543169822606822606822
|
||||
template: 'Linux Agent 2 Native'
|
||||
name: 'Linux Agent 2 Native'
|
||||
groups:
|
||||
- name: 'Templates/OS'
|
||||
items:
|
||||
- uuid: 12519512951295129512951295129512
|
||||
name: 'Memória Disponível'
|
||||
key: 'vm.memory.size[available]'
|
||||
units: B
|
||||
preprocessing:
|
||||
- type: DISCARD_UNCHANGED_HEARTBEAT
|
||||
parameters:
|
||||
- 10m
|
||||
tags:
|
||||
- tag: component
|
||||
value: memory
|
||||
discovery_rules:
|
||||
- uuid: 61261261261261261261261261261261
|
||||
name: 'Descoberta de FS'
|
||||
key: vfs.fs.discovery
|
||||
filter:
|
||||
evaltype: AND
|
||||
conditions:
|
||||
- macro: '{#FSTYPE}'
|
||||
value: 'ext|xfs'
|
||||
operator: MATCHES_REGEX
|
||||
trigger_prototypes:
|
||||
- uuid: 73473473473473473473473473473473
|
||||
expression: 'timeleft(/host/vfs.fs.size,1h,0)<1h'
|
||||
name: 'Disco {#FSNAME} saturando em < 1h'
|
||||
priority: HIGH
|
||||
tags:
|
||||
- tag: scope
|
||||
value: capacity
|
||||
|
||||
9. Conclusão
|
||||
A engenharia de templates Zabbix 7.0 em YAML exige uma mudança de mentalidade: de operador de interface para arquiteto de código. A adesão estrita às regras de persistência de UUID garante a integridade histórica dos dados. O uso preferencial de itens nativos do Agent 2 e a aplicação de pré-processamento inteligente (Master/Dependent items) otimizam o desempenho da coleta. Finalmente, a incorporação de funções preditivas e dashboards no código do template eleva o nível de maturidade do monitoramento, transformando dados reativos em inteligência proativa. Este relatório serve como a base técnica para a implementação de pipelines de observabilidade modernos e escaláveis no ecossistema Zabbix.
|
||||
Referências citadas
|
||||
1. 3 Templates - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/data_collection/templates
|
||||
2. configuration.export - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/api/reference/configuration/export
|
||||
3. Template guidelines - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/guidelines/en/template_guidelines
|
||||
4. zabbix-prusa/template/7.0/Prusa_by_Prom.yaml at main · smejdil, acessado em janeiro 4, 2026, https://github.com/smejdil/zabbix-prusa/blob/main/template/7.0/Prusa_by_Prom.yaml
|
||||
5. UUID when importing new items - ZABBIX Forums, acessado em janeiro 4, 2026, https://www.zabbix.com/forum/zabbix-troubleshooting-and-problems/450493-uuid-when-importing-new-items
|
||||
6. 14 Configuration export/import - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/xml_export_import
|
||||
7. 1 Configuring a template - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/config/templates/template
|
||||
8. 3 Agent 2 - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/5.2/manual/concepts/agent2
|
||||
9. 1 Zabbix agent, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/config/items/itemtypes/zabbix_agent
|
||||
10. 2 Item value preprocessing - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/config/items/preprocessing
|
||||
11. 1 Zabbix agent 2, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/config/items/itemtypes/zabbix_agent/zabbix_agent2
|
||||
12. Source of template_app_docker.yaml - Zabbix - ZABBIX GIT, acessado em janeiro 4, 2026, https://git.zabbix.com/projects/ZBX/repos/zabbix/browse/templates/app/docker/template_app_docker.yaml?at=release%2F7.0
|
||||
13. 3 Templates - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/xml_export_import/templates
|
||||
14. 3 Preprocessing examples - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/config/items/preprocessing/examples
|
||||
15. 15 Dependent items - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/config/items/itemtypes/dependent_items
|
||||
16. 7 Calculated items - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/config/items/itemtypes/calculated
|
||||
17. 5 Trend functions - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/appendix/functions/trends
|
||||
18. 7 Predictive trigger functions - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/config/triggers/prediction
|
||||
19. 1 Dashboards - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/dashboards
|
||||
20. 8 Graph - Zabbix, acessado em janeiro 4, 2026, https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/dashboards/widgets/graph
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
import yaml
|
||||
import uuid
|
||||
import sys
|
||||
|
||||
# Files
|
||||
SOURCE_FILE = r"templates_work\template_windows_gold_ptbr.yaml"
|
||||
TARGET_FILE = r"templates_work\template_windows_gold_ptbr.yaml"
|
||||
|
||||
# Translations Map (English substring -> Portuguese replacement)
|
||||
TRANSLATIONS = {
|
||||
# Itens Base
|
||||
"Host name of Zabbix agent running": "Nome do Host (Agent)",
|
||||
"Zabbix agent ping": "Status do Agente Zabbix (Ping)",
|
||||
"Version of Zabbix agent running": "Versão do Agente Zabbix",
|
||||
"Cache bytes": "Memória: Cache Bytes",
|
||||
"Free system page table entries": "Memória: Entradas de Tabela de Página Livres",
|
||||
"Memory page faults per second": "Memória: Page Faults/seg",
|
||||
"Memory pages per second": "Memória: Pages/seg (Swap I/O)",
|
||||
"Memory pool non-paged": "Memória: Non-paged Pool",
|
||||
"Used swap space in %": "Swap: % de Uso",
|
||||
"CPU DPC time": "CPU: Tempo DPC",
|
||||
"CPU interrupt time": "CPU: Tempo de Interrupção",
|
||||
"CPU privileged time": "CPU: Tempo Privilegiado (Kernel)",
|
||||
"CPU user time": "CPU: Tempo de Usuário",
|
||||
"Context switches per second": "CPU: Context Switches/seg",
|
||||
"CPU queue length": "CPU: Tamanho da Fila (Queue Length)",
|
||||
"Number of threads": "Sistema: Número de Threads",
|
||||
"Number of processes": "Sistema: Número de Processos",
|
||||
"CPU utilization": "CPU: Utilização Total",
|
||||
"System name": "Sistema: Nome do Computador",
|
||||
"System local time": "Sistema: Hora Local",
|
||||
"Operating system architecture": "Sistema: Arquitetura do SO",
|
||||
"Operating system": "Sistema: Versão do SO",
|
||||
"Free swap space": "Swap: Espaço Livre",
|
||||
"Total swap space": "Swap: Espaço Total",
|
||||
"System description": "Sistema: Descrição",
|
||||
"Uptime": "Sistema: Uptime",
|
||||
"Total memory": "Memória: Total",
|
||||
"Used memory": "Memória: Usada",
|
||||
"Memory utilization": "Memória: % de Utilização",
|
||||
"Number of cores": "Hardware: Número de Cores",
|
||||
"Zabbix agent availability": "Disponibilidade do Agente Zabbix",
|
||||
|
||||
# Network Discovery
|
||||
"Interface {#IFNAME}({#IFALIAS}): Inbound packets discarded": "Interface {#IFNAME}: Pacotes Descartados (In)",
|
||||
"Interface {#IFNAME}({#IFALIAS}): Inbound packets with errors": "Interface {#IFNAME}: Erros de Pacote (In)",
|
||||
"Interface {#IFNAME}({#IFALIAS}): Bits received": "Interface {#IFNAME}: Tráfego de Entrada",
|
||||
"Interface {#IFNAME}({#IFALIAS}): Outbound packets discarded": "Interface {#IFNAME}: Pacotes Descartados (Out)",
|
||||
"Interface {#IFNAME}({#IFALIAS}): Outbound packets with errors": "Interface {#IFNAME}: Erros de Pacote (Out)",
|
||||
"Interface {#IFNAME}({#IFALIAS}): Bits sent": "Interface {#IFNAME}: Tráfego de Saída",
|
||||
"Interface {#IFNAME}({#IFALIAS}): Speed": "Interface {#IFNAME}: Velocidade Negociada",
|
||||
"Interface {#IFNAME}({#IFALIAS}): Operational status": "Interface {#IFNAME}: Status Operacional",
|
||||
"Interface {#IFNAME}({#IFALIAS}): Interface type": "Interface {#IFNAME}: Tipo de Interface",
|
||||
|
||||
# Triggers & Descriptions & Event Names
|
||||
"Windows: Number of free system page table entries is too low": "⚠️ Windows: Esgotamento de Tabela de Páginas",
|
||||
"Windows: The Memory Pages/sec is too high": "⚠️ Windows: Excesso de Paginação (Swap)",
|
||||
"Windows: CPU interrupt time is too high": "⚠️ Windows: CPU com muitas Interrupções (Hardware?)",
|
||||
"Windows: CPU privileged time is too high": "⚠️ Windows: Uso Elevado de Kernel (Privileged Time)",
|
||||
"Windows: High CPU utilization": "🔥 Windows: Uso de CPU Crítico",
|
||||
"Windows: System name has changed": "ℹ️ Windows: Nome do Host Mudou",
|
||||
"Windows: System time is out of sync": "⚠️ Windows: Hora do Sistema Dessincronizada",
|
||||
"Windows: Operating system description has changed": "ℹ️ Windows: SO Atualizado/Alterado",
|
||||
"Windows: Host has been restarted": "⚠️ Windows: Servidor Reiniciou",
|
||||
"Windows: High memory utilization": "🧠 Windows: Memória Esgotada",
|
||||
"Windows: Zabbix agent is not available": "🚨 Windows: Agente Zabbix Indisponível",
|
||||
"Windows: Interface {#IFNAME}({#IFALIAS}): Link down": "🚨 Interface {#IFNAME}: Link Down",
|
||||
"Windows: Interface {#IFNAME}({#IFALIAS}): Ethernet has changed to lower speed than it was before": "⚠️ Interface {#IFNAME}: Velocidade Reduzida (Negociação?)",
|
||||
"Windows: Interface {#IFNAME}({#IFALIAS}): High bandwidth usage": "🔥 Interface {#IFNAME}: Saturação de Banda",
|
||||
"Windows: Interface {#IFNAME}({#IFALIAS}): High error rate": "🔥 Interface {#IFNAME}: Alta Taxa de Erros",
|
||||
|
||||
# Common Description Terms
|
||||
"The system is running out of free memory.": "O sistema está ficando sem memória livre. Verifique processos consumidores.",
|
||||
"CPU utilization is too high. The system might be slow to respond.": "O uso de CPU está sitematicamente alto. O servidor pode ficar lento.",
|
||||
"The host's system time is different from Zabbix server time.": "A hora do servidor difere da hora do Zabbix Server. Verifique o NTP.",
|
||||
"The device uptime is less than 10 minutes.": "O servidor foi reiniciado recentemente (Uptime < 10m).",
|
||||
"For passive agents only, host availability is used with `{$AGENT.TIMEOUT}` as a time threshold.": "O Agente Zabbix parou de responder. Verifique se o serviço está rodando ou se há bloqueio de firewall.",
|
||||
|
||||
# Generic replacements
|
||||
"Windows by Zabbix agent": "Windows Gold Edition"
|
||||
}
|
||||
|
||||
NEW_ITEMS = [
|
||||
{
|
||||
'uuid': '',
|
||||
'name': 'RDP: Sessões Ativas (Total)',
|
||||
'key': 'perf_counter_en["\\Terminal Services\\Total Sessions"]',
|
||||
'delay': '1m',
|
||||
'value_type': 'FLOAT',
|
||||
'units': '',
|
||||
'description': 'Número total de sessões de Terminal Services (RDP) ativas.',
|
||||
'tags': [{'tag': 'component', 'value': 'security'}, {'tag': 'component', 'value': 'remote_access'}],
|
||||
'triggers': [{
|
||||
'uuid': '',
|
||||
'expression': 'min(/Windows Gold Edition/perf_counter_en["\\Terminal Services\\Total Sessions"],15m)>2',
|
||||
'name': '⚠️ Windows: Muitas Sessões RDP Ativas',
|
||||
'event_name': '⚠️ Windows: Muitas Sessões RDP Ativas ({ITEM.LASTVALUE} > 2)',
|
||||
'priority': 'WARNING',
|
||||
'description': 'Existem muitas sessões de terminal abertas. Isso pode consumir recursos ou indicar sessões "penduradas".'
|
||||
}]
|
||||
},
|
||||
{
|
||||
'uuid': '',
|
||||
'name': 'Disco: Tamanho da Fila (Queue Length)',
|
||||
'key': 'perf_counter_en["\\PhysicalDisk(_Total)\\Current Disk Queue Length"]',
|
||||
'delay': '1m',
|
||||
'value_type': 'FLOAT',
|
||||
'description': 'Número de solicitações de I/O aguardando serviço. Valores altos constantes indicam gargalo de disco.',
|
||||
'tags': [{'tag': 'component', 'value': 'storage'}, {'tag': 'component', 'value': 'performance'}],
|
||||
'triggers': [{
|
||||
'uuid': '',
|
||||
'expression': 'min(/Windows Gold Edition/perf_counter_en["\\PhysicalDisk(_Total)\\Current Disk Queue Length"],10m)>2',
|
||||
'name': '🐢 Windows: Disco Lento (Queue Length Alta)',
|
||||
'event_name': '🐢 Windows: Disco Lento (Queue Total > 2 por 10m)',
|
||||
'priority': 'AVERAGE',
|
||||
'description': 'A fila de disco está constantemente alta. O armazenamento não está dando conta das requisições.'
|
||||
}]
|
||||
},
|
||||
{
|
||||
'uuid': '',
|
||||
'name': 'Segurança: Falhas de Login (Audit Failure)',
|
||||
'key': 'eventlog[Security,,,,4625]',
|
||||
'delay': '1m',
|
||||
'value_type': 'LOG',
|
||||
'description': 'Monitora o Event ID 4625 (Logon falhou) no log de Segurança.',
|
||||
'tags': [{'tag': 'component', 'value': 'security'}],
|
||||
'triggers': [{
|
||||
'uuid': '',
|
||||
'expression': 'count(/Windows Gold Edition/eventlog[Security,,,,4625],2m)>5',
|
||||
'name': '👮 Windows: Possível Brute Force (Falhas de Login)',
|
||||
'event_name': '👮 Windows: 5+ Falhas de Login em 2m',
|
||||
'priority': 'HIGH',
|
||||
'description': 'Foram detectadas múltiplas falhas de login (Event ID 4625) em curto período.'
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
||||
def load_yaml(path):
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
def clean_tags_and_fix_uuids(data):
|
||||
generated_uuids = set()
|
||||
|
||||
def process_node(node):
|
||||
if isinstance(node, dict):
|
||||
# Clean tags
|
||||
for tag in ['wizard_ready', 'readme', 'vendor', 'config']:
|
||||
if tag in node:
|
||||
del node[tag]
|
||||
|
||||
# Fix UUIDs
|
||||
if 'uuid' in node:
|
||||
# Generate new UUID always to ensure clean slate, unless strictly needed to keep?
|
||||
# Let's regenerate to be safe and Gold.
|
||||
new_uuid = uuid.uuid4().hex
|
||||
while new_uuid in generated_uuids:
|
||||
new_uuid = uuid.uuid4().hex
|
||||
node['uuid'] = new_uuid
|
||||
generated_uuids.add(new_uuid)
|
||||
|
||||
# Translate Strings
|
||||
for key in ['name', 'description', 'event_name', 'comment']:
|
||||
if key in node and isinstance(node[key], str):
|
||||
# Sort by length descending to avoid substring collisions
|
||||
for eng, pt in sorted(TRANSLATIONS.items(), key=lambda x: len(x[0]), reverse=True):
|
||||
node[key] = node[key].replace(eng, pt)
|
||||
|
||||
# Recursive
|
||||
for k, v in list(node.items()):
|
||||
process_node(v)
|
||||
elif isinstance(node, list):
|
||||
for item in node:
|
||||
process_node(item)
|
||||
|
||||
process_node(data)
|
||||
|
||||
def main():
|
||||
print(f"Loading {SOURCE_FILE}...")
|
||||
try:
|
||||
source = load_yaml(SOURCE_FILE)
|
||||
except FileNotFoundError:
|
||||
print("File not found! Make sure you are in the correct directory.")
|
||||
return
|
||||
|
||||
# 1. Update Header
|
||||
if 'zabbix_export' in source:
|
||||
source['zabbix_export']['version'] = '7.0'
|
||||
if 'templates' in source['zabbix_export']:
|
||||
template = source['zabbix_export']['templates'][0]
|
||||
template['name'] = "Windows Server Gold pt-BR"
|
||||
template['description'] = "Template Windows Server Gold Edition (Pt-BR).\n\nMonitoramento Otimizado por Arthur 'O Farol'.\nInclui: RDP, Fila de Disco, Auditoria de Login e traduções completas."
|
||||
|
||||
# 2. Inject New Items
|
||||
if 'items' not in template:
|
||||
template['items'] = []
|
||||
|
||||
print(f"Injecting {len(NEW_ITEMS)} new items...")
|
||||
for item in NEW_ITEMS:
|
||||
template['items'].append(item)
|
||||
|
||||
# 3. Clean and Fix
|
||||
print("Translating and checking UUIDs...")
|
||||
clean_tags_and_fix_uuids(source)
|
||||
|
||||
# 4. Save
|
||||
print(f"Saving to {TARGET_FILE}...")
|
||||
with open(TARGET_FILE, 'w', encoding='utf-8') as f:
|
||||
yaml.dump(source, f, sort_keys=False, indent=2, width=float("inf"), allow_unicode=True)
|
||||
|
||||
print("Build Complete!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
import sys
|
||||
|
||||
TARGET_FILE = r"C:\Users\joao.goncalves\Desktop\zabbix-itguys\templates_gold\windows_active_agent\template_windows_gold_ptbr.yaml"
|
||||
|
||||
# Tuple of (Broken String, Fixed String)
|
||||
# Using raw strings for safety
|
||||
REPAIRS = [
|
||||
(
|
||||
r"""description: "⚠️ A velocidade da interface caiu (Ex: 1Gb -> 100Mb).\n\n📉 Impacto: Lentidão na transferência de dados.\n🛠️ Ação: 1. Verifique a categoria do cabo (Cat5e/Cat6). 2. Verifique configurações de Duplex/Speed no switch e servidor.\"""",
|
||||
r"""description: "⚠️ A velocidade da interface caiu (Ex: 1Gb -> 100Mb).\n\n📉 Impacto: Lentidão na transferência de dados.\n🛠️ Ação: 1. Verifique a categoria do cabo (Cat5e/Cat6). 2. Verifique configurações de Duplex/Speed no switch e servidor.""""
|
||||
),
|
||||
(
|
||||
r"""description: "⚠️ Uso de banda elevado.\n\n📉 Impacto: A interface atingiu o limite de tráfego. O acesso ao servidor ficará lento e pacotes podem ser descartados.\n🛠️ Ação: 1. Identifique qual processo/usuário está consumindo banda. 2. Avalie necessidade de upgrade de link.\"""",
|
||||
r"""description: "⚠️ Uso de banda elevado.\n\n📉 Impacto: A interface atingiu o limite de tráfego. O acesso ao servidor ficará lento e pacotes podem ser descartados.\n🛠️ Ação: 1. Identifique qual processo/usuário está consumindo banda. 2. Avalie necessidade de upgrade de link.""""
|
||||
),
|
||||
(
|
||||
r"""description: "⚠️ Erros de transmissão detectados.\n\n📉 Impacto: Perda de pacotes, retransmissões e lentidão.\n🛠️ Ação: 1. Substitua o cabo de rede. 2. Teste outra porta no switch.\"""",
|
||||
r"""description: "⚠️ Erros de transmissão detectados.\n\n📉 Impacto: Perda de pacotes, retransmissões e lentidão.\n🛠️ Ação: 1. Substitua o cabo de rede. 2. Teste outra porta no switch.""""
|
||||
)
|
||||
]
|
||||
|
||||
def fix_file():
|
||||
print(f"Reading {TARGET_FILE}...")
|
||||
try:
|
||||
with open(TARGET_FILE, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
except Exception as e:
|
||||
print(f"Error reading: {e}")
|
||||
return
|
||||
|
||||
fixed_count = 0
|
||||
for broken, fixed in REPAIRS:
|
||||
# Check if broken version exists
|
||||
# Normalize line endings just in case? Content mostly has \n
|
||||
if broken in content:
|
||||
print("Found broken block. Fixing...")
|
||||
content = content.replace(broken, fixed)
|
||||
fixed_count += 1
|
||||
else:
|
||||
print("Broken block not found (maybe already fixed or whitespace mismatch).")
|
||||
# print(f"Looking for:\n{broken!r}")
|
||||
|
||||
if fixed_count > 0:
|
||||
try:
|
||||
with open(TARGET_FILE, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
print(f"Saved fixed file. Fixed {fixed_count} blocks.")
|
||||
except Exception as e:
|
||||
print(f"Error writing: {e}")
|
||||
else:
|
||||
print("No repairs needed.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
fix_file()
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
import sys
|
||||
|
||||
TARGET_FILE = r"C:\Users\joao.goncalves\Desktop\zabbix-itguys\templates_gold\windows_active_agent\template_windows_gold_ptbr.yaml"
|
||||
|
||||
def repair_indentation():
|
||||
print(f"Reading {TARGET_FILE}...")
|
||||
try:
|
||||
with open(TARGET_FILE, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
except Exception as e:
|
||||
print(f"Error reading: {e}")
|
||||
return
|
||||
|
||||
fixed_lines = []
|
||||
i = 0
|
||||
while i < len(lines):
|
||||
line = lines[i].rstrip('\n') # Keep indentation? No, rstrip end
|
||||
|
||||
# Check if this line is a "description" line that needs merging
|
||||
if "description: ⚠️" in line:
|
||||
# This is likely the start of a broken block.
|
||||
# We need to look ahead for the broken parts.
|
||||
description_content = line.split("description: ", 1)[1] # Get content after "description: "
|
||||
|
||||
# If it doesn't start with quote, let's start expecting breakage
|
||||
if not description_content.startswith('"'):
|
||||
current_desc = description_content
|
||||
i += 1
|
||||
# Consume next lines if they start with specific markers
|
||||
while i < len(lines):
|
||||
next_line = lines[i].strip() # Remove indentation of next line (it's 0 usually if broken)
|
||||
if not next_line: # Skip empty lines
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if next_line.startswith("📉 Impacto") or next_line.startswith("🛠️ Ação"):
|
||||
current_desc += "\\n\\n" + next_line
|
||||
i += 1
|
||||
else:
|
||||
# Not a broken part, stop consuming
|
||||
break
|
||||
|
||||
# Now verify if we need to quote it
|
||||
# It's safest to ensure it's quoted
|
||||
if not current_desc.startswith('"'):
|
||||
current_desc = '"' + current_desc
|
||||
if not current_desc.endswith('"'):
|
||||
current_desc = current_desc + '"'
|
||||
|
||||
# Reconstruct the line preserving original indentation
|
||||
indentation = line.split("description:")[0]
|
||||
fixed_lines.append(f"{indentation}description: {current_desc}\n")
|
||||
continue # i is already advanced
|
||||
else:
|
||||
# Already quoted? might be fine, or might be the "simple fix" case
|
||||
pass
|
||||
|
||||
fixed_lines.append(lines[i])
|
||||
i += 1
|
||||
|
||||
try:
|
||||
with open(TARGET_FILE, 'w', encoding='utf-8') as f:
|
||||
f.writelines(fixed_lines)
|
||||
print(f"Saved repaired file.")
|
||||
except Exception as e:
|
||||
print(f"Error writing: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
repair_indentation()
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
import sys
|
||||
|
||||
TARGET_FILE = r"C:\Users\joao.goncalves\Desktop\zabbix-itguys\templates_gold\windows_active_agent\template_windows_gold_ptbr.yaml"
|
||||
|
||||
def simple_fix():
|
||||
print(f"Reading {TARGET_FILE}...")
|
||||
try:
|
||||
with open(TARGET_FILE, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
except Exception as e:
|
||||
print(f"Error reading: {e}")
|
||||
return
|
||||
|
||||
fixed_count = 0
|
||||
new_lines = []
|
||||
for line in lines:
|
||||
stripped = line.strip()
|
||||
# Check if it's a description line and ends with escaped quote
|
||||
if stripped.startswith('description: "') and stripped.endswith('\\"'):
|
||||
print(f"Fixing line: {stripped[-20:]}")
|
||||
# Remove the backslash before the last quote
|
||||
# The line ends with \"\n (or just \" if last line)
|
||||
# We want to replace \"\n with "\n
|
||||
|
||||
# rstrip newline first
|
||||
content = line.rstrip('\n')
|
||||
if content.endswith('\\"'):
|
||||
content = content[:-2] + '"'
|
||||
fixed_count += 1
|
||||
new_lines.append(content + '\n')
|
||||
else:
|
||||
new_lines.append(line)
|
||||
else:
|
||||
new_lines.append(line)
|
||||
|
||||
if fixed_count > 0:
|
||||
try:
|
||||
with open(TARGET_FILE, 'w', encoding='utf-8') as f:
|
||||
f.writelines(new_lines)
|
||||
print(f"Saved fixed file. Fixed {fixed_count} lines.")
|
||||
except Exception as e:
|
||||
print(f"Error writing: {e}")
|
||||
else:
|
||||
print("No lines needed fixing.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
simple_fix()
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
import yaml
|
||||
import argparse
|
||||
import sys
|
||||
import re
|
||||
|
||||
def load_yaml(path):
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
def save_yaml(data, path):
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
yaml.dump(data, f, sort_keys=False, indent=2, width=float("inf"), allow_unicode=True)
|
||||
|
||||
def normalize_expression(expression):
|
||||
"""
|
||||
Removes the /Template Name/ part from item paths in the expression.
|
||||
Example: min(/Windows by Zabbix agent/system.cpu.util,5m) -> min(//system.cpu.util,5m)
|
||||
"""
|
||||
# Regex to match /Template Name/Key
|
||||
# It usually looks like: /Host or Template/Key
|
||||
# We want to replace the first part with empty string if it starts with /
|
||||
if not expression:
|
||||
return ""
|
||||
|
||||
# We use a simple heuristic: replace /[^/]+/ with //
|
||||
# But we must be careful not to break the key.
|
||||
# Zabbix expression format: function(/Host/Key, params)
|
||||
# We want function(//Key, params)
|
||||
|
||||
# Pattern: Look for / followed by anything not / followed by /
|
||||
return re.sub(r'\/[^\/]+\/', '//', expression)
|
||||
|
||||
def build_map(template_data):
|
||||
"""
|
||||
Builds a map of entities from the template data.
|
||||
"""
|
||||
mapping = {
|
||||
'items': {},
|
||||
'item_details': {}, # Store full item dict for property syncing
|
||||
'discovery_rules': {},
|
||||
'triggers': {},
|
||||
'item_prototypes': {}, # Keyed by DiscoveryRuleKey:ItemKey
|
||||
'trigger_prototypes': {}, # Keyed by DiscoveryRuleKey:Expression
|
||||
'template_uuid': None
|
||||
}
|
||||
|
||||
if 'zabbix_export' not in template_data or 'templates' not in template_data['zabbix_export']:
|
||||
return mapping
|
||||
|
||||
tmpl = template_data['zabbix_export']['templates'][0]
|
||||
mapping['template_uuid'] = tmpl.get('uuid')
|
||||
|
||||
# Items
|
||||
for item in tmpl.get('items', []):
|
||||
mapping['items'][item['key']] = item.get('uuid')
|
||||
mapping['item_details'][item['key']] = item
|
||||
|
||||
# Triggers
|
||||
for trigger in tmpl.get('triggers', []):
|
||||
norm_expr = normalize_expression(trigger['expression'])
|
||||
mapping['triggers'][norm_expr] = trigger.get('uuid')
|
||||
|
||||
# Discovery Rules
|
||||
for rule in tmpl.get('discovery_rules', []):
|
||||
mapping['discovery_rules'][rule['key']] = rule.get('uuid')
|
||||
|
||||
# Item Prototypes
|
||||
for proto in rule.get('item_prototypes', []):
|
||||
# Composite key: RuleKey:ProtoKey
|
||||
comp_key = f"{rule['key']}:{proto['key']}"
|
||||
mapping['item_prototypes'][comp_key] = proto.get('uuid')
|
||||
|
||||
# Trigger Prototypes
|
||||
for trig_proto in proto.get('trigger_prototypes', []):
|
||||
# Note: Trigger prototypes are nested under item prototypes in old formats,
|
||||
# but in 6.0+ they might be separate or nested.
|
||||
# In the provided YAMLs, they are under item_prototypes for dependent items?
|
||||
# Wait, looking at file content...
|
||||
# In file 7 (Active standard), trigger_prototypes are under discovery_rules
|
||||
# AND items can have trigger_prototypes (rare).
|
||||
# Let's check the structure of file 7 again.
|
||||
pass
|
||||
|
||||
# Trigger Prototypes (Directly under Discovery Rule)
|
||||
for trig_proto in rule.get('trigger_prototypes', []):
|
||||
norm_expr = normalize_expression(trig_proto['expression'])
|
||||
comp_key = f"{rule['key']}:{norm_expr}"
|
||||
mapping['trigger_prototypes'][comp_key] = trig_proto.get('uuid')
|
||||
|
||||
return mapping
|
||||
|
||||
def sync_uuids(source_path, target_path, output_path):
|
||||
print(f"Loading Source: {source_path}")
|
||||
source_data = load_yaml(source_path)
|
||||
print(f"Loading Target: {target_path}")
|
||||
target_data = load_yaml(target_path)
|
||||
|
||||
source_map = build_map(source_data)
|
||||
|
||||
if not source_map['template_uuid']:
|
||||
print("Error: No template found in source.")
|
||||
return
|
||||
|
||||
# Sync Process
|
||||
target_tmpl = target_data['zabbix_export']['templates'][0]
|
||||
|
||||
print(f"Syncing Template UUID: {source_map['template_uuid']}")
|
||||
target_tmpl['uuid'] = source_map['template_uuid']
|
||||
|
||||
stats = {'items': 0, 'triggers': 0, 'discovery': 0, 'item_proto': 0, 'trigger_proto': 0}
|
||||
|
||||
# Sync Items
|
||||
for item in target_tmpl.get('items', []):
|
||||
if item['key'] in source_map['items']:
|
||||
item['uuid'] = source_map['items'][item['key']]
|
||||
stats['items'] += 1
|
||||
|
||||
# Additional Fix: Copy critical fields if missing in Target (Gold)
|
||||
# but present in Source (Base). This fixes invalid/incomplete Gold items.
|
||||
source_item = source_map['item_details'].get(item['key'])
|
||||
if source_item:
|
||||
for field in ['type', 'delay', 'value_type', 'units', 'trends']:
|
||||
if field not in item and field in source_item:
|
||||
item[field] = source_item[field]
|
||||
# Log if we are patching to debug
|
||||
# print(f"Patched {field} for {item['key']}")
|
||||
|
||||
# Sync Triggers
|
||||
for trigger in target_tmpl.get('triggers', []):
|
||||
norm_expr = normalize_expression(trigger['expression'])
|
||||
# Try exact match first (in case descriptions differ but expression is same)
|
||||
# Note: In source map we keyed by expression.
|
||||
if norm_expr in source_map['triggers']:
|
||||
trigger['uuid'] = source_map['triggers'][norm_expr]
|
||||
stats['triggers'] += 1
|
||||
|
||||
# Sync Discovery Rules
|
||||
for rule in target_tmpl.get('discovery_rules', []):
|
||||
if rule['key'] in source_map['discovery_rules']:
|
||||
rule['uuid'] = source_map['discovery_rules'][rule['key']]
|
||||
stats['discovery'] += 1
|
||||
|
||||
# Sync Item Prototypes
|
||||
for proto in rule.get('item_prototypes', []):
|
||||
comp_key = f"{rule['key']}:{proto['key']}"
|
||||
if comp_key in source_map['item_prototypes']:
|
||||
proto['uuid'] = source_map['item_prototypes'][comp_key]
|
||||
stats['item_proto'] += 1
|
||||
|
||||
# Sync Trigger Prototypes
|
||||
for trig_proto in rule.get('trigger_prototypes', []):
|
||||
norm_expr = normalize_expression(trig_proto['expression'])
|
||||
comp_key = f"{rule['key']}:{norm_expr}"
|
||||
if comp_key in source_map['trigger_prototypes']:
|
||||
trig_proto['uuid'] = source_map['trigger_prototypes'][comp_key]
|
||||
stats['trigger_proto'] += 1
|
||||
|
||||
print("Sync Complete.")
|
||||
print(f"Stats: {stats}")
|
||||
|
||||
print(f"Saving to {output_path}")
|
||||
save_yaml(target_data, output_path)
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Sync Zabbix Template UUIDs')
|
||||
parser.add_argument('--source', required=True, help='Path to Base Template (Source of UUIDs)')
|
||||
parser.add_argument('--target', required=True, help='Path to Gold Template (Target to update)')
|
||||
parser.add_argument('--output', required=True, help='Path to Output File')
|
||||
|
||||
args = parser.parse_args()
|
||||
sync_uuids(args.source, args.target, args.output)
|
||||
|
|
@ -1,50 +1,111 @@
|
|||
# INSTRUÇÕES DE INSTALAÇÃO - AGENTE ZABBIX P/ OPENVPN
|
||||
=====================================================
|
||||
# INSTRUÇÕES DE INSTALAÇÃO - AGENTE ZABBIX P/ OPENVPN (CACHE MODE)
|
||||
==================================================================
|
||||
|
||||
Para que o monitoramento do OpenVPN funcione no Template Hybrid Gold, você deve realizar os passos abaixo em CADA firewall pfSense.
|
||||
Para que o monitoramento do OpenVPN funcione no Template Hybrid Gold (v2+), você deve realizar os passos abaixo em CADA firewall pfSense.
|
||||
|
||||
⚠️ NOTA IMPORTANTE: Esta versão utiliza um sistema de CACHE para evitar timeouts no Zabbix.
|
||||
- openvpn-collector.sh: Roda via CRON a cada minuto e coleta dados dos sockets.
|
||||
- openvpn-discovery.sh: Apenas lê o cache instantaneamente.
|
||||
|
||||
REQUISITOS
|
||||
----------
|
||||
1. Acesso SSH ao pfSense (Opção 8 no console).
|
||||
2. Pacote "Zabbix Agent" instalado no pfSense (System > Package Manager).
|
||||
3. OpenVPN rodando e com usuários conectados.
|
||||
|
||||
PASSO 1: INSTALAR O SCRIPT DE DESCOBERTA
|
||||
----------------------------------------
|
||||
Este script é usado pelo Zabbix para descobrir automaticamente os usuários conectados.
|
||||
|
||||
PASSO 1: INSTALAR OS SCRIPTS
|
||||
----------------------------
|
||||
1. Crie a pasta se não existir:
|
||||
mkdir -p /opt/zabbix/
|
||||
|
||||
2. Copie o arquivo 'files/openvpn-discovery.sh' para '/opt/zabbix/openvpn-discovery.sh' no firewall.
|
||||
(Você pode usar SCP ou criar o arquivo com 'vi' e colar o conteúdo).
|
||||
2. Copie os arquivos da pasta 'files/' para o firewall em '/opt/zabbix/':
|
||||
- openvpn-collector.sh
|
||||
- openvpn-discovery.sh
|
||||
|
||||
3. Dê permissão de execução:
|
||||
chmod +x /opt/zabbix/openvpn-collector.sh
|
||||
chmod +x /opt/zabbix/openvpn-discovery.sh
|
||||
|
||||
PASSO 2: CONFIGURAR O AGENTE
|
||||
----------------------------
|
||||
Este arquivo ensina o Zabbix a usar o script acima e ler os logs.
|
||||
PASSO 2: CONFIGURAR O CRON JOB
|
||||
------------------------------
|
||||
Como a coleta via socket é pesada para o timeout do agente, usamos o cron para atualizar o cache.
|
||||
|
||||
1. Copie o arquivo 'files/userparameter_openvpn.conf' para '/usr/local/etc/zabbix50/zabbix_agentd.conf.d/userparameter_openvpn.conf'
|
||||
1. Instale o pacote "Cron" no pfSense (opcional, mas facilita) OU edite via terminal:
|
||||
|
||||
⚠️ NOTA: O caminho pode variar dependendo da versão do pacote Zabbix Agent (ex: zabbix60, zabbix40). Verifique com 'ls /usr/local/etc/'.
|
||||
vi /etc/crontab
|
||||
|
||||
PASSO 3: VERIFICAÇÃO DE CAMINHOS DE LOG
|
||||
---------------------------------------
|
||||
O script assume que os logs de status do OpenVPN estão no padrão:
|
||||
/var/log/openvpn/status*.log
|
||||
2. Adicione a seguinte linha no final do arquivo:
|
||||
|
||||
Se o seu pfSense estiver configurado para salvar em outro lugar (verifique em OpenVPN > Servers > Edit > Advanced Settings ou Logs), você DEVE editar os dois arquivos (.sh e .conf) e corrigir o caminho antes de instalar.
|
||||
* * * * * root /opt/zabbix/openvpn-collector.sh
|
||||
|
||||
PASSO 4: REINICIAR O SERVIÇO
|
||||
----------------------------
|
||||
Após copiar os arquivos, reinicie o agente para aplicar as mudanças:
|
||||
3. Salve e saia. O cron irá atualizar o arquivo /tmp/openvpn_discovery.json a cada minuto.
|
||||
|
||||
PASSO 3: HABILITAR PERMISSÕES E INCLUDE NO AGENTE
|
||||
-------------------------------------------------
|
||||
O usuário 'zabbix' precisa de permissão para ler os sockets e o arquivo de configuração de UserParameter precisa ser carregado.
|
||||
|
||||
1. Edite o arquivo de configuração do agente:
|
||||
vi /usr/local/etc/zabbix7/zabbix_agentd.conf
|
||||
(O caminho pode variar: zabbix6, zabbix5, etc)
|
||||
|
||||
2. Adicione/Verifique as seguintes configurações:
|
||||
|
||||
# Carregar UserParameters
|
||||
Include=/usr/local/etc/zabbix7/zabbix_agentd.conf.d/*.conf
|
||||
|
||||
# Aumentar Timeout (recomendado)
|
||||
Timeout=30
|
||||
|
||||
# Permitir execução de comandos remotos (se necessário para debug)
|
||||
UnsafeUserParameters=1
|
||||
|
||||
3. Adicione o usuário zabbix ao grupo 'wheel' para ter acesso aos sockets do OpenVPN:
|
||||
pw groupmod wheel -m zabbix
|
||||
|
||||
PASSO 4: INSTALAR USERPARAMETERS
|
||||
--------------------------------
|
||||
1. Copie o arquivo 'files/userparameter_openvpn.conf' para '/usr/local/etc/zabbix7/zabbix_agentd.conf.d/userparameter_openvpn.conf'
|
||||
|
||||
PASSO 5: REINICIAR E TESTAR
|
||||
---------------------------
|
||||
1. Reinicie o agente:
|
||||
service zabbix_agentd restart
|
||||
|
||||
TESTE
|
||||
-----
|
||||
No terminal do pfSense, teste se o agente consegue ler a versão do OpenVPN:
|
||||
zabbix_agentd -t openvpn.version
|
||||
2. Gere o cache manualmente pela primeira vez:
|
||||
/opt/zabbix/openvpn-collector.sh
|
||||
|
||||
3. Teste a leitura do discovery pelo agente:
|
||||
zabbix_agentd -t openvpn.discovery
|
||||
|
||||
Deve retornar algo como: [t|{"data":[{"{#VPN.USER}":"joao",...}]}]
|
||||
|
||||
TROUBLESHOOTING
|
||||
---------------
|
||||
- Se zabbix_agentd -t retornar "Permission denied": Verifique se o usuário zabbix está no grupo wheel.
|
||||
- Se retornar TIMEOUT: Verifique se você está usando o script DE LEITURA (openvpn-discovery.sh) no UserParameter e não o coletor.
|
||||
- Se retornar VAZIO { "data": [] }: Execute o coletor manualmente e veja se gera erros. Verifique se existem arquivos em /var/etc/openvpn/server*/sock
|
||||
|
||||
PASSO 6: INSTALAR O ACCESS TRACKER (REPLAY DE ACESSOS) [OPCIONAL]
|
||||
------------------------------------------------------------------
|
||||
O Access Tracker é um script adicional que correlaciona usuários VPN com a tabela de estados do firewall,
|
||||
permitindo visualizar quais destinos cada usuário acessou (replay de sessão).
|
||||
|
||||
1. Copie o arquivo 'files/openvpn-access-tracker.sh' para '/opt/zabbix/':
|
||||
chmod +x /opt/zabbix/openvpn-access-tracker.sh
|
||||
|
||||
2. Adicione ao cron (executa a cada minuto):
|
||||
echo '* * * * * root /opt/zabbix/openvpn-access-tracker.sh' >> /etc/crontab
|
||||
|
||||
3. O script gerará logs em /var/log/openvpn_user_activity.log
|
||||
Formato: TIMESTAMP|USER|VIRTUAL_IP|DESTINO:PORTA|PROTOCOLO|ESTADO
|
||||
|
||||
Nota: Este script requer que o openvpn-collector.sh esteja rodando (usa o cache de métricas).
|
||||
|
||||
NOVAS MÉTRICAS DISPONÍVEIS (v7)
|
||||
-------------------------------
|
||||
- openvpn.user.time_online[USER]: Tempo online em segundos
|
||||
- openvpn.user.bytes_recv.cached[USER]: Bytes recebidos (cache)
|
||||
- openvpn.user.bytes_sent.cached[USER]: Bytes enviados (cache)
|
||||
- openvpn.access.destinations[USER]: Lista de destinos acessados
|
||||
- openvpn.access.log.tail[N]: Últimas N linhas do log de replay
|
||||
|
||||
Se retornar [t|2.x.x], está funcionando!
|
||||
|
|
|
|||
|
|
@ -1,106 +1,134 @@
|
|||
# Instalação do Monitoramento OpenVPN no pfSense
|
||||
## Padrão IT Guys Gold (v2 - Management Interface)
|
||||
## Padrão IT Guys Gold (v3 - Cache System)
|
||||
|
||||
Este guia descreve como instalar os scripts de monitoramento OpenVPN no pfSense usando a Management Interface via sockets Unix.
|
||||
Este guia descreve como instalar os scripts de monitoramento OpenVPN no pfSense usando o sistema de **CACHE** para alta performance e zero timeout no Zabbix.
|
||||
|
||||
---
|
||||
|
||||
## Arquitetura
|
||||
|
||||
1. **openvpn-collector.sh**: Executado via cron a cada minuto. Coleta dados de todos os sockets e salva em JSON.
|
||||
2. **openvpn-discovery.sh**: Executado pelo Zabbix Agent. Apenas lê o arquivo JSON gerado (instantâneo).
|
||||
|
||||
---
|
||||
|
||||
## Pré-requisitos
|
||||
|
||||
- pfSense 2.x ou superior
|
||||
- Zabbix Agent 2 instalado (pacote `zabbix-agent72`)
|
||||
- Pelo menos um servidor OpenVPN configurado
|
||||
- Zabbix Agent instalado (pacote `zabbix-agent7` ou similar)
|
||||
- Sockets OpenVPN ativos em `/var/etc/openvpn/server*/sock`
|
||||
|
||||
---
|
||||
|
||||
## Passo 1: Copiar o Script de Discovery
|
||||
## Passo 1: Instalar os Scripts
|
||||
|
||||
```bash
|
||||
# Via SSH no pfSense:
|
||||
mkdir -p /opt/zabbix
|
||||
|
||||
# Copie o conteúdo do arquivo openvpn-discovery.sh para:
|
||||
vi /opt/zabbix/openvpn-discovery.sh
|
||||
# Copie os arquivos da pasta files/ para o firewall:
|
||||
# - openvpn-collector.sh
|
||||
# - openvpn-discovery.sh
|
||||
|
||||
# Torne executável
|
||||
# Defina permissão de execução:
|
||||
chmod +x /opt/zabbix/openvpn-collector.sh
|
||||
chmod +x /opt/zabbix/openvpn-discovery.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Passo 2: Instalar os UserParameters
|
||||
## Passo 2: Configurar o Cron Job
|
||||
|
||||
O coletor precisa rodar automaticamente.
|
||||
|
||||
```bash
|
||||
# Copie o conteúdo do arquivo userparameter_openvpn.conf para:
|
||||
vi /usr/local/etc/zabbix72/zabbix_agentd.conf.d/userparameter_openvpn.conf
|
||||
# Adicione ao /etc/crontab:
|
||||
echo '* * * * * root /opt/zabbix/openvpn-collector.sh' >> /etc/crontab
|
||||
|
||||
# Execute manualmente uma vez para gerar o cache inicial:
|
||||
/opt/zabbix/openvpn-collector.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Passo 3: Reiniciar o Zabbix Agent
|
||||
## Passo 3: Configurar Zabbix Agent
|
||||
|
||||
```bash
|
||||
# Edite a configuração (caminho pode variar, ex: /usr/local/etc/zabbix7/...)
|
||||
vi /usr/local/etc/zabbix7/zabbix_agentd.conf
|
||||
|
||||
# GARANTA QUE ESTAS LINHAS EXISTAM:
|
||||
Include=/usr/local/etc/zabbix7/zabbix_agentd.conf.d/*.conf
|
||||
Timeout=30
|
||||
UnsafeUserParameters=1
|
||||
|
||||
# Adicione usuários zabbix ao grupo wheel (permissão socket):
|
||||
pw groupmod wheel -m zabbix
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Passo 4: Instalar UserParameters
|
||||
|
||||
```bash
|
||||
# Copie o userparameter_openvpn.conf para a pasta de include:
|
||||
# Ex: /usr/local/etc/zabbix7/zabbix_agentd.conf.d/
|
||||
```
|
||||
|
||||
Reinicie o agente:
|
||||
```bash
|
||||
service zabbix_agentd restart
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Passo 4: Testar a Instalação
|
||||
## Passo 5: Teste
|
||||
|
||||
```bash
|
||||
# Testar discovery de usuários
|
||||
# Teste de leitura instantânea
|
||||
zabbix_agentd -t openvpn.discovery
|
||||
|
||||
# Saída esperada (JSON com usuários conectados):
|
||||
# {"data":[{"{#VPN.USER}":"joao.silva","{#VPN.SERVER}":"server14",...}]}
|
||||
|
||||
# Testar contagem total de usuários
|
||||
zabbix_agentd -t openvpn.user.count.total
|
||||
|
||||
# Testar status de servidor específico
|
||||
zabbix_agentd -t openvpn.server.status[server14]
|
||||
# Saída esperada (imediata):
|
||||
# [t|{"data":[{"{#VPN.USER}":"joao.silva"...}]}]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Passo 5: Importar Template no Zabbix
|
||||
## Passo 6: Instalar Access Tracker (Replay de Acessos) [OPCIONAL]
|
||||
|
||||
1. Acesse **Configuração → Templates → Importar**
|
||||
2. Selecione o arquivo `template_pfsense_hybrid_gold.yaml`
|
||||
3. Clique em **Importar**
|
||||
O **Access Tracker** correlaciona usuários VPN com a tabela de estados do firewall (`pfctl`), gerando um log de atividade para replay.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Script retorna `{"data":[]}`
|
||||
- Verifique se os sockets existem: `ls -la /var/etc/openvpn/server*/sock`
|
||||
- Verifique permissões: o usuário `zabbix` precisa ler os sockets
|
||||
|
||||
### Erro de permissão nos sockets
|
||||
```bash
|
||||
# Adicione o usuário zabbix ao grupo wheel (temporário)
|
||||
pw groupmod wheel -m zabbix
|
||||
service zabbix_agentd restart
|
||||
# Copie e dê permissão:
|
||||
chmod +x /opt/zabbix/openvpn-access-tracker.sh
|
||||
|
||||
# Adicione ao cron:
|
||||
echo '* * * * * root /opt/zabbix/openvpn-access-tracker.sh' >> /etc/crontab
|
||||
```
|
||||
|
||||
### Testar manualmente um socket
|
||||
```bash
|
||||
echo "status 2" | nc -U /var/etc/openvpn/server14/sock
|
||||
```
|
||||
**Log gerado:** `/var/log/openvpn_user_activity.log`
|
||||
**Formato:** `TIMESTAMP|USER|VIRTUAL_IP|DESTINO:PORTA|PROTOCOLO|ESTADO`
|
||||
|
||||
---
|
||||
|
||||
## Métricas Disponíveis
|
||||
## Novas Métricas Disponíveis (v7)
|
||||
|
||||
| Chave | Descrição |
|
||||
|-------|-----------|
|
||||
| `openvpn.user.time_online[USER]` | Tempo online em segundos |
|
||||
| `openvpn.user.bytes_recv.cached[USER]` | Bytes recebidos (via cache) |
|
||||
| `openvpn.user.bytes_sent.cached[USER]` | Bytes enviados (via cache) |
|
||||
| `openvpn.access.destinations[USER]` | Lista de destinos acessados |
|
||||
| `openvpn.access.log.tail[N]` | Últimas N linhas do log de replay |
|
||||
| `openvpn.access.count[USER]` | Contagem de conexões do usuário |
|
||||
|
||||
---
|
||||
|
||||
## Retenção de Dados no Zabbix
|
||||
|
||||
| Tipo de Dado | Histórico | Tendência |
|
||||
|--------------|-----------|-----------|
|
||||
| Logs de Replay (texto) | 30 dias | N/A |
|
||||
| Métricas (bytes, tempo) | 30 dias | 365 dias |
|
||||
| Eventos/Alertas | 365 dias | N/A |
|
||||
|
||||
| UserParameter | Descrição |
|
||||
|---------------|-----------|
|
||||
| `openvpn.discovery` | Discovery LLD de usuários conectados |
|
||||
| `openvpn.server.discovery` | Discovery LLD de servidores OpenVPN |
|
||||
| `openvpn.user.count.total` | Total de usuários conectados |
|
||||
| `openvpn.user.count[serverX]` | Usuários por servidor |
|
||||
| `openvpn.server.status[serverX]` | Status do servidor (1/0) |
|
||||
| `openvpn.user.bytes_received[user]` | Bytes recebidos pelo usuário |
|
||||
| `openvpn.user.bytes_sent[user]` | Bytes enviados pelo usuário |
|
||||
| `openvpn.user.connected_since[user]` | Timestamp de conexão |
|
||||
| `openvpn.user.status[user]` | Status do usuário (1/0) |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
#!/bin/sh
|
||||
# OpenVPN Access Tracker - Sampled Replay (Arthur's Gold Standard v1)
|
||||
# Correlaciona usuários VPN com a tabela de estados do Packet Filter
|
||||
# Compatível com: pfSense 2.x / FreeBSD
|
||||
#
|
||||
# Instalação:
|
||||
# 1. Copie para /opt/zabbix/openvpn-access-tracker.sh
|
||||
# 2. chmod +x /opt/zabbix/openvpn-access-tracker.sh
|
||||
# 3. Adicione ao cron: */1 * * * * /opt/zabbix/openvpn-access-tracker.sh
|
||||
#
|
||||
# Output: /var/log/openvpn_user_activity.log
|
||||
# Format: TIMESTAMP|USER|REAL_IP|DST_IP:PORT|PROTOCOL
|
||||
|
||||
METRICS_FILE="/tmp/openvpn_metrics.json"
|
||||
LOG_FILE="/var/log/openvpn_user_activity.log"
|
||||
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# Verifica se temos dados de VPN
|
||||
if [ ! -f "$METRICS_FILE" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Extrai lista de usuários e seus IPs virtuais
|
||||
# Formato esperado: "user": { ... "virtual_ip": "10.0.8.5" ... }
|
||||
user_ips=$(cat "$METRICS_FILE" | sed 's/},{/}\n{/g' | grep -oE '"[^"]+":{"bytes_recv"[^}]+' | \
|
||||
sed 's/"//g' | awk -F: '{user=$1; for(i=2;i<=NF;i++) if($i ~ /virtual_ip/) {getline; print user":"$2}}' 2>/dev/null)
|
||||
|
||||
# Alternativa mais robusta: usar jq se disponível, senão parse manual
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
# jq disponível - parse limpo
|
||||
user_list=$(jq -r 'to_entries[] | "\(.key):\(.value.virtual_ip)"' "$METRICS_FILE" 2>/dev/null)
|
||||
else
|
||||
# Parse manual simplificado
|
||||
user_list=$(cat "$METRICS_FILE" | tr ',' '\n' | tr '{' '\n' | tr '}' '\n' | \
|
||||
grep -E '^"[a-zA-Z0-9._-]+"|virtual_ip' | paste - - 2>/dev/null | \
|
||||
sed 's/"//g;s/virtual_ip://g' | awk '{print $1":"$2}')
|
||||
fi
|
||||
|
||||
# Se não temos usuários, sai
|
||||
[ -z "$user_list" ] && exit 0
|
||||
|
||||
# Captura tabela de estados
|
||||
state_table=$(pfctl -ss 2>/dev/null)
|
||||
[ -z "$state_table" ] && exit 0
|
||||
|
||||
# Para cada usuário VPN, busca conexões na state table
|
||||
echo "$user_list" | while IFS=: read -r user vip; do
|
||||
[ -z "$user" ] || [ -z "$vip" ] && continue
|
||||
|
||||
# Busca estados onde o IP virtual é a origem
|
||||
# Formato pfctl -ss: all tcp 10.0.8.5:54321 -> 192.168.1.100:443 ESTABLISHED:ESTABLISHED
|
||||
echo "$state_table" | grep " $vip:" | while read -r state_line; do
|
||||
# Extrai protocolo, destino
|
||||
proto=$(echo "$state_line" | awk '{print $2}')
|
||||
dst=$(echo "$state_line" | awk '{print $4}' | sed 's/->//g')
|
||||
state=$(echo "$state_line" | awk '{print $NF}')
|
||||
|
||||
[ -z "$dst" ] && continue
|
||||
|
||||
# Loga a atividade
|
||||
printf "%s|%s|%s|%s|%s|%s\n" "$TIMESTAMP" "$user" "$vip" "$dst" "$proto" "$state" >> "$LOG_FILE"
|
||||
done
|
||||
done
|
||||
|
||||
# Rotação simples: mantém só últimas 50000 linhas (~5MB)
|
||||
if [ -f "$LOG_FILE" ] && [ $(wc -l < "$LOG_FILE") -gt 50000 ]; then
|
||||
tail -40000 "$LOG_FILE" > "$LOG_FILE.tmp" && mv "$LOG_FILE.tmp" "$LOG_FILE"
|
||||
fi
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/sh
|
||||
# OpenVPN Discovery - COLETOR (Arthur's Gold Standard v6-CACHE)
|
||||
# OpenVPN Discovery - COLETOR (Arthur's Gold Standard v7-METRICS)
|
||||
# Este script roda via CRON e grava o resultado em cache
|
||||
# Compatível com: pfSense 2.x / FreeBSD
|
||||
#
|
||||
|
|
@ -7,15 +7,24 @@
|
|||
# 1. Copie para /opt/zabbix/openvpn-collector.sh
|
||||
# 2. chmod +x /opt/zabbix/openvpn-collector.sh
|
||||
# 3. Adicione ao cron: */1 * * * * /opt/zabbix/openvpn-collector.sh
|
||||
#
|
||||
# v7 Changelog:
|
||||
# - Adicionado métricas expandidas: Bytes Received, Bytes Sent, Connected Since
|
||||
# - Novo cache secundário para métricas: /tmp/openvpn_metrics.json
|
||||
|
||||
SOCKET_DIR="/var/etc/openvpn"
|
||||
CACHE_FILE="/tmp/openvpn_discovery.json"
|
||||
CACHE_FILE_TMP="/tmp/openvpn_discovery.json.tmp"
|
||||
METRICS_FILE="/tmp/openvpn_metrics.json"
|
||||
METRICS_FILE_TMP="/tmp/openvpn_metrics.json.tmp"
|
||||
|
||||
# Inicia JSON
|
||||
# Inicia JSON de discovery
|
||||
printf '{"data":[' > "$CACHE_FILE_TMP"
|
||||
# Inicia JSON de métricas
|
||||
printf '{' > "$METRICS_FILE_TMP"
|
||||
|
||||
first=1
|
||||
first_discovery=1
|
||||
first_metrics=1
|
||||
|
||||
# Loop através de cada socket
|
||||
for sockdir in "$SOCKET_DIR"/server*/; do
|
||||
|
|
@ -27,27 +36,41 @@ for sockdir in "$SOCKET_DIR"/server*/; do
|
|||
server_name=$(basename "$sockdir")
|
||||
|
||||
# Consulta o socket e processa linha por linha
|
||||
# CLIENT_LIST format: type, cn, realaddr, virtaddr, virtaddr6, bytes_received, bytes_sent, connected_since_human, connected_since_unix, username, clientid, peerid, cipher
|
||||
(echo "status 2"; sleep 0.3; echo "quit") | /usr/bin/nc -U "$sockfile" 2>/dev/null | \
|
||||
grep "^CLIENT_LIST," | grep -v "Common Name" | \
|
||||
while IFS=',' read -r type cn realaddr virtaddr rest; do
|
||||
while IFS=',' read -r type cn realaddr virtaddr virtaddr6 bytes_recv bytes_sent conn_human conn_unix rest; do
|
||||
[ -z "$cn" ] && continue
|
||||
|
||||
real_ip=$(echo "$realaddr" | cut -d: -f1)
|
||||
virt_ip=$(echo "$virtaddr" | cut -d: -f1)
|
||||
|
||||
if [ $first -eq 0 ]; then
|
||||
printf ','
|
||||
# --- Discovery JSON ---
|
||||
if [ $first_discovery -eq 0 ]; then
|
||||
printf ',' >> "$CACHE_FILE_TMP"
|
||||
fi
|
||||
printf '{"{#VPN.USER}":"%s","{#VPN.SERVER}":"%s","{#VPN.REAL_IP}":"%s","{#VPN.VIRTUAL_IP}":"%s"}' "$cn" "$server_name" "$real_ip" "$virt_ip" >> "$CACHE_FILE_TMP"
|
||||
first_discovery=0
|
||||
|
||||
printf '{"{#VPN.USER}":"%s","{#VPN.SERVER}":"%s","{#VPN.REAL_IP}":"%s","{#VPN.VIRTUAL_IP}":"%s"}' "$cn" "$server_name" "$real_ip" "$virt_ip"
|
||||
first=0
|
||||
done >> "$CACHE_FILE_TMP"
|
||||
# --- Metrics JSON ---
|
||||
# Format: "username": { "bytes_recv": N, "bytes_sent": N, "connected_since": N, "real_ip": "x.x.x.x", "virtual_ip": "y.y.y.y" }
|
||||
if [ $first_metrics -eq 0 ]; then
|
||||
printf ',' >> "$METRICS_FILE_TMP"
|
||||
fi
|
||||
printf '"%s":{"bytes_recv":%s,"bytes_sent":%s,"connected_since":%s,"real_ip":"%s","virtual_ip":"%s","server":"%s"}' \
|
||||
"$cn" "${bytes_recv:-0}" "${bytes_sent:-0}" "${conn_unix:-0}" "$real_ip" "$virt_ip" "$server_name" >> "$METRICS_FILE_TMP"
|
||||
first_metrics=0
|
||||
done
|
||||
|
||||
first=0
|
||||
first_discovery=0
|
||||
first_metrics=0
|
||||
done
|
||||
|
||||
printf ']}\n' >> "$CACHE_FILE_TMP"
|
||||
printf '}\n' >> "$METRICS_FILE_TMP"
|
||||
|
||||
# Move atomicamente para evitar leitura parcial
|
||||
mv "$CACHE_FILE_TMP" "$CACHE_FILE"
|
||||
mv "$METRICS_FILE_TMP" "$METRICS_FILE"
|
||||
chmod 644 "$CACHE_FILE"
|
||||
chmod 644 "$METRICS_FILE"
|
||||
|
|
|
|||
|
|
@ -709,6 +709,115 @@ zabbix_export:
|
|||
- tag: scope
|
||||
value: availability
|
||||
discovery_rules:
|
||||
- uuid: 34ed656ffcf845b0b5598870de258002
|
||||
name: Descoberta de Usuários OpenVPN
|
||||
type: ZABBIX_ACTIVE
|
||||
key: openvpn.discovery
|
||||
delay: 5m
|
||||
description: |
|
||||
Descobre usuários conectados ao OpenVPN através do script openvpn-discovery.sh.
|
||||
Requisito: Zabbix Agent ativo com UserParameter configurado.
|
||||
item_prototypes:
|
||||
- uuid: a8a060a8e0494d3d99a71cd4f2b6a7c8
|
||||
name: 'OpenVPN [{#VPN.USER}]: Download Total (Bytes)'
|
||||
type: ZABBIX_ACTIVE
|
||||
key: 'openvpn.user.bytes_recv.cached[{#VPN.USER}]'
|
||||
delay: 1m
|
||||
history: 30d
|
||||
trends: 365d
|
||||
units: B
|
||||
description: Total de bytes recebidos (download) pelo usuário VPN.
|
||||
tags:
|
||||
- tag: component
|
||||
value: vpn
|
||||
- tag: vpn_user
|
||||
value: '{#VPN.USER}'
|
||||
- uuid: 36362e120e9445a1bbdc750afc0f6a1f
|
||||
name: 'OpenVPN [{#VPN.USER}]: Upload Total (Bytes)'
|
||||
type: ZABBIX_ACTIVE
|
||||
key: 'openvpn.user.bytes_sent.cached[{#VPN.USER}]'
|
||||
delay: 1m
|
||||
history: 30d
|
||||
trends: 365d
|
||||
units: B
|
||||
description: Total de bytes enviados (upload) pelo usuário VPN.
|
||||
tags:
|
||||
- tag: component
|
||||
value: vpn
|
||||
- tag: vpn_user
|
||||
value: '{#VPN.USER}'
|
||||
- uuid: 7eee5d914f0346c8a2b1c3d4e5f6a7b8
|
||||
name: 'OpenVPN [{#VPN.USER}]: Tempo Online (Segundos)'
|
||||
type: ZABBIX_ACTIVE
|
||||
key: 'openvpn.user.time_online[{#VPN.USER}]'
|
||||
delay: 1m
|
||||
history: 30d
|
||||
trends: 365d
|
||||
units: s
|
||||
description: Tempo de conexão do usuário VPN em segundos.
|
||||
tags:
|
||||
- tag: component
|
||||
value: vpn
|
||||
- tag: vpn_user
|
||||
value: '{#VPN.USER}'
|
||||
- uuid: c3a4b5c6d7e84f0991a2b3c4d5e6f7a8
|
||||
name: 'OpenVPN [{#VPN.USER}]: Status'
|
||||
type: ZABBIX_ACTIVE
|
||||
key: 'openvpn.user.status[{#VPN.USER}]'
|
||||
delay: 1m
|
||||
history: 30d
|
||||
trends: '0'
|
||||
valuemap:
|
||||
name: VPN User Status
|
||||
description: Status de conexão do usuário VPN (1=conectado, 0=desconectado).
|
||||
tags:
|
||||
- tag: component
|
||||
value: vpn
|
||||
- tag: vpn_user
|
||||
value: '{#VPN.USER}'
|
||||
- uuid: 1f2a3b4c5d6e4f8a9b0c1d2e3f4a5b6c
|
||||
name: 'OpenVPN [{#VPN.USER}]: IP Real'
|
||||
type: ZABBIX_ACTIVE
|
||||
key: 'openvpn.user.real_address.new[{#VPN.USER}]'
|
||||
delay: 1m
|
||||
history: 30d
|
||||
trends: '0'
|
||||
value_type: TEXT
|
||||
description: Endereço IP real (público) do usuário VPN.
|
||||
tags:
|
||||
- tag: component
|
||||
value: vpn
|
||||
- tag: vpn_user
|
||||
value: '{#VPN.USER}'
|
||||
- uuid: 9e8d7c6b5a4941f2bccd1e2f3a4b5c6d
|
||||
name: 'OpenVPN [{#VPN.USER}]: Destinos Acessados'
|
||||
type: ZABBIX_ACTIVE
|
||||
key: 'openvpn.access.destinations[{#VPN.USER}]'
|
||||
delay: 5m
|
||||
history: 30d
|
||||
trends: '0'
|
||||
value_type: TEXT
|
||||
description: Lista de destinos únicos acessados pelo usuário VPN (para replay).
|
||||
tags:
|
||||
- tag: component
|
||||
value: vpn
|
||||
- tag: component
|
||||
value: audit
|
||||
- tag: vpn_user
|
||||
value: '{#VPN.USER}'
|
||||
graph_prototypes:
|
||||
- uuid: 2b3c4d5e6f7a4892abcd1e2f3a4b5c6d
|
||||
name: 'OpenVPN [{#VPN.USER}]: Tráfego'
|
||||
graph_items:
|
||||
- color: 199C0D
|
||||
item:
|
||||
host: 'PFSense by SNMP'
|
||||
key: 'openvpn.user.bytes_recv.cached[{#VPN.USER}]'
|
||||
- sortorder: '1'
|
||||
color: F63100
|
||||
item:
|
||||
host: 'PFSense by SNMP'
|
||||
key: 'openvpn.user.bytes_sent.cached[{#VPN.USER}]'
|
||||
- uuid: e9fa3f6d8d864df8b0132f690ae54a1b
|
||||
name: Descoberta de interfaces de rede
|
||||
type: DEPENDENT
|
||||
|
|
@ -2755,6 +2864,14 @@ zabbix_export:
|
|||
newvalue: Disponível
|
||||
- value: '2'
|
||||
newvalue: Desconhecido
|
||||
- uuid: 830106fa5d2a45f9897c9154431eef08
|
||||
name: VPN User Status
|
||||
mappings:
|
||||
- value: '0'
|
||||
newvalue: Desconectado
|
||||
- value: '1'
|
||||
newvalue: Conectado
|
||||
|
||||
graphs:
|
||||
- uuid: 18b72f3eafe54206a574f431e7bb563a
|
||||
name: 'PFSense: Códigos de Motivo (Packet Filter)'
|
||||
|
|
|
|||
|
|
@ -1,21 +1,18 @@
|
|||
# Documentação: PFSense Hybrid: SNMP + OpenVPN Agent
|
||||
# Documentação: PFSense by SNMP
|
||||
|
||||
**Template:** PFSense Hybrid: SNMP + OpenVPN Agent
|
||||
**Template:** PFSense by SNMP
|
||||
**Descrição:**
|
||||
Template Híbrido para monitoramento do pfSense.
|
||||
|
||||
SNMP: Monitoramento de interfaces, firewall, serviços (DHCP, DNS, Nginx).
|
||||
Agent: Monitoramento avançado de OpenVPN (usuários, túneis S2S, tráfego).
|
||||
|
||||
Requisitos:
|
||||
1. Habilite o daemon SNMP em Services na interface web do pfSense.
|
||||
2. Instale o Zabbix Agent e configure os UserParameters OpenVPN (ver INSTRUCOES_AGENTE.txt).
|
||||
Template para monitoramento do pfSense via SNMP
|
||||
Configuração:
|
||||
1. Habilite o daemon SNMP em Services na interface web do pfSense: https://docs.netgate.com/pfsense/en/latest/services/snmp.html
|
||||
2. Configure a regra de firewall para permitir acesso do Zabbix Proxy/Server via SNMP: https://docs.netgate.com/pfsense/en/latest/firewall/index.html#managing-firewall-rules
|
||||
3. Associe o template ao host.
|
||||
|
||||
MIBs: BEGEMOT-PF-MIB, HOST-RESOURCES-MIB
|
||||
Keys Agent: openvpn.*
|
||||
MIBs usadas:
|
||||
BEGEMOT-PF-MIB
|
||||
HOST-RESOURCES-MIB
|
||||
|
||||
Gerado pelo Padrão Gold (Arthur) - ITGuys
|
||||
Gerado originalmente pela ferramenta oficial "Templator", Otimizado para Padrão Gold (Arthur)
|
||||
|
||||
## Itens Monitorados
|
||||
|
||||
|
|
@ -45,6 +42,44 @@ Gerado pelo Padrão Gold (Arthur) - ITGuys
|
|||
|
||||
### Regras de Descoberta (LLD)
|
||||
|
||||
#### Descoberta de Usuários OpenVPN (`openvpn.discovery`)
|
||||
- **Protótipos de Itens:**
|
||||
- OpenVPN [{#VPN.USER}]: Download Total (Bytes) (`openvpn.user.bytes_recv.cached[{#VPN.USER}]`)
|
||||
- OpenVPN [{#VPN.USER}]: Upload Total (Bytes) (`openvpn.user.bytes_sent.cached[{#VPN.USER}]`)
|
||||
- OpenVPN [{#VPN.USER}]: Tempo Online (Segundos) (`openvpn.user.time_online[{#VPN.USER}]`)
|
||||
- OpenVPN [{#VPN.USER}]: Status (`openvpn.user.status[{#VPN.USER}]`)
|
||||
- OpenVPN [{#VPN.USER}]: IP Real (`openvpn.user.real_address.new[{#VPN.USER}]`)
|
||||
- OpenVPN [{#VPN.USER}]: Destinos Acessados (`openvpn.access.destinations[{#VPN.USER}]`)
|
||||
#### Descoberta de interfaces de rede (`pfsense.net.if.discovery`)
|
||||
- **Protótipos de Itens:**
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Tráfego IPv4 de entrada bloqueado (`net.if.in.block.v4.bps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Pacotes IPv4 de entrada bloqueados (`net.if.in.block.v4.pps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Tráfego IPv6 de entrada bloqueado (`net.if.in.block.v6.bps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Pacotes IPv6 de entrada bloqueados (`net.if.in.block.v6.pps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Pacotes de entrada descartados (`net.if.in.discards[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Pacotes de entrada com erros (`net.if.in.errors[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Tráfego IPv4 de entrada permitido (`net.if.in.pass.v4.bps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Pacotes IPv4 de entrada permitidos (`net.if.in.pass.v4.pps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Tráfego IPv6 de entrada permitido (`net.if.in.pass.v6.bps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Pacotes IPv6 de entrada permitidos (`net.if.in.pass.v6.pps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Bits recebidos (`net.if.in[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Tráfego IPv4 de saída bloqueado (`net.if.out.block.v4.bps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Pacotes IPv4 de saída bloqueados (`net.if.out.block.v4.pps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Tráfego IPv6 de saída bloqueado (`net.if.out.block.v6.bps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Pacotes de saída descartados (`net.if.out.discards[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Pacotes de saída com erros (`net.if.out.errors[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Tráfego IPv4 de saída permitido (`net.if.out.pass.v4.bps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Pacotes IPv4 de saída permitidos (`net.if.out.pass.v4.pps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Tráfego IPv6 de saída permitido (`net.if.out.pass.v6.bps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Pacotes IPv6 de saída permitidos (`net.if.out.pass.v6.pps[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Bits enviados (`net.if.out[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Contagem de referências de regras (`net.if.rules.refs[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Velocidade (`net.if.speed[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Status operacional (`net.if.status[{#SNMPINDEX}]`)
|
||||
- Interface [{#IFNAME}({#IFALIAS})]: Tipo de interface (`net.if.type[{#SNMPINDEX}]`)
|
||||
#### Descoberta de Processos DHCP (`pfsense.dhcp.discovery`)
|
||||
- **Protótipos de Itens:**
|
||||
- Processo DHCP [{#HR_SW_PARAMS}]: Status (`pfsense.dhcp.process.status[{#HR_SW_PARAMS}]`)
|
||||
#### Descoberta de Usuários OpenVPN (`openvpn.discovery`)
|
||||
- **Protótipos de Itens:**
|
||||
- OpenVPN [{#VPN.USER}]: Download Total (Bytes) (`openvpn.user.bytes_received.total[{#VPN.USER}]`)
|
||||
|
|
@ -71,3 +106,14 @@ Gerado pelo Padrão Gold (Arthur) - ITGuys
|
|||
### Protótipos de Triggers (LLD)
|
||||
|
||||
**Regra: Descoberta de Usuários OpenVPN**
|
||||
|
||||
**Regra: Descoberta de interfaces de rede**
|
||||
- [WARNING] **🐢 Congestionamento: Descartes na interface {#IFNAME}**
|
||||
- [WARNING] **⚠️ PFSense: Interface [{#IFNAME}({#IFALIAS})]: Alta taxa de erros de entrada**
|
||||
- [WARNING] **⚠️ PFSense: Interface [{#IFNAME}({#IFALIAS})]: Alta taxa de erros de saída**
|
||||
- [AVERAGE] **🔌 PFSense: Interface [{#IFNAME}({#IFALIAS})]: Link indisponível**
|
||||
|
||||
**Regra: Descoberta de Processos DHCP**
|
||||
- [HIGH] **🚨 DHCP Parado: Instância {#HR_SW_PARAMS} não está rodando**
|
||||
|
||||
**Regra: Descoberta de Usuários OpenVPN**
|
||||
|
|
|
|||
|
|
@ -40,4 +40,39 @@ UserParameter=openvpn.user.real_address.new[*],for sock in /var/etc/openvpn/serv
|
|||
|
||||
# Status do usuário (1=conectado, 0=desconectado)
|
||||
# Uso: openvpn.user.status[joao.silva]
|
||||
UserParameter=openvpn.user.status[*],for sock in /var/etc/openvpn/server*/sock; do [ -S "$sock" ] && (echo "status 2"; sleep 0.2; echo "quit") | /usr/bin/nc -U "$sock" 2>/dev/null | grep -q "^CLIENT_LIST,$1," && echo 1 && exit; done; echo 0
|
||||
UserParameter=openvpn.user.status[*],for sock in /var/etc/openvpn/server*/sock; do [ -S "$sock" ] && (echo "status 2"; sleep 0.2; echo "quit") | /usr/bin/nc -U "$sock" 2>/dev/null | grep -q "^CLIENT_LIST,$1," && echo 1 && exit; done; echo 0
|
||||
|
||||
# ============================================================================
|
||||
# MÉTRICAS AVANÇADAS v6 (Arthur's Gold Standard)
|
||||
# Requer: openvpn-collector.sh rodando via cron (gera /tmp/openvpn_metrics.json)
|
||||
# ============================================================================
|
||||
|
||||
# Tempo online em segundos (calculado a partir do connected_since)
|
||||
# Uso: openvpn.user.time_online[joao.silva]
|
||||
UserParameter=openvpn.user.time_online[*],conn=$(cat /tmp/openvpn_metrics.json 2>/dev/null | grep -oE '"$1":\{[^}]+' | grep -oE 'connected_since":[0-9]+' | cut -d: -f2); [ -n "$conn" ] && [ "$conn" -gt 0 ] && echo $(( $(date +%s) - $conn )) || echo 0
|
||||
|
||||
# Métricas via cache JSON (mais rápido que consultar socket)
|
||||
# Bytes recebidos (via cache)
|
||||
UserParameter=openvpn.user.bytes_recv.cached[*],cat /tmp/openvpn_metrics.json 2>/dev/null | grep -oE '"$1":\{[^}]+' | grep -oE 'bytes_recv":[0-9]+' | cut -d: -f2 || echo 0
|
||||
|
||||
# Bytes enviados (via cache)
|
||||
UserParameter=openvpn.user.bytes_sent.cached[*],cat /tmp/openvpn_metrics.json 2>/dev/null | grep -oE '"$1":\{[^}]+' | grep -oE 'bytes_sent":[0-9]+' | cut -d: -f2 || echo 0
|
||||
|
||||
# IP Virtual do usuário (via cache)
|
||||
UserParameter=openvpn.user.virtual_ip.cached[*],cat /tmp/openvpn_metrics.json 2>/dev/null | grep -oE '"$1":\{[^}]+virtual_ip":"[^"]+' | grep -oE 'virtual_ip":"[^"]+' | cut -d'"' -f3 || echo ""
|
||||
|
||||
# ============================================================================
|
||||
# LOG DE ACESSO (REPLAY) - Requer: openvpn-access-tracker.sh via cron
|
||||
# ============================================================================
|
||||
|
||||
# Últimas N linhas do log de atividade (para widget de replay)
|
||||
# Uso: openvpn.access.log.tail[100] -> últimas 100 linhas
|
||||
UserParameter=openvpn.access.log.tail[*],tail -$1 /var/log/openvpn_user_activity.log 2>/dev/null || echo ""
|
||||
|
||||
# Contagem de conexões de um usuário específico (últimas 24h)
|
||||
# Uso: openvpn.access.count[joao.silva]
|
||||
UserParameter=openvpn.access.count[*],grep -c "|$1|" /var/log/openvpn_user_activity.log 2>/dev/null || echo 0
|
||||
|
||||
# Destinos únicos acessados por um usuário (lista)
|
||||
# Uso: openvpn.access.destinations[joao.silva]
|
||||
UserParameter=openvpn.access.destinations[*],grep "|$1|" /var/log/openvpn_user_activity.log 2>/dev/null | cut -d'|' -f4 | sort -u | head -50 | tr '\n' ',' | sed 's/,$//' || echo ""
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,118 @@
|
|||
# Documentação: Windows by Zabbix agent active
|
||||
|
||||
**Template:** Windows by Zabbix agent active
|
||||
**Descrição:**
|
||||
Template Windows Server Gold Edition (Pt-BR).
|
||||
|
||||
Monitoramento Otimizado por Arthur 'O Farol'.
|
||||
Inclui: RDP, Fila de Disco, Auditoria de Login e traduções completas.
|
||||
|
||||
## Itens Monitorados
|
||||
|
||||
### Itens Globais
|
||||
- **Nome do Host (Agent)** (`agent.hostname`)
|
||||
- **Status do Agente Zabbix (Ping)** (`agent.ping`)
|
||||
- **Versão do Agente Zabbix** (`agent.version`)
|
||||
- **Memória: Cache Bytes** (`perf_counter_en["\Memory\Cache Bytes"]`)
|
||||
- **Memória: Entradas de Tabela de Página Livres** (`perf_counter_en["\Memory\Free System Page Table Entries"]`)
|
||||
- **Memória: Page Faults/seg** (`perf_counter_en["\Memory\Page Faults/sec"]`)
|
||||
- **Memória: Pages/seg (Swap I/O)** (`perf_counter_en["\Memory\Pages/sec"]`)
|
||||
- **Memória: Non-paged Pool** (`perf_counter_en["\Memory\Pool Nonpaged Bytes"]`)
|
||||
- **Swap: % de Uso** (`perf_counter_en["\Paging file(_Total)\% Usage"]`)
|
||||
- **CPU: Tempo DPC** (`perf_counter_en["\Processor Information(_total)\% DPC Time"]`)
|
||||
- **CPU: Tempo de Interrupção** (`perf_counter_en["\Processor Information(_total)\% Interrupt Time"]`)
|
||||
- **CPU: Tempo Privilegiado (Kernel)** (`perf_counter_en["\Processor Information(_total)\% Privileged Time"]`)
|
||||
- **CPU: Tempo de Usuário** (`perf_counter_en["\Processor Information(_total)\% User Time"]`)
|
||||
- **CPU: Context Switches/seg** (`perf_counter_en["\System\Context Switches/sec"]`)
|
||||
- **CPU: Tamanho da Fila (Queue Length)** (`perf_counter_en["\System\Processor Queue Length"]`)
|
||||
- **Sistema: Número de Threads** (`perf_counter_en["\System\Threads"]`)
|
||||
- **Sistema: Número de Processos** (`proc.num[]`)
|
||||
- **CPU: Utilização Total** (`system.cpu.util`)
|
||||
- **Sistema: Nome do Computador** (`system.hostname`)
|
||||
- **Sistema: Hora Local** (`system.localtime`)
|
||||
- **Sistema: Arquitetura do SO** (`system.sw.arch`)
|
||||
- **Sistema: Versão do SO** (`system.sw.os`)
|
||||
- **Swap: Espaço Livre** (`system.swap.free`)
|
||||
- **Swap: Espaço Livre in %** (`system.swap.pfree`)
|
||||
- **Swap: Espaço Total** (`system.swap.size[,total]`)
|
||||
- **Sistema: Descrição** (`system.uname`)
|
||||
- **Sistema: Uptime** (`system.uptime`)
|
||||
- **Get filesystems** (`vfs.fs.get`)
|
||||
- **Memória: Total** (`vm.memory.size[total]`)
|
||||
- **Memória: Usada** (`vm.memory.size[used]`)
|
||||
- **Memória: % de Utilização** (`vm.memory.util`)
|
||||
- **Windows: Network interfaces WMI get** (`wmi.getall[root\cimv2,"select Name,Description,NetConnectionID,Speed,AdapterTypeId,NetConnectionStatus,GUID from win32_networkadapter where PhysicalAdapter=True and NetConnectionStatus>0"]`)
|
||||
- **Hardware: Número de Cores** (`wmi.get[root/cimv2,"Select NumberOfLogicalProcessors from Win32_ComputerSystem"]`)
|
||||
- **Disponibilidade do Agente Zabbix** (`zabbix[host,agent,disponível]`)
|
||||
- **RDP: Sessões Ativas (Total)** (`perf_counter_en["\Terminal Services\Total Sessions"]`)
|
||||
- **Disco: Tamanho da Fila (Queue Length)** (`perf_counter_en["\PhysicalDisk(_Total)\Current Disk Queue Length"]`)
|
||||
- **Segurança: Falhas de Login (Audit Failure)** (`eventlog[Security,,,,4625]`)
|
||||
|
||||
### Regras de Descoberta (LLD)
|
||||
|
||||
#### Descoberta de interfaces de rede (`net.if.discovery`)
|
||||
- **Protótipos de Itens:**
|
||||
- Interface {#IFNAME}: Pacotes Descartados (In) (`net.if.in["{#IFGUID}",dropped]`)
|
||||
- Interface {#IFNAME}: Erros de Pacote (In) (`net.if.in["{#IFGUID}",errors]`)
|
||||
- Interface {#IFNAME}: Tráfego de Entrada (`net.if.in["{#IFGUID}"]`)
|
||||
- Interface {#IFNAME}: Pacotes Descartados (Out) (`net.if.out["{#IFGUID}",dropped]`)
|
||||
- Interface {#IFNAME}: Erros de Pacote (Out) (`net.if.out["{#IFGUID}",errors]`)
|
||||
- Interface {#IFNAME}: Tráfego de Saída (`net.if.out["{#IFGUID}"]`)
|
||||
- Interface {#IFNAME}: Velocidade Negociada (`net.if.speed["{#IFGUID}"]`)
|
||||
- Interface {#IFNAME}: Status Operacional (`net.if.status["{#IFGUID}"]`)
|
||||
- Interface {#IFNAME}: Tipo de Interface (`net.if.type["{#IFGUID}"]`)
|
||||
#### Descoberta de discos físicos (`perf_instance_en.discovery[PhysicalDisk]`)
|
||||
- **Protótipos de Itens:**
|
||||
- {#DEVNAME}: Utilização de disco por tempo ocioso (`perf_counter_en["\PhysicalDisk({#DEVNAME})\% Idle Time",60]`)
|
||||
- {#DEVNAME}: Tamanho médio da fila de leitura (`perf_counter_en["\PhysicalDisk({#DEVNAME})\Avg. Disk Read Queue Length",60]`)
|
||||
- {#DEVNAME}: Tempo médio de espera de leitura (`perf_counter_en["\PhysicalDisk({#DEVNAME})\Avg. Disk sec/Read",60]`)
|
||||
- {#DEVNAME}: Tempo médio de espera de escrita (`perf_counter_en["\PhysicalDisk({#DEVNAME})\Avg. Disk sec/Write",60]`)
|
||||
- {#DEVNAME}: Tamanho médio da fila de escrita (`perf_counter_en["\PhysicalDisk({#DEVNAME})\Avg. Disk Write Queue Length",60]`)
|
||||
- {#DEVNAME}: Tamanho médio da fila de disco (avgqu-sz) (`perf_counter_en["\PhysicalDisk({#DEVNAME})\Current Disk Queue Length",60]`)
|
||||
- {#DEVNAME}: Taxa de leitura de disco (`perf_counter_en["\PhysicalDisk({#DEVNAME})\Disk Reads/sec",60]`)
|
||||
- {#DEVNAME}: Taxa de escrita de disco (`perf_counter_en["\PhysicalDisk({#DEVNAME})\Disk Writes/sec",60]`)
|
||||
#### Descoberta de serviços Windows (`service.discovery`)
|
||||
- **Protótipos de Itens:**
|
||||
- Estado do serviço "{#SERVICE.NAME}" ({#SERVICE.DISPLAYNAME}) (`service.info["{#SERVICE.NAME}",state]`)
|
||||
#### Descoberta de sistemas de arquivos montados (`vfs.fs.dependent.discovery`)
|
||||
- **Protótipos de Itens:**
|
||||
- FS [{#FSLABEL}({#FSNAME})]: Espaço: Disponível (`vfs.fs.dependent.size[{#FSNAME},free]`)
|
||||
- FS [{#FSLABEL}({#FSNAME})]: Espaço: Usado, em % (`vfs.fs.dependent.size[{#FSNAME},pused]`)
|
||||
- FS [{#FSLABEL}({#FSNAME})]: Espaço: Total (`vfs.fs.dependent.size[{#FSNAME},total]`)
|
||||
- FS [{#FSLABEL}({#FSNAME})]: Espaço: Usado (`vfs.fs.dependent.size[{#FSNAME},used]`)
|
||||
- FS [{#FSLABEL}({#FSNAME})]: Obter dados (`vfs.fs.dependent[{#FSNAME},data]`)
|
||||
|
||||
## Alertas (Triggers)
|
||||
|
||||
### Triggers Globais
|
||||
- [WARNING] **⚠️ Windows: Esgotamento de Tabela de Páginas**
|
||||
- [WARNING] **⚠️ Windows: Excesso de Paginação (Swap)**
|
||||
- [WARNING] **⚠️ Windows: CPU com muitas Interrupções (Hardware?)**
|
||||
- [WARNING] **⚠️ Windows: Uso Elevado de Kernel (Privileged Time)**
|
||||
- [WARNING] **🔥 Windows: Uso de CPU Crítico**
|
||||
- [INFO] **ℹ️ Windows: Nome do Host Mudou**
|
||||
- [WARNING] **⚠️ Windows: Hora do Sistema Dessincronizada**
|
||||
- [INFO] **ℹ️ Windows: SO Atualizado/Alterado**
|
||||
- [WARNING] **⚠️ Windows: Servidor Reiniciou**
|
||||
- [AVERAGE] **🧠 Windows: Memória Esgotada**
|
||||
- [AVERAGE] **🚨 Windows: Agente Zabbix Indisponível**
|
||||
- [WARNING] **⚠️ Windows: Muitas Sessões RDP Ativas**
|
||||
- [AVERAGE] **🐢 Windows: Disco Lento (Queue Length Alta)**
|
||||
- [HIGH] **👮 Windows: Possível Brute Force (Falhas de Login)**
|
||||
|
||||
### Protótipos de Triggers (LLD)
|
||||
|
||||
**Regra: Descoberta de interfaces de rede**
|
||||
- [AVERAGE] **🚨 Interface {#IFNAME}: Link Down**
|
||||
|
||||
**Regra: Descoberta de discos físicos**
|
||||
- [WARNING] **🔥 Windows: Disco Saturado (I/O) em {#DEVNAME}**
|
||||
- [WARNING] **⚠️ Windows: Latência de Leitura Alta em {#DEVNAME}**
|
||||
- [WARNING] **⚠️ Windows: Latência de Escrita Alta em {#DEVNAME}**
|
||||
|
||||
**Regra: Descoberta de serviços Windows**
|
||||
- [AVERAGE] **🚨 Windows: Serviço Crítico Parado: {#SERVICE.DISPLAYNAME} ({#SERVICE.NAME})**
|
||||
|
||||
**Regra: Descoberta de sistemas de arquivos montados**
|
||||
- [AVERAGE] **🚨 Windows: Disco Crítico em {#FSNAME} ({#FSLABEL})**
|
||||
- [WARNING] **⚠️ Windows: Disco Cheio em {#FSNAME} ({#FSLABEL})**
|
||||
|
|
@ -0,0 +1,236 @@
|
|||
import yaml
|
||||
import sys
|
||||
import re
|
||||
|
||||
# File Paths
|
||||
SOURCE_FILE = r"C:\Users\joao.goncalves\Desktop\zabbix-itguys\templates_gold\windows_active_agent\template_windows_gold_ptbr.yaml"
|
||||
TARGET_FILE = r"C:\Users\joao.goncalves\Desktop\zabbix-itguys\templates_gold\windows_active_agent\template_windows_gold_ptbr.yaml" # Overwrite
|
||||
|
||||
# Translations Dictionary
|
||||
TRANSLATIONS = {
|
||||
# Items & General Descriptions
|
||||
'The agent always returns "1" for this item. May be used in combination with `nodata()` for the availability check.': 'O agente sempre retorna "1" para este item. Pode ser usado com `nodata()` para verificação de disponibilidade.',
|
||||
'Cache Bytes is the sum of the Memory\\System Cache Resident Bytes, Memory\\System Driver Resident Bytes, Memory\\System Code Resident Bytes, and Memory\\Pool Paged Resident Bytes counters. This counter displays the last observed value only; it is not an average.': 'Cache Bytes é a soma dos bytes residentes do Cache do Sistema, Drivers, Código e Pool Paged. Mostra apenas o último valor observado, não a média.',
|
||||
'This indicates the number of page table entries not currently in use by the system. If the number is less than 5,000, there may be a memory leak or you running out of memory.': 'Indica o número de entradas da tabela de páginas não utilizadas. Se menor que 5.000, pode haver vazamento de memória.',
|
||||
'Page Faults/sec is the average number of pages faulted per second. It is measured in number of pages faulted per second because only one page is faulted in each fault operation, hence this is also equal to the number of page fault operations. This counter includes both hard faults (those that require disk access) and soft faults (where the faulted page is found elsewhere in physical memory.) Most processors can handle large numbers of soft faults without significant consequence. However, hard faults, which require disk access, can cause significant delays.': 'Page Faults/seg é a média de falhas de página por segundo. Inclui falhas hard (disco) e soft (memória). Falhas hard causam atrasos significativos.',
|
||||
'This measures the rate at which pages are read from or written to disk to resolve hard page faults.': 'Mede a taxa de leitura/escrita de páginas no disco para resolver hard faults.',
|
||||
'If the value is greater than 1,000, as a result of excessive paging, there may be a memory leak.': 'Se > 1.000, indica paginação excessiva e possível vazamento de memória.',
|
||||
'The Memory Pages/sec in the last 5 minutes exceeds `{$MEM.PAGE_SEC.CRIT.MAX}`. If the value is greater than 1,000, as a result of excessive paging, there may be a memory leak.': 'A taxa de Pages/sec excedeu `{$MEM.PAGE_SEC.CRIT.MAX}` nos últimos 5m. Se > 1.000, indica possível vazamento de memória.',
|
||||
'This measures the size, in bytes, of the non-paged pool. This is an area of system memory for objects that cannot be written to disk but instead must remain in physical memory as long as they are allocated.': 'Mede o tamanho (bytes) do pool não paginado (memória física obrigatória).',
|
||||
'There is a possible memory leak if the value is greater than 175MB (or 100MB with the /3GB switch). Consequently, Event ID 2019 is recorded in the system event log.': 'Possível vazamento se > 175MB (Event ID 2019).',
|
||||
'The used space of swap volume/file in percent.': 'Espaço usado do arquivo de swap em porcentagem.',
|
||||
'Processor DPC time is the time that a single processor spent receiving and servicing deferred procedure calls (DPCs). DPCs are interrupts that run at a lower priority than standard interrupts. `% DPC Time` is a component of `% Privileged Time` because DPCs are executed in privileged mode. If a high `% DPC Time` is sustained, there may be a processor bottleneck or an application or hardware related issue that can significantly diminish overall system performance.': 'Tempo de DPC é o tempo gasto em chamadas de procedimento diferido (DPCs). Alto uso constante indica gargalo de CPU, driver ou hardware.',
|
||||
'The processor information `% Interrupt Time` counter indicates how much time the processor spends handling hardware interrupts during sample intervals. It reflects the activity of devices like the system clock, mouse, disk drivers, and network cards. A value above 20% suggests possible hardware issues.': 'Tempo de Interrupção indica tempo da CPU tratando interrupções de hardware (mouse, disco, rede). Acima de 20% sugere problemas de hardware.',
|
||||
'The CPU Interrupt Time in the last 5 minutes exceeds `{$CPU.INTERRUPT.CRIT.MAX}`%.': 'O Tempo de Interrupção da CPU nos últimos 5 minutos excede `{$CPU.INTERRUPT.CRIT.MAX}`%.',
|
||||
'The processor information `% Privileged Time` counter shows the percent of time that the processor is spent executing in Kernel (or Privileged) mode. Privileged mode includes services interrupts inside Interrupt Service Routines (ISRs), executing Deferred Procedure Calls (DPCs), Device Driver calls and other kernel-mode functions of the Windows Operating System.': 'Tempo Privilegiado mostra % de tempo da CPU em modo Kernel (Drivers, DPCs, ISRs).',
|
||||
'The CPU: Tempo Privilegiado (Kernel) in the last 5 minutes exceeds {$CPU.PRIV.CRIT.MAX}%.': 'O Tempo Privilegiado (Kernel) da CPU excede {$CPU.PRIV.CRIT.MAX}% nos últimos 5m.',
|
||||
'The processor information `% User Time` counter shows the percent of time that the processor(s) is spent executing in User mode.': 'Tempo de Usuário mostra % de tempo da CPU em modo Usuário (Aplicações).',
|
||||
'Context Switches/sec is the combined rate at which all processors on the computer are switched from one thread to another.': 'Context Switches/sec é a taxa de troca de threads nos processadores.',
|
||||
'Context switches occur when a running thread voluntarily relinquishes the processor, is preempted by a higher priority ready thread, or switches between user-mode and privileged (kernel) mode to use an Executive or subsystem service.': 'Ocorre quando threads cedem lugar a outras ou alternam modos.',
|
||||
'It is the sum of Thread\\Context Switches/sec for all threads running on all processors in the computer and is measured in numbers of switches.': 'É a soma de trocas de contexto para todas as threads.',
|
||||
'There are context switch counters on the System and Thread objects. This counter displays the difference between the values observed in the last two samples, divided by the duration of the sample interval.': 'Mostra a diferença entre amostras dividida pelo intervalo.',
|
||||
'The Processor Queue Length shows the number of threads that are observed as delayed in the processor Ready Queue and are waiting to be executed.': 'Processor Queue Length mostra threads aguardando execução na fila da CPU.',
|
||||
'The number of threads used by all running processes.': 'Número total de threads usadas por todos os processos.',
|
||||
'The number of processes.': 'Número total de processos em execução.',
|
||||
'CPU: Utilização Total expressed in %.': 'Utilização Total da CPU expressa em %.',
|
||||
'The host name of the system.': 'Nome do host do sistema.',
|
||||
'The name of the system has changed. Acknowledge to close the problem manually.': 'O nome do sistema mudou. Reconheça para fechar o problema manualmente.',
|
||||
'The local system time of the host.': 'Hora local do sistema.',
|
||||
'The architecture of the operating system.': 'Arquitetura do sistema operacional.',
|
||||
'The description of the operating system has changed. Possible reasons are that the system has been updated or replaced. Acknowledge to close the problem manually.': 'A descrição do SO mudou. O sistema pode ter sido atualizado. Reconheça para fechar.',
|
||||
'The free space of the swap volume/file expressed in bytes.': 'Espaço livre do arquivo de swap em bytes.',
|
||||
'The free space of the swap volume/file expressed in %.': 'Espaço livre do arquivo de swap em %.',
|
||||
'The total space of the swap volume/file expressed in bytes.': 'Tamanho total do arquivo de swap em bytes.',
|
||||
'Sistema: Descrição of the host.': 'Descrição do sistema operacional do host.',
|
||||
'The system uptime expressed in the following format: "N days, hh:mm:ss".': 'Tempo de atividade do sistema no formato: "N dias, hh:mm:ss".',
|
||||
'The `vfs.fs.get` key acquires raw information set about the filesystems. Later to be extracted by preprocessing in dependent items.': 'A chave `vfs.fs.get` adquire informações brutas sobre sistemas de arquivos para pré-processamento.',
|
||||
'Memória: Total expressed in bytes.': 'Memória total expressa em bytes.',
|
||||
'Memória: Usada in bytes.': 'Memória usada em bytes.',
|
||||
'Memória: % de Utilização in %.': 'Porcentagem de memória utilizada.',
|
||||
'Raw data of `win32_networkadapter.`': 'Dados brutos de `win32_networkadapter`.',
|
||||
'The number of logical processors available on the computer.': 'Número de processadores lógicos disponíveis.',
|
||||
'Used for monitoring the availability status of the agent.': 'Usado para monitorar a disponibilidade do agente.',
|
||||
|
||||
# Discovery Rules & Prototypes
|
||||
'Discovery of installed network interfaces.': 'Descoberta de interfaces de rede instaladas.',
|
||||
'The number of incoming packets dropped on the network interface.': 'Número de pacotes de entrada descartados na interface.',
|
||||
'The number of incoming packets with errors on the network interface.': 'Número de pacotes de entrada com erros na interface.',
|
||||
'Incoming traffic on the network interface.': 'Tráfego de entrada na interface de rede.',
|
||||
'The number of outgoing packets dropped on the network interface.': 'Número de pacotes de saída descartados na interface.',
|
||||
'The number of outgoing packets with errors on the network interface.': 'Número de pacotes de saída com erros na interface.',
|
||||
'Outgoing traffic on the network interface.': 'Tráfego de saída na interface de rede.',
|
||||
'Estimated bandwidth of the network interface if any.': 'Largura de banda estimada da interface de rede.',
|
||||
'The operational status of the network interface.': 'Status operacional da interface de rede.',
|
||||
'This trigger expression works as follows:': 'Esta trigger funciona assim:',
|
||||
'1. It can be triggered if the operations status is down.': '1. Dispara se o status operacional for Down.',
|
||||
'2. `{$IFCONTROL:"{#IFNAME}"}=1` - a user can redefine the context macro to "0", marking this interface as not important.': '2. `{$IFCONTROL:"{#IFNAME}"}=1` - defina a macro como "0" para ignorar esta interface.',
|
||||
'Used for the discovery of Windows services of different types as defined in the template\'s macros.': 'Descoberta de serviços Windows baseada nas macros do template.',
|
||||
'The service has a state other than "Running" for the last three times.': 'O serviço não está no estado "Running" nas últimas 3 verificações.',
|
||||
'Discovery of filesystems of different types.': 'Descoberta de sistemas de arquivos.',
|
||||
'Available storage space expressed in bytes.': 'Espaço disponível em bytes.',
|
||||
'Calculated as the percentage of currently used space compared to the maximum available space.': 'Calculado como porcentagem de espaço usado em relação ao total.',
|
||||
'The volume\'s space usage exceeds the `{$VFS.FS.PUSED.MAX.CRIT:"{#FSNAME}"}%` limit.': 'O uso do volume excede o limite crítico `{$VFS.FS.PUSED.MAX.CRIT:"{#FSNAME}"}%`.',
|
||||
'The trigger expression is based on the current used and maximum available spaces.': 'A trigger baseia-se no espaço usado e máximo disponível.',
|
||||
'Event name represents the total volume space, which can differ from the maximum available space, depending on the filesystem type.': 'O nome do evento mostra o espaço total, que pode diferir do disponível dependendo do sistema de arquivos.',
|
||||
'The volume\'s space usage exceeds the `{$VFS.FS.PUSED.MAX.WARN:"{#FSNAME}"}%` limit.': 'O uso do volume excede o limite de aviso `{$VFS.FS.PUSED.MAX.WARN:"{#FSNAME}"}%`.',
|
||||
'Total space expressed in bytes.': 'Espaço total em bytes.',
|
||||
'Used storage expressed in bytes.': 'Espaço usado em bytes.',
|
||||
'Intermediate data of `{#FSNAME}` filesystem.': 'Dados intermediários do sistema de arquivos `{#FSNAME}`.',
|
||||
|
||||
# Macros Section
|
||||
'Timeout after which agent is considered unavailable. Works only for agents reachable from Zabbix server/proxy (passive mode).': 'Timeout para considerar agente indisponível (apenas modo passivo).',
|
||||
'The critical threshold of the % Interrupt Time counter.': 'Limiar crítico para % Interrupt Time.',
|
||||
'The threshold of the % Privileged Time counter.': 'Limiar crítico para % Privileged Time.',
|
||||
'The threshold of the Processor Queue Length counter.': 'Limiar para Processor Queue Length.',
|
||||
'The critical threshold of the CPU: Utilização Total expressed in %.': 'Limiar crítico para Utilização Total da CPU (%).',
|
||||
'Warning threshold of error packet rate. Can be used with interface name as context.': 'Limiar de aviso para taxa de erros de pacote.',
|
||||
'Used as a threshold in the interface utilization trigger.': 'Limiar para trigger de utilização de interface.',
|
||||
'Macro for the interface operational state for the "link down" trigger. Can be used with interface name as context.': 'Macro para estado operacional (trigger link down). Use 0 para desativar.',
|
||||
'The warning threshold of the Memory Pages/sec counter.': 'Limiar de aviso para Memory Pages/sec.',
|
||||
'The warning threshold of the Free System Page Table Entries counter.': 'Limiar de aviso para Free System Page Table Entries.',
|
||||
'The warning threshold of the Memory util item.': 'Limiar de aviso para uso de memória.',
|
||||
'Used in Network interface discovery. Can be overridden on the host or linked template level.': 'Usado na descoberta de interface de rede. Pode ser sobrescrito.',
|
||||
'Used in Service discovery. Can be overridden on the host or linked template level.': 'Usado na descoberta de serviços. Pode ser sobrescrito.',
|
||||
'The warning threshold of the minimum free swap.': 'Limiar de aviso para swap livre mínimo.',
|
||||
'The upper threshold for difference of system time.': 'Limiar superior para diferença de tempo do sistema.',
|
||||
'The lower threshold for difference of system time. Used in recovery expression to avoid trigger flapping.': 'Limiar inferior para diferença de tempo (recuperação).',
|
||||
'Used in physical disk discovery. Can be overridden on the host or linked template level.': 'Usado na descoberta de disco físico.',
|
||||
'Disk read average response time (in s) before the trigger fires.': 'Tempo médio de leitura (s) para disparar trigger.',
|
||||
'The warning threshold of disk time utilization in percent.': 'Limiar de aviso para utilização de disco (%).',
|
||||
'Disk write average response time (in s) before the trigger fires.': 'Tempo médio de escrita (s) para disparar trigger.',
|
||||
'Used in filesystem discovery. Can be overridden on the host or linked template level.': 'Usado na descoberta de sistema de arquivos.',
|
||||
'The critical threshold of the filesystem utilization.': 'Limiar crítico de utilização do sistema de arquivos.',
|
||||
'The warning threshold of the filesystem utilization.': 'Limiar de aviso de utilização do sistema de arquivos.',
|
||||
'The CPU Queue Length in the last 5 minutes exceeds `{$CPU.QUEUE.CRIT.MAX}`. According to actual observations, PQL should not exceed the number of cores * 2. To fine-tune the conditions, use the macro `{$CPU.QUEUE.CRIT.MAX }`.': 'A fila da CPU excedeu `{$CPU.QUEUE.CRIT.MAX}` nos últimos 5m. Idealmente PQL < Cores * 2.',
|
||||
'This trigger is ignored, if there is no swap configured': 'Esta trigger é ignorada se não houver swap configurado.',
|
||||
|
||||
# Missing Discovery Prototypes (Added in V2)
|
||||
'{#DEVNAME}: Disk utilization by idle time': '{#DEVNAME}: Utilização de disco por tempo ocioso',
|
||||
'{#DEVNAME}: Average disk read queue length': '{#DEVNAME}: Tamanho médio da fila de leitura',
|
||||
'{#DEVNAME}: Disk read request avg waiting time': '{#DEVNAME}: Tempo médio de espera de leitura',
|
||||
'{#DEVNAME}: Disk write request avg waiting time': '{#DEVNAME}: Tempo médio de espera de escrita',
|
||||
'{#DEVNAME}: Average disk write queue length': '{#DEVNAME}: Tamanho médio da fila de escrita',
|
||||
'{#DEVNAME}: Disk average queue size (avgqu-sz)': '{#DEVNAME}: Tamanho médio da fila de disco (avgqu-sz)',
|
||||
'{#DEVNAME}: Disk read rate': '{#DEVNAME}: Taxa de leitura de disco',
|
||||
'{#DEVNAME}: Disk write rate': '{#DEVNAME}: Taxa de escrita de disco',
|
||||
'State of service "{#SERVICE.NAME}" ({#SERVICE.DISPLAYNAME})': 'Estado do serviço "{#SERVICE.NAME}" ({#SERVICE.DISPLAYNAME})',
|
||||
'FS [{#FSLABEL}({#FSNAME})]: Space: Available': 'FS [{#FSLABEL}({#FSNAME})]: Espaço: Disponível',
|
||||
'FS [{#FSLABEL}({#FSNAME})]: Space: Used, in %': 'FS [{#FSLABEL}({#FSNAME})]: Espaço: Usado, em %',
|
||||
'FS [{#FSLABEL}({#FSNAME})]: Space: Total': 'FS [{#FSLABEL}({#FSNAME})]: Espaço: Total',
|
||||
'FS [{#FSLABEL}({#FSNAME})]: Space: Used': 'FS [{#FSLABEL}({#FSNAME})]: Espaço: Usado',
|
||||
'FS [{#FSLABEL}({#FSNAME})]: Get data': 'FS [{#FSLABEL}({#FSNAME})]: Obter dados',
|
||||
'Windows: {#DEVNAME}: Disk is overloaded': 'Windows: {#DEVNAME}: Disco sobrecarregado',
|
||||
'Windows: {#DEVNAME}: Disk read request responses are too high': 'Windows: {#DEVNAME}: Tempo de resposta de leitura muito alto',
|
||||
'Windows: {#DEVNAME}: Disk write request responses are too high': 'Windows: {#DEVNAME}: Tempo de resposta de escrita muito alto',
|
||||
'Windows: "{#SERVICE.NAME}" ({#SERVICE.DISPLAYNAME}) is not running': 'Windows: "{#SERVICE.NAME}" ({#SERVICE.DISPLAYNAME}) não está rodando',
|
||||
'Windows: FS [{#FSLABEL}({#FSNAME})]: Space is critically low': 'Windows: FS [{#FSLABEL}({#FSNAME})]: Espaço criticamente baixo',
|
||||
'Windows: FS [{#FSLABEL}({#FSNAME})]: Space is low': 'Windows: FS [{#FSLABEL}({#FSNAME})]: Espaço baixo',
|
||||
|
||||
# Trigger Descriptions
|
||||
'The volume\'s space usage exceeds the `{$VFS.FS.PUSED.MAX.CRIT:"{#FSNAME}"}%` limit.': 'O uso de espaço do volume excede o limite crítico de `{$VFS.FS.PUSED.MAX.CRIT:"{#FSNAME}"}%`.',
|
||||
'The volume\'s space usage exceeds the `{$VFS.FS.PUSED.MAX.WARN:"{#FSNAME}"}%` limit.': 'O uso de espaço do volume excede o limite de aviso de `{$VFS.FS.PUSED.MAX.WARN:"{#FSNAME}"}%`.',
|
||||
|
||||
# Remaining Triggers
|
||||
'Windows: CPU: Tamanho da Fila (Queue Length) is too high': 'Windows: CPU: Tamanho da Fila (Queue Length) muito alto',
|
||||
'Windows: CPU: Tamanho da Fila (Queue Length) is too high (over {$CPU.QUEUE.CRIT.MAX} for 5m)': 'Windows: CPU: Tamanho da Fila (Queue Length) muito alto (acima de {$CPU.QUEUE.CRIT.MAX} por 5m)',
|
||||
'Windows: High swap space usage': 'Windows: Uso de Swap Elevado',
|
||||
'Windows: High swap space usage (less than {$SWAP.PFREE.MIN.WARN}% free)': 'Windows: Uso de Swap Elevado (menos de {$SWAP.PFREE.MIN.WARN}% livre)',
|
||||
|
||||
# Network Trigger Descriptions (Arthur Style)
|
||||
'The utilization of the network interface is close to its estimated maximum bandwidth.':
|
||||
'⚠️ Uso de banda elevado.\n\n📉 Impacto: A interface atingiu o limite de tráfego. O acesso ao servidor ficará lento e pacotes podem ser descartados.\n🛠️ Ação: 1. Identifique qual processo/usuário está consumindo banda. 2. Avalie necessidade de upgrade de link.',
|
||||
|
||||
'This Ethernet connection has transitioned down from its known maximum speed. This might be a sign of autonegotiation issues. Acknowledge to close the problem manually.':
|
||||
'⚠️ A velocidade da interface caiu (Ex: 1Gb -> 100Mb).\n\n📉 Impacto: Lentidão na transferência de dados.\n🛠️ Ação: 1. Verifique a categoria do cabo (Cat5e/Cat6). 2. Verifique configurações de Duplex/Speed no switch e servidor.',
|
||||
|
||||
'It recovers when it is below 80% of the `{$IF.ERRORS.WARN:"{#IFNAME}"}` threshold.':
|
||||
'⚠️ Erros de transmissão detectados.\n\n📉 Impacto: Perda de pacotes, retransmissões e lentidão.\n🛠️ Ação: 1. Substitua o cabo de rede. 2. Teste outra porta no switch.',
|
||||
|
||||
# Disk Trigger Descriptions (Arthur Style)
|
||||
'The disk appears to be under heavy load.':
|
||||
'⚠️ Disco operando perto da capacidade máxima.\n\n📉 Impacto: Lentidão geral no sistema, aplicações travando e demora para buscar arquivos.\n🛠️ Ação: 1. Verifique quais processos estão consumindo I/O (Resource Monitor). 2. Considere mover arquivos para outro disco ou upgrade para SSD.',
|
||||
|
||||
'This trigger might indicate the disk {#DEVNAME} saturation.':
|
||||
'⚠️ Latência alta no disco (Lentidão).\n\n📉 Impacto: O sistema demora para ler/gravar dados. Bancos de dados e sistemas de arquivos serão afetados.\n🛠️ Ação: 1. Verifique saúde do disco (SMART/Event Log). 2. Verifique se há backup ou antivírus rodando no momento.',
|
||||
|
||||
# Event Names
|
||||
'for 5m)': 'por 5m)',
|
||||
|
||||
# Discovery Rule Names
|
||||
'Network interfaces discovery': 'Descoberta de interfaces de rede',
|
||||
'Physical disks discovery': 'Descoberta de discos físicos',
|
||||
'Windows services discovery': 'Descoberta de serviços Windows',
|
||||
'Mounted filesystem discovery': 'Descoberta de sistemas de arquivos montados',
|
||||
|
||||
# Disk Graph Prototypes
|
||||
'{#DEVNAME}: Disk average queue length': '{#DEVNAME}: Tamanho médio da fila de disco',
|
||||
'{#DEVNAME}: Disk average waiting time': '{#DEVNAME}: Tempo médio de espera do disco',
|
||||
'{#DEVNAME}: Disk read/write rates': '{#DEVNAME}: Taxas de leitura/escrita do disco',
|
||||
'{#DEVNAME}: Disk utilization and queue': '{#DEVNAME}: Utilização e fila do disco',
|
||||
|
||||
# Disk Item Descriptions
|
||||
'Rate of read operations on the disk.': 'Taxa de operações de leitura no disco.',
|
||||
'Rate of write operations on the disk.': 'Taxa de operações de escrita no disco.',
|
||||
'The disk is idle.': 'O disco está ocioso.',
|
||||
|
||||
# ValueMaps
|
||||
'Disconnected': 'Desconectado',
|
||||
'Connecting': 'Conectando',
|
||||
'Connected': 'Conectado',
|
||||
'Disconnecting': 'Desconectando',
|
||||
'Hardware Not Present': 'Hardware Ausente',
|
||||
'Hardware Disabled': 'Hardware Desabilitado',
|
||||
'Hardware Malfunction': 'Falha de Hardware',
|
||||
'Media Disconnected': 'Mídia Desconectada',
|
||||
'Authenticating': 'Autenticando',
|
||||
'Authentication Succeeded': 'Autenticação com Sucesso',
|
||||
'Authentication Failed': 'Falha na Autenticação',
|
||||
'Invalid Address': 'Endereço Inválido',
|
||||
'Credentials Required': 'Credenciais Necessárias',
|
||||
'Running': 'Em Execução',
|
||||
'Paused': 'Pausado',
|
||||
'Start pending': 'Início Pendente',
|
||||
'Pause pending': 'Pausa Pendente',
|
||||
'Continue pending': 'Continuação Pendente',
|
||||
'Stop pending': 'Parada Pendente',
|
||||
'Stopped': 'Parado',
|
||||
'No such service': 'Serviço Inexistente',
|
||||
'not available': 'indisponível',
|
||||
'available': 'disponível',
|
||||
'unknown': 'desconhecido',
|
||||
# 'Up': 'Operante', # Skipping 'Up' as it might be too generic and replace things it shouldn't
|
||||
}
|
||||
|
||||
def translate_yaml(file_path):
|
||||
print(f"Loading {file_path}...")
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
except Exception as e:
|
||||
print(f"Error reading file: {e}")
|
||||
return
|
||||
|
||||
# Simple string replacement for safety and retaining structure
|
||||
# This avoids YAML re-formating issues (like flow style vs block style)
|
||||
count = 0
|
||||
for eng, pt in TRANSLATIONS.items():
|
||||
if eng in content:
|
||||
# Check if it's actually in a valid context (basic check)
|
||||
# We assume the English strings are unique enough
|
||||
new_content = content.replace(eng, pt)
|
||||
if new_content != content:
|
||||
content = new_content
|
||||
count += 1
|
||||
# print(f"Translated: {eng[:30]}... -> {pt[:30]}...")
|
||||
|
||||
print(f"Applied {count} translations.")
|
||||
|
||||
try:
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
print(f"Saved translated file to {file_path}")
|
||||
except Exception as e:
|
||||
print(f"Error writing file: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
translate_yaml(TARGET_FILE)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"folders": [
|
||||
{
|
||||
"name": "minions-da-itguys",
|
||||
"path": "../minions-da-itguys"
|
||||
},
|
||||
{
|
||||
"name": "zabbix-itguys",
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
||||
Loading…
Reference in New Issue