- Add SNMP_WALK_POLICIES env var and UI checkbox to skip ACD-POLICY-MIB (~73% of all OIDs), cutting walk time from ~25s to ~11s - Add /api/ping endpoint with reachability check before walk starts - Show "NID Management is UP" (green) or "NID is DOWN" (red) status - Block walk if target is unreachable Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
181 lines
8.1 KiB
Bash
Executable File
181 lines
8.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
# snmp-walk.sh — Live SNMP walk → parse → HTML viewer pipeline
|
|
#
|
|
# Usage:
|
|
# ./snmp-walk.sh # uses SNMP_TARGET from .env
|
|
# ./snmp-walk.sh 10.0.0.1 # override target IP
|
|
# ./snmp-walk.sh 10.0.0.1 full # override target + walk mode
|
|
#
|
|
# Reads configuration from .env (community, version, walk mode).
|
|
# Produces: walks/{IP}_{TIMESTAMP}_walk.txt
|
|
# walks/{IP}_{TIMESTAMP}_walk_monitoring.json
|
|
# walks/nid-viewer.html
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ENV_FILE="${SCRIPT_DIR}/.env"
|
|
|
|
# ── Load .env ────────────────────────────────────────────────────────
|
|
if [[ -f "$ENV_FILE" ]]; then
|
|
set -a
|
|
# shellcheck source=/dev/null
|
|
source "$ENV_FILE"
|
|
set +a
|
|
else
|
|
echo "Warning: ${ENV_FILE} not found — using defaults" >&2
|
|
fi
|
|
|
|
# ── Resolve parameters (CLI overrides .env) ──────────────────────────
|
|
TARGET="${1:-${SNMP_TARGET:-}}"
|
|
WALK_MODE="${2:-${SNMP_WALK_MODE:-targeted}}"
|
|
VERSION="${SNMP_VERSION:-2c}"
|
|
|
|
if [[ -z "$TARGET" ]]; then
|
|
echo "Error: No target IP specified."
|
|
echo " Set SNMP_TARGET in .env or pass as argument: $0 <ip>"
|
|
exit 1
|
|
fi
|
|
|
|
# ── Validate prerequisites ───────────────────────────────────────────
|
|
for cmd in snmpwalk python3; do
|
|
if ! command -v "$cmd" &>/dev/null; then
|
|
echo "Error: '$cmd' not found. Please install it." >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
# Prefer snmpbulkwalk (GETBULK PDUs — much faster) over snmpwalk (GETNEXT)
|
|
if command -v snmpbulkwalk &>/dev/null; then
|
|
WALK_CMD=snmpbulkwalk
|
|
BULK_ARGS=() # use default -Cr10; higher values truncate on some devices
|
|
else
|
|
WALK_CMD=snmpwalk
|
|
BULK_ARGS=()
|
|
fi
|
|
|
|
# ── Build snmpwalk auth flags ────────────────────────────────────────
|
|
SNMP_AUTH=()
|
|
if [[ "$VERSION" == "3" ]]; then
|
|
SNMP_AUTH+=(-v3)
|
|
SNMP_AUTH+=(-u "${SNMP_V3_USER:?SNMP_V3_USER required for v3}")
|
|
SNMP_AUTH+=(-l "${SNMP_V3_SEC_LEVEL:-authPriv}")
|
|
if [[ "${SNMP_V3_SEC_LEVEL:-authPriv}" != "noAuthNoPriv" ]]; then
|
|
SNMP_AUTH+=(-a "${SNMP_V3_AUTH_PROTO:-SHA}")
|
|
SNMP_AUTH+=(-A "${SNMP_V3_AUTH_PASS:?SNMP_V3_AUTH_PASS required}")
|
|
fi
|
|
if [[ "${SNMP_V3_SEC_LEVEL:-authPriv}" == "authPriv" ]]; then
|
|
SNMP_AUTH+=(-x "${SNMP_V3_PRIV_PROTO:-AES}")
|
|
SNMP_AUTH+=(-X "${SNMP_V3_PRIV_PASS:?SNMP_V3_PRIV_PASS required}")
|
|
fi
|
|
else
|
|
SNMP_AUTH+=(-v "${VERSION}" -c "${SNMP_COMMUNITY:-public}")
|
|
fi
|
|
|
|
# ── Define OID subtrees ──────────────────────────────────────────────
|
|
# Targeted: only what the viewer/parser needs
|
|
WALK_POLICIES="${SNMP_WALK_POLICIES:-true}"
|
|
|
|
TARGETED_OIDS=(
|
|
.1.3.6.1.2.1.1 # System (sysDescr, sysName, sysUpTime, …)
|
|
.1.3.6.1.2.1.2 # IF-MIB (interface table)
|
|
.1.3.6.1.2.1.4 # IP-MIB (addresses, routes)
|
|
.1.3.6.1.2.1.31 # IF-MIB extensions (ifName, ifAlias, 64-bit counters)
|
|
.1.3.6.1.2.1.55 # IPv6-MIB
|
|
.1.3.111.2.802.1.1.13 # LLDP-MIB (neighbors, stats)
|
|
.1.3.6.1.4.1.22420.1.1 # ACD-DESC-MIB (device identity, connectors, sensors)
|
|
.1.3.6.1.4.1.22420.2.1 # ACD-ALARM-MIB
|
|
.1.3.6.1.4.1.22420.2.2 # ACD-FILTER-MIB
|
|
.1.3.6.1.4.1.22420.2.4 # ACD-SFP-MIB (transceiver info/diag)
|
|
.1.3.6.1.4.1.22420.2.6 # ACD-REGULATOR-MIB
|
|
.1.3.6.1.4.1.22420.2.8 # ACD-SMAP-MIB (CoS profiles)
|
|
.1.3.6.1.4.1.22420.2.9 # ACD-PORT-MIB (port config/status)
|
|
)
|
|
|
|
if [[ "$WALK_POLICIES" == "true" ]]; then
|
|
TARGETED_OIDS+=(.1.3.6.1.4.1.22420.2.3) # ACD-POLICY-MIB (~73% of all OIDs)
|
|
fi
|
|
|
|
# ── Prepare output paths ─────────────────────────────────────────────
|
|
TIMESTAMP="$(date +%Y-%m-%d_%H-%M-%S)"
|
|
SAFE_IP="${TARGET//./-}"
|
|
WALKS_DIR="${SCRIPT_DIR}/walks"
|
|
WALK_FILE="${WALKS_DIR}/${SAFE_IP}_${TIMESTAMP}_walk.txt"
|
|
ERROR_FILE="${WALKS_DIR}/${SAFE_IP}_${TIMESTAMP}_errors.txt"
|
|
|
|
mkdir -p "$WALKS_DIR"
|
|
|
|
# ── Execute SNMP walk ─────────────────────────────────────────────────
|
|
echo "═══════════════════════════════════════════════════════"
|
|
echo " SNMP NID Viewer — Live Walk"
|
|
echo "═══════════════════════════════════════════════════════"
|
|
echo " Target: ${TARGET}"
|
|
echo " Version: SNMPv${VERSION}"
|
|
echo " Mode: ${WALK_MODE}"
|
|
echo " Walker: ${WALK_CMD}${BULK_ARGS:+ (max-rep=${BULK_ARGS[1]#-Cr})}"
|
|
echo " Output: ${WALK_FILE}"
|
|
echo "═══════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
WALK_START="$(date +%s)"
|
|
|
|
if [[ "$WALK_MODE" == "full" ]]; then
|
|
echo "[1/3] Walking full OID tree (.1) ..."
|
|
"$WALK_CMD" -On -OQ "${BULK_ARGS[@]}" "${SNMP_AUTH[@]}" "$TARGET" .1 \
|
|
> "$WALK_FILE" 2> "$ERROR_FILE" || true
|
|
else
|
|
echo "[1/3] Walking ${#TARGETED_OIDS[@]} targeted subtrees ..."
|
|
: > "$WALK_FILE"
|
|
: > "$ERROR_FILE"
|
|
for oid in "${TARGETED_OIDS[@]}"; do
|
|
echo " ↳ ${oid}"
|
|
"$WALK_CMD" -On -OQ "${BULK_ARGS[@]}" "${SNMP_AUTH[@]}" "$TARGET" "$oid" \
|
|
>> "$WALK_FILE" 2>> "$ERROR_FILE" || true
|
|
done
|
|
fi
|
|
|
|
WALK_END="$(date +%s)"
|
|
WALK_LINES="$(wc -l < "$WALK_FILE")"
|
|
WALK_SECS=$(( WALK_END - WALK_START ))
|
|
echo " ✓ Walk complete: ${WALK_LINES} lines in ${WALK_SECS}s"
|
|
|
|
# Remove empty error file
|
|
if [[ ! -s "$ERROR_FILE" ]]; then
|
|
rm -f "$ERROR_FILE"
|
|
fi
|
|
|
|
if [[ "$WALK_LINES" -eq 0 ]]; then
|
|
echo ""
|
|
echo "Error: Walk returned no data. Check:"
|
|
echo " - Device reachability (ping ${TARGET})"
|
|
echo " - SNMP community/credentials in .env"
|
|
echo " - Firewall rules (UDP 161)"
|
|
[[ -s "$ERROR_FILE" ]] && echo "" && cat "$ERROR_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
# ── Parse walk → monitoring JSON ──────────────────────────────────────
|
|
echo ""
|
|
echo "[2/3] Parsing walk data ..."
|
|
python3 "${SCRIPT_DIR}/snmp-parse.py" "$WALK_FILE"
|
|
|
|
MONITORING_JSON="${WALK_FILE%.txt}_monitoring.json"
|
|
if [[ ! -f "$MONITORING_JSON" ]]; then
|
|
echo "Error: snmp-parse.py did not produce ${MONITORING_JSON}" >&2
|
|
exit 1
|
|
fi
|
|
echo " ✓ Monitoring JSON: ${MONITORING_JSON}"
|
|
|
|
# ── Build HTML viewer ─────────────────────────────────────────────────
|
|
echo ""
|
|
echo "[3/3] Building HTML viewer ..."
|
|
python3 "${SCRIPT_DIR}/build_nid_viewer.py" "$MONITORING_JSON"
|
|
echo " ✓ Viewer: ${WALKS_DIR}/nid-viewer.html"
|
|
|
|
# ── Summary ───────────────────────────────────────────────────────────
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════════════"
|
|
echo " Done! Open walks/nid-viewer.html in a browser."
|
|
echo "═══════════════════════════════════════════════════════"
|