feat: declare the SNMP health OIDs instead of collecting them (0.2.0) #10
No files matched your search
@@ -30,7 +30,7 @@ CLI notes
|
|||||||
import re
|
import re
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
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
|
||||||
@@ -69,6 +69,19 @@ class NetgearSmartDriver(ConfigLifecycleMixin, SwitchDriver):
|
|||||||
# Netmiko device type – handles prompt ``(hostname) >`` / ``(hostname) #``
|
# Netmiko device type – handles prompt ``(hostname) >`` / ``(hostname) #``
|
||||||
NETMIKO_DEVICE_TYPE = "netgear_prosafe"
|
NETMIKO_DEVICE_TYPE = "netgear_prosafe"
|
||||||
|
|
||||||
|
#: Where the switch publishes its health values over SNMP
|
||||||
|
#: (napalm-device-types ``SnmpHealthProfile``); the application polls.
|
||||||
|
#: CPU is text ("5 Secs ( 3.2%) 60 Secs ( …"); the five-second figure counts.
|
||||||
|
SNMP_HEALTH_PROFILE: ClassVar[Dict[str, Any]] = {
|
||||||
|
"uptime": {"oids": ["1.3.6.1.2.1.1.3.0"]},
|
||||||
|
"cpu": {"oids": ["1.3.6.1.4.1.4526.100.1.1.4.9.0"], "pattern": r"5\s+Secs\s*\(\s*([\d.]+)\s*%\)"},
|
||||||
|
"memory": {
|
||||||
|
"total": {"oids": ["1.3.6.1.4.1.4526.100.1.1.4.2.0"]},
|
||||||
|
"free": {"oids": ["1.3.6.1.4.1.4526.100.1.1.4.1.0"]},
|
||||||
|
"unit": "KiB",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
# PoE priority mapping between the CLI's "low/high/critical" and the
|
# PoE priority mapping between the CLI's "low/high/critical" and the
|
||||||
# generic priority strings used across drivers.
|
# generic priority strings used across drivers.
|
||||||
_POE_PRIORITY_MAP = {"low": "PPP_LOW", "high": "PPP_HIGH", "critical": "PPP_CRITICAL"}
|
_POE_PRIORITY_MAP = {"low": "PPP_LOW", "high": "PPP_HIGH", "critical": "PPP_CRITICAL"}
|
||||||
@@ -2040,76 +2053,3 @@ class NetgearSmartDriver(ConfigLifecycleMixin, SwitchDriver):
|
|||||||
finally:
|
finally:
|
||||||
self._exit_config_mode()
|
self._exit_config_mode()
|
||||||
self._save_config()
|
self._save_config()
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
# Health metrics (SNMP)
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
async def get_health_metrics(cls, snmp_get, snmp_walk) -> dict:
|
|
||||||
import asyncio
|
|
||||||
import re
|
|
||||||
from napalm_device_types._ucd_metrics import build_if_metrics, ticks_to_seconds
|
|
||||||
|
|
||||||
_OID_SNMP_UPTIME = "1.3.6.1.2.1.1.3.0"
|
|
||||||
_NETGEAR_MEM_FREE = "1.3.6.1.4.1.4526.100.1.1.4.1.0"
|
|
||||||
_NETGEAR_MEM_TOTAL = "1.3.6.1.4.1.4526.100.1.1.4.2.0"
|
|
||||||
_NETGEAR_CPU_STR = "1.3.6.1.4.1.4526.100.1.1.4.9.0"
|
|
||||||
_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"
|
|
||||||
|
|
||||||
(
|
|
||||||
uptime_raw,
|
|
||||||
free_s,
|
|
||||||
total_s,
|
|
||||||
cpu_s,
|
|
||||||
descr,
|
|
||||||
speed,
|
|
||||||
in_oct,
|
|
||||||
out_oct,
|
|
||||||
in_err,
|
|
||||||
out_err,
|
|
||||||
) = await asyncio.gather(
|
|
||||||
snmp_get(_OID_SNMP_UPTIME),
|
|
||||||
snmp_get(_NETGEAR_MEM_FREE),
|
|
||||||
snmp_get(_NETGEAR_MEM_TOTAL),
|
|
||||||
snmp_get(_NETGEAR_CPU_STR),
|
|
||||||
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(uptime_raw)
|
|
||||||
if secs is not None:
|
|
||||||
metrics["uptime_seconds"] = secs
|
|
||||||
|
|
||||||
if free_s and total_s:
|
|
||||||
try:
|
|
||||||
free_kb = int(free_s)
|
|
||||||
total_kb = int(total_s)
|
|
||||||
used_kb = max(0, total_kb - free_kb)
|
|
||||||
metrics["memory_total_bytes"] = total_kb * 1024
|
|
||||||
metrics["memory_used_bytes"] = used_kb * 1024
|
|
||||||
metrics["memory_percent"] = round(used_kb / total_kb * 100, 1) if total_kb else 0.0
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if cpu_s:
|
|
||||||
m = re.search(r"5\s+Secs\s*\(\s*([\d.]+)\s*%\)", cpu_s)
|
|
||||||
if m:
|
|
||||||
try:
|
|
||||||
metrics["cpu_percent"] = float(m.group(1))
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
build_if_metrics(metrics, descr, speed, in_oct, out_oct, in_err, out_err)
|
|
||||||
return metrics
|
|
||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "napalm-netgear"
|
name = "napalm-netgear"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
description = "NAPALM driver for Netgear switches (Plus/Smart)"
|
description = "NAPALM driver for Netgear switches (Plus/Smart)"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = { text = "Apache-2.0" }
|
license = { text = "Apache-2.0" }
|
||||||
|
|||||||
@@ -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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from napalm_netgear.netgear_smart import NetgearSmartDriver
|
||||||
|
|
||||||
|
PROFILE = NetgearSmartDriver.SNMP_HEALTH_PROFILE
|
||||||
|
|
||||||
|
|
||||||
|
def test_the_driver_does_not_collect_itself():
|
||||||
|
assert "get_health_metrics" not in vars(NetgearSmartDriver)
|
||||||
|
|
||||||
|
|
||||||
|
def test_uptime_from_the_standard_sysuptime():
|
||||||
|
assert PROFILE["uptime"] == {"oids": ["1.3.6.1.2.1.1.3.0"]}
|
||||||
|
|
||||||
|
|
||||||
|
def test_memory_from_total_and_free_in_kib():
|
||||||
|
assert PROFILE["memory"] == {
|
||||||
|
"total": {"oids": ["1.3.6.1.4.1.4526.100.1.1.4.2.0"]},
|
||||||
|
"free": {"oids": ["1.3.6.1.4.1.4526.100.1.1.4.1.0"]},
|
||||||
|
"unit": "KiB",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_cpu_is_the_five_second_figure_in_a_text_value():
|
||||||
|
cpu = PROFILE["cpu"]
|
||||||
|
assert cpu["oids"] == ["1.3.6.1.4.1.4526.100.1.1.4.9.0"]
|
||||||
|
text = " 5 Secs ( 3.2%) 60 Secs ( 4.1%) 300 Secs ( 2.0%)"
|
||||||
|
assert re.search(cpu["pattern"], text).group(1) == "3.2"
|
||||||
Reference in new issue
Block a user