Files
christianmanivong 0052ba7884 feat: Intel AMT driver over WS-Management (0.1.0)
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.
2026-10-18 14:55:32 +02:00

98 lines
3.5 KiB
Python

"""What AMT listens on: plain HTTP or TLS, the KVM console and IDE/USB redirection."""
import pytest
from napalm_amt.parsers import parse_management_protocols
from ..conftest import instances
def _protocols(**overrides):
args = {
"tls_settings": instances("AMT_TLSSettingData.pull.xml"),
"redirection": instances("AMT_RedirectionService.get.xml")[0],
"kvm_settings": instances("IPS_KVMRedirectionSettingData.get.xml")[0],
"kvm_saps": instances("CIM_KVMRedirectionSAP.pull.xml"),
}
args.update(overrides)
return parse_management_protocols(**args)
def test_amt_without_tls_listens_on_plain_http():
assert _protocols() == {
"ipmi": {"enabled": False, "port": 623},
"ssh": {"enabled": False, "port": 22},
"http": {"enabled": True, "port": 16992},
"https": {"enabled": False, "port": 16993},
"snmp": {"enabled": False, "port": 161},
# KVM is enabled (MEBx), offline until someone connects; over the redirection
# port, as the standard VNC port 5900 is off.
"kvm": {"enabled": True, "port": 16994},
# IDE-R/USB-R and SOL are both on (EnabledState 32771).
"virtual_media": {"enabled": True, "port": 16994},
}
def test_amt_with_tls_listens_on_16993_and_redirects_over_tls():
tls = [
{
"InstanceID": "Intel(r) AMT 802.3 TLS Settings",
"Enabled": "true",
"AcceptNonSecureConnections": "false",
}
]
protocols = _protocols(tls_settings=tls)
assert protocols["https"] == {"enabled": True, "port": 16993}
assert protocols["http"] == {"enabled": False, "port": 16992}
assert protocols["kvm"]["port"] == 16995
assert protocols["virtual_media"]["port"] == 16995
def test_tls_that_still_accepts_plain_connections_keeps_http_open():
tls = [
{
"InstanceID": "Intel(r) AMT 802.3 TLS Settings",
"Enabled": "true",
"AcceptNonSecureConnections": "true",
}
]
assert _protocols(tls_settings=tls)["http"]["enabled"] is True
def test_the_lms_tls_setting_is_local_and_ignored():
tls = [{"InstanceID": "Intel(r) AMT LMS TLS Settings", "Enabled": "true"}]
assert _protocols(tls_settings=tls)["https"]["enabled"] is False
def test_kvm_on_the_standard_vnc_port():
kvm = {**instances("IPS_KVMRedirectionSettingData.get.xml")[0], "Is5900PortEnabled": "true"}
assert _protocols(kvm_settings=kvm)["kvm"] == {"enabled": True, "port": 5900}
@pytest.mark.parametrize("sap_state", ["3", "4"])
def test_kvm_disabled(sap_state):
saps = [{"EnabledState": sap_state}]
assert _protocols(kvm_saps=saps)["kvm"]["enabled"] is False
def test_kvm_disabled_in_mebx():
kvm = {**instances("IPS_KVMRedirectionSettingData.get.xml")[0], "EnabledByMEBx": "false"}
assert _protocols(kvm_settings=kvm)["kvm"]["enabled"] is False
def test_kvm_unknown_without_any_data():
assert _protocols(kvm_settings={}, kvm_saps=[])["kvm"]["enabled"] is False
@pytest.mark.parametrize(
("state", "enabled"),
[("32768", False), ("32769", True), ("32770", False), ("32771", True), ("", False)],
)
def test_virtual_media_is_ide_redirection(state, enabled):
assert _protocols(redirection={"EnabledState": state})["virtual_media"]["enabled"] is enabled
def test_redirection_listener_off_closes_virtual_media():
redirection = {"EnabledState": "32771", "ListenerEnabled": "false"}
assert _protocols(redirection=redirection)["virtual_media"]["enabled"] is False