feat: NAPALM driver for HPE OfficeConnect 1820/1920S
These switches have no CLI at all — no SSH, no Telnet and no ArubaOS-Switch REST API — so the ProCurve driver cannot serve them despite the shared vendor. The only management surface is the web UI, which ships its table data as JavaScript array literals; those parse with ast.literal_eval, so the driver needs no HTML parser and no dependency beyond napalm/requests. Read-only by design: the platform exposes a single administrator account with no privilege levels, and serves HTTPS only after a certificate has been uploaded, so the polling credential is necessarily the admin credential over a plain channel. Implements get_facts, get_interfaces, get_vlans, get_vlans_detail and get_mac_address_table, plus HTTP/SNMP fingerprints for discovery. Tested against an HPE OfficeConnect 1820 8G PoE+ (65W), J9982A, PT.02.19.
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
# napalm-hpe-officeconnect
|
||||
|
||||
NAPALM driver for **HPE OfficeConnect** web-managed switches — 1820 and 1920S.
|
||||
|
||||
## Why this is not part of `napalm-hpe-aruba-procurve`
|
||||
|
||||
Despite the shared vendor, these are unrelated platforms:
|
||||
|
||||
| | ProCurve / ArubaOS-Switch | OfficeConnect 1820 / 1920S |
|
||||
|---|---|---|
|
||||
| Base OS | ProVision / ArubaOS-Switch | Broadcom FASTPATH derivative |
|
||||
| SSH / Telnet | yes | **none at all** |
|
||||
| REST API | ArubaOS-Switch REST v3/v6/v7 | none |
|
||||
| Management | CLI + REST + web | web only |
|
||||
|
||||
The ProCurve driver's four transports (REST, SSH, legacy-KEX SSH, Telnet) all
|
||||
require something this hardware does not have. There is no shared transport,
|
||||
no shared command set and no shared parser, so the two drivers share nothing
|
||||
but a vendor name.
|
||||
|
||||
The real HP **1920** (without the S) is a *third* platform — Comware 5, with a
|
||||
`display`-style CLI — and would need its own driver again.
|
||||
|
||||
## Design
|
||||
|
||||
The switch has no machine API, so the driver reads the web UI. Every list page
|
||||
is a jQuery DataTable whose payload is embedded as JavaScript:
|
||||
|
||||
```js
|
||||
var aDataSet = [
|
||||
['<input type="checkbox" ...>', '1', '', 'Enabled', 'Normal', 'Link Up', ...]
|
||||
];
|
||||
var aColumns = [ { "sTitle": "Interface", ... }, ... ];
|
||||
```
|
||||
|
||||
That array literal is also valid Python, so `parsers.extract_data_set` parses
|
||||
it with `ast.literal_eval`. No HTML parser is involved and the package needs
|
||||
no dependency beyond `napalm` and `requests`.
|
||||
|
||||
This is a property of firmware PT.02.xx and newer. Older 1820 firmware
|
||||
server-rendered the same tables as `<tr>`/`<td>` markup — which is why the
|
||||
(unmaintained, last commit 2017) [hp1820-cli](https://github.com/BookGin/hp1820-cli)
|
||||
scraper does not work on current firmware. Its endpoint list was nonetheless a
|
||||
useful map when writing this driver.
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Purpose | Path |
|
||||
|---|---|
|
||||
| Login | `POST /htdocs/login/login.lua` |
|
||||
| Logout | `/htdocs/pages/main/logout.lsp` |
|
||||
| Facts | `/htdocs/pages/base/dashboard.lsp` |
|
||||
| Interfaces | `/htdocs/pages/base/port_summary.lsp` |
|
||||
| MAC table | `/htdocs/pages/base/mac_address_table.lsp` |
|
||||
| VLANs | `/htdocs/pages/switching/vlan_status.lsp` |
|
||||
| VLAN membership | `/htdocs/pages/switching/vlan_per_port.lsp?vlan=<id>` |
|
||||
|
||||
Authentication is a form POST answering JSON; an empty `error` field means
|
||||
success. Firmware generations disagree about the other fields, so `error` is
|
||||
the only one worth branching on.
|
||||
|
||||
## Read-only by design
|
||||
|
||||
The driver implements no write path. Two properties of the platform make that
|
||||
the right default:
|
||||
|
||||
- **One account, no privilege levels.** `user_accounts.lsp` offers a username
|
||||
and a password change — there is no read-only role — so the polling
|
||||
credential is necessarily the administrator credential.
|
||||
- **HTTP unless a certificate was uploaded.** The switch serves HTTPS only
|
||||
after an operator installs a certificate; out of the box the session, and
|
||||
therefore that admin credential, crosses the network in the clear.
|
||||
|
||||
Set `optional_args={"scheme": "https"}` once a certificate is in place.
|
||||
|
||||
**Session hygiene:** the switch keeps a small table of concurrent sessions and
|
||||
reclaims them only on idle timeout. `close()` always logs out, including on
|
||||
the failure path, or repeated polling will eventually lock the administrator
|
||||
out of the web UI.
|
||||
|
||||
## Supported methods
|
||||
|
||||
| Method | Status |
|
||||
|---|---|
|
||||
| `open` / `close` / `is_alive` | ✅ |
|
||||
| `get_facts` | ✅ |
|
||||
| `get_interfaces` | ✅ |
|
||||
| `get_vlans` | ✅ |
|
||||
| `get_vlans_detail` | ✅ tagged/untagged split |
|
||||
| `get_mac_address_table` | ✅ |
|
||||
| `get_interfaces_counters` | ❌ see below |
|
||||
| `get_config` | ❌ not yet |
|
||||
| config load / commit / rollback | ❌ by design |
|
||||
|
||||
### Known gaps
|
||||
|
||||
- **`get_interfaces_counters`** raises `NotImplementedError`.
|
||||
`port_summary_stats.lsp` declares its columns but ships an empty dataset on
|
||||
PT.02.19 and carries no AJAX endpoint that would fill it. Returning zeros
|
||||
would be indistinguishable from a switch that has genuinely passed no
|
||||
traffic, so the driver refuses rather than inventing data.
|
||||
- **`get_config`** is unimplemented. The source would be
|
||||
`/htdocs/lua/ajax/file_download_ajax.lua?protocol=6`, reachable but not yet
|
||||
mapped.
|
||||
- **SNMP.** The switch answers SNMPv2c (verified against a J9982A: `sysDescr`
|
||||
repeats the model string and `sysObjectID` is `1.3.6.1.4.1.11.2.3.7.11.170`),
|
||||
and the driver declares SNMP fingerprints accordingly. It does not yet
|
||||
implement `get_snmp_config` or `get_health_metrics`, so CPU/memory readings —
|
||||
which the web dashboard does show — are not surfaced.
|
||||
|
||||
## Usage
|
||||
|
||||
```python
|
||||
from napalm import get_network_driver
|
||||
|
||||
Driver = get_network_driver("hpe_officeconnect")
|
||||
|
||||
with Driver("192.0.2.20", "admin", "secret") as dev:
|
||||
print(dev.get_facts())
|
||||
print(dev.get_vlans())
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
Fixtures are real pages captured from an HPE OfficeConnect 1820 8G PoE+
|
||||
(J9982A, PT.02.19), scrubbed of serial number, MAC addresses, IP addresses,
|
||||
hostname and location.
|
||||
|
||||
```bash
|
||||
pip install -e ".[dev]"
|
||||
pytest tests/
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0
|
||||
Reference in New Issue
Block a user