Files
ipwatch/backend/app/scripts/rebuild_ip_relations.py
2026-02-07 16:57:37 +01:00

119 lines
3.7 KiB
Python

"""
Reconstruit ip_parent depuis config.yaml, puis recalcule ip_enfant depuis ip_parent.
"""
from __future__ import annotations
import json
import sqlite3
from pathlib import Path
from typing import Any, Dict, List, Optional
import yaml
CONFIG_PATH = Path(__file__).resolve().parents[3] / "config.yaml"
def load_config() -> Dict[str, Any]:
with CONFIG_PATH.open("r", encoding="utf-8") as handle:
return yaml.safe_load(handle) or {}
def normalize_children(value: Any) -> Optional[List[str]]:
if value is None:
return None
if isinstance(value, str):
return [value] if value else []
if isinstance(value, list):
return [str(item) for item in value if item]
return []
def ensure_columns(conn: sqlite3.Connection) -> None:
cursor = conn.execute("PRAGMA table_info(ip)")
columns = {row[1] for row in cursor.fetchall()}
if "ip_parent" not in columns:
conn.execute("ALTER TABLE ip ADD COLUMN ip_parent TEXT")
if "ip_enfant" not in columns:
conn.execute("ALTER TABLE ip ADD COLUMN ip_enfant TEXT")
conn.commit()
def collect_parent_mapping(config: Dict[str, Any]) -> Dict[str, Dict[str, Any]]:
mapping: Dict[str, Dict[str, Any]] = {}
ip_classes = config.get("ip_classes", {}) or {}
for ip_address, data in ip_classes.items():
if not isinstance(data, dict):
continue
if "ip_parent" in data or "ip_enfant" in data:
mapping[ip_address] = {
"ip_parent": data.get("ip_parent"),
"ip_enfant": normalize_children(data.get("ip_enfant"))
}
for host in config.get("hosts", []) or []:
if not isinstance(host, dict):
continue
ip_address = host.get("ip")
if not ip_address:
continue
if "ip_parent" in host or "ip_enfant" in host:
entry = mapping.setdefault(ip_address, {})
entry.setdefault("ip_parent", host.get("ip_parent"))
entry.setdefault("ip_enfant", normalize_children(host.get("ip_enfant")))
return mapping
def main() -> None:
config = load_config()
db_path = Path(config.get("database", {}).get("path", "./data/db.sqlite"))
mapping = collect_parent_mapping(config)
if not db_path.exists():
raise FileNotFoundError(f"Base de données introuvable: {db_path}")
conn = sqlite3.connect(db_path)
try:
ensure_columns(conn)
if mapping:
for ip_address, values in mapping.items():
ip_parent = values.get("ip_parent")
ip_enfant = values.get("ip_enfant")
if ip_enfant is not None:
conn.execute(
"UPDATE ip SET ip_parent = ?, ip_enfant = ? WHERE ip = ?",
(ip_parent, json.dumps(ip_enfant), ip_address)
)
else:
conn.execute(
"UPDATE ip SET ip_parent = ? WHERE ip = ?",
(ip_parent, ip_address)
)
cursor = conn.execute("SELECT ip, ip_parent FROM ip")
rows = cursor.fetchall()
parent_children: Dict[str, List[str]] = {}
for ip_address, ip_parent in rows:
if ip_parent:
parent_children.setdefault(ip_parent, []).append(ip_address)
for ip_address, _ in rows:
children = parent_children.get(ip_address, [])
conn.execute(
"UPDATE ip SET ip_enfant = ? WHERE ip = ?",
(json.dumps(children), ip_address)
)
conn.commit()
print("Reconstruction terminée.")
finally:
conn.close()
if __name__ == "__main__":
main()