From 0bc4984f894b05aff7939e5e59b2b0ea5958ec0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Toledo?= Date: Tue, 13 Jan 2026 13:08:27 -0300 Subject: [PATCH] chore: Update validation script and generate Exchange docs - tools: Fixed warning collection in validate_zabbix_template.py. - docs: Generated template_exchange_gold_ptbr_generated.md with latest template changes. --- .../template_exchange_gold_ptbr_generated.md | 74 +++++++++++++++++ validate_zabbix_template.py | 83 +++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 templates_gold/exchange/template_exchange_gold_ptbr_generated.md diff --git a/templates_gold/exchange/template_exchange_gold_ptbr_generated.md b/templates_gold/exchange/template_exchange_gold_ptbr_generated.md new file mode 100644 index 0000000..33fc466 --- /dev/null +++ b/templates_gold/exchange/template_exchange_gold_ptbr_generated.md @@ -0,0 +1,74 @@ +# Documentação: Microsoft Exchange Server 2016 by Zabbix agent active + +**Template:** Microsoft Exchange Server 2016 by Zabbix agent active +**Descrição:** +Template Gold para Microsoft Exchange Server (2016/2019). + +Monitoramento 360º com foco em performance e disponibilidade. + +Inclui: +- Filas de Transporte (Submission, Delivery, Poison) +- Banco de Dados (Latência, Page Faults, Status) +- Serviços MSExchange (Discovery Automático) +- Web Access (OWA/ECP) +- Métricas de ActiveSync e WebServices + +Desenvolvido por Arthur "O Farol" Mendes. + +## Itens Monitorados + +### Itens Globais +- **Bancos de Dados: Total Montados** (`perf_counter_en["\MSExchange Active Manager(_total)\Database Mounted"]`) +- **ActiveSync: Comandos Ping Pendentes** (`perf_counter_en["\MSExchange ActiveSync\Ping Commands Pending", {$MS.EXCHANGE.PERF.INTERVAL}]`) +- **ActiveSync: Requisições por Segundo** (`perf_counter_en["\MSExchange ActiveSync\Requests/sec", {$MS.EXCHANGE.PERF.INTERVAL}]`) +- **OWA: Usuários Únicos Atuais** (`perf_counter_en["\MSExchange OWA\Current Unique Users", {$MS.EXCHANGE.PERF.INTERVAL}]`) +- **OWA: Requisições por Segundo** (`perf_counter_en["\MSExchange OWA\Requests/sec", {$MS.EXCHANGE.PERF.INTERVAL}]`) +- **WebServices: Requisições por Segundo** (`perf_counter_en["\MSExchangeWS\Requests/sec", {$MS.EXCHANGE.PERF.INTERVAL}]`) +- **Zabbix: Disponibilidade do Agente (Active)** (`zabbix[host,active_agent,available]`) +- **Fila de Transporte: Submission Queue** (`perf_counter_en["\MSExchangeTransport Queues(_Total)\Submission Queue Length"]`) +- **Fila de Transporte: Active Mailbox Delivery** (`perf_counter_en["\MSExchangeTransport Queues(_Total)\Active Mailbox Delivery Queue Length"]`) +- **Fila de Transporte: Poison Queue** (`perf_counter_en["\MSExchangeTransport Queues(_Total)\Poison Queue Length"]`) +- **Fila de Transporte: Retry Mailbox Delivery** (`perf_counter_en["\MSExchangeTransport Queues(_Total)\Retry Mailbox Delivery Queue Length"]`) +- **Service: Status do Microsoft Exchange Transport Submission** (`service.info["MSExchangeSubmission",state]`) +- **Service: Status do Microsoft Exchange Transport** (`service.info["MSExchangeTransport",state]`) + +### Regras de Descoberta (LLD) + +#### Descoberta de Serviços Exchange (`service.discovery`) + - **Protótipos de Itens:** + - Serviço: Status do {#SERVICE.DISPLAYNAME} (`service.info["{#SERVICE.NAME}",state]`) +#### Descoberta de Bancos de Dados (`perf_instance.discovery["MSExchange Active Manager"]`) + - **Protótipos de Itens:** + - Banco [{#INSTANCE}]: Função da Cópia (`perf_counter_en["\MSExchange Active Manager({#INSTANCE})\Database Copy Role Active"]`) + - Banco [{#INSTANCE}]: Page Faults/seg (`perf_counter_en["\MSExchange Database({#INF.STORE})\Database Page Fault Stalls/sec", {$MS.EXCHANGE.PERF.INTERVAL}]`) + - Banco [{#INSTANCE}]: Logs Aguardando (Stalled) (`perf_counter_en["\MSExchange Database({#INF.STORE})\Log Record Stalls/sec", {$MS.EXCHANGE.PERF.INTERVAL}]`) + - Banco [{#INSTANCE}]: Latência de Leitura (Ativo) (`perf_counter_en["\MSExchange Database ==> Instances({#INF.STORE}/_Total)\I/O Database Reads (Attached) Average Latency", {$MS.EXCHANGE.PERF.INTERVAL}]`) + - Banco [{#INSTANCE}]: Latência de Escrita (Ativo) (`perf_counter_en["\MSExchange Database ==> Instances({#INF.STORE}/_Total)\I/O Database Writes (Attached) Average Latency", {$MS.EXCHANGE.PERF.INTERVAL}]`) + - Banco [{#INSTANCE}]: Estado (`perf_counter_en["\MSExchangeIS Store({#INSTANCE})\Database State"]`) + - Banco [{#INSTANCE}]: Tamanho do Arquivo (`perf_counter_en["\MSExchange Database({#INF.STORE})\Database File Size In Bytes", {$MS.EXCHANGE.PERF.INTERVAL}]`) + - Banco [{#INSTANCE}]: Total de Itens (`perf_counter_en["\MSExchange IS Store({#INF.STORE})\Item Count", {$MS.EXCHANGE.PERF.INTERVAL}]`) + +## Alertas (Triggers) + +### Triggers Globais +- [HIGH] **📉 Exchange: Queda Anômala de Tráfego OWA** +- [HIGH] **🚨 Exchange: Agente Zabbix Indisponível** +- [AVERAGE] **⚠️ Exchange: Fila de Submissão Alta** +- [HIGH] **🔮 Exchange: Fila de Submissão em Crescimento Rápido** +- [AVERAGE] **⚠️ Exchange: Fila de Entrega Local Alta** +- [HIGH] **🔮 Exchange: Fila de Entrega em Crescimento Rápido** +- [HIGH] **🚨 Exchange: Mensagens em Quarentena (Poison Queue) detectadas** +- [HIGH] **🚨 Serviço Parado: Microsoft Exchange Transport Submission** +- [HIGH] **🚨 Serviço Parado: Microsoft Exchange Transport** + +### Protótipos de Triggers (LLD) + +**Regra: Descoberta de Serviços Exchange** +- [HIGH] **🚨 Serviço Parado: {#SERVICE.DISPLAYNAME}** + +**Regra: Descoberta de Bancos de Dados** +- [AVERAGE] **⚠️ Exchange: Page Faults Elevados em {#INSTANCE}** +- [AVERAGE] **🐢 Exchange: Escrita de Logs Travada em {#INSTANCE}** +- [WARNING] **🐢 Exchange: Latência de Leitura Alta em {#INSTANCE}** +- [WARNING] **🐢 Exchange: Latência de Escrita Alta em {#INSTANCE}** +- [WARNING] **⚠️ Exchange: Banco de Dados Grande em {#INSTANCE}** diff --git a/validate_zabbix_template.py b/validate_zabbix_template.py index c832bcf..ac0b0cb 100644 --- a/validate_zabbix_template.py +++ b/validate_zabbix_template.py @@ -257,6 +257,76 @@ def validate_nested_structure(content): return errors +def validate_zabbix_7_compliance(content): + """ + Check for Zabbix 7.0 specific issues and common YAML gotchas. + - Boolean keys (no: 1 -> False: 1) + - REGEXP vs MATCHES_REGEX + - Forbidden tags (e.g. 'no' in http steps) + - Hostname mismatches in triggers + """ + errors = [] + warnings = [] + + # 1. Get Template Name for Hostname Mismatch Check + template_name = None + if isinstance(content, dict) and 'zabbix_export' in content: + if 'templates' in content and isinstance(content['templates'], list): + if len(content['templates']) > 0: + template_name = content['templates'][0].get('name') + + def check_node(node, path="root"): + if isinstance(node, dict): + # Check 1: Boolean Keys + # PyYAML loads unquoted 'no', 'on', 'off' as booleans if unsafe, safe_load handles standard yaml 1.1 booleans + # But we are checking the KEYS of the dict. + # Convert keys to list to avoid runtime error during iteration + for k, v in node.items(): + if isinstance(k, bool): + errors.append(f"[INVALID YAML KEY] Found boolean key '{k}' at {path}. Quote it! (e.g. 'no': 1)") + + # Check 3: Forbidden tags in httptests + if path.endswith("steps") and isinstance(node, list) is False: # We are inside a step dict + if k == 'no': + errors.append(f"[FORBIDDEN TAG] Tag 'no' found at {path}. Zabbix 7.0 determines order by list position.") + + # Check 2: Deprecated Operators + if k == 'operator' and v == 'REGEXP': + errors.append(f"[DEPRECATED CONSTANT] 'REGEXP' at {path}. Use 'MATCHES_REGEX' for Zabbix 7.0+.") + + # Check 4: Hostname Mismatch in Triggers + if k == 'expression' and isinstance(v, str) and template_name: + # Look for {HOST.HOST} usage or literal matches + # Only flagged if we find a LITERAL string that looks like a hostname but isn't the current template name + # AND it's not a standard macro + + # Regex to find /Host Name/Key + # Matches: /Hostname/key + matches = re.findall(r'\/([^\/]+)\/', v) + for match in matches: + if match != template_name and match != '{HOST.HOST}' and '$' not in match: + # Heuristic: If it looks like "Microsoft Exchange..." but isn't exact match + if "Microsoft" in match or "Exchange" in match or "Windows" in match: + warnings.append(f"[HOSTNAME MISMATCH] Trigger at {path} references '{match}' but template is '{template_name}'.") + + # Check 5: Empty parameters in functions (e.g. forecast(...,,15m)) + if ',,' in v: + warnings.append(f"[POTENTIAL SYNTAX ERROR] Found empty parameter ',,' in expression at {path}. Zabbix sometimes rejects this. Use explicit '0' or '0s'.") + if 'avg(' in v and re.search(r'avg\(.*,\d+[smhdw],\d+[smhdw]\)', v): + warnings.append(f"[POTENTIAL SYNTAX ERROR] Found 'avg' with comma separation (1h,1d) at {path}. Zabbix 7.0 uses colon (1h:now-1d).") + + for k, v in node.items(): + check_node(v, f"{path}.{k}") + + elif isinstance(node, list): + for i, item in enumerate(node): + check_node(item, f"{path}[{i}]") + + check_node(content) + return errors, warnings + + + def check_duplicate_yaml_keys(file_path): """ Check for duplicate YAML keys at the same level (e.g., two 'macros:' sections). @@ -427,6 +497,19 @@ def validate_yaml(file_path): else: print(" ✅ Structure nesting looks correct") + # ========== 7. Zabbix 7.0 Compliance Check ========== + print("\n[7/7] Checking for Zabbix 7.0 Compliance & Common Errors...") + z7_errors, z7_warnings = validate_zabbix_7_compliance(content) + + if z7_errors: + all_errors.extend(z7_errors) + print(f" ❌ Found {len(z7_errors)} compliance errors") + else: + print(" ✅ Zabbix 7.0 compliance looks good") + + if z7_warnings: + warnings.extend(z7_warnings) + # ========== Summary ========== print("\n" + "=" * 60)