An `amt` driver (napalm_amt.AmtDriver), a ManagementControllerDriver for the management controller of Intel vPro machines, with its own lean WS-Management client (requests + ElementTree, HTTP Digest, ports 16992/16993). It reads the machine's identity, hardware with the SMBIOS system UUID, firmware (AMT with build, BIOS), power state and the hardware event log, reports what AMT listens on (plain HTTP or TLS, KVM incl. port 5900, IDE-R), and switches the machine's power. AMT cannot be reset over WS-Management, so there is no reboot_host. Discovery recognises AMT by its ports and its Server header. Tested against Intel's published AMT 12 recordings (go-wsman-messages, Apache-2.0, see NOTICE). `python -m napalm_amt.record` records a real AMT read-only; the first test devices are two Lenovo ThinkCentre M910x.
76 lines
2.1 KiB
Python
76 lines
2.1 KiB
Python
"""AMT's hardware event log (AMT_MessageLog records), from the recorded NUC9."""
|
|
|
|
import base64
|
|
|
|
import pytest
|
|
|
|
from napalm_amt.parsers import parse_event_record
|
|
|
|
from ..conftest import instances
|
|
|
|
|
|
def _records():
|
|
(out,) = instances("AMT_MessageLog.GetRecords.xml")
|
|
return out["RecordArray"]
|
|
|
|
|
|
def test_failed_logins_are_critical():
|
|
entry = parse_event_record(_records()[0], "1")
|
|
assert entry == {
|
|
"id": "1",
|
|
"timestamp": 1704511587.0,
|
|
"severity": "Critical",
|
|
"message": "Intel(r) ME: Authentication failed 10 times. The system may be under attack.",
|
|
}
|
|
|
|
|
|
def test_bios_progress_is_ok():
|
|
entry = parse_event_record(_records()[1], "2")
|
|
assert entry["severity"] == "OK"
|
|
assert entry["message"] == "BIOS: PCI resource configuration"
|
|
assert entry["timestamp"] == 1694565922.0
|
|
|
|
|
|
def _record(sensor_type, offset, severity, entity, data=(0,) * 8, timestamp=1700000000):
|
|
raw = (
|
|
timestamp.to_bytes(4, "little")
|
|
+ bytes([0xFF, sensor_type, 0x6F, offset, 0x68, severity, 0xFF, entity, 0])
|
|
+ bytes(data)
|
|
)
|
|
return base64.b64encode(raw).decode()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("severity", "expected"),
|
|
[
|
|
(0, "OK"),
|
|
(1, "OK"),
|
|
(2, "OK"),
|
|
(4, "OK"),
|
|
(8, "Warning"),
|
|
(16, "Critical"),
|
|
(32, "Critical"),
|
|
],
|
|
)
|
|
def test_severity(severity, expected):
|
|
assert parse_event_record(_record(37, 0, severity, 34), "1")["severity"] == expected
|
|
|
|
|
|
def test_firmware_error():
|
|
entry = parse_event_record(_record(15, 0, 16, 34, (0, 1, 0, 0, 0, 0, 0, 0)), "1")
|
|
assert entry["message"] == ("BIOS: No system memory is physically installed in the system.")
|
|
|
|
|
|
def test_unknown_sensor_type_is_named():
|
|
entry = parse_event_record(_record(200, 0, 2, 2), "1")
|
|
assert entry["message"] == "Unknown: sensor type 200"
|
|
|
|
|
|
def test_no_timestamp_is_none():
|
|
assert parse_event_record(_record(30, 0, 16, 34, timestamp=0), "1")["timestamp"] is None
|
|
|
|
|
|
def test_a_short_or_broken_record_is_skipped():
|
|
assert parse_event_record("AAAA", "1") is None
|
|
assert parse_event_record("not base64!", "1") is None
|