life-noc/patch_bpm_native.sh

260 lines
7.7 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 du dépôt"
need_file "domains.yaml"
need_file "scripts/generate_bpm.py"
need_file "Makefile"
need_file "ansible/roles/life_noc/defaults/main.yml"
need_file "ansible/roles/life_noc/tasks/main.yml"
echo "==> Sauvegarde minimale"
mkdir -p "$ROOT/.patch-backup"
cp -a "$ROOT/scripts/generate_bpm.py" "$ROOT/.patch-backup/generate_bpm.py.bak"
cp -a "$ROOT/Makefile" "$ROOT/.patch-backup/Makefile.bak"
cp -a "$ROOT/ansible/roles/life_noc/defaults/main.yml" "$ROOT/.patch-backup/life_noc_defaults_main.yml.bak"
cp -a "$ROOT/ansible/roles/life_noc/tasks/main.yml" "$ROOT/.patch-backup/life_noc_tasks_main.yml.bak"
[[ -f "$ROOT/preuve-de-reproductibilite.md" ]] && cp -a "$ROOT/preuve-de-reproductibilite.md" "$ROOT/.patch-backup/preuve-de-reproductibilite.md.bak"
[[ -f "$ROOT/decisions-techniques.md" ]] && cp -a "$ROOT/decisions-techniques.md" "$ROOT/.patch-backup/decisions-techniques.md.bak"
echo "==> Réécriture de scripts/generate_bpm.py"
cat > "$ROOT/scripts/generate_bpm.py" <<'PYEOF'
#!/usr/bin/env python3
from __future__ import annotations
import re
from pathlib import Path
import sys
import yaml
ROOT = Path(__file__).resolve().parents[1]
DOMAINS_YAML = ROOT / "domains.yaml"
OUTPUT_DIR = ROOT / "bpm"
OUTPUT_FILE = OUTPUT_DIR / "Life-NOC.conf"
HOST_NAME = "life-noc"
TITLE = "Life-NOC"
OWNER = "icingadmin"
def slugify(value: str) -> str:
value = value.strip().lower()
replacements = {
"à": "a", "â": "a", "ä": "a",
"ç": "c",
"é": "e", "è": "e", "ê": "e", "ë": "e",
"î": "i", "ï": "i",
"ô": "o", "ö": "o",
"ù": "u", "û": "u", "ü": "u",
"ÿ": "y",
"œ": "oe", "æ": "ae",
"'": "", "": "",
}
for old, new in replacements.items():
value = value.replace(old, new)
value = re.sub(r"[^a-z0-9\-]+", "-", value)
value = re.sub(r"-{2,}", "-", value)
return value.strip("-")
def aliasify(value: str) -> str:
value = value.strip().upper()
replacements = {
"À": "A", "Â": "A", "Ä": "A",
"Ç": "C",
"É": "E", "È": "E", "Ê": "E", "Ë": "E",
"Î": "I", "Ï": "I",
"Ô": "O", "Ö": "O",
"Ù": "U", "Û": "U", "Ü": "U",
"Ÿ": "Y",
"Œ": "OE", "Æ": "AE",
"'": "", "": "",
}
for old, new in replacements.items():
value = value.replace(old, new)
value = re.sub(r"[^A-Z0-9\-]+", "-", value)
value = re.sub(r"-{2,}", "-", value)
return value.strip("-")
def read_domains() -> dict:
data = yaml.safe_load(DOMAINS_YAML.read_text(encoding="utf-8"))
if not isinstance(data, dict) or "domains" not in data:
raise ValueError("domains.yaml doit contenir une clé racine 'domains'")
domains = data["domains"]
if not isinstance(domains, dict):
raise ValueError("domains.yaml: 'domains' doit être un mapping")
return domains
def collect_services(domain_data: dict, domain_name: str) -> list[str]:
items = domain_data.get("items", [])
if not isinstance(items, list):
raise ValueError(f"Domaine '{domain_name}': 'items' doit être une liste")
services: list[str] = []
for item in items:
if not isinstance(item, dict):
raise ValueError(f"Domaine '{domain_name}': item invalide (dict attendu)")
item_name = item.get("name")
if not item_name:
raise ValueError(f"Domaine '{domain_name}': item sans champ 'name'")
service_name = f"{slugify(domain_name)}-{slugify(str(item_name))}"
services.append(f"{HOST_NAME};{service_name}")
if not services:
raise ValueError(f"Domaine '{domain_name}' ne contient aucun item")
return services
def header() -> str:
return f"""### Business Process Config File ###
#
# Title : {TITLE}
# Description :
# Owner : {OWNER}
# AddToMenu : yes
# Backend :
# Statetype : soft
#
###################################
"""
def main() -> int:
domains = read_domains()
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
lines: list[str] = [header()]
aliases: list[tuple[str, str]] = []
for domain_name, domain_data in domains.items():
if not isinstance(domain_data, dict):
raise ValueError(f"Domaine '{domain_name}': structure invalide")
alias = aliasify(domain_name)
label = domain_data.get("label", domain_name)
services = collect_services(domain_data, domain_name)
expr = " & ".join(services)
lines.append(f"{alias} = {expr}\n")
aliases.append((alias, str(label)))
lines.append("\n")
root_expr = " & ".join(alias for alias, _label in aliases)
lines.append(f"LIFE-NOC = {root_expr}\n")
lines.append("display 1;LIFE-NOC;LIFE-NOC\n")
for alias, label in aliases:
lines.append(f"display 1;{alias};{label}\n")
OUTPUT_FILE.write_text("".join(lines), encoding="utf-8")
print(f"BPM généré: {OUTPUT_FILE.relative_to(ROOT)}")
print("Processus générés :")
print(" - LIFE-NOC")
for alias, _label in aliases:
print(f" - {alias}")
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except Exception as exc:
print(f"ERREUR: {exc}", file=sys.stderr)
raise
PYEOF
chmod +x "$ROOT/scripts/generate_bpm.py"
echo "==> Ajustements texte ciblés"
python3 - "$ROOT" <<'PYEOF'
from pathlib import Path
import re
import sys
root = Path(sys.argv[1])
def replace_text(path_str, replacements):
path = root / path_str
if not path.exists():
return
text = path.read_text(encoding="utf-8")
original = text
for old, new in replacements:
text = text.replace(old, new)
if text != original:
path.write_text(text, encoding="utf-8")
print(f"Modifié: {path_str}")
def regex_replace(path_str, pattern, repl, must_match=False):
path = root / path_str
if not path.exists():
return
text = path.read_text(encoding="utf-8")
new_text, count = re.subn(pattern, repl, text, flags=re.MULTILINE)
if must_match and count == 0:
raise SystemExit(f"Aucun match dans {path_str} pour: {pattern}")
if new_text != text:
path.write_text(new_text, encoding="utf-8")
print(f"Modifié: {path_str}")
# Makefile
replace_text("Makefile", [
("bpm/life-noc.json", "bpm/Life-NOC.conf"),
])
# defaults main.yml
replace_text("ansible/roles/life_noc/defaults/main.yml", [
("/etc/icingaweb2/modules/businessprocess/processes/life-noc.json",
"/etc/icingaweb2/modules/businessprocess/processes/Life-NOC.conf"),
])
# tasks main.yml
replace_text("ansible/roles/life_noc/tasks/main.yml", [
("bpm/life-noc.json", "bpm/Life-NOC.conf"),
("life-noc.json", "Life-NOC.conf"),
])
# docs
for doc in ["preuve-de-reproductibilite.md", "decisions-techniques.md"]:
replace_text(doc, [
("bpm/life-noc.json", "bpm/Life-NOC.conf"),
("life-noc.json", "Life-NOC.conf"),
("export JSON", "export natif Business Process"),
("artefact JSON", "artefact natif Business Process"),
])
PYEOF
echo "==> Nettoyage de l'ancien artefact si présent"
rm -f "$ROOT/bpm/life-noc.json"
echo "==> Génération du nouveau BPM"
(
cd "$ROOT"
python3 scripts/generate_bpm.py
)
echo "==> Vérification rapide"
if [[ -f "$ROOT/bpm/Life-NOC.conf" ]]; then
echo "OK: bpm/Life-NOC.conf généré"
else
echo "ERREUR: bpm/Life-NOC.conf absent" >&2
exit 1
fi
echo
echo "Patch terminé."
echo "Fichiers sauvegardés dans: $ROOT/.patch-backup"
echo "Prochaine étape recommandée:"
echo " make check"
echo "Puis redéploiement avec BPM activé."