This commit is contained in:
2026-03-23 17:35:41 +02:00
parent 26450a767b
commit 674f7c84f9

View File

@@ -2,7 +2,7 @@
"""
NATS Registration Listener (fox100 + NetBox hostname/action_next lookup + timing + problem counter)
-------------------------------------------------------------------------------------------
- One device GET (status + tags + custom_fields.action_next), no duplicate fetch
- One device GET (custom_fields.action_next), no duplicate fetch
- Keeps: nb_problems counter, timings, iface_id diagnostics, same formatting
- For fox100:
* If action_next is empty/absent -> print a simple stdout note and do nothing else
@@ -275,16 +275,16 @@ async def nb_problem(log_status, msg: str):
def nb_lookup_device_by_mac(mac: str, log_status) -> Tuple[
Optional[str], Optional[int], Optional[int], Optional[str], Optional[Set[str]], Optional[Any], Optional[Any], Optional[Any], Optional[Any], Optional[Any]
Optional[str], Optional[int], Optional[int], Optional[str], Optional[Any], Optional[Any], Optional[Any], Optional[Any], Optional[Any]
]:
"""
Resolve MAC -> (hostname, iface_id, device_id, device_status_value, tag_slugs_set, action_next, action_last, action_next_timestamp, action_state, sot_ts)
Resolve MAC -> (hostname, iface_id, device_id, action_next, action_last, action_next_timestamp, action_state, sot_ts)
- Logs problems for anomalies (mac not found, unassigned, wrong type, iface fetch fail).
- If device detail fetch fails, returns host/id with status/tags/custom_fields as None.
- If device detail fetch fails, returns host/id with custom_fields as None.
"""
mac_norm = normalize_mac(mac)
if not mac_norm:
return None, None, None, None, None, None, None, None, None, None
return None, None, None, None, None, None, None, None, None
# Step 0: short TTL cache (avoid repeated NetBox GETs for chatty devices)
if NB_LOOKUP_CACHE_TTL > 0:
@@ -293,13 +293,8 @@ def nb_lookup_device_by_mac(mac: str, log_status) -> Tuple[
if cached:
exp, val = cached
if exp > nowm:
host, iface_id, dev_id, status_val, tag_slugs, action_next, action_last, action_next_timestamp, action_state, sot_ts = val
if tag_slugs is not None:
try:
tag_slugs = set(tag_slugs)
except Exception:
pass
return host, iface_id, dev_id, status_val, tag_slugs, action_next, action_last, action_next_timestamp, action_state, sot_ts
host, iface_id, dev_id, action_next, action_last, action_next_timestamp, action_state, sot_ts = val
return host, iface_id, dev_id, action_next, action_last, action_next_timestamp, action_state, sot_ts
NB_LOOKUP_CACHE.pop(mac_norm, None)
base = NB_URL.rstrip("/")
@@ -319,12 +314,12 @@ def nb_lookup_device_by_mac(mac: str, log_status) -> Tuple[
data, code = http_get_json(f"{base}/api/dcim/mac-addresses/", params={"mac_address": mac_norm, "limit": "2"}, headers=h)
if code != 200 or not data:
asyncio.create_task(nb_problem(log_status, f"[{ts()}] nb: mac query http={code} mac={mac_norm}"))
return None, None, None, None, None, None, None, None, None, None
return None, None, None, None, None, None, None, None, None
results = (data or {}).get("results") or []
if not results:
asyncio.create_task(nb_problem(log_status, f"[{ts()}] nb: mac not found mac={mac_norm}"))
return None, None, None, None, None, None, None, None, None, None
return None, None, None, None, None, None, None, None, None
rec = results[0]
aot = (rec.get("assigned_object_type") or "").strip()
@@ -335,10 +330,10 @@ def nb_lookup_device_by_mac(mac: str, log_status) -> Tuple[
if not aot or aoid is None:
asyncio.create_task(nb_problem(log_status, f"[{ts()}] nb: mac unassigned mac={mac_norm}"))
return None, None, None, None, None, None, None, None, None, None
return None, None, None, None, None, None, None, None, None
if aot != "dcim.interface":
asyncio.create_task(nb_problem(log_status, f"[{ts()}] nb: mac assigned to {aot} mac={mac_norm} iface_id={aoid}"))
return None, aoid, None, None, None, None, None, None, None, None
return None, aoid, None, None, None, None, None, None, None
# Step 2: Interface -> Device (shallow)
iface, code2 = http_get_json(f"{base}/api/dcim/interfaces/{aoid}/", params={"fields": "device"}, headers=h)
@@ -346,30 +341,22 @@ def nb_lookup_device_by_mac(mac: str, log_status) -> Tuple[
iface, code2 = http_get_json(f"{base}/api/dcim/interfaces/{aoid}/", headers=h)
if code2 != 200 or not iface:
asyncio.create_task(nb_problem(log_status, f"[{ts()}] nb: iface fetch http={code2} iface_id={aoid}"))
return None, aoid, None, None, None, None, None, None, None, None
return None, aoid, None, None, None, None, None, None, None
dev = iface.get("device") or {}
host = dev.get("name") or dev.get("display")
dev_id = dev.get("id")
if not host or dev_id is None:
asyncio.create_task(nb_problem(log_status, f"[{ts()}] nb: iface has no device iface_id={aoid}"))
return None, aoid, None, None, None, None, None, None, None, None
return None, aoid, None, None, None, None, None, None, None
# Step 3: Device detail (single fetch for status, tags, custom_fields.*)
device, code3 = http_get_json(f"{base}/api/dcim/devices/{dev_id}/", params={"fields": "status,tags,custom_fields"}, headers=h)
# Step 3: Device detail (single fetch for custom_fields.*)
device, code3 = http_get_json(f"{base}/api/dcim/devices/{dev_id}/", params={"fields": "custom_fields"}, headers=h)
if code3 == 400:
device, code3 = http_get_json(f"{base}/api/dcim/devices/{dev_id}/", headers=h)
if code3 != 200 or not device:
# treat as "no extra info"
return host, aoid, dev_id, None, None, None, None, None, None, None
status_val = ((device.get("status") or {}).get("value")) or None
tags = device.get("tags") or []
tag_slugs = set()
for t in tags:
slug = t.get("slug")
if isinstance(slug, str):
tag_slugs.add(slug)
return host, aoid, dev_id, None, None, None, None, None, None
cf = device.get("custom_fields") or {}
action_next = cf.get("action_next")
@@ -387,8 +374,6 @@ def nb_lookup_device_by_mac(mac: str, log_status) -> Tuple[
host,
aoid,
dev_id,
(status_val if isinstance(status_val, str) else None),
(tuple(tag_slugs) if tag_slugs is not None else None),
action_next,
action_last,
action_next_timestamp,
@@ -399,7 +384,7 @@ def nb_lookup_device_by_mac(mac: str, log_status) -> Tuple[
except Exception:
pass
return host, aoid, dev_id, (status_val if isinstance(status_val, str) else None), tag_slugs, action_next, action_last, action_next_timestamp, action_state, sot_ts
return host, aoid, dev_id, action_next, action_last, action_next_timestamp, action_state, sot_ts
# =========================
@@ -538,7 +523,7 @@ async def main():
if product == "fox100":
nb_start = time.perf_counter()
try:
host, iface_id, dev_id, status_val, tag_slugs, action_next, action_last, action_next_timestamp, action_state, sot_ts = nb_lookup_device_by_mac(
host, iface_id, dev_id, action_next, action_last, action_next_timestamp, action_state, sot_ts = nb_lookup_device_by_mac(
mac=mac, log_status=log_status
)
event["iface_id"] = iface_id