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
|
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):
|
def check_duplicate_yaml_keys(file_path):
|
||||||
"""
|
"""
|
||||||
Check for duplicate YAML keys at the same level (e.g., two 'macros:' sections).
|
Check for duplicate YAML keys at the same level (e.g., two 'macros:' sections).
|
||||||
|
|
@ -427,6 +497,19 @@ def validate_yaml(file_path):
|
||||||
else:
|
else:
|
||||||
print(" ✅ Structure nesting looks correct")
|
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 ==========
|
# ========== Summary ==========
|
||||||
print("\n" + "=" * 60)
|
print("\n" + "=" * 60)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue