monitor.snmp¶
otto SNMP manager — general SNMP v2c polling for performance monitoring.
This is the reusable core that lets otto monitor any SNMP speaker — network gear, a Linux box running net-snmp, or a Zephyr device running otto’s test-bed agent — over a separate channel from command execution. It is not embedded-only: a Unix host may also be monitored via SNMP.
Two layers, mirroring the shell-monitoring split in otto.monitor.parsers
(where MetricParser owns presentation and lab
data owns “what command to run”):
Acquisition —
SnmpClient: a thin async pysnmp v2c GET wrapper. Lab data (the host’ssnmpblock) supplies only connection params and the bare list of OIDs to poll. No presentation fields ever live in lab data.Presentation —
SnmpMetric+ the descriptor registry: maps each OID to how it is charted (label, chart group, unit, tab) and how its raw varbind is interpreted (scale). This is the SNMP analog ofMetricParser; graphing decisions live here. Built-in descriptors cover a standard OID set; private/device OIDs register a descriptor from an init module viaregister_snmp_metric(). An OID with no registered descriptor falls back to default styling (resolve_snmp_metric()) so a host can add a bare OID with zero code and still get a chart.
The pysnmp dependency is imported lazily inside SnmpClient.get() so this
module imports cleanly without it, and unit tests can mock at the get
boundary rather than against pysnmp internals.
-
class otto.monitor.snmp.SnmpMetric(*, oid: str, label: str, chart: str, y_title: str =
'', unit: str ='', tab: str ='metrics', tab_label: str ='Metrics', scale: float =1.0)¶ Bases:
OttoModelHow a single OID’s value is interpreted and charted.
Mirrors the presentation attributes
MetricParseralready exposes (chart/y_title/unit/tab/tab_label) plus ascalefactor that converts the raw integer varbind into a real value (e.g. sysUpTime is in hundredths of a second →scale=0.01for seconds; a CPU OID reported in centi-percent →scale=0.01for percent).These are deliberately not sourced from lab data — graphing stays in the monitor module.
frozen=True: a descriptor is an immutable, low-volume value object shared across ticks; the registry only ever replaces, never mutates. Built and registered through the public path (register_snmp_metric()) for first- and third-party descriptors alike.- to_point(raw: float) MetricDataPoint¶
Apply
scaleto a raw numeric varbind, returning a chartable point.
- otto.monitor.snmp.register_snmp_metric(metric: SnmpMetric) None¶
Register (or override) the descriptor for
metric.oid.Call from an init module listed in
.otto/settings.tomlto teach otto how to chart a private/device-specific OID — the same extension pattern asotto.monitor.parsers.register_host_parsers()andotto.host.command_frame.register_command_frame().
- otto.monitor.snmp.get_snmp_metric(oid: str) SnmpMetric | None¶
Return the registered descriptor for
oid, orNone.
- otto.monitor.snmp.resolve_snmp_metric(oid: str) SnmpMetric¶
Return the descriptor for
oid, or a default-styled fallback.The fallback charts the OID under its own label with no unit on the generic
metricstab, so a host can poll a bare OID it declared in lab data without anyone having registered a descriptor for it.
- otto.monitor.snmp.points_from_values(values: dict[str, float | None]) list[tuple[str, MetricDataPoint, SnmpMetric]]¶
Map
{oid: raw_value}to(label, point, descriptor)triples.Each raw varbind is scaled by its descriptor and labelled for charting. OIDs with a
Nonevalue (no such instance / error) are skipped.
-
class otto.monitor.snmp.SnmpClient(address: str, port: int =
161, community: str ='public', version: '1' | '2c' ='2c', timeout: float =2.0, retries: int =1)¶ Bases:
objectAsync SNMP v1/v2c GET client for a single endpoint.
The endpoint
(address, port)is whatever is reachable from the otto host — for a device behind a hop, that is the local end of a UDP forward / relay, not the device’s own address. Keeping the endpoint explicit means this client knows nothing about hop topology.- async get(oids: list[str]) dict[str, float | None]¶
GET
oidsin one PDU; return{oid: numeric_value_or_None}.Non-numeric or errored varbinds map to
Noneso the caller can skip them. On a transport/PDU error the whole batch returnsNonevalues and the error is logged — a failed tick is non-fatal, matching the shell collector’s per-host error handling.
- class otto.monitor.snmp.SnmpSource(client: SnmpClient, oids: list[str])¶
Bases:
objectA
MonitorTarget’s SNMP collection mode.Pairs the
SnmpClient(where/how to reach the agent) with the bare list of OIDs to poll each tick. Presentation for those OIDs comes from the descriptor registry, not from here — this is acquisition only.- client : SnmpClient¶