life-noc/lib/life_noc_inputs.py
2026-03-15 14:43:50 -04:00

144 lines
4.4 KiB
Python

from __future__ import annotations
from datetime import datetime, timezone
from pathlib import Path
import yaml
INPUTS_DIR = Path("data/inputs")
DOMAINS_FILE = Path("domains.yaml")
def utc_now_iso() -> str:
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
def utc_today_date() -> str:
return datetime.now(timezone.utc).strftime("%Y-%m-%d")
def domain_file(domain: str) -> Path:
return INPUTS_DIR / f"{domain}.yaml"
def load_domain(domain: str) -> dict:
path = domain_file(domain)
if not path.exists():
return {}
data = yaml.safe_load(path.read_text(encoding="utf-8"))
if data is None:
return {}
if not isinstance(data, dict):
raise ValueError(f"Fichier invalide: {path}")
return data
def save_domain(domain: str, data: dict) -> Path:
path = domain_file(domain)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(
yaml.safe_dump(data, sort_keys=False, allow_unicode=True),
encoding="utf-8",
)
return path
def list_items(domain: str) -> list[str]:
return list(load_domain(domain).keys())
def get_item(domain: str, item_key: str) -> dict:
data = load_domain(domain)
if item_key not in data:
raise KeyError(item_key)
item = data[item_key]
if not isinstance(item, dict):
raise ValueError(f"Entrée invalide pour {item_key}")
return item
def set_item(domain: str, item_key: str, value: str, origin: str = "manual") -> dict:
data = load_domain(domain)
data[item_key] = {
"value": value,
"captured_at": utc_now_iso(),
"origin": origin,
}
save_domain(domain, data)
return data[item_key]
def complete_item(domain: str, item_key: str, origin: str = "manual") -> dict:
return set_item(domain, item_key, utc_today_date(), origin=origin)
def load_domains_definition() -> dict:
if not DOMAINS_FILE.exists():
raise ValueError(f"Fichier introuvable: {DOMAINS_FILE}")
data = yaml.safe_load(DOMAINS_FILE.read_text(encoding="utf-8"))
if not isinstance(data, dict):
raise ValueError("domains.yaml invalide")
domains = data.get("domains")
if not isinstance(domains, dict):
raise ValueError("domains.yaml invalide: clé 'domains' absente ou invalide")
return domains
def get_defined_service(domain: str, item_key: str) -> dict:
domains = load_domains_definition()
items = domains.get(domain)
if not isinstance(items, list):
raise KeyError(domain)
for item in items:
if isinstance(item, dict) and item.get("name") == item_key:
return item
raise KeyError(item_key)
def compute_state_for_item(domain: str, item_key: str) -> str:
service = get_defined_service(domain, item_key)
probe = service.get("probe")
if not isinstance(probe, dict):
return "MOCK"
probe_type = str(probe.get("type", "")).strip()
source = probe.get("source", {})
thresholds = probe.get("thresholds", {})
metric = probe.get("metric", {})
if str(source.get("type", "")).strip() != "manual_date":
return "CRITICAL"
if str(metric.get("unit", "")).strip() != "days":
return "CRITICAL"
item = get_item(domain, item_key)
value = str(item.get("value", "")).strip()
dt = datetime.strptime(value, "%Y-%m-%d").replace(tzinfo=timezone.utc)
now = datetime.now(timezone.utc)
if probe_type == "elapsed_time":
days = (now - dt).total_seconds() / 86400.0
if "critical_gte" in thresholds and days >= float(thresholds["critical_gte"]):
return "CRITICAL"
if "warning_gte" in thresholds and days >= float(thresholds["warning_gte"]):
return "WARNING"
if "ok_gte" in thresholds and days >= float(thresholds["ok_gte"]):
return "OK"
if "unknown_lt" in thresholds and days < float(thresholds["unknown_lt"]):
return "UNKNOWN"
return "CRITICAL"
if probe_type == "days_until_due":
days = (dt - now).total_seconds() / 86400.0
if "critical_lt" in thresholds and days < float(thresholds["critical_lt"]):
return "CRITICAL"
if "warning_lt" in thresholds and days < float(thresholds["warning_lt"]):
return "WARNING"
if "ok_lt" in thresholds and days < float(thresholds["ok_lt"]):
return "OK"
if "unknown_gte" in thresholds and days >= float(thresholds["unknown_gte"]):
return "UNKNOWN"
return "CRITICAL"
return "CRITICAL"