From 39d5e692700499c1376e73260c315e7b3cb00c03 Mon Sep 17 00:00:00 2001 From: Christian Manivong Date: Fri, 16 Oct 2026 12:02:00 +0200 Subject: [PATCH] feat: declare the SNMP health OIDs instead of collecting them (0.3.0) The driver no longer collects over SNMP. SNMP_HEALTH_PROFILE states where the switch publishes its values; the application polls and computes (napalm-device-types docs/STRUCTURE.md). This also fixes the memory figure: NETSWITCH-MIB hpLocalMemEntry column 6 is free memory, not used. On swt-l0-3-40 total 58720256 = free 39105640 + allocated 19614616, so the switch showed 66.6 % used instead of 33.4 %. The profile names column 6 as free. Interface counters now come from the 64-bit ifXTable where the switch has it, as the application reads them for every device. Closes #9 --- napalm_procurve/procurve.py | 77 ++++++--------------------------- pyproject.toml | 2 +- tests/unit/test_snmp_profile.py | 33 ++++++++++++++ 3 files changed, 48 insertions(+), 64 deletions(-) create mode 100644 tests/unit/test_snmp_profile.py diff --git a/napalm_procurve/procurve.py b/napalm_procurve/procurve.py index 1406017..24750c7 100644 --- a/napalm_procurve/procurve.py +++ b/napalm_procurve/procurve.py @@ -19,7 +19,7 @@ Netmiko device type: ``hp_procurve`` / ``hp_procurve_telnet`` import logging import re import socket -from typing import Any, Dict, List, Optional, Union +from typing import Any, ClassVar, Dict, List, Optional, Union import netaddr from netmiko import ConnectHandler @@ -104,6 +104,19 @@ class ProcurveDriver(ConfigLifecycleMixin, SwitchDriver): NETMIKO_DEVICE_TYPE = "hp_procurve" NETMIKO_DEVICE_TYPE_TELNET = "hp_procurve_telnet" + #: Where the switch publishes its health values over SNMP + #: (napalm-device-types ``SnmpHealthProfile``); the application polls. + #: Memory is NETSWITCH-MIB ``hpLocalMemEntry``: .5 total, .6 free, .7 allocated. + SNMP_HEALTH_PROFILE: ClassVar[Dict[str, Any]] = { + "uptime": {"oids": ["1.3.6.1.4.1.11.2.14.11.1.2.4.1.5.1"]}, + "cpu": {"oids": ["1.3.6.1.4.1.11.2.14.11.5.1.9.6.1.0", "1.3.6.1.4.1.11.2.3.7.8.6.1.0"]}, + "memory": { + "total": {"oids": ["1.3.6.1.4.1.11.2.14.11.5.1.1.2.1.1.1.5.1"]}, + "free": {"oids": ["1.3.6.1.4.1.11.2.14.11.5.1.1.2.1.1.1.6.1"]}, + "unit": "bytes", + }, + } + def __init__( self, hostname: str, @@ -1295,68 +1308,6 @@ class ProcurveDriver(ConfigLifecycleMixin, SwitchDriver): else f"[warn] Verification — community not found: {out[:200]}") return {"success": success, "output": "\n".join(lines)} - # ------------------------------------------------------------------ - # Health metrics (SNMP) - # ------------------------------------------------------------------ - - @classmethod - async def get_health_metrics(cls, snmp_get, snmp_walk) -> dict: - import asyncio - from napalm_device_types._ucd_metrics import build_if_metrics, ticks_to_seconds - - _HP_CPU_STAT = "1.3.6.1.4.1.11.2.14.11.5.1.9.6.1.0" - _HP_CPU_STAT_OLD = "1.3.6.1.4.1.11.2.3.7.8.6.1.0" - _HP_MEM_TOTAL = "1.3.6.1.4.1.11.2.14.11.5.1.1.2.1.1.1.5.1" - _HP_MEM_USED = "1.3.6.1.4.1.11.2.14.11.5.1.1.2.1.1.1.6.1" - _HP_UPTIME = "1.3.6.1.4.1.11.2.14.11.1.2.4.1.5.1" - _OID_IF_DESCR = "1.3.6.1.2.1.2.2.1.2" - _OID_IF_SPEED = "1.3.6.1.2.1.2.2.1.5" - _OID_IF_IN_OCT = "1.3.6.1.2.1.2.2.1.10" - _OID_IF_OUT_OCT = "1.3.6.1.2.1.2.2.1.16" - _OID_IF_IN_ERR = "1.3.6.1.2.1.2.2.1.14" - _OID_IF_OUT_ERR = "1.3.6.1.2.1.2.2.1.20" - - (hp_uptime, cpu_raw, cpu_old, mem_t, mem_u, - descr, speed, in_oct, out_oct, in_err, out_err) = await asyncio.gather( - snmp_get(_HP_UPTIME), - snmp_get(_HP_CPU_STAT), - snmp_get(_HP_CPU_STAT_OLD), - snmp_get(_HP_MEM_TOTAL), - snmp_get(_HP_MEM_USED), - snmp_walk(_OID_IF_DESCR), - snmp_walk(_OID_IF_SPEED), - snmp_walk(_OID_IF_IN_OCT), - snmp_walk(_OID_IF_OUT_OCT), - snmp_walk(_OID_IF_IN_ERR), - snmp_walk(_OID_IF_OUT_ERR), - ) - - metrics: dict = {} - - secs = ticks_to_seconds(hp_uptime) - if secs is not None: - metrics["uptime_seconds"] = secs - - cpu = cpu_raw or cpu_old - if cpu is not None: - try: - metrics["cpu_percent"] = float(cpu) - except ValueError: - pass - - if mem_t and mem_u: - try: - total = int(mem_t) - used = int(mem_u) - metrics["memory_total_bytes"] = total - metrics["memory_used_bytes"] = used - metrics["memory_percent"] = round(used / total * 100, 1) if total else 0.0 - except ValueError: - pass - - build_if_metrics(metrics, descr, speed, in_oct, out_oct, in_err, out_err) - return metrics - # --------------------------------------------------------------------------- # Helpers diff --git a/pyproject.toml b/pyproject.toml index 2bfa2f1..9973f20 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "napalm-hpe-aruba-procurve" -version = "0.2.0" +version = "0.3.0" description = "NAPALM driver for HPE/Aruba ProCurve switches with auto-detecting transport (REST API, SSH, legacy SSH, Telnet)" readme = "README.md" license = { text = "Apache-2.0" } diff --git a/tests/unit/test_snmp_profile.py b/tests/unit/test_snmp_profile.py new file mode 100644 index 0000000..3d42aa4 --- /dev/null +++ b/tests/unit/test_snmp_profile.py @@ -0,0 +1,33 @@ +"""The switch's SNMP health OIDs, declared as data (napalm-device-types docs/STRUCTURE.md). + +The driver does not collect over SNMP; the application polls with this profile. +""" + +from napalm_procurve.procurve import ProcurveDriver + +PROFILE = ProcurveDriver.SNMP_HEALTH_PROFILE +MEM = "1.3.6.1.4.1.11.2.14.11.5.1.1.2.1.1.1" # NETSWITCH-MIB hpLocalMemEntry + + +def test_the_driver_does_not_collect_itself(): + assert "get_health_metrics" not in vars(ProcurveDriver) + + +def test_uptime_from_the_switch_mib(): + assert PROFILE["uptime"] == {"oids": ["1.3.6.1.4.1.11.2.14.11.1.2.4.1.5.1"]} + + +def test_cpu_from_the_current_oid_then_the_older_firmware_s(): + assert PROFILE["cpu"] == { + "oids": ["1.3.6.1.4.1.11.2.14.11.5.1.9.6.1.0", "1.3.6.1.4.1.11.2.3.7.8.6.1.0"] + } + + +def test_memory_column_6_is_free_not_used(): + # On swt-l0-3-40 (2026-10-16): total (.5) 58720256 = free (.6) 39105640 + # + allocated (.7) 19614616. Read as "used", .6 showed 66.6 % instead of 33.4 % (#9). + assert PROFILE["memory"] == { + "total": {"oids": [f"{MEM}.5.1"]}, + "free": {"oids": [f"{MEM}.6.1"]}, + "unit": "bytes", + } -- 2.54.0