Initial commit

This commit is contained in:
HalbeBruno
2026-02-18 10:18:46 -03:00
commit b264b583b8
24 changed files with 2338 additions and 0 deletions

35
doc/create_dist.md Normal file
View File

@@ -0,0 +1,35 @@
# Manual de Criação de Distribuição (Developer Guide)
Este documento destina-se a geração de novas versões de distribuição da **API** e emissão delicenças.
## 1. Gerando o Pacote de Distribuição
Para criar um pacote pronto para o cliente (binário protegido), execute:
```bash
# Executar da raiz
./tools/build.sh
```
**Saída:**
* **Staging:** `dist/ipv0-olt-api/` (Arquivos soltos para conferência)
* **Release:** `dist/release/ipv0-olt-api.zip` (Arquivo final para o cliente)
## 2. Gerenciamento de Licenças
A aplicação não rodará sem uma licença válida. Utilize o script automatizado para gerar e organizar licenças:
```bash
./tools/gen_license.sh
```
O script solicitará:
1. **Nome do Cliente** (Cria pasta em `dist/licenses/CLIENTE`).
2. **Tipo de Licença** (Data ou Hardware).
3. **Dados** (Vencimento ou Machine ID).
A licença gerada será salva em: `dist/licenses/<CLIENTE>/license.key`.
## 3. Atualizando a Versão
Ao modificar o código fonte:
1. Edite `config.py` ou features.
2. Rode `./build.sh`.
3. Envie o novo `release_production.zip` para o cliente.

112
doc/expansion.md Normal file
View File

@@ -0,0 +1,112 @@
# Guia de Expansão e Desenvolvimento
Este documento explica como adicionar novos recursos (métodos) e suportar novos fabricantes (drivers) na API Zabbix OLT.
## Arquitetura
A API segue um padrão de **Factory** simplificado:
1. **Driver Base (`drivers/__init__.py`)**: Define a interface comum (`OltDriver`).
2. **Implementações (`drivers/nokia.py`, etc)**: Classes concretas que herdam de `OltDriver`.
3. **API (`app.py`)**: Roteia as requisições para o método correto do driver instanciado.
---
## 1. Adicionar Novo Tipo de Monitoramento (Ex: Interfaces)
Para adicionar uma nova coleta de dados (ex: estatísticas de interface, temperatura, CPU):
### Passo 1: Atualizar o Contrato
Edite `drivers/__init__.py` e adicione o método abstrato na classe `OltDriver`.
```python
@abstractmethod
def get_interface_stats(self):
"""Retorna estatísticas de interfaces Ethernet/Uplink/PON."""
pass
```
### Passo 2: Implementar nos Drivers
Atualize **todas** as classes que herdam de `OltDriver` (ex: `drivers/nokia.py`).
```python
def get_interface_stats(self):
connection = self.connect()
output = connection.send_command_timing("show interface ...")
# Implementar lógica de parsing (regex)
stats = self._parse_interfaces(output)
connection.disconnect()
return stats
```
### Passo 3: Criar Rota na API
Edite `app.py` para expor o novo método.
```python
@app.route('/api/v1/interface_stats', methods=['GET'])
@cache_response
def get_interface_stats():
# ... (Copiar lógica de instanciação do driver de get_pon_stats) ...
try:
stats = driver.get_interface_stats()
return jsonify({"data": stats, "meta": ...})
except Exception as e:
return jsonify({'error': str(e)}), 500
```
---
## 2. Adicionar Novo Fabricante (Vendor)
Para suportar uma nova OLT (ex: Huawei, ZTE):
### Passo 1: Criar o Driver
Crie um arquivo em `drivers/` (ex: `drivers/huawei.py`).
```python
from drivers import OltDriver
import re
class HuaweiDriver(OltDriver):
def connect(self):
# Configurar conexão Netmiko (device_type='huawei')
return ConnectHandler(...)
def get_pon_stats(self):
connection = self.connect()
output = connection.send_command("display ont info ...")
connection.disconnect()
return self._parse_output(output)
```
### Passo 2: Registrar o Driver
Edite `app.py` e importe a nova classe.
```python
from drivers.huawei import HuaweiDriver
DRIVERS = {
'nokia': NokiaDriver,
'fiberhome': FiberhomeDriver,
'huawei': HuaweiDriver # <--- Novo registro
}
```
### Passo 3: Configurar Host
No `hosts.json`, defina o driver para o IP correspondente.
```json
"10.10.10.1": {
"driver": "huawei",
...
}
```
---
## Dicas de Desenvolvimento
- **Netmiko Timing**: Use `send_command_timing` se o equipamento tiver prompts complexos ou lentidão.
- **Regex**: Teste suas expressões regulares com outputs reais variados para garantir robustez.
- **Cache**: O decorador `@cache_response` em `utils/cache.py` já trata cache por URL (host distinto = cache distinto).

96
doc/install.md Normal file
View File

@@ -0,0 +1,96 @@
# Guia de Instalação: API Zabbix OLT
Este documento descreve os passos para instalação e configuração da API em ambiente Linux.
## Pré-requisitos
- Sistema Operacional Linux (Debian/Ubuntu/CentOS)
- Python 3.9 ou superior
- Git
## Passos de Instalação
### 1. Clonar o Repositório
O diretório padrão de instalação será `/opt/zbx-ipv0`.
```bash
sudo mkdir -p /opt/zbx-ipv0
sudo chown $USER:$USER /opt/zbx-ipv0
git clone https://git.ipv0.com.br/halbebruno/zabbix-api /opt/zbx-ipv0
cd /opt/zbx-ipv0
```
### 2. Configurar Ambiente Virtual (venv)
É recomendado usar um ambiente virtual para isolar as dependências.
```bash
python3 -m venv venv
source venv/bin/activate
```
### 3. Instalar Dependências
```bash
pip install -r requirements.txt
# Para produção, instale também o Gunicorn
pip install gunicorn
```
### 4. Configuração
#### 4.1 Inventário de Hosts
Crie ou edite o arquivo `hosts.json` na raiz do projeto com as credenciais das OLTs.
```json
{
"10.186.203.14": {
"username": "admin",
"password": "senha_segura",
"driver": "nokia",
"port": 22,
"ssh_options": {
"disabled_algorithms": {
"pubkeys": ["rsa-sha2-256", "rsa-sha2-512"]
}
}
}
}
```
#### 4.2 Variáveis de Ambiente (Opcional)
Você pode sobrescrever configurações padrão via variáveis de ambiente ou editando `config.py`.
### 5. Execução como Serviço (Systemd)
Para garantir que a API inicie automaticamente e rode em background, crie um serviço systemd.
Crie o arquivo `/etc/systemd/system/zabbix-api.service`:
```ini
[Unit]
Description=Zabbix OLT API
After=network.target
[Service]
User=root
Group=root
WorkingDirectory=/opt/zbx-ipv0
Environment="PATH=/opt/zbx-ipv0/venv/bin"
ExecStart=/opt/zbx-ipv0/venv/bin/gunicorn --workers 4 --bind 0.0.0.0:5000 app:app
Restart=always
[Install]
WantedBy=multi-user.target
```
Ative e inicie o serviço:
```bash
sudo systemctl daemon-reload
sudo systemctl enable zabbix-api
sudo systemctl start zabbix-api
sudo systemctl status zabbix-api
```
## Teste
Verifique se a API está rodando:
```bash
curl http://127.0.0.1:5000/api/v1/pon_stats?host=SEU_IP_DA_OLT
```

86
doc/install_dist.md Normal file
View File

@@ -0,0 +1,86 @@
# Manual de Instalação (Cliente)
Este guia descreve como instalar a **IPv0 OLT API** em seu servidor Linux.
## Pré-requisitos
* Linux (Ubuntu 20.04+, Debian 11+, CentOS 8+)
* Python 3.8 ou superior
* Acesso root/sudo
## 1. Instalação Automática
1. Transfira o arquivo `ipv0-olt-api.zip` para o servidor (ex: `/opt`).
2. Descompacte o arquivo:
```bash
unzip ipv0-olt-api.zip -d ipv0-olt-api
cd ipv0-olt-api
```
3. Execute o script de instalação como root:
```bash
sudo ./install.sh
```
* Este script instalará as dependências e configurará o serviço.
* **Atenção:** Ao final, ele exibirá o **Machine ID**. Copie este código para solicitar sua licença.
## 2. Ativação da Licença e Início do Serviço
A aplicação não iniciará sem uma licença válida.
1. Envie o **Machine ID** para o suporte.
2. Você receberá um arquivo de licença chamado `license.key`.
3. Copie este arquivo para a pasta da aplicação e INICIE o serviço:
```bash
# Copiar a licença
sudo cp license.key /opt/ipv0-olt-api/
sudo chown root:root /opt/ipv0-olt-api/license.key
# Habilitar e Iniciar o serviço agora:
sudo systemctl enable --now ipv0-olt-api
```
## 3. Configuração (hosts.json)
Edite o arquivo `hosts.json` para adicionar suas OLTs.
Caminho: `/opt/ipv0-olt-api/hosts.json`
**Exemplo Completo:**
```json
{
"10.155.156.2": {
"username": "zabbix",
"password": "p4ssw0rd",
"driver": "nokia",
"snmp_community": "public",
"port": 22,
"ssh_options": {
"disabled_algorithms": {
"pubkeys": [
"rsa-sha2-256",
"rsa-sha2-512"
]
}
}
},
"192.168.1.10": {
"username": "admin",
"password": "simple_password",
"driver": "fiberhome",
"port": 23
}
}
```
Após editar, reinicie o serviço.
## 4. Diagnóstico e Debug
A API inclui uma ferramenta de diagnóstico. Para verificar status, licença e conexão:
```bash
cd /opt/ipv0-olt-api
sudo ./venv/bin/python3 debug.py
```
### Comandos Úteis
* **Ver logs:** `sudo journalctl -u ipv0-olt-api -f`
* ** Status do Serviço:** `sudo systemctl status ipv0-olt-api`
* **Testar API:** `curl http://localhost:5050/health`

945
doc/templates/template-nokia-api.xml vendored Normal file
View File

@@ -0,0 +1,945 @@
<?xml version="1.0" encoding="UTF-8"?>
<zabbix_export>
<version>7.2</version>
<template_groups>
<template_group>
<uuid>b01bb96a1ed547e1a8770677a646aa3c</uuid>
<name>Templates IPv0</name>
</template_group>
<template_group>
<uuid>1a62bf6492d64062a2b5f58e30234244</uuid>
<name>Templates Nokia</name>
</template_group>
</template_groups>
<templates>
<template>
<uuid>41049df2762c47218e8282386e938ff7</uuid>
<template>IPv0 - Template Olt Nokia API</template>
<name>IPv0 - Template Olt Nokia API</name>
<groups>
<group>
<name>Templates IPv0</name>
</group>
<group>
<name>Templates Nokia</name>
</group>
</groups>
<items>
<item>
<uuid>2e17d6504d804ef098c6d35614ac0626</uuid>
<name>Get OLT Stats</name>
<type>HTTP_AGENT</type>
<key>olt.api.stats</key>
<delay>3m</delay>
<history>1h</history>
<value_type>TEXT</value_type>
<timeout>90s</timeout>
<url>http://127.0.0.1:5050/api/v1/olt_stats</url>
<query_fields>
<query_field>
<name>host</name>
<value>{HOST.IP}</value>
</query_field>
<query_field>
<name>driver</name>
<value>nokia</value>
</query_field>
</query_fields>
</item>
</items>
<discovery_rules>
<discovery_rule>
<uuid>7a978a056189440f8bc3252788ce5034</uuid>
<name>Discovery Card de Gerencia</name>
<type>DEPENDENT</type>
<key>olt.mgmt.card.discovery</key>
<item_prototypes>
<item_prototype>
<uuid>69b6137ee1f1498eb495ca9c14e0c9f1</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Utilização de Memória %</name>
<type>CALCULATED</type>
<key>mng.avgUsage[{#CARD_INDEX}]</key>
<delay>2m</delay>
<value_type>FLOAT</value_type>
<units>%</units>
<params>(last(//mng.memAbsoluteUsage[{#CARD_INDEX}])*100)/last(//mng.totalMemSize[{#CARD_INDEX}])</params>
<tags>
<tag>
<tag>Card</tag>
<value>MGMT</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>b460b66d4d8c47959388655797c47abb</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Utilização de CPU %</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.9.29.1.1.4.{#CARD_INDEX}</snmp_oid>
<key>mng.cpuLoadAverage[{#CARD_INDEX}]</key>
<delay>2m</delay>
<value_type>FLOAT</value_type>
<units>%</units>
<tags>
<tag>
<tag>Card</tag>
<value>MGMT</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>8f8f575a9ca24fd88519fe42a6e436b8</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Status Administrativo</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.23.3.1.5.{#CARD_INDEX}</snmp_oid>
<key>mng.eqptBoardAdminStatus[{#CARD_INDEX}]</key>
<delay>2m</delay>
<valuemap>
<name>CARD: Status Administrativo</name>
</valuemap>
<tags>
<tag>
<tag>Card</tag>
<value>MGMT</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>6effd55c130a47a2bf9ff51e1aaf7f37</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Código PBA</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.23.3.1.15.{#CARD_INDEX}</snmp_oid>
<key>mng.eqptBoardInventoryPBACode[{#CARD_INDEX}]</key>
<delay>1d</delay>
<value_type>CHAR</value_type>
<tags>
<tag>
<tag>application</tag>
<value>inventory</value>
</tag>
<tag>
<tag>Card</tag>
<value>MGMT</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>538be380bc604f44b4e25f8a2eb2e7ba</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: SN do Card</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.23.3.1.19.{#CARD_INDEX}</snmp_oid>
<key>mng.eqptBoardInventorySerialNumber[{#CARD_INDEX}]</key>
<delay>1d</delay>
<value_type>CHAR</value_type>
<tags>
<tag>
<tag>application</tag>
<value>inventory</value>
</tag>
<tag>
<tag>Card</tag>
<value>MGMT</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>8a2b29a22fce4f27817e3b39b741c973</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Status Operacional do Card</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.23.3.1.6.{#CARD_INDEX}</snmp_oid>
<key>mng.eqptBoardOperStatus[{#CARD_INDEX}]</key>
<delay>2m</delay>
<valuemap>
<name>CARD: Status Operacional</name>
</valuemap>
<tags>
<tag>
<tag>Card</tag>
<value>MGMT</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>3bb2deae12174e56ab4a91f9620028bb</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME} / Sensor {#SENSOR_INDEX}: Temperatura Atual</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.23.10.1.2.{#CARD_INDEX}.{#SENSOR_INDEX}</snmp_oid>
<key>mng.eqptBoardThermalSensorActualTemperature[{#CARD_INDEX}.{#SENSOR_INDEX}]</key>
<delay>2m</delay>
<units>°C</units>
<tags>
<tag>
<tag>Card</tag>
<value>MGMT</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>4f7a5fecd1554ea0baa33ee04ba9ef39</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Status Energético do Card</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.23.3.1.4.{#CARD_INDEX}</snmp_oid>
<key>mng.eqptSlotPowerStatus[{#CARD_INDEX}]</key>
<delay>2m</delay>
<valuemap>
<name>CARD: Power Status</name>
</valuemap>
<tags>
<tag>
<tag>Card</tag>
<value>MGMT</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>279d9f528e6e4c22a2947530ec4df837</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Utilização de Memória</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.9.29.2.1.2.{#CARD_INDEX}</snmp_oid>
<key>mng.memAbsoluteUsage[{#CARD_INDEX}]</key>
<delay>2m</delay>
<units>!MB</units>
<tags>
<tag>
<tag>Card</tag>
<value>MGMT</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>79604b14350941cf9cc896cc22648ef1</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Status de Operação da CPU</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.9.29.1.1.5.{#CARD_INDEX}</snmp_oid>
<key>mng.operateStatus[{#CARD_INDEX}]</key>
<delay>10m</delay>
<valuemap>
<name>CARD: Status CPU</name>
</valuemap>
<tags>
<tag>
<tag>Card</tag>
<value>MGMT</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>0bc920aa3f95405a86f6bfd5fb2b2ee8</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Total de Memória</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.9.29.2.1.1.{#CARD_INDEX}</snmp_oid>
<key>mng.totalMemSize[{#CARD_INDEX}]</key>
<delay>2m</delay>
<units>!MB</units>
<tags>
<tag>
<tag>Card</tag>
<value>MGMT</value>
</tag>
</tags>
</item_prototype>
</item_prototypes>
<master_item>
<key>olt.api.stats</key>
</master_item>
<preprocessing>
<step>
<type>JAVASCRIPT</type>
<parameters>
<parameter>var data = JSON.parse(value);
var output = [];
if (data.FANT) {
data.FANT.forEach(function (card) {
output.push({
&quot;{#CARD_INDEX}&quot;: card.cardIndex,
&quot;{#CARD_NAME}&quot;: card.cardName,
&quot;{#CARD_NUMBER}&quot;: card.cardNumber,
&quot;{#CARD_TYPE}&quot;: card.cardType,
&quot;{#CARD_CLASS}&quot;: card.cardClass
});
});
}
return JSON.stringify(output);</parameter>
</parameters>
</step>
</preprocessing>
</discovery_rule>
<discovery_rule>
<uuid>846ecdc97b7e45a9a62142aed73703d9</uuid>
<name>Discovery PONs</name>
<type>DEPENDENT</type>
<key>olt.pon.discovery</key>
<item_prototypes>
<item_prototype>
<uuid>a2702a688be54c88b8a3c3dc057b312f</uuid>
<name>{#PON_NAME} Status Operacional</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.2.1.2.2.1.8.{#PON_CODE}</snmp_oid>
<key>ifOperStatus[{#PON_CODE}]</key>
<value_type>CHAR</value_type>
<valuemap>
<name>PON: Status Operacional</name>
</valuemap>
<tags>
<tag>
<tag>GPON Port</tag>
<value>{#PON_NAME}</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>0b8b225f12c142a3b4001e5e48522b45</uuid>
<name>{#PON_NAME} ONTs Offline</name>
<type>DEPENDENT</type>
<key>olt.pon.onts.offline[{#PON_CODE}]</key>
<preprocessing>
<step>
<type>JSONPATH</type>
<parameters>
<parameter>$.FGLT[*].pons[?(@.ponCode=='{#PON_CODE}')].onuStats.down.first()</parameter>
</parameters>
</step>
</preprocessing>
<master_item>
<key>olt.api.stats</key>
</master_item>
<tags>
<tag>
<tag>GPON Port</tag>
<value>{#PON_NAME}</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>d665247611d44c0d99320118b0a3788f</uuid>
<name>{#PON_NAME} ONTs Online</name>
<type>DEPENDENT</type>
<key>olt.pon.onts.online[{#PON_CODE}]</key>
<preprocessing>
<step>
<type>JSONPATH</type>
<parameters>
<parameter>$.FGLT[*].pons[?(@.ponCode=='{#PON_CODE}')].onuStats.up.first()</parameter>
</parameters>
</step>
</preprocessing>
<master_item>
<key>olt.api.stats</key>
</master_item>
<tags>
<tag>
<tag>GPON Port</tag>
<value>{#PON_NAME}</value>
</tag>
</tags>
<trigger_prototypes>
<trigger_prototype>
<uuid>ddc136525d274ef4b88d7e45f5c1cac7</uuid>
<expression>((last(/IPv0 - Template Olt Nokia API/olt.pon.onts.online[{#PON_CODE}],#2)+0.1)
- last(/IPv0 - Template Olt Nokia API/olt.pon.onts.online[{#PON_CODE}]))
/
(last(/IPv0 - Template Olt Nokia API/olt.pon.onts.online[{#PON_CODE}],#2)+0.1)*100&gt;={$LIMITONTOFF}
and
last(/IPv0 - Template Olt Nokia API/olt.pon.onts.online[{#PON_CODE}])&lt;&gt;0</expression>
<recovery_mode>RECOVERY_EXPRESSION</recovery_mode>
<recovery_expression>((last(/IPv0 - Template Olt Nokia API/olt.pon.onts.online[{#PON_CODE}],#2)+0.1)
- last(/IPv0 - Template Olt Nokia API/olt.pon.onts.online[{#PON_CODE}]))
/
(last(/IPv0 - Template Olt Nokia API/olt.pon.onts.online[{#PON_CODE}],#2)+0.1)*100&lt;={$LIMITONTOFF}
and
last(/IPv0 - Template Olt Nokia API/olt.pon.onts.online[{#PON_CODE}])&gt;=
avg(/IPv0 - Template Olt Nokia API/olt.pon.onts.online[{#PON_CODE}],12h)</recovery_expression>
<name>Queda Massiva de ONUs {#PON_INDEX}</name>
<priority>HIGH</priority>
<manual_close>YES</manual_close>
</trigger_prototype>
</trigger_prototypes>
</item_prototype>
<item_prototype>
<uuid>7362cd3b3c814d6992928cd2e971fb6b</uuid>
<name>{#PON_NAME} ONTs Total</name>
<type>DEPENDENT</type>
<key>olt.pon.onts.total[{#PON_CODE}]</key>
<preprocessing>
<step>
<type>JSONPATH</type>
<parameters>
<parameter>$.FGLT..[?(@.ponCode=='{#PON_CODE}')].onuStats.total.first()</parameter>
</parameters>
</step>
</preprocessing>
<master_item>
<key>olt.api.stats</key>
</master_item>
<tags>
<tag>
<tag>GPON Port</tag>
<value>{#PON_NAME}</value>
</tag>
</tags>
<trigger_prototypes>
<trigger_prototype>
<uuid>d0c4dee94181467685df65cfcc3a77a5</uuid>
<expression>last(/IPv0 - Template Olt Nokia API/olt.pon.onts.total[{#PON_CODE}])&gt;{$ALERTLIMMITONTS}</expression>
<recovery_mode>RECOVERY_EXPRESSION</recovery_mode>
<recovery_expression>last(/IPv0 - Template Olt Nokia API/olt.pon.onts.total[{#PON_CODE}])&lt;{$ALERTLIMMITONTS}</recovery_expression>
<name>Limite de ONTs</name>
<priority>AVERAGE</priority>
<manual_close>YES</manual_close>
</trigger_prototype>
</trigger_prototypes>
</item_prototype>
<item_prototype>
<uuid>5148cc790e694fc183aec93c3e2ab2bd</uuid>
<name>Interface GPON {#PON_INDEX} Operational status</name>
<type>DEPENDENT</type>
<key>olt.pon.status.oper[{#PON_INDEX}]</key>
<value_type>TEXT</value_type>
<status>DISABLED</status>
<discover>NO_DISCOVER</discover>
<preprocessing>
<step>
<type>JSONPATH</type>
<parameters>
<parameter>$.data[?(@.pon_index=='{#PON_INDEX}')].oper_status.first()</parameter>
</parameters>
</step>
</preprocessing>
<master_item>
<key>olt.api.stats</key>
</master_item>
<tags>
<tag>
<tag>GPON Port</tag>
<value>{#PON_NAME}</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>929d97d69e7d42618bfb063368f2937b</uuid>
<name>{#PON_NAME}: Voltagem</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.56.5.1.9.{#CARD_INDEX}.{#PON_INDEX}</snmp_oid>
<key>sfpDiagSupplyVoltage[{#CARD_INDEX}.{#PON_INDEX}]</key>
<delay>2m</delay>
<value_type>FLOAT</value_type>
<units>V</units>
<preprocessing>
<step>
<type>TRIM</type>
<parameters>
<parameter>&quot;</parameter>
</parameters>
</step>
<step>
<type>TRIM</type>
<parameters>
<parameter>VDC</parameter>
</parameters>
</step>
</preprocessing>
<tags>
<tag>
<tag>GPON Port</tag>
<value>{#PON_NAME}</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>83148e945c884ce99713c43806af6283</uuid>
<name>{#PON_NAME}: Temperatura</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.56.5.1.10.{#CARD_INDEX}.{#PON_INDEX}</snmp_oid>
<key>sfpDiagTemperature[{#CARD_INDEX}.{#PON_INDEX}]</key>
<delay>2m</delay>
<value_type>FLOAT</value_type>
<units>ºC</units>
<preprocessing>
<step>
<type>TRIM</type>
<parameters>
<parameter>&quot;</parameter>
</parameters>
</step>
<step>
<type>TRIM</type>
<parameters>
<parameter>degrees Celsius</parameter>
</parameters>
</step>
</preprocessing>
<tags>
<tag>
<tag>GPON Port</tag>
<value>{#PON_NAME}</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>256a6c2404ef4d759c75c1d5f4104b59</uuid>
<name>{#PON_NAME}: Corrente Elétrica</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.56.5.1.8.{#CARD_INDEX}.{#PON_INDEX}</snmp_oid>
<key>sfpDiagTxBiasCurrent[{#CARD_INDEX}.{#PON_INDEX}]</key>
<delay>2m</delay>
<value_type>FLOAT</value_type>
<units>!mA</units>
<preprocessing>
<step>
<type>TRIM</type>
<parameters>
<parameter>&quot;</parameter>
</parameters>
</step>
<step>
<type>TRIM</type>
<parameters>
<parameter>mA</parameter>
</parameters>
</step>
</preprocessing>
<tags>
<tag>
<tag>GPON Port</tag>
<value>{#PON_NAME}</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>3da4a5d55323446ea0b6ada7676c5597</uuid>
<name>{#PON_NAME}: Tx Power</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.56.5.1.6.{#CARD_INDEX}.{#PON_INDEX}</snmp_oid>
<key>sfpDiagTxPower[{#CARD_INDEX}.{#PON_INDEX}]</key>
<delay>2m</delay>
<value_type>FLOAT</value_type>
<units>dBm</units>
<preprocessing>
<step>
<type>TRIM</type>
<parameters>
<parameter>&quot;</parameter>
</parameters>
</step>
<step>
<type>TRIM</type>
<parameters>
<parameter>dBm</parameter>
</parameters>
</step>
</preprocessing>
<tags>
<tag>
<tag>GPON Port</tag>
<value>{#PON_NAME}</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>70e2452a22da41d6b4229d6c575c1999</uuid>
<name>{#PON_NAME}: Tipo do SFP</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.56.6.1.13.{#CARD_INDEX}.{#PON_INDEX}</snmp_oid>
<key>sfpInvSpecificalType[{#CARD_INDEX}.{#PON_INDEX}]</key>
<delay>2m</delay>
<valuemap>
<name>PON: SFP Type</name>
</valuemap>
<tags>
<tag>
<tag>GPON Port</tag>
<value>{#PON_NAME}</value>
</tag>
</tags>
</item_prototype>
</item_prototypes>
<master_item>
<key>olt.api.stats</key>
</master_item>
<preprocessing>
<step>
<type>JAVASCRIPT</type>
<parameters>
<parameter>var data = JSON.parse(value);
var output = [];
if (data.FGLT) {
data.FGLT.forEach(function(card) {
if (card.pons) {
card.pons.forEach(function(pon) {
output.push({
&quot;{#CARD_INDEX}&quot;: card.cardIndex,
&quot;{#PON_INDEX}&quot;: pon.ponIndex,
&quot;{#PON_CODE}&quot;: pon.ponCode,
&quot;{#PON_NAME}&quot;: pon.ponName
});
});
}
});
}
return JSON.stringify(output);</parameter>
</parameters>
</step>
</preprocessing>
</discovery_rule>
<discovery_rule>
<uuid>de352b4307a24dc3b7a7ba228224663d</uuid>
<name>Discovery Card de Serviço</name>
<type>DEPENDENT</type>
<key>olt.service.card.discovery</key>
<item_prototypes>
<item_prototype>
<uuid>bb009bd92e18473ebbcc4daea67577c6</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Utilização de Memória %</name>
<type>CALCULATED</type>
<key>srv.avgUsage[{#CARD_INDEX}]</key>
<delay>2m</delay>
<value_type>FLOAT</value_type>
<units>%</units>
<params>(last(//srv.memAbsoluteUsage[{#CARD_INDEX}])*100)/last(//srv.totalMemSize[{#CARD_INDEX}])</params>
<preprocessing>
<step>
<type>JAVASCRIPT</type>
<parameters>
<parameter>return Math.round(value * 100)/100;</parameter>
</parameters>
</step>
</preprocessing>
<tags>
<tag>
<tag>Card</tag>
<value>Service</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>bf0fc61688d24828a22a23437f0baf26</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Utilização de CPU %</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.9.29.1.1.4.{#CARD_INDEX}</snmp_oid>
<key>srv.cpuLoadAverage[{#CARD_INDEX}]</key>
<delay>2m</delay>
<units>%</units>
<tags>
<tag>
<tag>Card</tag>
<value>Service</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>b4ffa90bd79744669c4b1acbeefb8329</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Status Administrativo</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.23.3.1.5.{#CARD_INDEX}</snmp_oid>
<key>srv.eqptBoardAdminStatus[{#CARD_INDEX}]</key>
<delay>2m</delay>
<valuemap>
<name>CARD: Status Administrativo</name>
</valuemap>
<tags>
<tag>
<tag>Card</tag>
<value>Service</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>4aa8a84284a4439b996183274d01f8b8</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Código PBA</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.23.3.1.15.{#CARD_INDEX}</snmp_oid>
<key>srv.eqptBoardInventoryPBACode[{#CARD_INDEX}]</key>
<delay>1d</delay>
<value_type>CHAR</value_type>
<tags>
<tag>
<tag>application</tag>
<value>inventory</value>
</tag>
<tag>
<tag>Card</tag>
<value>Service</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>c0f2e77e0c594edebd4720ae608b8311</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: SN do Card</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.23.3.1.19.{#CARD_INDEX}</snmp_oid>
<key>srv.eqptBoardInventorySerialNumber[{#CARD_INDEX}]</key>
<delay>1d</delay>
<value_type>CHAR</value_type>
<tags>
<tag>
<tag>application</tag>
<value>inventory</value>
</tag>
<tag>
<tag>Card</tag>
<value>Service</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>0acd1bc1e82441bfa195ec8b97d0c034</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Status Operacional do Card</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.23.3.1.6.{#CARD_INDEX}</snmp_oid>
<key>srv.eqptBoardOperStatus[{#CARD_INDEX}]</key>
<delay>2m</delay>
<valuemap>
<name>CARD: Status Operacional</name>
</valuemap>
<tags>
<tag>
<tag>Card</tag>
<value>Service</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>d955f5a1d1324e7baf380f63e4a1b6b3</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME} / Sensor {#SENSOR_INDEX}: Temperatura Atual</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.23.10.1.2.{#CARD_INDEX}.{#SENSOR_INDEX}</snmp_oid>
<key>srv.eqptBoardThermalSensorActualTemperature[{#CARD_INDEX}.{#SENSOR_INDEX}]</key>
<delay>2m</delay>
<value_type>FLOAT</value_type>
<units>ºC</units>
<tags>
<tag>
<tag>Card</tag>
<value>Service</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>372b8ece709443f99d076ccd1b6927cf</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Status Energético do Card</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.23.3.1.4.{#CARD_INDEX}</snmp_oid>
<key>srv.eqptSlotPowerStatus[{#CARD_INDEX}]</key>
<delay>2m</delay>
<valuemap>
<name>CARD: Power Status</name>
</valuemap>
<tags>
<tag>
<tag>Card</tag>
<value>Service</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>039582f21ece4b5b9ede608fdcaf769e</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Utilização de Memória</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.9.29.2.1.2.{#CARD_INDEX}</snmp_oid>
<key>srv.memAbsoluteUsage[{#CARD_INDEX}]</key>
<delay>2m</delay>
<value_type>FLOAT</value_type>
<units>!MB</units>
<tags>
<tag>
<tag>Card</tag>
<value>Service</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>2a206cc0b25e451285a37057a606b348</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Status de Operação da CPU</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.9.29.1.1.5.{#CARD_INDEX}</snmp_oid>
<key>srv.operateStatus[{#CARD_INDEX}]</key>
<delay>10m</delay>
<value_type>FLOAT</value_type>
<valuemap>
<name>CARD: Status CPU</name>
</valuemap>
<tags>
<tag>
<tag>Card</tag>
<value>Service</value>
</tag>
</tags>
</item_prototype>
<item_prototype>
<uuid>76599aec4242436685dfc13209792312</uuid>
<name>{#CARD_TYPE}-{#CARD_CLASS} / {#CARD_NAME}: Total de Memória</name>
<type>SNMP_AGENT</type>
<snmp_oid>1.3.6.1.4.1.637.61.1.9.29.2.1.1.{#CARD_INDEX}</snmp_oid>
<key>srv.totalMemSize[{#CARD_INDEX}]</key>
<delay>2m</delay>
<value_type>FLOAT</value_type>
<units>!MB</units>
<tags>
<tag>
<tag>Card</tag>
<value>Service</value>
</tag>
</tags>
</item_prototype>
</item_prototypes>
<master_item>
<key>olt.api.stats</key>
</master_item>
<preprocessing>
<step>
<type>JAVASCRIPT</type>
<parameters>
<parameter>var data = JSON.parse(value);
var output = [];
if (data.FGLT) {
data.FGLT.forEach(function (card) {
output.push({
&quot;{#CARD_CLASS}&quot;: card.cardClass,
&quot;{#CARD_INDEX}&quot;: card.cardIndex,
&quot;{#CARD_NAME}&quot;: card.cardName,
&quot;{#CARD_NUMBER}&quot;: card.cardNumber,
&quot;{#CARD_TYPE}&quot;: card.cardType
});
});
}
return JSON.stringify(output);</parameter>
</parameters>
</step>
</preprocessing>
</discovery_rule>
</discovery_rules>
<tags>
<tag>
<tag>ipv0</tag>
</tag>
<tag>
<tag>target</tag>
<value>nokia</value>
</tag>
</tags>
<macros>
<macro>
<macro>{$ALERTLIMMITONTS}</macro>
<value>120</value>
</macro>
<macro>
<macro>{$LIMITONTOFF}</macro>
<value>20</value>
<description>Valor em %</description>
</macro>
</macros>
<valuemaps>
<valuemap>
<uuid>f3ba4a6f09994b2fa4753ca09cfec605</uuid>
<name>CARD: Power Status</name>
<mappings>
<mapping>
<value>1</value>
<newvalue>powerUp</newvalue>
</mapping>
<mapping>
<value>2</value>
<newvalue>powerDown</newvalue>
</mapping>
</mappings>
</valuemap>
<valuemap>
<uuid>ca194f4197714aa58de43a4088308a30</uuid>
<name>CARD: Status Administrativo</name>
<mappings>
<mapping>
<value>1</value>
<newvalue>Unlock</newvalue>
</mapping>
<mapping>
<value>2</value>
<newvalue>Lock</newvalue>
</mapping>
</mappings>
</valuemap>
<valuemap>
<uuid>f36bdc78e7f341c8a3421d8a00e930f8</uuid>
<name>CARD: Status CPU</name>
<mappings>
<mapping>
<value>1</value>
<newvalue>start</newvalue>
</mapping>
<mapping>
<value>2</value>
<newvalue>stop</newvalue>
</mapping>
<mapping>
<value>3</value>
<newvalue>proceeding</newvalue>
</mapping>
<mapping>
<value>4</value>
<newvalue>idle</newvalue>
</mapping>
<mapping>
<value>5</value>
<newvalue>not-operational</newvalue>
</mapping>
</mappings>
</valuemap>
<valuemap>
<uuid>9cd3f98309994cd1be946cd7d2819d4a</uuid>
<name>CARD: Status Operacional</name>
<mappings>
<mapping>
<value>1</value>
<newvalue>Enabled</newvalue>
</mapping>
<mapping>
<value>2</value>
<newvalue>Disabled</newvalue>
</mapping>
</mappings>
</valuemap>
<valuemap>
<uuid>987074d3178f4941ad79d06d4cff5e3f</uuid>
<name>PON: SFP Type</name>
<mappings>
<mapping>
<value>0</value>
<newvalue>Desconhecido</newvalue>
</mapping>
<mapping>
<value>7</value>
<newvalue>B</newvalue>
</mapping>
<mapping>
<value>8</value>
<newvalue>B+</newvalue>
</mapping>
<mapping>
<value>9</value>
<newvalue>C+</newvalue>
</mapping>
<mapping>
<value>10</value>
<newvalue>C++</newvalue>
</mapping>
</mappings>
</valuemap>
<valuemap>
<uuid>2546518a57394c75a2cc34f2b4f18517</uuid>
<name>PON: Status Operacional</name>
<mappings>
<mapping>
<value>1</value>
<newvalue>Up</newvalue>
</mapping>
<mapping>
<value>2</value>
<newvalue>Down</newvalue>
</mapping>
</mappings>
</valuemap>
</valuemaps>
</template>
</templates>
</zabbix_export>

120
doc/zabbix_integration.md Normal file
View File

@@ -0,0 +1,120 @@
# Guia Técnico de Integração Zabbix
Este documento descreve como construir templates Zabbix para consumir a **IPv0 OLT API**. Ele detalha os Headers, Regras de Descoberta (LLD), Pré-processamentos Java Script e estrutura dos itens.
## 1. Visão Geral (Master Item)
Toda a coleta de dados de uma OLT deve ser centralizada em um único **Master Item (HTTP Agent)**. Isso aproveita o cache da API e evita sobrecarga de conexões.
### Configuração do Master Item
* **Nome:** `OLT API Stats`
* **Type:** `HTTP agent`
* **Key:** `olt.api.stats`
* **URL:** `http://{$API_IP}:{$API_PORT}/api/v1/olt_stats`
* **Query Fields:**
* `host`: `{HOST.CONN}` ou `{HOST.IP}`
* **Headers:**
* `Content-Type`: `application/json`
* **Timeout:** `30s` (ou mais, dependendo do tamanho da OLT)
* **History:** `1h` (NÃO guarde histórico longo do JSON bruto se for muito grande)
* **Trends:** `0` (Texto não tem trend)
---
## 2. Padrão de Descoberta (Low Level Discovery - LLD)
A API retorna um JSON estruturado hierarquicamente (`NGFC`, `FGLT`, etc). Para criar itens no Zabbix, precisamos "achatar" essa estrutura usando **LLD Dependent Rules**.
### 2.1 LLD de Cards (Placas)
Para descobrir as placas (FGLT, FANT, etc):
* **Type:** `Dependent item`
* **Master Item:** `OLT API Stats`
* **Key:** `olt.card.discovery`
* **Preprocessing:**
1. **JavaScript**:
```javascript
var data = JSON.parse(value);
var output = [];
// Itera sobre tipos de cards conhecidos
['FGLT', 'FANT', 'NGFC'].forEach(function(type) {
if (data[type]) {
data[type].forEach(function(card) {
output.push({
"{#CARD_INDEX}": card.cardIndex,
"{#CARD_NAME}": card.cardName,
"{#CARD_TYPE}": card.cardType,
"{#CARD_SLOT}": card.cardSlot || card.cardNumber // Ajuste conforme driver
});
});
}
});
return JSON.stringify(output);
```
### 2.2 LLD de PONs (Portas)
Para descobrir as portas PON e criar métricas de suporte (Total/Online/Offline):
* **Type:** `Dependent item`
* **Master Item:** `OLT API Stats`
* **Key:** `olt.pon.discovery`
* **Preprocessing:**
1. **JavaScript**:
```javascript
var data = JSON.parse(value);
var output = [];
if (data.FGLT) {
data.FGLT.forEach(function(card) {
if (card.pons) {
card.pons.forEach(function(pon) {
output.push({
"{#PON_NAME}": pon.ponName,
"{#PON_INDEX}": pon.ponIndex,
"{#PON_CODE}": pon.ponCode, // Importante para SNMP
"{#CARD_INDEX}": card.cardIndex
});
});
}
});
}
return JSON.stringify(output);
```
---
## 3. Protótipos de Itens (Item Prototypes)
### 3.1 Métricas via JSON (Dependentes)
Métricas como "ONTs Online" vêm direto do JSON. Não use SNMP ou HTTP novo. Use **Dependent Item**.
* **Name:** `PON {#PON_NAME}: ONTs Online`
* **Type:** `Dependent item`
* **Master Item:** `OLT API Stats`
* **Key:** `pon.online[{#PON_INDEX}]`
* **Preprocessing:**
1. **JSONPath**:
```
$.FGLT[?(@.cardIndex=='{#CARD_INDEX}')].pons[?(@.ponIndex=='{#PON_INDEX}')].onuStats.up.first()
```
### 3.2 Métricas via SNMP (SNMP Agent)
Métricas físicas (Temperatura, Voltagem, Status Operacional) devem ser coletadas via SNMP direto da OLT, usando os índices descobertos.
* **Name:** `PON {#PON_NAME}: Temperatura`
* **Type:** `SNMP agent`
* **Key:** `pon.temp[{#PON_INDEX}]`
* **SNMP OID:**
* Exemplo Nokia: `1.3.6.1.4.1.637.61.1.56.5.1.10.{#CARD_INDEX}.{#PON_INDEX}`
* Exemplo Interface Genérica: `1.3.6.1.2.1.2.2.1.8.{#PON_CODE}`
---
## 4. Templates Disponíveis
Abaixo listamos os templates XML prontos para importação que seguem este padrão:
* **OLT Nokia**: [doc/templates/template-nokia-api.xml](doc/templates/template-nokia-api.xml)
* *Suporta: 7360 ISAM, Placas FGLT/FANT, Métricas de ONTs, Status Físico (SFP).*
---
**Nota:** Mantenha os templates versionados junto com o código da API para garantir compatibilidade com as estruturas JSON retornadas.