Add SNMP device discovery API
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.core.secrets import encrypt_secret
|
||||
from app.models import Credential
|
||||
from app.services.snmp import DiscoveredSnmpDevice, DiscoveredSnmpInterface, SnmpCredential, SnmpDiscoveryError
|
||||
|
||||
|
||||
def test_snmp_discovery_uses_profile_and_returns_friendly_results(client: TestClient, db_session, monkeypatch) -> None:
|
||||
profile = Credential(
|
||||
name="Core Switch",
|
||||
credential_type="snmp",
|
||||
encrypted_secret=encrypt_secret("private-community"),
|
||||
extra={"version": "2c", "port": 1161, "timeout_seconds": 4, "retries": 2},
|
||||
)
|
||||
db_session.add(profile)
|
||||
db_session.commit()
|
||||
calls: list[tuple[str, SnmpCredential]] = []
|
||||
|
||||
def fake_discover(host: str, credential: SnmpCredential) -> DiscoveredSnmpDevice:
|
||||
calls.append((host, credential))
|
||||
return DiscoveredSnmpDevice(
|
||||
host=host,
|
||||
device_name="core-sw-1",
|
||||
description="Core switch",
|
||||
uptime_seconds=12345,
|
||||
interfaces=[
|
||||
DiscoveredSnmpInterface(
|
||||
index=1,
|
||||
name="Gi1/0/1",
|
||||
description="Uplink",
|
||||
admin_status="up",
|
||||
oper_status="up",
|
||||
speed_bps=1_000_000_000,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr("app.api.discovery.discover_snmp_device", fake_discover)
|
||||
|
||||
response = client.post("/discovery/snmp", json={"host": "192.0.2.10", "credential_profile_id": profile.id})
|
||||
|
||||
assert response.status_code == 200
|
||||
assert calls == [
|
||||
(
|
||||
"192.0.2.10",
|
||||
SnmpCredential(community="private-community", port=1161, timeout_seconds=4, retries=2),
|
||||
)
|
||||
]
|
||||
body = response.json()
|
||||
assert body["host"] == "192.0.2.10"
|
||||
assert body["credential_profile_id"] == profile.id
|
||||
assert body["device_name"] == "core-sw-1"
|
||||
assert body["description"] == "Core switch"
|
||||
assert body["uptime_seconds"] == 12345
|
||||
assert body["interfaces"] == [
|
||||
{
|
||||
"index": 1,
|
||||
"name": "Gi1/0/1",
|
||||
"description": "Uplink",
|
||||
"admin_status": "up",
|
||||
"oper_status": "up",
|
||||
"speed_bps": 1_000_000_000,
|
||||
}
|
||||
]
|
||||
assert body["monitorable_items"] == [
|
||||
{
|
||||
"item_id": "device.uptime",
|
||||
"item_type": "device_uptime",
|
||||
"group": "Device Health",
|
||||
"label": "Device uptime",
|
||||
"unit": "seconds",
|
||||
},
|
||||
{
|
||||
"item_id": "interface.1.status",
|
||||
"item_type": "interface_status",
|
||||
"group": "Interface Gi1/0/1",
|
||||
"label": "Gi1/0/1 status",
|
||||
"unit": None,
|
||||
},
|
||||
{
|
||||
"item_id": "interface.1.traffic",
|
||||
"item_type": "interface_traffic",
|
||||
"group": "Interface Gi1/0/1",
|
||||
"label": "Gi1/0/1 traffic",
|
||||
"unit": "bps",
|
||||
},
|
||||
{
|
||||
"item_id": "interface.1.errors",
|
||||
"item_type": "interface_errors",
|
||||
"group": "Interface Gi1/0/1",
|
||||
"label": "Gi1/0/1 errors and discards",
|
||||
"unit": "count",
|
||||
},
|
||||
]
|
||||
assert "private-community" not in response.text
|
||||
assert "1.3.6" not in response.text
|
||||
|
||||
|
||||
def test_snmp_discovery_rejects_missing_profile(client: TestClient) -> None:
|
||||
response = client.post("/discovery/snmp", json={"host": "192.0.2.10", "credential_profile_id": 999})
|
||||
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_snmp_discovery_rejects_profile_without_secret(client: TestClient, db_session) -> None:
|
||||
profile = Credential(
|
||||
name="No Secret",
|
||||
credential_type="snmp",
|
||||
encrypted_secret=None,
|
||||
extra={"version": "2c"},
|
||||
)
|
||||
db_session.add(profile)
|
||||
db_session.commit()
|
||||
|
||||
response = client.post("/discovery/snmp", json={"host": "192.0.2.10", "credential_profile_id": profile.id})
|
||||
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_snmp_discovery_reports_probe_failure(client: TestClient, db_session, monkeypatch) -> None:
|
||||
profile = Credential(
|
||||
name="Core Switch",
|
||||
credential_type="snmp",
|
||||
encrypted_secret=encrypt_secret("private-community"),
|
||||
extra={"version": "2c"},
|
||||
)
|
||||
db_session.add(profile)
|
||||
db_session.commit()
|
||||
|
||||
def fake_discover(host: str, credential: SnmpCredential) -> DiscoveredSnmpDevice:
|
||||
raise SnmpDiscoveryError("timeout")
|
||||
|
||||
monkeypatch.setattr("app.api.discovery.discover_snmp_device", fake_discover)
|
||||
|
||||
response = client.post("/discovery/snmp", json={"host": "192.0.2.10", "credential_profile_id": profile.id})
|
||||
|
||||
assert response.status_code == 502
|
||||
assert "private-community" not in response.text
|
||||
Reference in New Issue
Block a user