docs: what the drivers need from the SNMP profile, opt-outs, and how getters behave
CI / test (3.10) (push) Successful in 26s
CI / test (3.11) (push) Successful in 24s
CI / test (3.12) (push) Successful in 26s
CI / test (3.13) (push) Successful in 25s
CI / test (3.10) (pull_request) Successful in 25s
CI / test (3.11) (pull_request) Successful in 24s
CI / test (3.12) (pull_request) Successful in 26s
CI / test (3.13) (pull_request) Successful in 25s

The SNMP profile has to express fallback OIDs, tables folded by first,
average or maximum, numbers inside text values, memory as used, free or
percent, and the uptime source. TX errors counting drops becomes
OPNsense's entry instead of every firewall's.

A driver opts out of an inherited template with None, so callers ask
callable(). USES_SSH, FULL_UPGRADE and platform stay as driver facts.
Getters do not write, a failed read raises, a write reports its real
result, and the application uses public driver methods only.
This commit is contained in:
christianmanivong committed 2026-10-14 10:56:17 +02:00
1 parent 01fe680456
commit c7ea15dbb4
1 file changed
+48 -5
+48 -5
View File
@@ -41,6 +41,7 @@ application SNMP polling, ping sweeps, discovery scoring, guest
| **Contract types** | Interfaces and data shapes other packages implement or fill. | `CommandChannelMixin`, `CommandResult`, `ByteStream`; the declaration of `ContainerEngineMixin`; the reader mixins' public method declarations; the SNMP profile type; `models` |
| **Reconciler** | Concrete and vendor-neutral, without I/O of its own. | `firewall_rules` and `dhcp` diff/apply, `_matching`, `lag` |
| **Introspection** | Concrete, without I/O. | `roles`; `base` (`FingerprintRule`, `PortSpec`, the fingerprint attributes) |
| **Driver facts** | Class attributes that describe the device or how it is reached, not what an application does with it. | `USES_SSH`, `FULL_UPGRADE`, `platform`, `SNMP_HEALTH_PROFILE` |
### Fix routines are templates
@@ -76,8 +77,13 @@ The same shape replaces every action in today's `run_device_action`:
| `fix_docker_permissions` | `grant_container_engine_access(user)` |
| `install_lldpd`, `install_auc` | `ensure_package(name)` |
`hasattr(driver, "configure_snmp_agent")` stays a truthful answer: the mixin is mixed in
by the driver, or by the platform package, not by a role base.
The mixin is mixed in by the driver, or by the platform package, not by a role base. A
driver that inherits a template it cannot run on its device, as a NAS driver built on the
Linux driver inherits the package proxy, opts out by setting the method to `None`. So a
caller asks `callable(getattr(driver, "configure_snmp_agent", None))`, never `hasattr`.
The caller verifies the result from its own side where it can; the SNMP agent is asked
by the application's SNMP client, not by a probe the driver hand-builds.
### SNMP: drivers declare data, the application polls
@@ -88,12 +94,29 @@ proprietary OIDs declares them as data, in a class attribute of a type defined h
```python
class ProcurveDriver(SwitchDriver):
SNMP_HEALTH_PROFILE: ClassVar[SnmpHealthProfile] = {
"uptime": "1.3.6.1.4.1.11.2.14.11.1.2.6.1.0", ...
"uptime": {"oids": ["1.3.6.1.4.1.11.2.14.11.1.2.4.1.5.1"], "format": "ticks"},
"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": "...", "free": "...", "unit": "bytes"},
}
```
Polling, the standard OIDs, the counter arithmetic and the interfaces worth skipping are
the application's.
One OID per value is not enough for the drivers there are. The profile type has to say:
- **Fallbacks:** an ordered list of OIDs; the first that answers wins (ProCurve's CPU).
- **Tables:** an OID to walk and how to fold its rows: first, average or maximum (TP-Link
reports CPU and memory per stack unit).
- **Text values:** a pattern that takes the number out of a string (Netgear reports CPU
as `"5 Secs ( 3.2%)"`).
- **Memory:** total with used or free, or a percentage only, and the unit.
- **Uptime:** which OID, standard ones included (`sysUpTime` where a device has no
`hrSystemUptime`), and its format.
- **Interfaces:** a pattern of names to skip, and whether the TX-error counter counts
drops. Today the second is `True` on every firewall, because OPNsense counts drops
there; it becomes OPNsense's profile entry.
Polling, the standard OIDs, the counter arithmetic (64-bit counters first, 32-bit as the
fallback) and the defaults are the application's.
### Warnings are facts
@@ -101,6 +124,25 @@ A driver reports facts: the proxy a host is configured with, a DSL line's SNR, t
firmware version it runs and the one it is offered. It does not compare them with a
setting of the application or with a threshold, and it does not name a warning.
The same goes for lookups a device does not make itself: what firmware a vendor
currently publishes is the application's catalogue, not a getter.
### Getters read, and say when they cannot
- A getter changes nothing on the device. It does not start a daemon, rewrite its
configuration or install a package on the way to an answer.
- A read that fails raises. An empty list means "there is none", never "could not ask";
a sync that deletes and re-adds on top of an empty answer would otherwise duplicate
everything.
- A write reports failure from the device's answer or exit status, never `success: True`
by default.
### The application uses public methods only
The application never calls a driver's private methods (`_get`, `_post`,
`_send_command`, `_action_*`). What it needs from a device becomes a declared method of
the driver.
## What moves to napalm-unix
| Module | Knows |
@@ -151,6 +193,7 @@ Layout: `napalm_unix/{posix,linux,freebsd,openssh,transport}/`.
| `rules_max_weight` | Scoring is how one application ranks drivers. The rules themselves stay with the driver. |
| `provisioning` (`QEMU_GUEST_AGENTS`, cloud-init network-config, decompressors) | Which agent a guest gets and how its network is configured is a guest profile. The hypervisor driver is handed the packages and commands. |
| `TYPE_LABEL`, `REBOOT_SETTLE_SECONDS` | A display name and a polling delay. |
| firmware catalogues (napalm-netgear's `netgear_plus`) | What a vendor publishes is not something the device reports. |
| `run_device_action` | Replaced by the templates above. |
`OSDriver.ROLE` stops defaulting to `"linux"`. Each OS driver states its own role.