36 Commits
Author SHA1 Message Date
Christian Manivong 7f07da6857 fix(cli): the trunk gets its own row, as over REST
Since f35b59e a CLI poll reports trunk members as `3` with
trunk_group `Trk3`, but `show interfaces brief` has no line for Trk3
itself, so the trunk was missing from the interface list. The REST path
built that row on its own.

Both paths now use napalm_device_types.add_lag_interfaces, and the REST
path's copy is gone. One visible change there: `lag_members` is now in
port order (7, 10) instead of API order; the description already was.

The CLI path does not know the mode yet, so its trunks carry no
lag_mode. That needs `show trunks`, whose output is not at hand.

Needs napalm-device-types f3fa75b.

Closes #5
2026-09-25 10:44:11 +02:00
Christian Manivong f35b59ec2d fix(cli): read J.15 port status, and say why each transport failed
A 2800-series switch on J.15.09 polled over CLI came back with no
interfaces and an empty OS version, while VLANs and ARP parsed fine.

`show interfaces brief` on that firmware has an Intrusion Alert column
between the `|` and Enabled, and puts Mode before MDI rather than after:

      Port   Type      | Alert     Enabled Status Mode       Mode ...
      3-Trk3 100/1000T | No        Yes     Down   1000FDx    MDI  ...

The regex read Alert as Enabled, then failed on Yes where it wanted
Up|Down, so no line matched. It now skips the Alert column where there is
one and takes the speed from either position. Trunk members are listed as
`<port>-Trk<n>`; the port is `<port>` and the suffix becomes its
trunk_group, so the per-port `show interfaces 3` is a command the switch
knows.

The empty OS version was the alternatives list in _send_command. It moved
to the next command on "% Invalid" or "Error", but ProCurve rejects an
unknown command with "Invalid input: system-information" -- so that line
was parsed as system information. "Invalid input" now counts as failure.

Getting there took longer than it should have, because the first symptom
was "Authentication failed: Login failed". That was Telnet's error, the
last transport tried; the REST probe and both SSH attempts had failed
before it and said nothing above debug level. In fact the switch had run
out of CLI sessions and closed SSH straight after the password. open()
now records why each transport failed, and both the auth error and the
final "Cannot connect" carry that list.

Fixtures are that switch's output, with hostname, serial and MAC
replaced.

Closes #2
Closes #3
Closes #4
2026-09-25 08:55:11 +02:00
Christian Manivong e3bbac0656 fix(api): change an existing VLAN membership instead of re-creating it
set_interface() always POSTed to vlans-ports, treating every membership as
new. Moving a port that already carries the VLAN from untagged to tagged is
not a create, though, and the switch says so:

    POST vlans-ports {"vlan_id":10,"port_id":"10","port_mode":"POM_TAGGED_STATIC"}
      -> 400 {"message":"Association exists"}

Only 409 was handled as "already there"; v7 firmware answers 400. The
membership is its own resource named {vlan_id}-{port_id} and takes a PUT:

    PUT vlans-ports/10-10 -> 200

So the exact case anyone hits first failed outright — a port holding VLAN 10
untagged alongside 30/40/50 tagged, with VLAN 10 to become tagged too.

The response body is now carried into both error messages. The ports PUT just
above already did this; here it was dropped, so "Association exists" — which
names the cause outright — never reached the caller. The message read
"vlans-ports POST HTTP 400" and nothing more.

Verified against a 2530-24G-PoEP on REST v7: set_interface("10", trunk
vlan 30), where that membership already exists, now completes and leaves the
port exactly as it was.
2026-08-18 16:22:21 +07:00
Christian Manivong 0dcede037f fix(deps): pin paramiko>=5.0.0 (CVE-2026-44405) 2026-07-02 12:22:55 +02:00
Christian Manivong 348a62927e fix(get_config): use netmiko hp_procurve on port 22
HP ProCurve needs invoke_shell (not exec_channel) — exec_command via
paramiko returns 'SSH command execution is not supported'. Netmiko's
hp_procurve device type handles this correctly. Port 22 explicit.
2026-06-29 15:51:32 +02:00
Christian Manivong 6e2ac6bd94 fix(get_config): back to paramiko with port 22 — no subprocess needed
Root cause was self.port=443 (REST API port) being used for SSH.
With port 22 paramiko works fine — same as the SSH console link.
2026-06-29 15:44:33 +02:00
Christian Manivong 2bb84aca4f fix(get_config): use port 22 for SSH fallback — self.port is the REST API port
In API transport mode, self.port = 443 (HTTPS). All SSH attempts were
connecting to port 443 which speaks TLS, not SSH — hence 'banner exchange
timed out'. Fix: hardcode port 22 for the SSH config fallback.
2026-06-29 15:37:02 +02:00
Christian Manivong a7ecc6427c fix(get_config): use openssh+sshpass subprocess — bypasses paramiko Mocana compat issue
paramiko 4.x is incompatible with Mocana SSH 6.3 on HP 2530/YA firmware.
OpenSSH subprocess with +diffie-hellman-group1-sha1 kex works correctly
and connects in < 5s instead of hitting the 15s banner timeout.
2026-06-29 15:13:40 +02:00
Christian Manivong fe8df73ad6 fix(get_config): close REST session before SSH fallback
HP ProCurve switches allow only 1 session per user. The REST API session
blocks SSH — closing it before the SSH attempt allows the connection.
_collect_config() is called last so all poll data is already collected.
2026-06-29 15:05:34 +02:00
Christian Manivong a496f02aa9 fix(get_config): use SSHClient.connect() without algorithm overrides
The SSH console link works on this switch using plain paramiko
SSHClient.connect() with no disabled_algorithms and no Transport hacks.
Our previous approaches (Transport._preferred_kex, socket-level timeout)
were breaking the negotiation. Revert to the simple approach that works.
2026-06-29 14:50:34 +02:00
Christian Manivong f7eff4b3ca fix(get_config): socket-level timeout for SSH fallback — covers KEX phase
paramiko banner_timeout/auth_timeout do not cover kex negotiation.
Using raw socket with settimeout(8) ensures the entire SSH handshake
is bounded, preventing the poll from hanging and timing out.
2026-06-29 14:28:21 +02:00
Christian Manivong 831727f2af fix(get_config): use paramiko directly with group1-sha1 for Mocana SSH 6.3
- Replace netmiko with direct paramiko connection for SSH config fallback
- Explicitly set preferred_kex to include diffie-hellman-group1-sha1
  (required by old Mocana SSH 6.3 on HP 2530 / YA firmware)
- Hard timeout caps: banner_timeout=auth_timeout=8s, no keys/agent
2026-06-29 13:53:09 +02:00
Christian Manivong 8a182c4fa4 fix(get_config): cap SSH fallback timeout at 8s to prevent poll timeout
Each SSH attempt was using driver timeout (30s). With 2 attempts that
consumed the entire poll budget → device marked OFFLINE. Now capped at
8s per attempt (max 16s total), well within the 30s poll limit.
2026-06-29 13:42:05 +02:00
Christian Manivong 0d53426636 fix(get_config): try legacy KEX first in SSH fallback for HP 2530/Mocana SSH 2026-06-29 12:54:39 +02:00
Christian Manivong 87db7b2873 fix(get_config): SSH fallback when REST API returns empty (HP 2530/YA firmware)
HP 2530 switches with YA firmware do not expose /rest/v7/running-config.
_get_config_via_ssh() opens a temporary netmiko session to run
'show running-config' as fallback when the API endpoint returns 404.
2026-06-29 12:36:09 +02:00
Christian Manivong 46aadbbe3b fix(get_config): use plain text GET for running/startup config
AOS-Switch returns the config body as text/plain, not JSON.
The previous get_config() called self.get() which calls resp.json(),
silently caught the JSONDecodeError, and returned ''. Now uses _get_text()
which reads resp.text directly.
2026-06-29 12:11:35 +02:00
Christian Manivong d1db7a452d fix: falsche OUI-Prefixes entfernen (gegen IEEE verifiziert) 2026-06-24 17:06:45 +02:00
Christian ManivongandClaude Sonnet 4.6 ef5e453f5d feat: OUI_PREFIXES für MAC/ARP-Fingerprinting
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:41:45 +02:00
Christian ManivongandClaude Sonnet 4.6 247964178a feat: Fingerprint-Attribute für Discovery-Scoring
Ergänzt DRIVER_NAME, HTTP_FINGERPRINT, SNMP_FINGERPRINT, SSH_FINGERPRINT,
PORT_SPECS und SNMP_OBJECT_ID_PREFIX gemäß docs/DISCOVERY_FINGERPRINTING.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 14:47:08 +02:00
Christian ManivongandClaude Sonnet 4.6 232936162e fix: try 'show system' as fallback for old ProCurve (no system-information)
Firmware J.15.x (2520G-8-PoE) only supports 'show system', not
'show system-information'. Adding it as the third fallback so serial
number and OS version can still be parsed via parse_system_info().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 23:46:58 +02:00
Christian ManivongandClaude Sonnet 4.6 55fe8b28f9 fix: search all lines for HP banner, not just first line
Old ProCurve show version starts with "Image stamp:" — the HP product
banner (e.g. "HP J9298A Switch 2520G-8-PoE") appears on a later line.
Scan all lines and use the first HP/HPE/Aruba banner found.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 23:40:44 +02:00
Christian ManivongandClaude Sonnet 4.6 ff37f3c59f fix: only parse HP/Aruba banner lines in parse_model_from_version
Guard against show version outputs that start with "Image stamp:" or
other non-banner lines — return ("", "") when the first line doesn't
begin with HP/HPE/Aruba.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 23:33:05 +02:00
Christian ManivongandClaude Sonnet 4.6 da5920a9bc fix: parse_model_from_version handles both HP banner orderings
Old switches show: "HP J9298A Switch 2520G-8-PoE" (model after Switch)
Newer switches:    "HP J9565A 2520G-8-PoE Switch" (model before Switch)

New approach: strip vendor prefix + J-code + "Switch" keyword, leaving
just the product name. Returns tuple (model, part_number).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 23:27:15 +02:00
Christian ManivongandClaude Sonnet 4.6 d2915f5829 fix: extract J-code part numbers in REST API get_facts() path
api_client.get_facts() now applies the same J-code extraction as the
CLI path: product_model "HP2530-8G Switch(J9777A)" → model="HP2530-8G
Switch", part_number="J9777A".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 23:10:07 +02:00
Christian ManivongandClaude Sonnet 4.6 2be268a65e fix: extract J-code part numbers from ProCurve model strings
parse_system_info() now extracts HPE/HP J-codes (e.g. J9298A, J9777A)
from the System Model field and returns them as part_number separately.
The model name is cleaned of the J-code and surrounding punctuation:

  "HP J9298A Switch 2520G-8-PoE" → model="HP 2520G-8-PoE Switch", pn="J9298A"
  "HP2530-8G Switch(J9777A)"     → model="HP2530-8G Switch",       pn="J9777A"

get_facts() includes part_number in the returned dict so NetOrk can
store it on Device.part_number and pass it to NetBox device types.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 22:57:33 +02:00
Christian ManivongandClaude Sonnet 4.6 f3f70cbf74 fix: normalize MAC address format in get_mac_address_table()
Raw MAC addresses from the ArubaOS-Switch API use a non-standard
format; normalize via napalm.base.helpers.mac() for consistency.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 17:17:23 +02:00
Christian ManivongandClaude Sonnet 4.6 576752da23 feat: synthesize LAG/trunk interfaces and support trunk member editing
get_interfaces() now fills in ports missing from the /ports collection
(e.g. the 4th SFP uplink on a 2530-48G) using system/status/switch, and
synthesizes a logical interface for each configured LAG/trunk group with
lag_members/lag_mode. New set_lag_members() adds/removes trunk members via
the REST /cli passthrough (PUT ports/{id} silently ignores trunk_group).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 14:47:00 +02:00
Christian Manivong ef544be540 feat: add PoE config and power-cycle support for ProCurve REST API
Adds get_poe_status()/set_poe() to expose per-port PoE configuration
(enable state, priority, allocation method, allocated power) and allow
toggling it via the AOS-Switch REST API.
2026-06-12 13:23:46 +02:00
Christian ManivongandClaude Sonnet 4.6 76a1939af9 fix: AOS-Switch REST API session cookie auth and VLAN PUT body
connect() never sent back the sessionId returned in the login response
body, so all writes (POST/PUT/DELETE) were silently rejected with
"Access is unauthorized" while reads worked fine. Also fix
_api_set_vlan to PUT the full VLAN object (AOS-Switch v3 rejects
partial PUT bodies with HTTP 400).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 01:38:02 +02:00
Christian ManivongandClaude Sonnet 4.6 22b83cf174 fix: avoid duplicate 'port' kwarg when netmiko_optional_args already contains it
Extracted _netmiko_kwargs() helper that strips port/timeout/disabled_algorithms
from netmiko_optional_args before spreading, so explicit values always win.
Used in both _try_ssh and _action_fix_snmp SSH fallback loop.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 23:47:33 +02:00
Christian ManivongandClaude Sonnet 4.6 0cab237b1d fix: fix_snmp SSH fallback when driver is connected via REST API
The REST API has no writable config endpoint for SNMP communities.
When _action_fix_snmp() is called on a REST-connected driver, it now
opens a temporary Netmiko SSH session (standard KEX, then legacy KEX
fallback), runs the config-mode CLI commands, and restores the REST
transport state on exit. SSH errors are surfaced verbatim instead of
being silently swallowed.

Also:
- _save_config: guard against REST transport (was calling self._device
  directly → NoneType AttributeError when transport == "api")
- _action_fix_snmp: extracted CLI logic into _action_fix_snmp_cli()
  so it is reused for both the SSH-fallback and native SSH/Telnet paths
- api_client: add get_snmp_communities() + configure_snmp_community()
  for future use; improve GET error logging (warn vs debug on non-404)
- _try_api: probe timeout capped at 15 s; SSL retry loop for
  self-signed certificates; improved log levels
- _api_set_interface / _cli_set_interface: handle enabled/description
  fields that were previously ignored
- probe(): broaden accepted status codes (301/302/303/403)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 23:12:32 +02:00
Christian ManivongandClaude Sonnet 4.6 aa55eb2bb9 feat: add get_health_metrics() via HP-MIB and IF-MIB
Implements SNMP health collection for ProCurve/Aruba switches using
HP-proprietary CPU/memory/uptime OIDs with IF-MIB interface counters.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:43:33 +02:00
Christian ManivongandClaude Sonnet 4.6 d7ed4fda1f fix: accept verify_ssl and verify aliases alongside ssl_verify
Mirrors the robust fallback pattern from napalm-opnsense so the driver
works regardless of which key name the caller passes in optional_args.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 22:41:27 +02:00
Christian ManivongandClaude Sonnet 4.6 5f780190c7 feat: SNMP support — get_snmp_config(), fix_snmp action, get_device_warnings()
get_snmp_config() uses single 'show snmp-server' command with read_timeout=10
to avoid blocking the poll. fix_snmp configures 'snmp-server community public
manager restricted'. get_device_warnings() added (was missing, caused AttributeError).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 13:09:51 +02:00
Christian Manivong e7d054ea2a fix: update repository URLs to chrismanivong account 2026-05-29 09:31:21 +02:00
Christian Manivong 35032fd034 initial commit 2026-05-29 09:30:53 +02:00