Mechanical: ruff format, and ruff check --fix with the rule set every NAPALM driver uses (E, F, I, UP, B at line length 100, Python 3.10). Mapping and Iterable come from collections.abc, imports are sorted. What ruff cannot fix comes in the next commit.
109 lines
3.6 KiB
Python
109 lines
3.6 KiB
Python
"""RedfishDriver against a recording of a real Supermicro X10DRL-i (BMC 3.91, Redfish 1.0.1).
|
|
|
|
Recorded 2026-10-17 with an SFT-OOB-LIC license only: the service root and most resources
|
|
answer, but ``Systems/1/Storage`` and ``UpdateService`` want the DCMS license as well (403,
|
|
``OemLicenseNotPassed``). Serial numbers, UUIDs, MACs, addresses, the host name and the SNMP
|
|
communities are scrubbed. ``STATUS.json`` lists the paths that did not answer 200; their
|
|
files hold the error body the BMC sent.
|
|
"""
|
|
|
|
import json
|
|
|
|
import pytest
|
|
from napalm_device_types import models
|
|
|
|
from napalm_redfish import RedfishDriver
|
|
from tests.conftest import BASE_URL, FIXTURES, MockupServer
|
|
|
|
MOCKUP = "supermicro-x10drl-i-3.91/redfish"
|
|
REFUSED = json.loads((FIXTURES / MOCKUP / "STATUS.json").read_text())
|
|
|
|
|
|
@pytest.fixture
|
|
def x10(http):
|
|
server = MockupServer(http, MOCKUP)
|
|
for path, status in REFUSED.items():
|
|
body = json.loads(
|
|
(FIXTURES / MOCKUP / path[len("/redfish/v1/") :] / "index.json").read_text()
|
|
)
|
|
server.override("GET", path, status, body)
|
|
return server
|
|
|
|
|
|
@pytest.fixture
|
|
def driver(x10):
|
|
d = RedfishDriver(
|
|
BASE_URL.removeprefix("https://"), "netork", "secret", optional_args={"verify_ssl": False}
|
|
)
|
|
d.open()
|
|
yield d
|
|
d.close()
|
|
|
|
|
|
def test_the_facts_name_the_board_not_super_server(driver):
|
|
facts = driver.get_facts()
|
|
assert facts["vendor"] == "Supermicro"
|
|
# Systems/1 says "Super Server"; the board is its PartNumber and the chassis model.
|
|
assert facts["model"] == "X10DRL-i"
|
|
assert facts["os_version"] == "3.91"
|
|
assert facts["serial_number"] == "ZM000S000001"
|
|
|
|
|
|
def test_the_inventory_survives_the_storage_it_may_not_read(driver):
|
|
inv = driver.get_hardware_inventory()
|
|
assert set(inv) == set(models.HardwareInventoryDict.__annotations__)
|
|
assert inv["model"] == "X10DRL-i"
|
|
assert inv["system_uuid"] == "00000000-0000-0000-0000-00005e00534c"
|
|
assert len(inv["cpus"]) == 2
|
|
assert len(inv["memory"]) == 8
|
|
assert inv["drives"] == []
|
|
|
|
|
|
def test_the_firmware_comes_from_the_manager_and_the_system_without_updateservice(driver):
|
|
assert driver.get_firmware_inventory() == [
|
|
{"name": "BMC", "version": "3.91", "updateable": None},
|
|
{"name": "BIOS", "version": "3.1c", "updateable": None},
|
|
]
|
|
|
|
|
|
def test_the_missing_license_is_named_with_what_it_withholds(driver):
|
|
assert driver.get_device_warnings() == [
|
|
{
|
|
"code": "bmc_license_partial",
|
|
"meta": {"licenses": "DCMS", "parts": ["drives", "firmware inventory"]},
|
|
}
|
|
]
|
|
|
|
|
|
def test_the_power_actions_are_the_ones_the_bmc_advertises(driver):
|
|
assert driver.get_power_state() == {
|
|
"state": "On",
|
|
"actions": ["GracefulShutdown", "ForceOff", "GracefulRestart", "ForceRestart"],
|
|
}
|
|
|
|
|
|
def test_the_protocols_report_ipmi_over_lan_on(driver):
|
|
protocols = driver.get_management_protocols()
|
|
assert protocols["ipmi"] == {"enabled": True, "port": 623}
|
|
assert protocols["https"] == {"enabled": True, "port": 443}
|
|
|
|
|
|
def test_the_sensors_and_the_event_log_read(driver):
|
|
env = driver.get_environment()
|
|
assert len(env["temperature"]) == 19
|
|
assert len(env["fans"]) == 4
|
|
assert isinstance(driver.get_event_log(limit=5), list)
|
|
|
|
|
|
# ── licenses as facts (#1111) ───────────────────────────────────────────
|
|
|
|
|
|
def test_the_missing_license_is_a_fact_with_what_it_withholds(driver):
|
|
assert driver.get_licenses() == [
|
|
{
|
|
"name": "DCMS",
|
|
"status": "missing",
|
|
"withholds": ["drives", "firmware inventory"],
|
|
}
|
|
]
|