feat: declare the SNMP health OIDs instead of collecting them (0.3.0)
CI / test (3.10) (push) Successful in 31s
CI / test (3.11) (push) Successful in 30s
CI / test (3.12) (push) Successful in 33s
CI / test (3.10) (pull_request) Successful in 33s
CI / test (3.11) (pull_request) Successful in 30s
CI / test (3.12) (pull_request) Successful in 32s

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
This commit is contained in:
Christian Manivong committed 2026-10-16 12:02:00 +02:00
1 parent 03c8f0588d
commit 39d5e69270
3 files changed
+48 -64

No files matched your search

+14 -63
View File
@@ -19,7 +19,7 @@ Netmiko device type: ``hp_procurve`` / ``hp_procurve_telnet``
import logging import logging
import re import re
import socket import socket
from typing import Any, Dict, List, Optional, Union from typing import Any, ClassVar, Dict, List, Optional, Union
import netaddr import netaddr
from netmiko import ConnectHandler from netmiko import ConnectHandler
@@ -104,6 +104,19 @@ class ProcurveDriver(ConfigLifecycleMixin, SwitchDriver):
NETMIKO_DEVICE_TYPE = "hp_procurve" NETMIKO_DEVICE_TYPE = "hp_procurve"
NETMIKO_DEVICE_TYPE_TELNET = "hp_procurve_telnet" 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__( def __init__(
self, self,
hostname: str, hostname: str,
@@ -1295,68 +1308,6 @@ class ProcurveDriver(ConfigLifecycleMixin, SwitchDriver):
else f"[warn] Verification — community not found: {out[:200]}") else f"[warn] Verification — community not found: {out[:200]}")
return {"success": success, "output": "\n".join(lines)} 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 # Helpers
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "napalm-hpe-aruba-procurve" 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)" description = "NAPALM driver for HPE/Aruba ProCurve switches with auto-detecting transport (REST API, SSH, legacy SSH, Telnet)"
readme = "README.md" readme = "README.md"
license = { text = "Apache-2.0" } license = { text = "Apache-2.0" }
+33
View File
@@ -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",
}