life-noc/patch_days_until_due_v3.sh

161 lines
5.4 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
set -euo pipefail
ROOT="${1:-.}"
need_file() {
local f="$1"
if [[ ! -f "$ROOT/$f" ]]; then
echo "Fichier introuvable: $f" >&2
exit 1
fi
}
echo "==> Vérification"
need_file "scripts/generate_services.py"
need_file "domains.yaml"
echo "==> Sauvegarde"
mkdir -p "$ROOT/.patch-backup-days-until-due-v3"
cp -a "$ROOT/scripts/generate_services.py" "$ROOT/.patch-backup-days-until-due-v3/generate_services.py.bak"
cp -a "$ROOT/domains.yaml" "$ROOT/.patch-backup-days-until-due-v3/domains.yaml.bak"
echo "==> Patch robuste de scripts/generate_services.py"
python3 - "$ROOT/scripts/generate_services.py" <<'PYEOF'
from pathlib import Path
import re
import sys
path = Path(sys.argv[1])
text = path.read_text(encoding="utf-8")
# 1) Ajouter les seuils lt/gte manquants dans render_probe_service, juste avant on_error
if 'vars.life_noc_threshold_unknown_gte' not in text:
marker = ' on_error = str(policy.get("on_error", "critical")).strip()\n'
inject = (
' if "unknown_gte" in thresholds:\n'
' lines.append(f\' vars.life_noc_threshold_unknown_gte = "{icinga_escape(str(thresholds["unknown_gte"]))}"\')\n'
' if "ok_lt" in thresholds:\n'
' lines.append(f\' vars.life_noc_threshold_ok_lt = "{icinga_escape(str(thresholds["ok_lt"]))}"\')\n'
' if "warning_lt" in thresholds:\n'
' lines.append(f\' vars.life_noc_threshold_warning_lt = "{icinga_escape(str(thresholds["warning_lt"]))}"\')\n'
' if "critical_lt" in thresholds:\n'
' lines.append(f\' vars.life_noc_threshold_critical_lt = "{icinga_escape(str(thresholds["critical_lt"]))}"\')\n'
)
if marker not in text:
raise SystemExit("Impossible de trouver le point d'injection des seuils dans render_probe_service")
text = text.replace(marker, inject + marker, 1)
# 2) Remplacer entièrement validate_probe(...)
new_validate = '''def validate_probe(item: dict) -> None:
probe = item["probe"]
if not isinstance(probe, dict):
raise ValueError("probe doit être un objet")
probe_type = str(probe.get("type", "")).strip()
if probe_type not in {"elapsed_time", "days_until_due"}:
raise ValueError("seuls probe.type=elapsed_time et days_until_due sont supportés")
source = probe.get("source")
if not isinstance(source, dict):
raise ValueError("probe.source doit être un objet")
if str(source.get("type", "")).strip() != "manual_date":
raise ValueError("seul probe.source.type=manual_date est supporté en v1")
has_inline_value = "value" in source
has_store_ref = "inputs_file" in source and "item_key" in source
if not has_inline_value and not has_store_ref:
raise ValueError("probe.source.value ou probe.source.inputs_file + item_key requis")
metric = probe.get("metric")
if not isinstance(metric, dict):
raise ValueError("probe.metric doit être un objet")
if str(metric.get("unit", "")).strip() != "days":
raise ValueError("seul probe.metric.unit=days est supporté en v1")
thresholds = probe.get("thresholds")
if not isinstance(thresholds, dict):
raise ValueError("probe.thresholds doit être un objet")
'''
pattern = r'def validate_probe\(item: dict\) -> None:\n(?: .*\n)+?(?=\ndef render_servicegroup|\ndef main\()'
new_text, count = re.subn(pattern, new_validate + "\n", text, flags=re.MULTILINE)
if count == 0:
raise SystemExit("Impossible de remplacer validate_probe(...) dans generate_services.py")
text = new_text
path.write_text(text, encoding="utf-8")
print("generate_services.py patché")
PYEOF
echo "==> Création du store"
mkdir -p "$ROOT/data/inputs"
cat > "$ROOT/data/inputs/obligations-legales-personnelles.yaml" <<'YAMLEOF'
renouvellement-permis-conduire:
value: "2026-09-20"
captured_at: "2026-03-14T23:30:00Z"
origin: manual
YAMLEOF
echo "==> Mise à jour de domains.yaml"
python3 - "$ROOT/domains.yaml" <<'PYEOF'
from pathlib import Path
import sys
import yaml
path = Path(sys.argv[1])
data = yaml.safe_load(path.read_text(encoding="utf-8"))
domain = "obligations-legales-personnelles"
items = data.get("domains", {}).get(domain)
if not isinstance(items, list):
raise SystemExit(f"Domaine introuvable ou invalide: {domain}")
target = None
for item in items:
if isinstance(item, dict) and item.get("name") == "renouvellement-permis-conduire":
target = item
break
if target is None:
raise SystemExit("Item 'renouvellement-permis-conduire' introuvable")
target["date"] = "2026-09-20"
target["notes"] = "Vérifier la proximité de léchéance du permis"
target["probe"] = {
"type": "days_until_due",
"source": {
"type": "manual_date",
"inputs_file": "/opt/life-noc/data/inputs/obligations-legales-personnelles.yaml",
"item_key": "renouvellement-permis-conduire",
},
"metric": {
"unit": "days",
},
"thresholds": {
"critical_lt": 7,
"warning_lt": 30,
"ok_lt": 90,
"unknown_gte": 90,
},
"policy": {
"on_error": "critical",
},
}
path.write_text(yaml.safe_dump(data, sort_keys=False, allow_unicode=True), encoding="utf-8")
print("domains.yaml mis à jour")
PYEOF
echo "==> Régénération"
(
cd "$ROOT"
python3 scripts/generate_services.py
)
echo
echo "Patch terminé."
echo "Étapes suivantes :"
echo " python3 scripts/generate_services.py"
echo " make check"
echo " make deploy-with-bpm"