Pure functions for ServiceRoot, ComputerSystem (facts, power state, reset action and ActionInfo), Processors, Memory, Storage/Drives/SimpleStorage, Chassis Thermal and Power as well as ThermalSubsystem/PowerSubsystem/Sensors (with environment_sources to pick whichever exists), Manager, EthernetInterfaces, ManagerNetworkProtocol, accounts, firmware inventory and log services/entries.
176 lines
5.8 KiB
Python
176 lines
5.8 KiB
Python
from napalm_redfish.parsers import (
|
|
parse_drive,
|
|
parse_memory,
|
|
parse_processor,
|
|
parse_simple_storage,
|
|
parse_storage,
|
|
)
|
|
|
|
SYSTEM = "/redfish/v1/Systems/437XR1138R2"
|
|
|
|
|
|
# --- Processors ----------------------------------------------------------------------------
|
|
|
|
|
|
def test_processor(rackmount):
|
|
cpu = parse_processor(rackmount(SYSTEM + "/Processors/CPU1"))
|
|
assert cpu == {
|
|
"id": "CPU1",
|
|
"name": "Processor",
|
|
"socket": "CPU 1",
|
|
"processor_type": "CPU",
|
|
"manufacturer": "Intel(R) Corporation",
|
|
"model": "Multi-Core Intel(R) Xeon(R) processor 7xxx Series",
|
|
"architecture": "x86",
|
|
"instruction_set": "x86-64",
|
|
"max_speed_mhz": 3700,
|
|
"cores": 8,
|
|
"threads": 16,
|
|
"serial_number": None,
|
|
"present": True,
|
|
"state": "Enabled",
|
|
# The CPU itself is OK; its HealthRollup (temperature warning) is not its health.
|
|
"health": "OK",
|
|
}
|
|
|
|
|
|
def test_processor_absent(rackmount):
|
|
cpu = parse_processor(rackmount(SYSTEM + "/Processors/CPU2"))
|
|
assert cpu["present"] is False
|
|
assert cpu["state"] == "Absent"
|
|
assert cpu["health"] is None
|
|
assert cpu["socket"] == "CPU 2"
|
|
assert cpu["model"] is None
|
|
assert cpu["cores"] is None
|
|
|
|
|
|
def test_processor_fpga(rackmount):
|
|
fpga = parse_processor(rackmount(SYSTEM + "/Processors/FPGA1"))
|
|
assert fpga["processor_type"] == "FPGA"
|
|
assert fpga["model"] == "Stratix 10"
|
|
# No Socket property: the location label stands in.
|
|
assert fpga["socket"] == "U168"
|
|
|
|
|
|
# --- Memory --------------------------------------------------------------------------------
|
|
|
|
|
|
def test_memory(rackmount):
|
|
dimm = parse_memory(rackmount(SYSTEM + "/Memory/DIMM1"))
|
|
assert dimm == {
|
|
"id": "DIMM1",
|
|
"name": "DIMM Slot 1",
|
|
"location": "DIMM 1",
|
|
"capacity_mib": 32768,
|
|
"memory_device_type": "DDR4",
|
|
"base_module_type": "RDIMM",
|
|
"speed_mhz": None,
|
|
"manufacturer": None,
|
|
"part_number": None,
|
|
"serial_number": None,
|
|
"present": True,
|
|
"state": "Enabled",
|
|
"health": "OK",
|
|
}
|
|
|
|
|
|
def test_memory_absent(rackmount):
|
|
dimm = parse_memory(rackmount(SYSTEM + "/Memory/DIMM4"))
|
|
assert dimm["present"] is False
|
|
assert dimm["capacity_mib"] is None
|
|
assert dimm["location"] == "DIMM 4"
|
|
|
|
|
|
def test_memory_older_schema():
|
|
# Memory 1.0-1.x: DeviceLocator instead of Location, speed in OperatingSpeedMhz.
|
|
dimm = parse_memory({
|
|
"Id": "1", "Name": "Memory 1", "DeviceLocator": "P1-DIMMA1", "CapacityMiB": 16384,
|
|
"OperatingSpeedMhz": 2133, "Manufacturer": "Samsung ", "PartNumber": "M393A2G40DB0-CPB",
|
|
"SerialNumber": "12345678", "MemoryDeviceType": "DDR4",
|
|
"Status": {"State": "Enabled", "Health": "OK"},
|
|
})
|
|
assert dimm["location"] == "P1-DIMMA1"
|
|
assert dimm["speed_mhz"] == 2133
|
|
assert dimm["manufacturer"] == "Samsung"
|
|
assert dimm["serial_number"] == "12345678"
|
|
|
|
|
|
def test_memory_zero_capacity_is_empty_slot():
|
|
# Some BMCs list empty slots as enabled with a capacity of 0.
|
|
dimm = parse_memory({"Id": "DIMM9", "CapacityMiB": 0, "Status": {"State": "Enabled"}})
|
|
assert dimm["present"] is False
|
|
|
|
|
|
# --- Storage -------------------------------------------------------------------------------
|
|
|
|
|
|
def test_storage(localstorage):
|
|
st = parse_storage(localstorage(SYSTEM + "/Storage/1"))
|
|
assert st["id"] == "1"
|
|
assert st["name"] == "Local Storage Controller"
|
|
assert st["state"] == "Enabled"
|
|
assert st["health"] == "OK"
|
|
assert st["controllers"] == [{
|
|
"name": "Contoso Integrated RAID",
|
|
"manufacturer": "Contoso",
|
|
"model": "12Gbs Integrated RAID",
|
|
"serial_number": "2M220100SL",
|
|
"firmware_version": "1.0.0.7",
|
|
"speed_gbps": 12,
|
|
"state": "Enabled",
|
|
"health": "OK",
|
|
}]
|
|
assert st["drive_paths"] == [
|
|
"/redfish/v1/Chassis/1U/Drives/35D38F11ACEF7BD3",
|
|
"/redfish/v1/Chassis/1U/Drives/3F5A8C54207B7233",
|
|
"/redfish/v1/Chassis/1U/Drives/32ADF365C6C1B7BD",
|
|
"/redfish/v1/Chassis/1U/Drives/3D58ECBC375FD9F2",
|
|
]
|
|
assert st["controllers_path"] is None
|
|
|
|
|
|
def test_storage_with_controller_collection():
|
|
# Storage 1.15 and later link a StorageController collection instead of an array.
|
|
st = parse_storage({"Id": "RAID", "Controllers": {"@odata.id": "/redfish/v1/x/Controllers"}})
|
|
assert st["controllers"] == []
|
|
assert st["controllers_path"] == "/redfish/v1/x/Controllers"
|
|
assert st["drive_paths"] == []
|
|
|
|
|
|
def test_drive(localstorage):
|
|
drive = parse_drive(localstorage("/redfish/v1/Chassis/1U/Drives/35D38F11ACEF7BD3"))
|
|
assert drive == {
|
|
"id": "35D38F11ACEF7BD3",
|
|
"name": "Drive Sample",
|
|
"manufacturer": "Contoso",
|
|
"model": "C123",
|
|
"serial_number": "1234567",
|
|
"part_number": "C123-1111",
|
|
"revision": "100A",
|
|
"capacity_bytes": 899527000064,
|
|
"media_type": "HDD",
|
|
"protocol": "SAS",
|
|
"failure_predicted": False,
|
|
"present": True,
|
|
"state": "Enabled",
|
|
"health": "OK",
|
|
}
|
|
|
|
|
|
def test_simple_storage(rackmount):
|
|
st = parse_simple_storage(rackmount(SYSTEM + "/SimpleStorage/1"))
|
|
assert st["id"] == "1"
|
|
assert st["name"] == "Simple Storage Controller"
|
|
assert st["health"] == "OK"
|
|
assert [d["name"] for d in st["drives"]] == [
|
|
"SATA Bay 1", "SATA Bay 2", "SATA Bay 3", "SATA Bay 4"]
|
|
bay1, bay2, bay3, _ = st["drives"]
|
|
assert bay1["model"] == "3000GT8"
|
|
assert bay1["capacity_bytes"] == 8000000000000
|
|
assert bay1["present"] is True
|
|
assert bay2["health"] == "Warning"
|
|
assert bay3["present"] is False
|
|
assert bay3["model"] is None
|
|
# Same keys as parse_drive, so callers can treat both alike.
|
|
assert set(bay1) == set(parse_drive({}))
|