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.
This commit is contained in:
parent
7c5cab088f
commit
0bc4984f89
|
|
@ -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}**
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue