Skip to content

Cepat-Kilat-Teknologi/go-snmp-olt-zte-c320

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

348 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Monitoring OLT ZTE C320 with SNMP

ci Go Report Card codecov Helm Chart

REST API service for monitoring ZTE C320 OLT devices via SNMP protocol, built with Go. Provides real-time ONU information including status, optical power levels, uptime, and serial numbers across all board/PON combinations.

Tech Stack

  • Go 1.26 - Programming language
  • Chi - Lightweight HTTP router
  • GoSNMP - SNMP library with BulkWalk support
  • Redis - Caching layer with background refresh
  • robfig/cron - Cron scheduling for power monitor
  • Zap - Structured JSON logger (standardized across all ISP adapters)
  • Prometheus client_golang - Metrics collection
  • Godotenv - Environment variable loader
  • Miniredis - In-memory Redis for testing
  • Docker - Containerization with distroless production image
  • Task - Task runner
  • Air - Hot reload for development
  • k6 - Load testing

Key Features

  • SNMP connection pool (4 connections) with concurrency semaphore (max 5 concurrent ops)
  • Redis caching with configurable TTL and cache pre-warming at startup
  • Cron-based and interval-based scheduling for RX Power monitor
  • API key authentication (optional, via X-API-Key header)
  • Singleflight request deduplication to prevent SNMP storms
  • Batched SNMP Get (4 OIDs per request) and BulkWalk for optimal performance
  • Consistent JSON response format with structured error details
  • SNMP Trap listener for real-time ONU offline detection with webhook notification
  • RX Power monitor with configurable high/low thresholds and cron scheduling
  • 98.6% test coverage

API Documentation

Full OpenAPI 3.1 specification: api/openapi.yaml

Getting Started

Prerequisites

  • Go 1.26+
  • Docker & Docker Compose
  • Task runner (go install github.com/go-task/task/v3/cmd/task@latest)
  • Access to a ZTE C320 OLT device (SNMP v2c)

Quick Start

# 1. Clone and configure
cp .env.example .env
# Edit .env with your OLT IP, SNMP community, and Redis settings

# 2. Start development (Redis in Docker + App with hot reload)
task dev

# 3. Test
curl http://localhost:8081/health
curl http://localhost:8081/api/v1/board/1/pon/1 | jq

Docker Compose (Development)

task up

Docker Compose (Production)

cd examples/docker
cp .env.example .env
# Edit .env with production values
docker compose up -d

Standalone Docker

docker network create local-dev && \
docker run -d --name redis-container \
--network local-dev -p 6379:6379 redis:7.2 && \
docker run -d -p 8081:8081 --name go-snmp-olt-zte-c320 \
--network local-dev -e REDIS_HOST=redis-container \
-e REDIS_PORT=6379 -e REDIS_DB=0 \
-e REDIS_MIN_IDLE_CONNECTIONS=10 -e REDIS_POOL_SIZE=100 \
-e REDIS_POOL_TIMEOUT=30 -e SNMP_HOST=x.x.x.x \
-e SNMP_PORT=161 -e SNMP_COMMUNITY=xxxx \
cepatkilatteknologi/snmp-olt-zte-c320:3.0.0

API Endpoints

Health Check

curl -sS localhost:8081/health | jq
{"status":"ok"}

Get All ONUs by Board and PON

curl -sS localhost:8081/api/v1/board/2/pon/7 | jq
{
  "code": 200,
  "status": "OK",
  "data": [
    {
      "board": 2,
      "pon": 7,
      "onu_id": 3,
      "name": "Customer-001",
      "onu_type": "F670LV7.1",
      "serial_number": "ZTEGC*******",
      "rx_power": "-22.22",
      "status": "Online"
    }
  ]
}

Get Specific ONU Detail

curl -sS localhost:8081/api/v1/board/2/pon/7/onu/4 | jq
{
  "code": 200,
  "status": "OK",
  "data": {
    "board": 2,
    "pon": 7,
    "onu_id": 4,
    "name": "Customer-002",
    "description": "Location Description",
    "onu_type": "F670LV7.1",
    "serial_number": "ZTEGC*******",
    "rx_power": "-20.71",
    "tx_power": "2.57",
    "status": "Online",
    "ip_address": "10.x.x.x",
    "last_online": "2024-08-11 10:09:37",
    "last_offline": "2024-08-11 10:08:35",
    "uptime": "5 days 13 hours 10 minutes 50 seconds",
    "last_down_time_duration": "0 days 0 hours 1 minutes 2 seconds",
    "offline_reason": "PowerOff",
    "gpon_optical_distance": "6701"
  }
}

Get Empty ONU IDs

curl -sS localhost:8081/api/v1/board/2/pon/5/onu_id/empty | jq

Get ONU IDs with Serial Numbers

curl -sS localhost:8081/api/v1/board/2/pon/7/onu_id_sn | jq

Update Empty ONU ID Cache

curl -sS -X POST localhost:8081/api/v1/board/2/pon/5/onu_id/update | jq

Paginated ONU List

curl -sS 'http://localhost:8081/api/v1/paginate/board/2/pon/8?limit=3&page=2' | jq
{
  "code": 200,
  "status": "OK",
  "data": [
    {"board": 2, "pon": 8, "onu_id": 4, "name": "Customer-004", "onu_type": "F670LV7.1", "serial_number": "ZTEGC*******", "rx_power": "-19.17", "status": "Online"},
    {"board": 2, "pon": 8, "onu_id": 5, "name": "Customer-005", "onu_type": "F660V6.0", "serial_number": "ZTEGD*******", "rx_power": "-19.54", "status": "Online"}
  ],
  "meta": {
    "page": 2,
    "limit": 3,
    "page_count": 23,
    "total_rows": 69
  }
}

Clear Cache

curl -sS -X DELETE localhost:8081/api/v1/board/2/pon/7/cache/clear | jq

Authentication

When API_KEY environment variable is set, all /api/v1 routes require the X-API-Key header:

curl -sS -H "X-API-Key: your-api-key" localhost:8081/api/v1/board/2/pon/7 | jq

Without a valid API key, the server returns 401 Unauthorized. If API_KEY is not set, authentication is disabled (backward compatible). Health check (/health) never requires authentication.

Response Format

Success:

{"code": 200, "status": "OK", "data": [...]}

Success with pagination:

{"code": 200, "status": "OK", "data": [...], "meta": {"page": 1, "limit": 10, "page_count": 7, "total_rows": 69}}

Error:

{"code": 400, "status": "Bad Request", "error": {"type": "VALIDATION_ERROR", "message": "board_id must be 1 or 2", "details": {"received": "99"}}}
Pagination Parameter Default Max
page 1 -
limit 10 100

SNMP Trap Listener

Real-time ONU event monitoring via SNMP Trap with multi-platform webhook notifications (Discord, Slack, Telegram). Events are classified into a 4-tier severity system with per-severity batch intervals:

Severity Events Default Interval
CRITICAL LOS, LOSi, LOFi, Offline, AuthFailed, PowerOff 5 minutes
HIGH Logging, Synchronization (stuck) 1 hour
MEDIUM HighRxPower, LowRxPower 4 hours
LOW DyingGasp 8 hours

Key features:

  • Deduplication — each ONU appears only once per batch (keyed by Board/PON/ONU)
  • Recovery detection — ONUs that come back online before flush are automatically removed
  • Double verification — SNMP GET on trap receive and again at batch flush to eliminate false alarms
TRAP_ENABLED=true
TRAP_PORT=1620
TRAP_WEBHOOK_URL=https://hooks.example.com/snmp-alerts
TRAP_WEBHOOK_TYPE=discord          # discord|slack|telegram|generic (auto-detected from URL if omitted)
TRAP_WEBHOOK_CHAT_ID=              # Required for Telegram only

See docs/SNMP_TRAP_WEBHOOK.md for full architecture documentation.

RX Power Monitor

Periodic scanning of all ONUs for abnormal optical power levels with webhook alerts.

# Interval only (every 5 minutes)
POWER_MONITOR_ENABLED=true
POWER_MONITOR_INTERVAL=300

# Cron only (specific times)
POWER_MONITOR_INTERVAL=0
POWER_MONITOR_CRON=0 8,12,15,17,0 * * *
POWER_MONITOR_TIMEZONE=Asia/Jakarta

# Both interval + cron
POWER_MONITOR_INTERVAL=300
POWER_MONITOR_CRON=0 8,12,15,17,0 * * *

Thresholds: RX_POWER_HIGH_THRESHOLD=-8.0 (overload), RX_POWER_LOW_THRESHOLD=-25.0 (weak signal).

Testing Traps Locally

# Terminal 1: Start app with trap enabled
# Set in .env: TRAP_ENABLED=true, TRAP_PORT=1620, TRAP_WEBHOOK_URL=http://localhost:9999/test
task dev

# Terminal 2: Run trap tests (sends 6 fake traps + starts webhook receiver)
task test-trap

Deployment Examples

Ready-to-use deployment configurations in examples/:

Method Directory Install
Docker Compose examples/docker/ docker compose up -d
Helm Chart examples/helm/ helm install olt-monitor snmp-olt/snmp-olt-zte-c320
Kustomize examples/kustomize/ kubectl apply -k examples/kustomize/overlays/production/

Helm Repository

helm repo add snmp-olt https://cepat-kilat-teknologi.github.io/go-snmp-olt-zte-c320/
helm repo update
helm install olt-monitor snmp-olt/snmp-olt-zte-c320 \
  --set snmp.host=192.168.1.1 \
  --set snmp.community=your-community

Architecture

cmd/api/          Entry point (loads .env, starts server)
app/              HTTP server setup, routing, middleware chain
config/           Environment-based configuration, OID generation
internal/
  handler/        HTTP handlers with request ID correlation
  middleware/     Auth, CORS, rate limiting, security headers, validation
  usecase/        Business logic, singleflight, caching strategy, cache pre-warming
  repository/     SNMP connection pool, Redis operations
  model/          Data models (ONU info, pagination)
  trap/           SNMP Trap listener, event handler, webhook notifications
  errors/         Typed application errors (validation, SNMP, Redis)
  utils/          OID extractors, power converters, response helpers
pkg/
  graceful/       Graceful shutdown with signal handling
  pagination/     Pagination calculation
  redis/          Redis client factory
  snmp/           SNMP connection setup
api/              OpenAPI 3.1 specification
scripts/          Trap testing tools
examples/         Deployment examples (Docker, Helm, Kustomize)

Performance

Tested with k6 (100 VUs, 1m40s) against a real ZTE C320 OLT:

Metric Value
Throughput 4,624 req/s
p(95) Response Time 2.06ms
p(99) Response Time 4.88ms
Median Response Time 217µs
Iterations (100 VUs) 51,043
Real Error Rate 0.07%
Test Coverage 98.6%

Caching Strategy

  • ONU list: 30 min TTL (configurable via REDIS_ONU_INFO_TTL), background refresh at 20% expiry
  • ONU detail: 15 min TTL (configurable via REDIS_ONU_DETAIL_TTL), fallback from cached list
  • ONU serial numbers: 30 min TTL, cached in Redis
  • Empty ONU IDs: 5 min TTL (configurable via REDIS_EMPTY_ONU_ID_TTL)
  • Cache pre-warming: All 32 board/pon combos scanned at startup (CACHE_PREWARM=true)
  • SNMP concurrency limit: Max 5 concurrent operations (SNMP_MAX_CONCURRENT=5)
  • Connection pool: 4 parallel SNMP connections

Available Tasks

Run task --list or task help to see all available tasks.

Task Description
task dev Start development (Redis in Docker + hot reload)
task up Start full Docker development environment
task test Run all unit tests
task test-coverage Run tests with coverage report
task test-html Generate HTML coverage report
task load-test Run k6 load testing
task prod-up Start production containers
task app-build Build the app binary
task build-image Build Docker image (local)
task push-image Build and push multi-arch image to Docker Hub
task clean Clean up containers, volumes, artifacts
task test-trap Test SNMP Trap listener with fake traps
task test-trap-webhook Start webhook receiver for manual testing

Load Testing

# Run load test (wait for cache pre-warm before testing)
task load-test

# Run with custom base URL and API key
k6 run -e BASE_URL=http://10.0.0.1:8081 -e API_KEY=your-key scripts/k6-load-test.js

License

MIT License

Packages

 
 
 

Contributors

Languages