kb-audit: fix парсер — ловит table-rows и раздел 🗑️ удалённых

This commit is contained in:
dttb
2026-04-18 00:24:20 +03:00
parent 6368738ade
commit c8cf27df08

View File

@@ -53,20 +53,38 @@ def parse_live():
def parse_inventory(path: Path):
"""Парсит inventory-файл. Извлекает упомянутые VMID + связанный контекст."""
"""Парсит inventory-файл. Извлекает упомянутые VMID + связанный контекст.
Ловит два формата:
1. "LXC 132" / "VM 250" — в заголовках и тексте
2. Table rows: | 132 | debian | ... | — в таблицах
"""
text = path.read_text()
found = {}
# Ищем все упоминания "LXC NNN" или "VM NNN" в заголовках и таблицах
for m in re.finditer(r"(?:LXC|VM)\s+(\d{2,4})\b", text):
vmid = m.group(1)
def add(vmid: str, idx: int):
if vmid not in found:
# контекст: 80 символов вокруг
start = max(0, m.start() - 20)
end = min(len(text), m.end() + 60)
start = max(0, idx - 20)
end = min(len(text), idx + 80)
found[vmid] = text[start:end].replace("\n", " ").strip()
for m in re.finditer(r"(?:LXC|VM)\s+(\d{2,4})\b", text):
add(m.group(1), m.start())
# table rows: строка начинается с `| NNN |` (игнорируем header-row с тире)
for m in re.finditer(r"^\s*\|\s*(\d{2,4})\s*\|", text, re.MULTILINE):
add(m.group(1), m.start())
return found
def find_deleted_section(path: Path) -> set:
"""Ищет VMID в секции '## 🗑️ Удалённые' чтобы не флагать их как missing."""
text = path.read_text()
# блок между '🗑️ Удалённые' и следующим '##'
m = re.search(r"##\s*🗑[^\n]*Удал[^\n]*\n(.*?)(?=\n##|\Z)", text, re.DOTALL)
if not m:
return set()
return set(re.findall(r"\|\s*(\d{2,4})\s*\|", m.group(1)))
def compare(live: dict, inventory: dict):
live_ids = set(live.keys())
inv_ids = set(inventory.keys())
@@ -84,7 +102,13 @@ def main():
live = parse_live()
inventory = parse_inventory(INVENTORY)
only_live, only_inv, common = compare(live, inventory)
deleted = find_deleted_section(INVENTORY)
only_live, only_inv_raw, common = compare(live, inventory)
# разделяем "в inventory но не в live" на 2 группы:
# - known-deleted (есть в секции "🗑️ Удалённые") — это ок
# - truly missing (нет и в live, и не в секции deleted) — проблема
only_inv = [v for v in only_inv_raw if v not in deleted]
known_deleted = [v for v in only_inv_raw if v in deleted]
lines = [
"---",
@@ -100,7 +124,8 @@ def main():
"",
f"- Живых гостей Proxmox: **{len(live)}**",
f"- Упомянуто в inventory: **{len(inventory)}**",
f"- В обоих: {len(common)} / только в live: {len(only_live)} / только в inventory: {len(only_inv)}",
f"- В обоих: {len(common)} / только в live: {len(only_live)} / отсутствуют в live: {len(only_inv)}",
f"- Известны как удалённые: {len(known_deleted)} (в `## 🗑️ Удалённые`)",
"",
]
@@ -113,13 +138,16 @@ def main():
lines += [""]
if only_inv:
lines += ["## 🗑 В inventory есть, в Proxmox НЕТ (удалён? переименован?)", ""]
lines += ["## В inventory есть, в Proxmox НЕТ (не в секции 🗑️ — проверить вручную)", ""]
lines += ["| VMID | Контекст из inventory |", "|---|---|"]
for vmid in only_inv:
ctx = inventory[vmid][:100]
lines += [f"| {vmid} | `...{ctx}...` |"]
lines += [""]
if known_deleted:
lines += [f"## ✓ Удалённые хосты (задокументированы): {', '.join(sorted(known_deleted, key=int))}", ""]
if not only_live and not only_inv:
lines += ["## ✓ Inventory полностью совпадает с живой инфраструктурой", ""]