feat: alternative fingerprint rules count once (4.8.0)
CI / test (3.10) (push) Successful in 28s
CI / test (3.11) (push) Successful in 25s
CI / test (3.12) (push) Successful in 27s
CI / test (3.13) (push) Successful in 26s

Discovery compares drivers by score divided by the most a driver could
score, and that maximum summed every positive rule. Rules that never
match together, such as one vendor's landing page or another's, made a
driver that knows several vendors lose to one that knows none:
napalm-redfish's Supermicro landing page scored 6 of 41 and lost to a
bare "linux" in the same BMC's SNMP sysDescr, 5 of 18.

FingerprintRule gets an optional group. rules_max_weight() sums the
positive rules and counts each group once, with its strongest rule.
Existing rules have no group and count as before.
This commit is contained in:
christianmanivong committed 2026-10-13 10:19:54 +02:00
1 parent 7afa590c0c
commit a1da0337e2
5 files changed
+97 -2

No files matched your search

+48
View File
@@ -8,6 +8,7 @@ from napalm_device_types import (
DeviceTypeDriver,
FingerprintRule,
FirewallDriver,
rules_max_weight,
HypervisorDriver,
OSDriver,
PortSpec,
@@ -90,6 +91,53 @@ def test_fingerprint_rule_negative():
assert r.negative is True
def test_fingerprint_rule_has_no_group_by_default():
assert FingerprintRule("fritz!box").group is None
def test_fingerprint_rule_group():
r = FingerprintRule("idrac", weight=6.0, group="landing_page")
assert r.group == "landing_page"
# ── rules_max_weight: the most a set of rules can add ─────────────────────────
def test_max_weight_sums_rules_that_can_match_together():
rules = [FingerprintRule("proxmox virtual environment", 9.0), FingerprintRule("pve", 2.0)]
assert rules_max_weight(rules) == 11.0
def test_max_weight_counts_one_rule_per_group():
# Alternatives: a page is ATEN's or iDRAC's or iLO's, never all three. Summing
# them made a driver that knows three BMC families lose to one that knows none.
rules = [
FingerprintRule("aten international", 6.0, group="landing_page"),
FingerprintRule("idrac", 6.0, group="landing_page"),
FingerprintRule("integrated lights-out", 4.0, group="landing_page"),
]
assert rules_max_weight(rules) == 6.0
def test_max_weight_mixes_groups_and_single_rules():
rules = [
FingerprintRule("redfishversion", 10.0, group="redfish_answer"),
FingerprintRule("@message.extendedinfo", 8.0, group="redfish_answer"),
FingerprintRule("#serviceroot.", 5.0),
FingerprintRule("aten international", 6.0, group="landing_page"),
FingerprintRule("idrac", 6.0, group="landing_page"),
]
assert rules_max_weight(rules) == 21.0
def test_max_weight_ignores_negative_rules():
rules = [FingerprintRule("vcenter", 9.0), FingerprintRule("vmware esxi", 9.0, negative=True)]
assert rules_max_weight(rules) == 9.0
def test_max_weight_of_no_rules_is_zero():
assert rules_max_weight([]) == 0.0
def test_fingerprint_rule_is_immutable():
r = FingerprintRule("test", weight=3.0)
with pytest.raises(AttributeError):