cd ..
This commit is contained in:
parent
54f7c8c300
commit
3247d98fb3
44 changed files with 2871 additions and 973 deletions
2
Makefile
2
Makefile
|
|
@ -61,6 +61,8 @@ validate-generated: $(ICINGA_FILES) bpm/Life-NOC.conf
|
|||
@grep -R 'check_life_noc_mock' icinga/templates icinga/commands icinga/services >/dev/null
|
||||
@$(PYTHON) -c 'import pathlib; p = pathlib.Path("bpm/Life-NOC.conf"); text = p.read_text(encoding="utf-8"); lines = [l.strip() for l in text.splitlines() if l.strip()]; assert any(l == "### Business Process Config File ###" for l in lines), "bpm/Life-NOC.conf invalide: en-tête BPM absent"; assert any(l.startswith("display 1;") for l in lines), "bpm/Life-NOC.conf invalide: aucun display absent"; print("Artefacts générés valides")'
|
||||
|
||||
check: generate validate
|
||||
|
||||
mock-ok:
|
||||
@bash checks/check_life_noc_mock.sh --state OK --message "Sous contrôle" --item-name "demo" --date "2026-03-13"
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ Type=simple
|
|||
User=root
|
||||
Group=root
|
||||
WorkingDirectory={{ life_noc_project_root }}
|
||||
ExecStart=/usr/bin/python3 -m uvicorn scripts.life_noc_input_api:app --host 127.0.0.1 --port 8787
|
||||
ExecStart=/usr/bin/python3 -m uvicorn scripts.life_noc_input_api:app --host 0.0.0.0 --port 8787
|
||||
Restart=on-failure
|
||||
RestartSec=3
|
||||
|
||||
|
|
|
|||
|
|
@ -1,121 +0,0 @@
|
|||
#!/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 "domains.yaml"
|
||||
need_file "icinga/commands/check_life_noc_probe.conf"
|
||||
need_file "scripts/generate_services.py"
|
||||
need_file "Makefile"
|
||||
|
||||
echo "==> Sauvegarde minimale"
|
||||
mkdir -p "$ROOT/.backup-days-until-due-pilot"
|
||||
cp -a "$ROOT/domains.yaml" "$ROOT/.backup-days-until-due-pilot/domains.yaml.bak"
|
||||
|
||||
echo "==> Création du store d'intrants"
|
||||
mkdir -p "$ROOT/data/inputs"
|
||||
cat > "$ROOT/data/inputs/obligations-legales-personnelles.yaml" <<'EOF'
|
||||
renouvellement-permis-conduire:
|
||||
value: "2026-09-20"
|
||||
captured_at: "2026-03-14T23:30:00Z"
|
||||
origin: manual
|
||||
EOF
|
||||
|
||||
echo "==> Mise à jour de domains.yaml"
|
||||
python3 - "$ROOT/domains.yaml" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
path = Path(sys.argv[1])
|
||||
data = yaml.safe_load(path.read_text(encoding="utf-8"))
|
||||
|
||||
domains = data.get("domains")
|
||||
if not isinstance(domains, dict):
|
||||
raise SystemExit("domains.yaml invalide: clé racine 'domains' absente ou invalide")
|
||||
|
||||
domain_name = "obligations-legales-personnelles"
|
||||
items = domains.get(domain_name)
|
||||
if not isinstance(items, list):
|
||||
raise SystemExit(f"Domaine introuvable ou invalide: {domain_name}")
|
||||
|
||||
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 dans domains.yaml")
|
||||
|
||||
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")
|
||||
PY
|
||||
|
||||
echo "==> Vérification rapide de la commande Icinga"
|
||||
for needle in \
|
||||
'--unknown-gte' \
|
||||
'--ok-lt' \
|
||||
'--warning-lt' \
|
||||
'--critical-lt'
|
||||
do
|
||||
if ! grep -q -- "$needle" "$ROOT/icinga/commands/check_life_noc_probe.conf"; then
|
||||
echo "ERREUR: argument manquant dans icinga/commands/check_life_noc_probe.conf : $needle" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "==> Génération"
|
||||
(
|
||||
cd "$ROOT"
|
||||
python3 scripts/generate_services.py
|
||||
)
|
||||
|
||||
echo "==> Validation"
|
||||
(
|
||||
cd "$ROOT"
|
||||
make check
|
||||
)
|
||||
|
||||
echo "==> Déploiement"
|
||||
(
|
||||
cd "$ROOT"
|
||||
make deploy-with-bpm
|
||||
)
|
||||
|
||||
echo
|
||||
echo "Terminé."
|
||||
echo "Test utile ensuite :"
|
||||
echo " python3 scripts/life_noc_input.py set obligations-legales-personnelles renouvellement-permis-conduire 2026-03-20"
|
||||
295
docs/architecture-life-noc.md
Normal file
295
docs/architecture-life-noc.md
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
# Architecture et fonctionnement de Life-NOC
|
||||
|
||||
## 1. Présentation générale
|
||||
|
||||
### 1.1 Définition
|
||||
|
||||
**Life-NOC** est un système de pilotage personnel qui applique à la vie réelle la logique d’un **NOC** (Network Operations Center / centre d’opérations).
|
||||
|
||||
Son but n’est pas d’automatiser la vie à la place de la personne. Son but est de :
|
||||
|
||||
- rendre visibles les suivis importants ;
|
||||
- transformer la charge mentale en état observable ;
|
||||
- soutenir la mémoire prospective ;
|
||||
- orienter l’attention vers ce qui mérite réellement d’être vu ;
|
||||
- réduire la friction entre la prise de conscience et l’action.
|
||||
|
||||
Life-NOC peut être résumé ainsi :
|
||||
|
||||
> **Voir clair, prioriser juste, agir au bon endroit.**
|
||||
|
||||
### 1.2 Finalité
|
||||
|
||||
Life-NOC sert à superviser des éléments de la vie personnelle, domestique, administrative, technique ou communautaire comme s’il s’agissait de services critiques dans une salle de contrôle.
|
||||
|
||||
Il permet par exemple de suivre :
|
||||
|
||||
- des revues périodiques ;
|
||||
- des échéances ;
|
||||
- des stocks ;
|
||||
- des vérifications techniques ;
|
||||
- des obligations administratives ;
|
||||
- des contrôles de maintenance ;
|
||||
- des routines de résilience ;
|
||||
- des points d’attention dans l’environnement physique.
|
||||
|
||||
### 1.3 Positionnement
|
||||
|
||||
Life-NOC n’est pas :
|
||||
|
||||
- un simple gestionnaire de tâches ;
|
||||
- un agenda ;
|
||||
- un ERP ;
|
||||
- un moteur d’automatisation généraliste ;
|
||||
- un outil d’inventaire pur.
|
||||
|
||||
Life-NOC est :
|
||||
|
||||
- un **système de supervision attentionnelle** ;
|
||||
- un **cadre d’évaluation de suivis** ;
|
||||
- un **point de convergence** entre intrants, règles, états et actions ;
|
||||
- une **interface de réduction de charge mentale**.
|
||||
|
||||
## 2. Principes de fonctionnement
|
||||
|
||||
### 2.1 Séparation des couches
|
||||
|
||||
Life-NOC repose sur quatre couches distinctes :
|
||||
|
||||
1. **définition** ;
|
||||
2. **ingestion** ;
|
||||
3. **persistance** ;
|
||||
4. **évaluation**.
|
||||
|
||||
**Définition**
|
||||
Contient les items à superviser, les méthodes, les seuils, les notes et les liens utiles.
|
||||
|
||||
**Ingestion**
|
||||
Contient les mécanismes par lesquels une donnée entre dans le système :
|
||||
- saisie manuelle ;
|
||||
- API ;
|
||||
- page HTML ;
|
||||
- QR code ;
|
||||
- plus tard MQTT, GUI avancée, etc.
|
||||
|
||||
**Persistance**
|
||||
Contient les intrants vivants à jour.
|
||||
|
||||
**Évaluation**
|
||||
Contient la logique qui transforme un intrant en état Life-NOC.
|
||||
|
||||
### 2.2 Philosophie générale
|
||||
|
||||
Le système suit cette logique :
|
||||
|
||||
- le **domaine** organise ;
|
||||
- la **méthode** évalue ;
|
||||
- l’**item** fait le lien entre les deux ;
|
||||
- l’**intrant** fournit la valeur vivante ;
|
||||
- la **page item** réduit la friction d’action ;
|
||||
- **Icinga** rend les états visibles dans un cadre de supervision.
|
||||
|
||||
## 3. États Life-NOC
|
||||
|
||||
### 3.1 États
|
||||
|
||||
- **UNKNOWN** : pas encore dû, pas encore à faire ;
|
||||
- **OK** : actionnable maintenant ;
|
||||
- **WARNING** : il faut se presser ;
|
||||
- **CRITICAL** : en retard, anormal, ou impossible à évaluer.
|
||||
|
||||
### 3.2 Politique d’erreur
|
||||
|
||||
Par défaut, si le système ne peut pas conclure techniquement, il retourne **CRITICAL**.
|
||||
|
||||
Exemples :
|
||||
|
||||
- fichier introuvable ;
|
||||
- donnée absente ;
|
||||
- format invalide ;
|
||||
- parsing impossible ;
|
||||
- seuil incohérent ;
|
||||
- type de sonde non pris en charge.
|
||||
|
||||
## 4. Organisation métier par domaines
|
||||
|
||||
Les domaines servent à organiser les suivis.
|
||||
|
||||
Exemples :
|
||||
|
||||
- revue ;
|
||||
- focus ;
|
||||
- finances-personnelles ;
|
||||
- obligations-legales-personnelles ;
|
||||
- maison ;
|
||||
- energie ;
|
||||
- voiture ;
|
||||
- projets ;
|
||||
- documentation ;
|
||||
- animaux.
|
||||
|
||||
Le domaine est une unité d’organisation métier, pas nécessairement une unité de calcul.
|
||||
|
||||
## 5. Taxonomie des méthodes de sonde
|
||||
|
||||
### 5.1 `elapsed_time`
|
||||
Mesure le temps écoulé depuis une dernière exécution.
|
||||
|
||||
### 5.2 `days_until_due`
|
||||
Mesure le temps restant avant une échéance fixe.
|
||||
|
||||
### 5.3 `elapsed_distance`
|
||||
Mesure une distance écoulée depuis une action passée.
|
||||
|
||||
### 5.4 `current_value`
|
||||
Évalue une valeur instantanée contre des seuils.
|
||||
|
||||
### 5.5 `remaining_quantity`
|
||||
Évalue ce qu’il reste d’un stock ou d’une réserve.
|
||||
|
||||
## 6. Portée actuellement validée
|
||||
|
||||
Au stade actuel, les méthodes réellement validées sont :
|
||||
|
||||
- `elapsed_time` ;
|
||||
- `days_until_due`.
|
||||
|
||||
## 7. Définition des items
|
||||
|
||||
Les items sont définis dans :
|
||||
|
||||
```text
|
||||
domains.yaml
|
||||
```
|
||||
|
||||
Un item peut contenir :
|
||||
|
||||
- `name`
|
||||
- `date`
|
||||
- `notes`
|
||||
- `notes_url`
|
||||
- `instructions_url`
|
||||
- `action_url`
|
||||
- `probe`
|
||||
|
||||
### 7.1 Rôle des champs descriptifs
|
||||
|
||||
- `notes` : résumé court ;
|
||||
- `notes_url` : contexte / référence ;
|
||||
- `instructions_url` : procédure ;
|
||||
- `action_url` : outil ou page d’action.
|
||||
|
||||
## 8. Store des intrants
|
||||
|
||||
Les intrants vivants sont stockés sous :
|
||||
|
||||
```text
|
||||
data/inputs/<domaine>.yaml
|
||||
```
|
||||
|
||||
Exemple :
|
||||
|
||||
```yaml
|
||||
revue-hebdomadaire-priorites:
|
||||
value: "2026-03-14"
|
||||
captured_at: "2026-03-14T23:16:41Z"
|
||||
origin: manual
|
||||
```
|
||||
|
||||
## 9. CLI des intrants
|
||||
|
||||
Commandes principales :
|
||||
|
||||
- `list`
|
||||
- `get`
|
||||
- `set`
|
||||
- `complete`
|
||||
|
||||
Exemples :
|
||||
|
||||
```bash
|
||||
life-noc-input list revue
|
||||
life-noc-input get revue revue-hebdomadaire-priorites
|
||||
life-noc-input set revue revue-hebdomadaire-priorites 2026-03-14
|
||||
life-noc-input complete revue revue-hebdomadaire-priorites
|
||||
```
|
||||
|
||||
## 10. API locale des intrants
|
||||
|
||||
API locale sur :
|
||||
|
||||
```text
|
||||
http://127.0.0.1:8787
|
||||
```
|
||||
|
||||
Endpoints JSON :
|
||||
|
||||
- `GET /health`
|
||||
- `GET /inputs/{domain}`
|
||||
- `GET /inputs/{domain}/{item_key}`
|
||||
- `POST /inputs/{domain}/{item_key}`
|
||||
- `POST /inputs/{domain}/{item_key}/complete`
|
||||
|
||||
Dépendances importantes :
|
||||
|
||||
- `python3-fastapi`
|
||||
- `python3-uvicorn`
|
||||
- `python3-multipart`
|
||||
|
||||
## 11. Pages HTML Life-NOC
|
||||
|
||||
Route :
|
||||
|
||||
```text
|
||||
/life-noc/item/<domaine>/<item_key>
|
||||
```
|
||||
|
||||
La page affiche :
|
||||
|
||||
- titre humain ;
|
||||
- état actuel ;
|
||||
- type de sonde ;
|
||||
- dernier intrant ;
|
||||
- domaine ;
|
||||
- item key ;
|
||||
- notes ;
|
||||
- liens utiles ;
|
||||
- bouton `Compléter`.
|
||||
|
||||
Le bouton utilise :
|
||||
|
||||
```text
|
||||
POST /life-noc/item/<domaine>/<item_key>/complete
|
||||
```
|
||||
|
||||
## 12. Intégration Icinga
|
||||
|
||||
Life-NOC s’appuie sur Icinga pour :
|
||||
|
||||
- la visualisation des états ;
|
||||
- le `Check Now` ;
|
||||
- les BPM natifs ;
|
||||
- les servicegroups ;
|
||||
- l’affichage des variables utiles.
|
||||
|
||||
## 13. Flux complet
|
||||
|
||||
1. définition dans `domains.yaml` ;
|
||||
2. intrant dans `data/inputs/<domaine>.yaml` ;
|
||||
3. mise à jour par CLI, API ou page HTML ;
|
||||
4. lecture par la sonde ;
|
||||
5. calcul de l’état ;
|
||||
6. affichage dans Icinga ;
|
||||
7. action de l’usager ;
|
||||
8. mise à jour de l’intrant.
|
||||
|
||||
## 14. Déploiement
|
||||
|
||||
Commandes usuelles :
|
||||
|
||||
```bash
|
||||
make check
|
||||
make deploy-with-bpm
|
||||
```
|
||||
|
||||
Le dépôt doit rester reproductible sans correctifs manuels cachés.
|
||||
83
docs/exploitation-life-noc.md
Normal file
83
docs/exploitation-life-noc.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# Exploitation et dépannage Life-NOC
|
||||
|
||||
## 1. Vérifications utiles
|
||||
|
||||
### Vérifier l’API
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8787/health
|
||||
```
|
||||
|
||||
### Vérifier un intrant
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8787/inputs/revue/revue-hebdomadaire-priorites
|
||||
```
|
||||
|
||||
### Vérifier une page item
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8787/life-noc/item/revue/revue-hebdomadaire-priorites
|
||||
```
|
||||
|
||||
## 2. Cas fréquent : l’intrant change mais pas l’état dans Icinga
|
||||
|
||||
Cela signifie souvent qu’Icinga n’a pas encore refait le check.
|
||||
|
||||
Il faut alors :
|
||||
|
||||
- lancer un `Check Now` ;
|
||||
- ou attendre le prochain check ;
|
||||
- ou tester directement le plugin à la main.
|
||||
|
||||
## 3. Cas fréquent : route HTML absente après déploiement
|
||||
|
||||
Vérifier :
|
||||
|
||||
- que le service API tourne ;
|
||||
- que le fichier déployé contient bien les routes HTML ;
|
||||
- que les dépendances FastAPI sont installées, notamment `python3-multipart`.
|
||||
|
||||
## 4. Vérifier le service API
|
||||
|
||||
```bash
|
||||
sudo systemctl status life-noc-input-api --no-pager
|
||||
sudo journalctl -u life-noc-input-api -n 80 --no-pager
|
||||
```
|
||||
|
||||
## 5. Vérifier directement un plugin
|
||||
|
||||
Exemple pour `elapsed_time` :
|
||||
|
||||
```bash
|
||||
/usr/lib/nagios/plugins/check_life_noc_probe.py --probe-type elapsed_time --source-type manual_date --inputs-file /opt/life-noc/data/inputs/revue.yaml --item-key revue-hebdomadaire-priorites --unit days --unknown-lt 5 --ok-gte 5 --warning-gte 7 --critical-gte 10 --on-error critical --label revue-hebdomadaire-priorites
|
||||
```
|
||||
|
||||
## 6. Déploiement
|
||||
|
||||
```bash
|
||||
make check
|
||||
make deploy-with-bpm
|
||||
```
|
||||
|
||||
## 7. Dépendances API importantes
|
||||
|
||||
Le service API nécessite :
|
||||
|
||||
- `python3-fastapi`
|
||||
- `python3-uvicorn`
|
||||
- `python3-multipart`
|
||||
|
||||
## 8. État actuel validé
|
||||
|
||||
Éléments validés en pratique :
|
||||
|
||||
- Icinga Web 2 ;
|
||||
- BPM natif ;
|
||||
- servicegroups ;
|
||||
- `Check Now` ;
|
||||
- store d’intrants ;
|
||||
- CLI ;
|
||||
- API locale ;
|
||||
- pages HTML d’item ;
|
||||
- méthodes `elapsed_time` et `days_until_due`.
|
||||
79
docs/guide-usager-life-noc.md
Normal file
79
docs/guide-usager-life-noc.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# Guide usager Life-NOC
|
||||
|
||||
## 1. À quoi sert Life-NOC
|
||||
|
||||
Life-NOC aide une personne à voir rapidement ce qui mérite son attention, sans tout garder dans sa tête.
|
||||
|
||||
Il sert à suivre par exemple :
|
||||
|
||||
- des revues régulières ;
|
||||
- des dates importantes ;
|
||||
- des entretiens ;
|
||||
- des vérifications ;
|
||||
- des obligations.
|
||||
|
||||
## 2. Ce que signifient les états
|
||||
|
||||
- **UNKNOWN** : pas encore le temps d’agir ;
|
||||
- **OK** : c’est le bon moment pour s’en occuper ;
|
||||
- **WARNING** : il faut accélérer ;
|
||||
- **CRITICAL** : c’est urgent ou il y a un problème.
|
||||
|
||||
## 3. Comment consulter un item
|
||||
|
||||
Un item peut être consulté :
|
||||
|
||||
- dans Icinga ;
|
||||
- via une page Life-NOC ;
|
||||
- plus tard via un QR code.
|
||||
|
||||
La page Life-NOC affiche :
|
||||
|
||||
- le nom du suivi ;
|
||||
- son état ;
|
||||
- la dernière valeur enregistrée ;
|
||||
- les notes ;
|
||||
- les instructions ;
|
||||
- un bouton pour marquer l’action comme faite.
|
||||
|
||||
## 4. Comment marquer une action comme faite
|
||||
|
||||
Quand l’item le permet, il suffit de cliquer sur **Compléter**.
|
||||
|
||||
Cela met à jour la valeur de l’intrant avec la date du jour.
|
||||
|
||||
## 5. À quoi servent les liens utiles
|
||||
|
||||
- **Notes** : pour comprendre le contexte ;
|
||||
- **Instructions** : pour savoir quoi faire ;
|
||||
- **Action** : pour aller directement au bon outil ou à la bonne page.
|
||||
|
||||
## 6. Ce que l’usager n’a pas besoin de savoir
|
||||
|
||||
L’usager n’a normalement pas besoin de comprendre :
|
||||
|
||||
- les fichiers YAML ;
|
||||
- le moteur de sonde ;
|
||||
- l’architecture technique ;
|
||||
- le fonctionnement interne d’Icinga.
|
||||
|
||||
Il lui suffit de :
|
||||
|
||||
- voir l’état ;
|
||||
- consulter les instructions ;
|
||||
- marquer l’action effectuée.
|
||||
|
||||
## 7. QR codes — direction prévue
|
||||
|
||||
Life-NOC est conçu pour permettre l’usage de QR codes pointant vers :
|
||||
|
||||
```text
|
||||
/life-noc/item/<domaine>/<item_key>
|
||||
```
|
||||
|
||||
Le scan permettra :
|
||||
|
||||
- d’ouvrir directement l’item ;
|
||||
- de lire les instructions ;
|
||||
- de confirmer l’action ;
|
||||
- de mettre à jour le système facilement.
|
||||
734
docs/life_noc_documentation_pack.md
Normal file
734
docs/life_noc_documentation_pack.md
Normal file
|
|
@ -0,0 +1,734 @@
|
|||
# Life-NOC — Documentation complète
|
||||
|
||||
## 1. Présentation générale
|
||||
|
||||
### 1.1 Définition
|
||||
|
||||
**Life-NOC** est un système de pilotage personnel qui applique à la vie réelle la logique d’un **NOC** (Network Operations Center / centre d’opérations).
|
||||
|
||||
Son but n’est pas d’automatiser la vie à la place de la personne.
|
||||
Son but est de :
|
||||
|
||||
- rendre visibles les suivis importants ;
|
||||
- transformer la charge mentale en état observable ;
|
||||
- soutenir la mémoire prospective ;
|
||||
- orienter l’attention vers ce qui mérite réellement d’être vu ;
|
||||
- réduire la friction entre la prise de conscience et l’action.
|
||||
|
||||
Life-NOC peut être résumé ainsi :
|
||||
|
||||
> **Voir clair, prioriser juste, agir au bon endroit.**
|
||||
|
||||
---
|
||||
|
||||
### 1.2 Finalité
|
||||
|
||||
Life-NOC sert à superviser des éléments de la vie personnelle, domestique, administrative, technique ou communautaire comme s’il s’agissait de services critiques dans une salle de contrôle.
|
||||
|
||||
Il permet par exemple de suivre :
|
||||
|
||||
- des revues périodiques ;
|
||||
- des échéances ;
|
||||
- des stocks ;
|
||||
- des vérifications techniques ;
|
||||
- des obligations administratives ;
|
||||
- des contrôles de maintenance ;
|
||||
- des routines de résilience ;
|
||||
- des points d’attention dans l’environnement physique.
|
||||
|
||||
---
|
||||
|
||||
### 1.3 Positionnement
|
||||
|
||||
Life-NOC n’est pas :
|
||||
|
||||
- un simple gestionnaire de tâches ;
|
||||
- un agenda ;
|
||||
- un ERP ;
|
||||
- un moteur d’automatisation généraliste ;
|
||||
- un outil d’inventaire pur.
|
||||
|
||||
Life-NOC est :
|
||||
|
||||
- un **système de supervision attentionnelle** ;
|
||||
- un **cadre d’évaluation de suivis** ;
|
||||
- un **point de convergence** entre intrants, règles, états et actions ;
|
||||
- une **interface de réduction de charge mentale**.
|
||||
|
||||
---
|
||||
|
||||
## 2. Principes de fonctionnement
|
||||
|
||||
### 2.1 Séparation des couches
|
||||
|
||||
Life-NOC repose sur quatre couches distinctes :
|
||||
|
||||
1. **définition** ;
|
||||
2. **ingestion** ;
|
||||
3. **persistance** ;
|
||||
4. **évaluation**.
|
||||
|
||||
#### Définition
|
||||
Contient les items à superviser, les méthodes, les seuils, les notes et les liens utiles.
|
||||
|
||||
#### Ingestion
|
||||
Contient les mécanismes par lesquels une donnée entre dans le système :
|
||||
- saisie manuelle ;
|
||||
- API ;
|
||||
- page HTML ;
|
||||
- QR code ;
|
||||
- plus tard MQTT, GUI avancée, etc.
|
||||
|
||||
#### Persistance
|
||||
Contient les intrants vivants à jour.
|
||||
|
||||
#### Évaluation
|
||||
Contient la logique qui transforme un intrant en état Life-NOC.
|
||||
|
||||
---
|
||||
|
||||
### 2.2 Philosophie générale
|
||||
|
||||
Le système suit cette logique :
|
||||
|
||||
- le **domaine** organise ;
|
||||
- la **méthode** évalue ;
|
||||
- l’**item** fait le lien entre les deux ;
|
||||
- l’**intrant** fournit la valeur vivante ;
|
||||
- la **page item** réduit la friction d’action ;
|
||||
- **Icinga** rend les états visibles dans un cadre de supervision.
|
||||
|
||||
---
|
||||
|
||||
## 3. États Life-NOC
|
||||
|
||||
Life-NOC utilise une sémantique propre des états.
|
||||
|
||||
### 3.1 États
|
||||
|
||||
- **UNKNOWN** : pas encore dû, pas encore à faire ;
|
||||
- **OK** : actionnable maintenant ;
|
||||
- **WARNING** : il faut se presser ;
|
||||
- **CRITICAL** : en retard, anormal, ou impossible à évaluer.
|
||||
|
||||
### 3.2 Différence avec l’usage classique de Nagios/Icinga
|
||||
|
||||
Dans Life-NOC :
|
||||
|
||||
- le vert ne signifie pas seulement « tout va bien » ;
|
||||
- le vert signifie souvent « c’est le bon moment pour agir » ;
|
||||
- le gris signifie que l’item n’est pas encore entré dans sa fenêtre d’action.
|
||||
|
||||
### 3.3 Politique d’erreur
|
||||
|
||||
Par défaut, si le système ne peut pas conclure techniquement, il retourne **CRITICAL**.
|
||||
|
||||
Exemples :
|
||||
|
||||
- fichier introuvable ;
|
||||
- donnée absente ;
|
||||
- format invalide ;
|
||||
- parsing impossible ;
|
||||
- seuil incohérent ;
|
||||
- type de sonde non pris en charge.
|
||||
|
||||
Cette politique force la correction des faux positifs techniques plutôt que leur invisibilisation.
|
||||
|
||||
---
|
||||
|
||||
## 4. Organisation métier par domaines
|
||||
|
||||
Life-NOC regroupe les items dans des **domaines**.
|
||||
|
||||
Exemples de domaines :
|
||||
|
||||
- revue ;
|
||||
- focus ;
|
||||
- finances-personnelles ;
|
||||
- fiscalite-personnelle ;
|
||||
- obligations-legales-personnelles ;
|
||||
- maison ;
|
||||
- garage-et-rangement ;
|
||||
- energie ;
|
||||
- resilience ;
|
||||
- stock-alimentaire ;
|
||||
- sante ;
|
||||
- voiture ;
|
||||
- jardin ;
|
||||
- informatique-personnelle ;
|
||||
- infrastructure-chezlepro ;
|
||||
- reseau-chezlepro ;
|
||||
- securite-chezlepro ;
|
||||
- exploitation-chezlepro ;
|
||||
- projets ;
|
||||
- communaute ;
|
||||
- documentation ;
|
||||
- animaux.
|
||||
|
||||
Le domaine est une unité d’organisation métier, pas nécessairement une unité de calcul.
|
||||
|
||||
Un même domaine peut contenir plusieurs méthodes de sonde.
|
||||
|
||||
---
|
||||
|
||||
## 5. Taxonomie des méthodes de sonde
|
||||
|
||||
Le modèle conceptuel v1 de Life-NOC prévoit cinq méthodes principales.
|
||||
|
||||
### 5.1 elapsed_time
|
||||
|
||||
Mesure le temps écoulé depuis un événement ou une exécution précédente.
|
||||
|
||||
Exemples :
|
||||
- revue hebdomadaire ;
|
||||
- inspection trimestrielle ;
|
||||
- test périodique.
|
||||
|
||||
Intrant attendu :
|
||||
- date de dernière exécution.
|
||||
|
||||
Unité typique :
|
||||
- jours.
|
||||
|
||||
---
|
||||
|
||||
### 5.2 days_until_due
|
||||
|
||||
Mesure le temps restant avant une échéance fixe.
|
||||
|
||||
Exemples :
|
||||
- renouvellement du permis ;
|
||||
- passeport ;
|
||||
- assurance ;
|
||||
- obligation légale.
|
||||
|
||||
Intrant attendu :
|
||||
- date d’échéance.
|
||||
|
||||
Unité typique :
|
||||
- jours.
|
||||
|
||||
---
|
||||
|
||||
### 5.3 elapsed_distance
|
||||
|
||||
Mesure la distance écoulée depuis une action passée.
|
||||
|
||||
Exemples :
|
||||
- vidange ;
|
||||
- entretien pneus ;
|
||||
- entretien freins.
|
||||
|
||||
Intrants attendus :
|
||||
- compteur courant ;
|
||||
- compteur au dernier entretien.
|
||||
|
||||
Unité typique :
|
||||
- kilomètres.
|
||||
|
||||
---
|
||||
|
||||
### 5.4 current_value
|
||||
|
||||
Évalue une valeur instantanée contre des seuils.
|
||||
|
||||
Exemples :
|
||||
- tension batterie ;
|
||||
- température ;
|
||||
- humidité ;
|
||||
- espace libre.
|
||||
|
||||
Intrant attendu :
|
||||
- valeur actuelle.
|
||||
|
||||
Unité typique :
|
||||
- variable selon le cas.
|
||||
|
||||
---
|
||||
|
||||
### 5.5 remaining_quantity
|
||||
|
||||
Évalue ce qu’il reste d’un stock ou d’une réserve.
|
||||
|
||||
Exemples :
|
||||
- nourriture chats ;
|
||||
- réserve d’eau ;
|
||||
- carburant ;
|
||||
- consommables.
|
||||
|
||||
Intrant attendu :
|
||||
- quantité restante.
|
||||
|
||||
Unité typique :
|
||||
- jours, litres, unités, pourcentage, etc.
|
||||
|
||||
---
|
||||
|
||||
## 6. Portée actuellement validée
|
||||
|
||||
Au stade actuel, les méthodes réellement validées dans le système sont :
|
||||
|
||||
- `elapsed_time` ;
|
||||
- `days_until_due`.
|
||||
|
||||
Les autres méthodes sont conceptuellement définies, mais pas encore consolidées de la même manière dans le dépôt.
|
||||
|
||||
---
|
||||
|
||||
## 7. Définition des items
|
||||
|
||||
Les items supervisés sont définis dans :
|
||||
|
||||
```text
|
||||
domains.yaml
|
||||
```
|
||||
|
||||
Chaque item peut contenir :
|
||||
|
||||
- `name` ;
|
||||
- `date` ;
|
||||
- `notes` ;
|
||||
- `notes_url` ;
|
||||
- `instructions_url` ;
|
||||
- `action_url` ;
|
||||
- `probe` ;
|
||||
- `thresholds` ;
|
||||
- `policy`.
|
||||
|
||||
### 7.1 Rôle des champs descriptifs
|
||||
|
||||
- `notes` : résumé humain court ;
|
||||
- `notes_url` : contexte / référence ;
|
||||
- `instructions_url` : quoi faire / procédure ;
|
||||
- `action_url` : où agir concrètement.
|
||||
|
||||
### 7.2 Champ probe
|
||||
|
||||
Le champ `probe` décrit :
|
||||
|
||||
- la méthode ;
|
||||
- la source ;
|
||||
- l’unité ;
|
||||
- les seuils ;
|
||||
- la politique d’erreur.
|
||||
|
||||
Exemple :
|
||||
|
||||
```yaml
|
||||
probe:
|
||||
type: elapsed_time
|
||||
source:
|
||||
type: manual_date
|
||||
inputs_file: "/opt/life-noc/data/inputs/revue.yaml"
|
||||
item_key: "revue-hebdomadaire-priorites"
|
||||
metric:
|
||||
unit: days
|
||||
thresholds:
|
||||
unknown_lt: 5
|
||||
ok_gte: 5
|
||||
warning_gte: 7
|
||||
critical_gte: 10
|
||||
policy:
|
||||
on_error: critical
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Store des intrants
|
||||
|
||||
### 8.1 Principe
|
||||
|
||||
Les intrants vivants ne sont pas mélangés à la définition des items.
|
||||
|
||||
Ils sont stockés sous :
|
||||
|
||||
```text
|
||||
data/inputs/<domaine>.yaml
|
||||
```
|
||||
|
||||
Exemples :
|
||||
|
||||
- `data/inputs/revue.yaml`
|
||||
- `data/inputs/obligations-legales-personnelles.yaml`
|
||||
|
||||
### 8.2 Contenu minimal d’un intrant
|
||||
|
||||
Un intrant contient en général :
|
||||
|
||||
- `value` ;
|
||||
- `captured_at` ;
|
||||
- `origin`.
|
||||
|
||||
Exemple :
|
||||
|
||||
```yaml
|
||||
revue-hebdomadaire-priorites:
|
||||
value: "2026-03-14"
|
||||
captured_at: "2026-03-14T23:16:41Z"
|
||||
origin: manual
|
||||
```
|
||||
|
||||
### 8.3 Rôle du store
|
||||
|
||||
Le store d’intrants permet :
|
||||
|
||||
- de changer une valeur sans toucher à `domains.yaml` ;
|
||||
- d’alimenter les sondes avec des valeurs vivantes ;
|
||||
- de préparer les futures interfaces GUI, API, QR et autres.
|
||||
|
||||
---
|
||||
|
||||
## 9. CLI de gestion des intrants
|
||||
|
||||
Life-NOC dispose d’une CLI de gestion des intrants.
|
||||
|
||||
### 9.1 Commandes principales
|
||||
|
||||
- `list`
|
||||
- `get`
|
||||
- `set`
|
||||
- `complete`
|
||||
|
||||
### 9.2 Exemples
|
||||
|
||||
```bash
|
||||
life-noc-input list revue
|
||||
life-noc-input get revue revue-hebdomadaire-priorites
|
||||
life-noc-input set revue revue-hebdomadaire-priorites 2026-03-14
|
||||
life-noc-input complete revue revue-hebdomadaire-priorites
|
||||
```
|
||||
|
||||
### 9.3 Rôle de complete
|
||||
|
||||
`complete` est particulièrement utile pour les items de type `elapsed_time/manual_date`.
|
||||
|
||||
Il inscrit automatiquement :
|
||||
|
||||
- `value = date du jour`
|
||||
- `captured_at = maintenant`
|
||||
- `origin = manual`
|
||||
|
||||
---
|
||||
|
||||
## 10. API locale des intrants
|
||||
|
||||
Life-NOC expose une API locale sur :
|
||||
|
||||
```text
|
||||
http://127.0.0.1:8787
|
||||
```
|
||||
|
||||
### 10.1 Endpoints JSON
|
||||
|
||||
- `GET /health`
|
||||
- `GET /inputs/{domain}`
|
||||
- `GET /inputs/{domain}/{item_key}`
|
||||
- `POST /inputs/{domain}/{item_key}`
|
||||
- `POST /inputs/{domain}/{item_key}/complete`
|
||||
|
||||
### 10.2 Exemple
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8787/health
|
||||
curl http://127.0.0.1:8787/inputs/revue
|
||||
curl http://127.0.0.1:8787/inputs/revue/revue-hebdomadaire-priorites
|
||||
curl -X POST http://127.0.0.1:8787/inputs/revue/revue-hebdomadaire-priorites \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"value":"2026-03-14","origin":"manual"}'
|
||||
```
|
||||
|
||||
### 10.3 Dépendances importantes
|
||||
|
||||
Le service FastAPI nécessite notamment :
|
||||
|
||||
- `python3-fastapi`
|
||||
- `python3-uvicorn`
|
||||
- `python3-multipart`
|
||||
|
||||
---
|
||||
|
||||
## 11. Pages HTML Life-NOC
|
||||
|
||||
Le serveur Life-NOC sert aussi des pages HTML simples destinées à l’action humaine.
|
||||
|
||||
### 11.1 URL d’item
|
||||
|
||||
Format :
|
||||
|
||||
```text
|
||||
/life-noc/item/<domaine>/<item_key>
|
||||
```
|
||||
|
||||
Exemple :
|
||||
|
||||
```text
|
||||
/life-noc/item/revue/revue-hebdomadaire-priorites
|
||||
```
|
||||
|
||||
### 11.2 Contenu de la page
|
||||
|
||||
La page affiche :
|
||||
|
||||
- titre humain ;
|
||||
- état actuel ;
|
||||
- type de sonde ;
|
||||
- dernier intrant ;
|
||||
- domaine ;
|
||||
- item key ;
|
||||
- notes ;
|
||||
- lien `notes_url` ;
|
||||
- lien `instructions_url` ;
|
||||
- lien `action_url` ;
|
||||
- bouton `Compléter`.
|
||||
|
||||
### 11.3 Route d’action HTML
|
||||
|
||||
Le bouton `Compléter` utilise :
|
||||
|
||||
```text
|
||||
POST /life-noc/item/<domaine>/<item_key>/complete
|
||||
```
|
||||
|
||||
Puis redirige vers la page de l’item.
|
||||
|
||||
---
|
||||
|
||||
## 12. Intégration Icinga
|
||||
|
||||
Life-NOC s’appuie sur Icinga 2 / Icinga Web 2 pour la visualisation des états supervisés.
|
||||
|
||||
### 12.1 Ce que le système sait faire
|
||||
|
||||
- déployer les définitions de services ;
|
||||
- exposer les custom variables ;
|
||||
- rendre les états lisibles dans Icinga ;
|
||||
- supporter `Check Now` ;
|
||||
- intégrer les BPM natifs ;
|
||||
- générer des servicegroups cohérents.
|
||||
|
||||
### 12.2 Informations visibles dans Icinga
|
||||
|
||||
Selon l’item, on peut voir notamment :
|
||||
|
||||
- l’état calculé ;
|
||||
- les variables de seuil ;
|
||||
- les variables de source ;
|
||||
- les liens utiles ;
|
||||
- `instructions_url` en variable personnalisée.
|
||||
|
||||
---
|
||||
|
||||
## 13. BPM et servicegroups
|
||||
|
||||
Life-NOC génère :
|
||||
|
||||
- des services Icinga ;
|
||||
- des groupes de services ;
|
||||
- une configuration BPM native.
|
||||
|
||||
L’objectif est de rendre visibles à la fois :
|
||||
|
||||
- les items unitaires ;
|
||||
- les regroupements par domaine ;
|
||||
- la vision d’ensemble hiérarchisée.
|
||||
|
||||
---
|
||||
|
||||
## 14. Flux de fonctionnement complet
|
||||
|
||||
Le fonctionnement complet suit le chemin suivant :
|
||||
|
||||
1. l’item est défini dans `domains.yaml` ;
|
||||
2. l’intrant vivant est stocké dans `data/inputs/<domaine>.yaml` ;
|
||||
3. la CLI, l’API ou la page HTML modifient cet intrant ;
|
||||
4. la sonde lit le store ;
|
||||
5. la sonde calcule l’état ;
|
||||
6. Icinga l’affiche ;
|
||||
7. l’usager agit ;
|
||||
8. l’intrant est mis à jour ;
|
||||
9. le cycle recommence.
|
||||
|
||||
---
|
||||
|
||||
## 15. Déploiement et reproductibilité
|
||||
|
||||
Le dépôt doit permettre de reproduire le système sans correctifs manuels cachés.
|
||||
|
||||
### 15.1 Principes
|
||||
|
||||
- les correctifs doivent vivre dans le dépôt ;
|
||||
- les dépendances nécessaires doivent être installées automatiquement ;
|
||||
- les scripts de chantier temporaires doivent être supprimés une fois les changements intégrés proprement.
|
||||
|
||||
### 15.2 Déploiement habituel
|
||||
|
||||
```bash
|
||||
make check
|
||||
make deploy-with-bpm
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 16. Documentation pour les usagers
|
||||
|
||||
# Guide usager Life-NOC
|
||||
|
||||
## 16.1 À quoi sert Life-NOC pour l’usager
|
||||
|
||||
Life-NOC aide une personne à voir rapidement ce qui mérite son attention, sans tout garder dans sa tête.
|
||||
|
||||
Il sert à suivre des choses comme :
|
||||
|
||||
- des revues régulières ;
|
||||
- des dates importantes ;
|
||||
- des entretiens ;
|
||||
- des vérifications ;
|
||||
- des obligations.
|
||||
|
||||
## 16.2 Ce que signifient les états
|
||||
|
||||
- **UNKNOWN** : pas encore le temps d’agir ;
|
||||
- **OK** : c’est le bon moment pour s’en occuper ;
|
||||
- **WARNING** : il faut accélérer ;
|
||||
- **CRITICAL** : c’est urgent ou il y a un problème.
|
||||
|
||||
## 16.3 Comment consulter un item
|
||||
|
||||
Un item peut être consulté :
|
||||
|
||||
- dans Icinga ;
|
||||
- via une page Life-NOC ;
|
||||
- plus tard via QR code.
|
||||
|
||||
La page Life-NOC affiche :
|
||||
|
||||
- le nom du suivi ;
|
||||
- son état ;
|
||||
- la dernière valeur enregistrée ;
|
||||
- les notes ;
|
||||
- les instructions ;
|
||||
- un bouton pour marquer l’action comme faite.
|
||||
|
||||
## 16.4 Comment marquer une action comme faite
|
||||
|
||||
Quand l’item le permet, il suffit de cliquer sur **Compléter**.
|
||||
|
||||
Cela met à jour la valeur de l’intrant avec la date du jour.
|
||||
|
||||
## 16.5 Quand utiliser les liens utiles
|
||||
|
||||
- **Notes** : pour comprendre le contexte ;
|
||||
- **Instructions** : pour savoir quoi faire ;
|
||||
- **Action** : pour aller directement au bon outil ou à la bonne page.
|
||||
|
||||
## 16.6 Ce que l’usager n’a pas besoin de faire
|
||||
|
||||
L’usager n’a normalement pas besoin de comprendre :
|
||||
|
||||
- le moteur de sonde ;
|
||||
- les fichiers YAML ;
|
||||
- la structure technique ;
|
||||
- l’architecture Icinga.
|
||||
|
||||
Il lui suffit de :
|
||||
|
||||
- voir l’état ;
|
||||
- consulter les instructions ;
|
||||
- marquer l’action effectuée.
|
||||
|
||||
---
|
||||
|
||||
## 17. Documentation d’exploitation
|
||||
|
||||
### 17.1 Vérifications utiles
|
||||
|
||||
#### Vérifier l’API
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8787/health
|
||||
```
|
||||
|
||||
#### Vérifier un intrant
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8787/inputs/revue/revue-hebdomadaire-priorites
|
||||
```
|
||||
|
||||
#### Vérifier une page item
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8787/life-noc/item/revue/revue-hebdomadaire-priorites
|
||||
```
|
||||
|
||||
### 17.2 Cas fréquent : l’intrant change mais pas l’état dans Icinga
|
||||
|
||||
Cela signifie souvent qu’Icinga n’a pas encore refait le check.
|
||||
|
||||
Il faut alors :
|
||||
|
||||
- lancer un `Check Now` ;
|
||||
- ou attendre le prochain check ;
|
||||
- ou tester directement le plugin à la main.
|
||||
|
||||
### 17.3 Cas fréquent : route HTML absente après déploiement
|
||||
|
||||
Vérifier :
|
||||
|
||||
- que le service API tourne ;
|
||||
- que le fichier déployé contient bien les routes HTML ;
|
||||
- que les dépendances FastAPI sont installées, notamment `python3-multipart`.
|
||||
|
||||
---
|
||||
|
||||
## 18. QR codes — direction prévue
|
||||
|
||||
Life-NOC est conçu pour pouvoir pointer des QR codes vers des pages item.
|
||||
|
||||
Format visé :
|
||||
|
||||
```text
|
||||
/life-noc/item/<domaine>/<item_key>
|
||||
```
|
||||
|
||||
Le scan permettrait :
|
||||
|
||||
- d’ouvrir l’item ;
|
||||
- de lire les instructions ;
|
||||
- de confirmer l’action ;
|
||||
- de mettre à jour le système facilement.
|
||||
|
||||
---
|
||||
|
||||
## 19. État actuel du projet
|
||||
|
||||
Le système a déjà validé en pratique :
|
||||
|
||||
- Icinga Web 2 fonctionnel ;
|
||||
- BPM natif fonctionnel ;
|
||||
- servicegroups fonctionnels ;
|
||||
- `Check Now` fonctionnel ;
|
||||
- store d’intrants séparé ;
|
||||
- CLI des intrants ;
|
||||
- API locale ;
|
||||
- pages HTML d’item ;
|
||||
- méthodes réelles `elapsed_time` et `days_until_due`.
|
||||
|
||||
---
|
||||
|
||||
## 20. Conclusion
|
||||
|
||||
Life-NOC dispose désormais d’un noyau opératoire réel.
|
||||
|
||||
Il ne s’agit plus seulement d’un concept ou d’une maquette.
|
||||
Le système sait déjà :
|
||||
|
||||
- définir des suivis ;
|
||||
- stocker des intrants ;
|
||||
- évaluer des états ;
|
||||
- exposer ces états ;
|
||||
- fournir des instructions ;
|
||||
- permettre l’action ;
|
||||
- réintégrer cette action dans la supervision.
|
||||
|
||||
C’est la base d’un véritable système de pilotage personnel orienté action.
|
||||
|
||||
657
docs/plan-demockage-life-noc.md
Normal file
657
docs/plan-demockage-life-noc.md
Normal file
|
|
@ -0,0 +1,657 @@
|
|||
# Plan de démockage Life-NOC
|
||||
|
||||
## 1. Objet
|
||||
|
||||
Ce document sert de plan directeur pour faire évoluer Life-NOC d’une preuve de concept partiellement mockée vers un système où **chaque item** :
|
||||
|
||||
- possède une **méthode réelle** ;
|
||||
- possède une **source d’intrants réelle** ;
|
||||
- possède une **page web canonique** ;
|
||||
- possède une **URL stable** ;
|
||||
- peut être **consulté**, **compris** et **renseigné** de manière interactive.
|
||||
|
||||
L’objectif final est :
|
||||
|
||||
> **1 item = 1 URL = 1 page = 1 logique = 1 source de vérité**
|
||||
|
||||
---
|
||||
|
||||
## 2. Principes retenus
|
||||
|
||||
### 2.1 Tout item doit être démocké
|
||||
|
||||
À terme, aucun item ne devrait dépendre d’un état mocké durablement.
|
||||
|
||||
Le mock a servi à :
|
||||
|
||||
- prouver l’architecture ;
|
||||
- faire exister la structure BPM et Icinga ;
|
||||
- valider les flux de déploiement ;
|
||||
- permettre une mise en place progressive.
|
||||
|
||||
Mais la cible est désormais :
|
||||
|
||||
- **zéro item purement mocké**.
|
||||
|
||||
### 2.2 Chaque item doit avoir sa page web
|
||||
|
||||
Chaque item doit avoir une URL canonique de la forme :
|
||||
|
||||
```text
|
||||
/life-noc/item/<domaine>/<item_key>
|
||||
```
|
||||
|
||||
Cette page doit devenir :
|
||||
|
||||
- la page d’information ;
|
||||
- la page d’instructions ;
|
||||
- la page d’action ;
|
||||
- la page de saisie des intrants.
|
||||
|
||||
### 2.3 La page web d’un item est l’instruction par défaut
|
||||
|
||||
Pour tout item :
|
||||
|
||||
- si `instructions_url` est défini, il surcharge ;
|
||||
- sinon, la page canonique de l’item est la page d’instructions implicite.
|
||||
|
||||
Règle :
|
||||
|
||||
```text
|
||||
instructions_url implicite = /life-noc/item/<domaine>/<item_key>
|
||||
```
|
||||
|
||||
### 2.4 Les domaines organisent, les méthodes évaluent
|
||||
|
||||
- le **domaine** organise les items par sens métier ;
|
||||
- la **méthode** exprime la logique de calcul ;
|
||||
- l’**item** relie domaine, méthode, intrant, UI et action.
|
||||
|
||||
Donc :
|
||||
|
||||
- plusieurs items d’un même domaine peuvent utiliser des méthodes différentes ;
|
||||
- plusieurs domaines peuvent réutiliser la même méthode.
|
||||
|
||||
---
|
||||
|
||||
## 3. Méthodes de sonde cibles
|
||||
|
||||
### 3.1 Méthodes déjà validées
|
||||
|
||||
#### `elapsed_time`
|
||||
Mesure le temps écoulé depuis une dernière exécution.
|
||||
|
||||
#### `days_until_due`
|
||||
Mesure le temps restant avant une échéance fixe.
|
||||
|
||||
### 3.2 Méthodes encore à industrialiser
|
||||
|
||||
#### `elapsed_distance`
|
||||
Mesure une distance écoulée depuis une action passée.
|
||||
|
||||
#### `current_value`
|
||||
Évalue une valeur instantanée contre des seuils.
|
||||
|
||||
#### `remaining_quantity`
|
||||
Évalue une quantité restante contre des seuils.
|
||||
|
||||
---
|
||||
|
||||
## 4. Types d’intrants cibles
|
||||
|
||||
Les intrants vivants continueront d’être stockés dans :
|
||||
|
||||
```text
|
||||
data/inputs/<domaine>.yaml
|
||||
```
|
||||
|
||||
Les types principaux d’intrants à supporter sont :
|
||||
|
||||
- `manual_date`
|
||||
- `manual_counter`
|
||||
- `manual_value`
|
||||
|
||||
À terme, d’autres sources pourront exister, mais le démockage initial se concentre sur les intrants simples et robustes.
|
||||
|
||||
---
|
||||
|
||||
## 5. Formulaires web cibles
|
||||
|
||||
Chaque item doit pouvoir afficher un formulaire adapté à son type réel.
|
||||
|
||||
### 5.1 `complete_date`
|
||||
Pour les items de type `elapsed_time` avec saisie de date de dernière exécution.
|
||||
|
||||
Exemples :
|
||||
- revue périodique ;
|
||||
- inspection ;
|
||||
- test ;
|
||||
- vérification périodique.
|
||||
|
||||
Fonctions attendues :
|
||||
- bouton `Compléter`
|
||||
- saisie manuelle d’une date
|
||||
- bouton `Aujourd’hui`
|
||||
|
||||
### 5.2 `due_date`
|
||||
Pour les items de type `days_until_due`.
|
||||
|
||||
Exemples :
|
||||
- permis ;
|
||||
- assurance ;
|
||||
- passeport ;
|
||||
- échéance administrative.
|
||||
|
||||
Fonctions attendues :
|
||||
- saisie d’une date d’échéance
|
||||
- bouton `Enregistrer`
|
||||
|
||||
### 5.3 `counter_pair`
|
||||
Pour les items de type `elapsed_distance`.
|
||||
|
||||
Exemples :
|
||||
- huile moteur ;
|
||||
- pneus ;
|
||||
- freins ;
|
||||
- timing belt.
|
||||
|
||||
Fonctions attendues :
|
||||
- compteur courant
|
||||
- compteur au dernier entretien
|
||||
- bouton `Enregistrer`
|
||||
|
||||
### 5.4 `numeric_value`
|
||||
Pour les items de type `current_value`.
|
||||
|
||||
Exemples :
|
||||
- tension batterie
|
||||
- capacité libre
|
||||
- température
|
||||
- mesure technique
|
||||
|
||||
Fonctions attendues :
|
||||
- saisie numérique
|
||||
- unité affichée
|
||||
- bouton `Enregistrer`
|
||||
|
||||
### 5.5 `remaining_quantity`
|
||||
Pour les items de type `remaining_quantity`.
|
||||
|
||||
Exemples :
|
||||
- réserve d’eau
|
||||
- stock nourriture chats
|
||||
- stock consommables
|
||||
- carburant
|
||||
|
||||
Fonctions attendues :
|
||||
- quantité restante
|
||||
- unité
|
||||
- bouton `Enregistrer`
|
||||
|
||||
---
|
||||
|
||||
## 6. Modèle cible d’un item réel
|
||||
|
||||
Le modèle canonique minimal d’un item réel devrait converger vers ceci :
|
||||
|
||||
```yaml
|
||||
- name: remplacement-filtre-fournaise
|
||||
title: "Remplacement du filtre de la fournaise"
|
||||
summary: "Suivi périodique du filtre principal."
|
||||
notes: "À faire selon la fréquence d’usage et la saison."
|
||||
notes_url: ""
|
||||
instructions: |
|
||||
1. Couper le système si nécessaire.
|
||||
2. Retirer le filtre usagé.
|
||||
3. Vérifier le sens du flux d’air.
|
||||
4. Installer le nouveau filtre.
|
||||
5. Confirmer la date dans Life-NOC.
|
||||
instructions_url: ""
|
||||
action_url: ""
|
||||
probe:
|
||||
type: elapsed_time
|
||||
source:
|
||||
type: manual_date
|
||||
inputs_file: "/opt/life-noc/data/inputs/maison.yaml"
|
||||
item_key: "remplacement-filtre-fournaise"
|
||||
metric:
|
||||
unit: days
|
||||
thresholds:
|
||||
unknown_lt: 30
|
||||
ok_gte: 30
|
||||
warning_gte: 60
|
||||
critical_gte: 90
|
||||
policy:
|
||||
on_error: critical
|
||||
ui:
|
||||
form_mode: complete_date
|
||||
allow_complete: true
|
||||
allow_manual_edit: true
|
||||
```
|
||||
|
||||
Tous les champs ne seront pas obligatoires immédiatement, mais cette structure donne la direction.
|
||||
|
||||
---
|
||||
|
||||
## 7. Tableau de migration
|
||||
|
||||
## 7.1 REVUE
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| revue-quotidienne-life-noc | elapsed_time | manual_date | complete_date | réel |
|
||||
| revue-hebdomadaire-priorites | elapsed_time | manual_date | complete_date | réel |
|
||||
| revue-mensuelle-systeme-vie | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revue-trimestrielle-orientation | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.2 FOCUS
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| entretien-processus-focus | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| nettoyage-inbox-mentale | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revue-limitation-engagements | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.3 FINANCES-PERSONNELLES
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| revision-comptes-bancaires | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-cartes-credit | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| paiement-cartes-credit | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revision-budget-personnel | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-prelevements-automatiques | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-placements | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-cotisations-reer | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-celi | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| preparation-dossier-financier-annuel | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.4 FISCALITE-PERSONNELLE
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| preparation-documents-impots | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| production-impots-federal | days_until_due / elapsed_time | manual_date | due_date / complete_date | à préciser |
|
||||
| production-impots-quebec | days_until_due / elapsed_time | manual_date | due_date / complete_date | à préciser |
|
||||
| paiement-solde-impots | days_until_due | manual_date | due_date | à migrer |
|
||||
| verification-avis-cotisation | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| archivage-documents-fiscaux | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-acomptes-provisionnels | days_until_due | manual_date | due_date | à migrer |
|
||||
|
||||
## 7.5 OBLIGATIONS-LEGALES-PERSONNELLES
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| verification-testament | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-mandat-inaptitude | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-directives-medicales | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-papiers-identite | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| renouvellement-permis-conduire | days_until_due | manual_date | due_date | réel |
|
||||
| verification-carte-assurance-maladie | days_until_due | manual_date | due_date | à migrer |
|
||||
| verification-passeport | days_until_due | manual_date | due_date | à migrer |
|
||||
|
||||
## 7.6 MAISON
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| remplacement-filtre-fournaise | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| inspection-fournaise | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| inspection-thermopompe | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| nettoyage-unites-exterieures | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| inspection-toiture | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| inspection-gouttieres | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| inspection-fondation | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-drainage-terrain | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| test-detecteurs-fumee | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| test-detecteurs-co | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| remplacement-piles-detecteurs | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-plomberie-visible | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| inspection-sump-pump | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-calfetrage | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| inspection-portes-garage | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-extincteurs | days_until_due / elapsed_time | manual_date | due_date / complete_date | à préciser |
|
||||
|
||||
## 7.7 GARAGE-ET-RANGEMENT
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| inspection-rangement-plafond | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revue-inventaire-garage | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-rouille-outillage | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| inspection-securite-garage | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| rotation-stockage-bacs | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.8 ENERGIE
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| inspection-batteries-lifepo4 | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-tension-batteries | current_value | manual_value | numeric_value | à migrer |
|
||||
| verification-smartshunt | current_value | manual_value | numeric_value | à préciser |
|
||||
| verification-cerbo-gx | elapsed_time / current_value | manual_date / manual_value | complete_date / numeric_value | à préciser |
|
||||
| verification-can-rs485 | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| inspection-cablage-energie | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-busbars | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-parametres-charge | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| test-charge-batteries | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| test-comportement-onduleur | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-journal-evenements-victron | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.9 RESILIENCE
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| test-generatrice-propane | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-carburant-generatrice | remaining_quantity | manual_value | remaining_quantity | à migrer |
|
||||
| verification-procedure-bascule | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-stock-lampes-piles | remaining_quantity | manual_value | remaining_quantity | à migrer |
|
||||
| verification-trousses-urgence | remaining_quantity / elapsed_time | manual_value / manual_date | remaining_quantity / complete_date | à préciser |
|
||||
| revision-plan-urgence | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| test-autonomie-base | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-moyens-cuisson-secours | remaining_quantity / elapsed_time | manual_value / manual_date | remaining_quantity / complete_date | à préciser |
|
||||
|
||||
## 7.10 STOCK-ALIMENTAIRE
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| rotation-nourriture-seche | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-reserve-eau | remaining_quantity | manual_value | remaining_quantity | à migrer |
|
||||
| verification-mylar-absorbeurs | remaining_quantity | manual_value | remaining_quantity | à migrer |
|
||||
| revue-inventaire-conserves | remaining_quantity | manual_value | remaining_quantity | à migrer |
|
||||
| revue-inventaire-farine-riz-pates | remaining_quantity | manual_value | remaining_quantity | à migrer |
|
||||
| verification-bacs-legumes-racines | remaining_quantity | manual_value | remaining_quantity | à migrer |
|
||||
| revue-supplements-vitamines | remaining_quantity | manual_value | remaining_quantity | à migrer |
|
||||
|
||||
## 7.11 SANTE
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| verification-trousse-premiers-soins | remaining_quantity / elapsed_time | manual_value / manual_date | remaining_quantity / complete_date | à préciser |
|
||||
| verification-expiration-medicaments | days_until_due | manual_date | due_date | à migrer |
|
||||
| revision-rendez-vous-medicaux | days_until_due | manual_date | due_date | à migrer |
|
||||
| verification-lunettes-prescriptions | days_until_due / elapsed_time | manual_date | due_date / complete_date | à préciser |
|
||||
| verification-dossier-sante | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.12 VOITURE
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| verification-huile-moteur | elapsed_distance | manual_counter | counter_pair | à migrer |
|
||||
| inspection-freins | elapsed_distance | manual_counter | counter_pair | à migrer |
|
||||
| verification-pneus | elapsed_distance | manual_counter | counter_pair | à migrer |
|
||||
| ajustement-valves | elapsed_distance / elapsed_time | manual_counter / manual_date | counter_pair / complete_date | à préciser |
|
||||
| verification-timing-belt | elapsed_distance | manual_counter | counter_pair | à migrer |
|
||||
| verification-batterie-voiture | current_value | manual_value | numeric_value | à migrer |
|
||||
| verification-balais-essuie-glace | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-liquides | current_value / elapsed_time | manual_value / manual_date | numeric_value / complete_date | à préciser |
|
||||
| verification-eclairage | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-immatriculation-assurance | days_until_due | manual_date | due_date | à migrer |
|
||||
|
||||
## 7.13 JARDIN
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| inspection-vignes | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| entretien-bleuetiers | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| entretien-framboisiers | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| inspection-kiwis-nordiques | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| entretien-rhubarbe | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| inspection-groseillier | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| inspection-muriers | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| entretien-houblon | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revision-pharmacopee-jardin | remaining_quantity | manual_value | remaining_quantity | à migrer |
|
||||
| revision-armoire-produits-jardin | remaining_quantity | manual_value | remaining_quantity | à migrer |
|
||||
|
||||
## 7.14 OUTILS-ET-EQUIPEMENTS
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| entretien-outils-jardin | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| inspection-outils-electriques | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-rallonges-et-connecteurs | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-compresseur-et-accessoires | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revision-inventaire-outillage | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.15 INFORMATIQUE-PERSONNELLE
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| verification-sauvegardes-personnelles | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| nettoyage-stockage-personnel | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-comptes-importants | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revue-mots-de-passe-personnels | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-documents-cloud-personnels | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.16 INFRASTRUCTURE-CHEZLEPRO
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| verification-proxmox | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-ceph | elapsed_time / current_value | manual_date / manual_value | complete_date / numeric_value | à préciser |
|
||||
| test-restauration-backups | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-pbs-truenas | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-ups-infrastructure | current_value | manual_value | numeric_value | à migrer |
|
||||
| verification-capacite-stockage | current_value | manual_value | numeric_value | à migrer |
|
||||
| verification-apt-cacher-ng | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-icinga2 | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-keycloak-openldap | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-nextcloud | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-mailcow | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-openvas | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-journaux-systemes | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.17 RESEAU-CHEZLEPRO
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| verification-firewalls | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-vpn-openvpn | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-crl-certificats | days_until_due / elapsed_time | manual_date | due_date / complete_date | à préciser |
|
||||
| verification-switches | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-vlans-segmentation | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-dns | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-dynamic-dns | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| audit-regles-firewall | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-geoblocking | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-certificats-publics | days_until_due | manual_date | due_date | à migrer |
|
||||
|
||||
## 7.18 SECURITE-CHEZLEPRO
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| verification-mises-a-jour-securite | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| audit-comptes-acces | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-ids-snort | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revue-pki-privee | days_until_due / elapsed_time | manual_date | due_date / complete_date | à préciser |
|
||||
| revue-politiques-securite | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-sauvegardes-configuration | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.19 EXPLOITATION-CHEZLEPRO
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| revision-playbooks-ansible | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-inventaires-ansible | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revision-documentation-technique | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-procedures-reprise | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revue-capacite-ressources | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-jobs-automatises | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.20 OBLIGATIONS-CHEZLEPRO
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| verification-registraire-entreprise | days_until_due | manual_date | due_date | à migrer |
|
||||
| verification-declarations-taxes | days_until_due | manual_date | due_date | à migrer |
|
||||
| verification-dossier-comptable-entreprise | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-facturation-clients | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-paiements-fournisseurs | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-contrats-ententes | days_until_due / elapsed_time | manual_date | due_date / complete_date | à préciser |
|
||||
| verification-assurances-entreprise | days_until_due | manual_date | due_date | à migrer |
|
||||
| archivage-documents-entreprise | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.21 ACTIFS-CHEZLEPRO
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| revision-inventaire-materiel | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-amortissables | days_until_due / elapsed_time | manual_date | due_date / complete_date | à préciser |
|
||||
| verification-serveurs-et-composants | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-reserve-pieces | remaining_quantity | manual_value | remaining_quantity | à migrer |
|
||||
| revision-actifs-transferts | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.22 PROJETS
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| revision-life-noc | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revision-alliance-boreale | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revision-erplibre | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revision-semence-numerique | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revision-ortrux-1 | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revision-district16 | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.23 COMMUNAUTE
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| verification-outils-aa | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-espace-87-16 | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-salles-visio-groupes | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-depots-rapports-rsg | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revision-outils-communication-communaute | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.24 DOCUMENTATION
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| revue-docs-personnelles-importantes | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revue-wiki-technique | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| revue-base-connaissances | elapsed_time | manual_date | complete_date | à migrer |
|
||||
| verification-sauvegarde-docs-cles | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
## 7.25 ANIMAUX
|
||||
|
||||
| item_key | méthode cible | intrant | formulaire | statut |
|
||||
|---|---|---|---|---|
|
||||
| verification-stock-nourriture-chats | remaining_quantity | manual_value | remaining_quantity | à migrer |
|
||||
| verification-friandises-et-litiere | remaining_quantity | manual_value | remaining_quantity | à migrer |
|
||||
| revision-routine-soins-animaux | elapsed_time | manual_date | complete_date | à migrer |
|
||||
|
||||
---
|
||||
|
||||
## 8. Priorité de migration
|
||||
|
||||
### Vague 1 — tout ce qui est date simple
|
||||
Objectif :
|
||||
- finir `elapsed_time`
|
||||
- finir `days_until_due`
|
||||
|
||||
C’est la vague la plus simple, la plus rentable et la moins risquée.
|
||||
|
||||
### Vague 2 — voiture
|
||||
Objectif :
|
||||
- introduire `elapsed_distance`
|
||||
|
||||
### Vague 3 — stocks et réserves
|
||||
Objectif :
|
||||
- introduire `remaining_quantity`
|
||||
|
||||
### Vague 4 — mesures techniques
|
||||
Objectif :
|
||||
- introduire `current_value`
|
||||
|
||||
---
|
||||
|
||||
## 9. Pages web cibles
|
||||
|
||||
Chaque item doit converger vers une page web canonique :
|
||||
|
||||
```text
|
||||
/life-noc/item/<domaine>/<item_key>
|
||||
```
|
||||
|
||||
Cette page doit devenir :
|
||||
|
||||
- la fiche de contexte ;
|
||||
- la fiche d’instructions ;
|
||||
- la fiche d’action ;
|
||||
- la fiche de saisie des intrants.
|
||||
|
||||
### 9.1 Contenu minimal
|
||||
|
||||
- titre humain
|
||||
- état actuel
|
||||
- dernier intrant
|
||||
- résumé
|
||||
- notes
|
||||
- instructions
|
||||
- liens utiles
|
||||
- formulaire adapté
|
||||
- action disponible
|
||||
|
||||
### 9.2 Règle sur `instructions_url`
|
||||
|
||||
La page de l’item est la page d’instructions par défaut.
|
||||
|
||||
Règle :
|
||||
|
||||
- si `instructions_url` est explicite, on l’utilise ;
|
||||
- sinon, on considère implicitement :
|
||||
|
||||
```text
|
||||
/life-noc/item/<domaine>/<item_key>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Critère de fin de démockage
|
||||
|
||||
Le démockage d’un item sera considéré terminé quand :
|
||||
|
||||
- l’item possède un `probe` réel ;
|
||||
- l’item possède un intrant réel ;
|
||||
- l’item possède une page web opérationnelle ;
|
||||
- l’item possède un formulaire web adapté ;
|
||||
- l’item possède une URL canonique stable ;
|
||||
- l’état Icinga est calculé à partir du vrai store.
|
||||
|
||||
---
|
||||
|
||||
## 11. Stratégie de mise en œuvre
|
||||
|
||||
### Phase 1
|
||||
Finir toutes les migrations `elapsed_time` et `days_until_due`.
|
||||
|
||||
### Phase 2
|
||||
Faire évoluer la page item pour afficher :
|
||||
- `title`
|
||||
- `summary`
|
||||
- `instructions`
|
||||
- formulaire adapté au type d’intrant.
|
||||
|
||||
### Phase 3
|
||||
Ajouter les endpoints HTML de mise à jour interactive des intrants.
|
||||
|
||||
### Phase 4
|
||||
Introduire successivement :
|
||||
- `elapsed_distance`
|
||||
- `remaining_quantity`
|
||||
- `current_value`
|
||||
|
||||
### Phase 5
|
||||
Éliminer complètement les items mockés restants.
|
||||
|
||||
---
|
||||
|
||||
## 12. Conclusion
|
||||
|
||||
La cible Life-NOC retenue est désormais claire :
|
||||
|
||||
- **tout item doit être réel**
|
||||
- **tout item doit avoir sa page**
|
||||
- **tout item doit avoir son URL**
|
||||
- **tout item doit être renseignable**
|
||||
- **tout item doit pouvoir guider l’action**
|
||||
|
||||
Ce plan sert de carte de migration pour converger progressivement vers ce modèle.
|
||||
|
|
@ -21,6 +21,7 @@ domains:
|
|||
- name: revue-hebdomadaire-priorites
|
||||
date: '2026-03-10'
|
||||
notes: Revoir les priorités de la semaine
|
||||
instructions_url: "https://chezlepro.ca/life-noc/test-instructions"
|
||||
probe:
|
||||
type: elapsed_time
|
||||
source:
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "actifs-chezlepro-revision-inventaire-materiel" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ACTIFS-CHEZLEPRO" ]
|
||||
notes = "Revoir l'inventaire du matériel de Chezlepro"
|
||||
vars.instructions_url = "/life-noc/item/actifs-chezlepro/revision-inventaire-materiel"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "actifs-chezlepro-verification-amortissables" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ACTIFS-CHEZLEPRO" ]
|
||||
notes = "Vérifier le registre des biens amortissables"
|
||||
vars.instructions_url = "/life-noc/item/actifs-chezlepro/verification-amortissables"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "actifs-chezlepro-verification-serveurs-et-composants" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ACTIFS-CHEZLEPRO" ]
|
||||
notes = "Vérifier l'état des serveurs et composants matériels"
|
||||
vars.instructions_url = "/life-noc/item/actifs-chezlepro/verification-serveurs-et-composants"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "actifs-chezlepro-verification-reserve-pieces" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ACTIFS-CHEZLEPRO" ]
|
||||
notes = "Vérifier les pièces de rechange critiques"
|
||||
vars.instructions_url = "/life-noc/item/actifs-chezlepro/verification-reserve-pieces"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,5 +55,6 @@ apply Service "actifs-chezlepro-revision-actifs-transferts" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ACTIFS-CHEZLEPRO" ]
|
||||
notes = "Réviser les actifs transférés ou à transférer à l'entreprise"
|
||||
vars.instructions_url = "/life-noc/item/actifs-chezlepro/revision-actifs-transferts"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "animaux-verification-stock-nourriture-chats" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ANIMAUX" ]
|
||||
notes = "Vérification du stock de nourriture pour chats"
|
||||
vars.instructions_url = "/life-noc/item/animaux/verification-stock-nourriture-chats"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "animaux-verification-friandises-et-litiere" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ANIMAUX" ]
|
||||
notes = "Vérification des stocks de friandises et de litière"
|
||||
vars.instructions_url = "/life-noc/item/animaux/verification-friandises-et-litiere"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,5 +33,6 @@ apply Service "animaux-revision-routine-soins-animaux" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ANIMAUX" ]
|
||||
notes = "Revue de la routine de soins et des besoins matériels des chats"
|
||||
vars.instructions_url = "/life-noc/item/animaux/revision-routine-soins-animaux"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "communaute-verification-outils-aa" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "COMMUNAUTE" ]
|
||||
notes = "Vérifier les outils numériques liés aux activités communautaires"
|
||||
vars.instructions_url = "/life-noc/item/communaute/verification-outils-aa"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "communaute-verification-espace-87-16" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "COMMUNAUTE" ]
|
||||
notes = "Vérifier l'espace Nextcloud du district"
|
||||
vars.instructions_url = "/life-noc/item/communaute/verification-espace-87-16"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "communaute-verification-salles-visio-groupes" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "COMMUNAUTE" ]
|
||||
notes = "Vérifier les salles de visioconférence des groupes"
|
||||
vars.instructions_url = "/life-noc/item/communaute/verification-salles-visio-groupes"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "communaute-verification-depots-rapports-rsg" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "COMMUNAUTE" ]
|
||||
notes = "Vérifier les dépôts de rapports RSG"
|
||||
vars.instructions_url = "/life-noc/item/communaute/verification-depots-rapports-rsg"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,5 +55,6 @@ apply Service "communaute-revision-outils-communication-communaute" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "COMMUNAUTE" ]
|
||||
notes = "Réviser les moyens de communication communautaires"
|
||||
vars.instructions_url = "/life-noc/item/communaute/revision-outils-communication-communaute"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "documentation-revue-docs-personnelles-importantes" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "DOCUMENTATION" ]
|
||||
notes = "Revoir l'organisation des documents personnels importants"
|
||||
vars.instructions_url = "/life-noc/item/documentation/revue-docs-personnelles-importantes"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "documentation-revue-wiki-technique" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "DOCUMENTATION" ]
|
||||
notes = "Revoir le wiki technique et sa cohérence"
|
||||
vars.instructions_url = "/life-noc/item/documentation/revue-wiki-technique"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "documentation-revue-base-connaissances" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "DOCUMENTATION" ]
|
||||
notes = "Revoir la base de connaissances globale"
|
||||
vars.instructions_url = "/life-noc/item/documentation/revue-base-connaissances"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,5 +44,6 @@ apply Service "documentation-verification-sauvegarde-docs-cles" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "DOCUMENTATION" ]
|
||||
notes = "Vérifier la sauvegarde des documents clés"
|
||||
vars.instructions_url = "/life-noc/item/documentation/verification-sauvegarde-docs-cles"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "energie-inspection-batteries-lifepo4" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ENERGIE" ]
|
||||
notes = "Inspection physique et logique des batteries LiFePO4"
|
||||
vars.instructions_url = "/life-noc/item/energie/inspection-batteries-lifepo4"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "energie-verification-tension-batteries" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ENERGIE" ]
|
||||
notes = "Vérification des tensions et cohérence des batteries"
|
||||
vars.instructions_url = "/life-noc/item/energie/verification-tension-batteries"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "energie-verification-smartshunt" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ENERGIE" ]
|
||||
notes = "Vérification SmartShunt et cohérence du monitoring"
|
||||
vars.instructions_url = "/life-noc/item/energie/verification-smartshunt"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "energie-verification-cerbo-gx" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ENERGIE" ]
|
||||
notes = "Vérification Cerbo GX et remontée des données"
|
||||
vars.instructions_url = "/life-noc/item/energie/verification-cerbo-gx"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "energie-verification-can-rs485" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ENERGIE" ]
|
||||
notes = "Vérification des communications CAN ou RS485"
|
||||
vars.instructions_url = "/life-noc/item/energie/verification-can-rs485"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +66,7 @@ apply Service "energie-inspection-cablage-energie" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ENERGIE" ]
|
||||
notes = "Inspection du câblage et des connexions énergétiques"
|
||||
vars.instructions_url = "/life-noc/item/energie/inspection-cablage-energie"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +77,7 @@ apply Service "energie-verification-busbars" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ENERGIE" ]
|
||||
notes = "Vérification du serrage, corrosion et échauffement des busbars"
|
||||
vars.instructions_url = "/life-noc/item/energie/verification-busbars"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +88,7 @@ apply Service "energie-verification-parametres-charge" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ENERGIE" ]
|
||||
notes = "Vérification des paramètres de charge et float"
|
||||
vars.instructions_url = "/life-noc/item/energie/verification-parametres-charge"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +99,7 @@ apply Service "energie-test-charge-batteries" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ENERGIE" ]
|
||||
notes = "Test de comportement en charge des batteries"
|
||||
vars.instructions_url = "/life-noc/item/energie/test-charge-batteries"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -101,6 +110,7 @@ apply Service "energie-test-comportement-onduleur" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ENERGIE" ]
|
||||
notes = "Vérifier le comportement du Multiplus sous charge légère"
|
||||
vars.instructions_url = "/life-noc/item/energie/test-comportement-onduleur"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -111,5 +121,6 @@ apply Service "energie-verification-journal-evenements-victron" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "ENERGIE" ]
|
||||
notes = "Vérification des événements et anomalies Victron"
|
||||
vars.instructions_url = "/life-noc/item/energie/verification-journal-evenements-victron"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "exploitation-chezlepro-revision-playbooks-ansible" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "EXPLOITATION-CHEZLEPRO" ]
|
||||
notes = "Revue des playbooks Ansible"
|
||||
vars.instructions_url = "/life-noc/item/exploitation-chezlepro/revision-playbooks-ansible"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "exploitation-chezlepro-verification-inventaires-ansible" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "EXPLOITATION-CHEZLEPRO" ]
|
||||
notes = "Vérification des inventaires Ansible"
|
||||
vars.instructions_url = "/life-noc/item/exploitation-chezlepro/verification-inventaires-ansible"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "exploitation-chezlepro-revision-documentation-technique" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "EXPLOITATION-CHEZLEPRO" ]
|
||||
notes = "Revue de la documentation technique Chezlepro"
|
||||
vars.instructions_url = "/life-noc/item/exploitation-chezlepro/revision-documentation-technique"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "exploitation-chezlepro-verification-procedures-reprise" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "EXPLOITATION-CHEZLEPRO" ]
|
||||
notes = "Vérifier les procédures de reprise et restauration"
|
||||
vars.instructions_url = "/life-noc/item/exploitation-chezlepro/verification-procedures-reprise"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "exploitation-chezlepro-revue-capacite-ressources" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "EXPLOITATION-CHEZLEPRO" ]
|
||||
notes = "Revue CPU RAM stockage et charge de l'infrastructure"
|
||||
vars.instructions_url = "/life-noc/item/exploitation-chezlepro/revue-capacite-ressources"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,5 +66,6 @@ apply Service "exploitation-chezlepro-verification-jobs-automatises" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "EXPLOITATION-CHEZLEPRO" ]
|
||||
notes = "Vérification des jobs automatisés et scripts périodiques"
|
||||
vars.instructions_url = "/life-noc/item/exploitation-chezlepro/verification-jobs-automatises"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "finances-personnelles-revision-comptes-bancaires" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FINANCES-PERSONNELLES" ]
|
||||
notes = "Révision mensuelle des comptes bancaires personnels"
|
||||
vars.instructions_url = "/life-noc/item/finances-personnelles/revision-comptes-bancaires"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "finances-personnelles-verification-cartes-credit" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FINANCES-PERSONNELLES" ]
|
||||
notes = "Vérification des soldes et transactions des cartes de crédit"
|
||||
vars.instructions_url = "/life-noc/item/finances-personnelles/verification-cartes-credit"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "finances-personnelles-paiement-cartes-credit" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FINANCES-PERSONNELLES" ]
|
||||
notes = "Paiement des cartes de crédit personnelles"
|
||||
vars.instructions_url = "/life-noc/item/finances-personnelles/paiement-cartes-credit"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "finances-personnelles-revision-budget-personnel" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FINANCES-PERSONNELLES" ]
|
||||
notes = "Révision mensuelle du budget personnel"
|
||||
vars.instructions_url = "/life-noc/item/finances-personnelles/revision-budget-personnel"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "finances-personnelles-verification-prelevements-automatiques" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FINANCES-PERSONNELLES" ]
|
||||
notes = "Vérification des prélèvements automatiques personnels"
|
||||
vars.instructions_url = "/life-noc/item/finances-personnelles/verification-prelevements-automatiques"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +66,7 @@ apply Service "finances-personnelles-verification-placements" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FINANCES-PERSONNELLES" ]
|
||||
notes = "Vérification périodique des placements et comptes enregistrés"
|
||||
vars.instructions_url = "/life-noc/item/finances-personnelles/verification-placements"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +77,7 @@ apply Service "finances-personnelles-verification-cotisations-reer" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FINANCES-PERSONNELLES" ]
|
||||
notes = "Vérification des cotisations REER"
|
||||
vars.instructions_url = "/life-noc/item/finances-personnelles/verification-cotisations-reer"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +88,7 @@ apply Service "finances-personnelles-verification-celi" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FINANCES-PERSONNELLES" ]
|
||||
notes = "Vérification de l'espace CELI et de son utilisation"
|
||||
vars.instructions_url = "/life-noc/item/finances-personnelles/verification-celi"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -91,5 +99,6 @@ apply Service "finances-personnelles-preparation-dossier-financier-annuel" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FINANCES-PERSONNELLES" ]
|
||||
notes = "Préparer le dossier financier annuel personnel"
|
||||
vars.instructions_url = "/life-noc/item/finances-personnelles/preparation-dossier-financier-annuel"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "fiscalite-personnelle-preparation-documents-impots" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FISCALITE-PERSONNELLE" ]
|
||||
notes = "Rassembler tous les documents fiscaux personnels"
|
||||
vars.instructions_url = "/life-noc/item/fiscalite-personnelle/preparation-documents-impots"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "fiscalite-personnelle-production-impots-federal" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FISCALITE-PERSONNELLE" ]
|
||||
notes = "Produire la déclaration de revenus fédérale"
|
||||
vars.instructions_url = "/life-noc/item/fiscalite-personnelle/production-impots-federal"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "fiscalite-personnelle-production-impots-quebec" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FISCALITE-PERSONNELLE" ]
|
||||
notes = "Produire la déclaration de revenus Québec"
|
||||
vars.instructions_url = "/life-noc/item/fiscalite-personnelle/production-impots-quebec"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "fiscalite-personnelle-paiement-solde-impots" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FISCALITE-PERSONNELLE" ]
|
||||
notes = "Payer tout solde d'impôt exigible"
|
||||
vars.instructions_url = "/life-noc/item/fiscalite-personnelle/paiement-solde-impots"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "fiscalite-personnelle-verification-avis-cotisation" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FISCALITE-PERSONNELLE" ]
|
||||
notes = "Vérifier les avis de cotisation ARC et Revenu Québec"
|
||||
vars.instructions_url = "/life-noc/item/fiscalite-personnelle/verification-avis-cotisation"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +66,7 @@ apply Service "fiscalite-personnelle-archivage-documents-fiscaux" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FISCALITE-PERSONNELLE" ]
|
||||
notes = "Archiver les documents fiscaux personnels"
|
||||
vars.instructions_url = "/life-noc/item/fiscalite-personnelle/archivage-documents-fiscaux"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -71,5 +77,6 @@ apply Service "fiscalite-personnelle-verification-acomptes-provisionnels" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FISCALITE-PERSONNELLE" ]
|
||||
notes = "Vérifier si des acomptes provisionnels sont requis"
|
||||
vars.instructions_url = "/life-noc/item/fiscalite-personnelle/verification-acomptes-provisionnels"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "focus-entretien-processus-focus" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FOCUS" ]
|
||||
notes = "Vérifier que les cartouches FOCUS sont à jour"
|
||||
vars.instructions_url = "/life-noc/item/focus/entretien-processus-focus"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "focus-nettoyage-inbox-mentale" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FOCUS" ]
|
||||
notes = "Vider et clarifier les éléments capturés hors système"
|
||||
vars.instructions_url = "/life-noc/item/focus/nettoyage-inbox-mentale"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,5 +33,6 @@ apply Service "focus-revue-limitation-engagements" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "FOCUS" ]
|
||||
notes = "Vérifier que les engagements actifs demeurent réalistes"
|
||||
vars.instructions_url = "/life-noc/item/focus/revue-limitation-engagements"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "garage-et-rangement-inspection-rangement-plafond" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "GARAGE-ET-RANGEMENT" ]
|
||||
notes = "Vérification des supports suspendus au plafond du garage"
|
||||
vars.instructions_url = "/life-noc/item/garage-et-rangement/inspection-rangement-plafond"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "garage-et-rangement-revue-inventaire-garage" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "GARAGE-ET-RANGEMENT" ]
|
||||
notes = "Revue de l'inventaire et de l'ordre du garage"
|
||||
vars.instructions_url = "/life-noc/item/garage-et-rangement/revue-inventaire-garage"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "garage-et-rangement-verification-rouille-outillage" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "GARAGE-ET-RANGEMENT" ]
|
||||
notes = "Vérification de la corrosion sur les outils et équipements"
|
||||
vars.instructions_url = "/life-noc/item/garage-et-rangement/verification-rouille-outillage"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "garage-et-rangement-inspection-securite-garage" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "GARAGE-ET-RANGEMENT" ]
|
||||
notes = "Vérification des conditions de sécurité du garage"
|
||||
vars.instructions_url = "/life-noc/item/garage-et-rangement/inspection-securite-garage"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,5 +55,6 @@ apply Service "garage-et-rangement-rotation-stockage-bacs" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "GARAGE-ET-RANGEMENT" ]
|
||||
notes = "Revue des contenus de bacs de rangement"
|
||||
vars.instructions_url = "/life-noc/item/garage-et-rangement/rotation-stockage-bacs"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "informatique-personnelle-verification-sauvegardes-personnelles" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFORMATIQUE-PERSONNELLE" ]
|
||||
notes = "Vérification des sauvegardes personnelles"
|
||||
vars.instructions_url = "/life-noc/item/informatique-personnelle/verification-sauvegardes-personnelles"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "informatique-personnelle-nettoyage-stockage-personnel" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFORMATIQUE-PERSONNELLE" ]
|
||||
notes = "Nettoyage du stockage numérique personnel"
|
||||
vars.instructions_url = "/life-noc/item/informatique-personnelle/nettoyage-stockage-personnel"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "informatique-personnelle-verification-comptes-importants" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFORMATIQUE-PERSONNELLE" ]
|
||||
notes = "Vérification des comptes numériques personnels importants"
|
||||
vars.instructions_url = "/life-noc/item/informatique-personnelle/verification-comptes-importants"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "informatique-personnelle-revue-mots-de-passe-personnels" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFORMATIQUE-PERSONNELLE" ]
|
||||
notes = "Revue des mots de passe personnels critiques"
|
||||
vars.instructions_url = "/life-noc/item/informatique-personnelle/revue-mots-de-passe-personnels"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,5 +55,6 @@ apply Service "informatique-personnelle-verification-documents-cloud-personnels"
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFORMATIQUE-PERSONNELLE" ]
|
||||
notes = "Vérifier la cohérence des documents personnels sauvegardés"
|
||||
vars.instructions_url = "/life-noc/item/informatique-personnelle/verification-documents-cloud-personnels"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "infrastructure-chezlepro-verification-proxmox" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFRASTRUCTURE-CHEZLEPRO" ]
|
||||
notes = "Vérification générale de l'environnement Proxmox"
|
||||
vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-proxmox"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "infrastructure-chezlepro-verification-ceph" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFRASTRUCTURE-CHEZLEPRO" ]
|
||||
notes = "Vérification générale de l'état Ceph"
|
||||
vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-ceph"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "infrastructure-chezlepro-test-restauration-backups" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFRASTRUCTURE-CHEZLEPRO" ]
|
||||
notes = "Test de restauration des sauvegardes"
|
||||
vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/test-restauration-backups"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "infrastructure-chezlepro-verification-pbs-truenas" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFRASTRUCTURE-CHEZLEPRO" ]
|
||||
notes = "Vérification des solutions de sauvegarde et synchronisation"
|
||||
vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-pbs-truenas"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "infrastructure-chezlepro-verification-ups-infrastructure" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFRASTRUCTURE-CHEZLEPRO" ]
|
||||
notes = "Vérification des UPS de l'infrastructure"
|
||||
vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-ups-infrastructure"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +66,7 @@ apply Service "infrastructure-chezlepro-verification-capacite-stockage" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFRASTRUCTURE-CHEZLEPRO" ]
|
||||
notes = "Vérifier capacité et croissance du stockage"
|
||||
vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-capacite-stockage"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +77,7 @@ apply Service "infrastructure-chezlepro-verification-apt-cacher-ng" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFRASTRUCTURE-CHEZLEPRO" ]
|
||||
notes = "Vérification du bon fonctionnement d'apt-cacher-ng"
|
||||
vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-apt-cacher-ng"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +88,7 @@ apply Service "infrastructure-chezlepro-verification-icinga2" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFRASTRUCTURE-CHEZLEPRO" ]
|
||||
notes = "Vérification de la supervision Icinga2"
|
||||
vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-icinga2"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +99,7 @@ apply Service "infrastructure-chezlepro-verification-keycloak-openldap" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFRASTRUCTURE-CHEZLEPRO" ]
|
||||
notes = "Vérification de l'identité et de l'authentification centralisées"
|
||||
vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-keycloak-openldap"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -101,6 +110,7 @@ apply Service "infrastructure-chezlepro-verification-nextcloud" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFRASTRUCTURE-CHEZLEPRO" ]
|
||||
notes = "Vérification de l'état Nextcloud"
|
||||
vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-nextcloud"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -111,6 +121,7 @@ apply Service "infrastructure-chezlepro-verification-mailcow" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFRASTRUCTURE-CHEZLEPRO" ]
|
||||
notes = "Vérification de l'infrastructure Mailcow"
|
||||
vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-mailcow"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -121,6 +132,7 @@ apply Service "infrastructure-chezlepro-verification-openvas" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFRASTRUCTURE-CHEZLEPRO" ]
|
||||
notes = "Vérification de la plateforme OpenVAS"
|
||||
vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-openvas"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -131,5 +143,6 @@ apply Service "infrastructure-chezlepro-verification-journaux-systemes" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "INFRASTRUCTURE-CHEZLEPRO" ]
|
||||
notes = "Revue des journaux systèmes critiques"
|
||||
vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-journaux-systemes"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "jardin-inspection-vignes" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "JARDIN" ]
|
||||
notes = "Inspection et entretien des vignes"
|
||||
vars.instructions_url = "/life-noc/item/jardin/inspection-vignes"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "jardin-entretien-bleuetiers" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "JARDIN" ]
|
||||
notes = "Entretien des bleuetiers"
|
||||
vars.instructions_url = "/life-noc/item/jardin/entretien-bleuetiers"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "jardin-entretien-framboisiers" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "JARDIN" ]
|
||||
notes = "Entretien des framboisiers"
|
||||
vars.instructions_url = "/life-noc/item/jardin/entretien-framboisiers"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "jardin-inspection-kiwis-nordiques" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "JARDIN" ]
|
||||
notes = "Vérification des kiwis nordiques"
|
||||
vars.instructions_url = "/life-noc/item/jardin/inspection-kiwis-nordiques"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "jardin-entretien-rhubarbe" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "JARDIN" ]
|
||||
notes = "Entretien de la rhubarbe"
|
||||
vars.instructions_url = "/life-noc/item/jardin/entretien-rhubarbe"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +66,7 @@ apply Service "jardin-inspection-groseillier" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "JARDIN" ]
|
||||
notes = "Inspection du groseillier"
|
||||
vars.instructions_url = "/life-noc/item/jardin/inspection-groseillier"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +77,7 @@ apply Service "jardin-inspection-muriers" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "JARDIN" ]
|
||||
notes = "Inspection des mûriers"
|
||||
vars.instructions_url = "/life-noc/item/jardin/inspection-muriers"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +88,7 @@ apply Service "jardin-entretien-houblon" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "JARDIN" ]
|
||||
notes = "Vérification et entretien du houblon"
|
||||
vars.instructions_url = "/life-noc/item/jardin/entretien-houblon"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +99,7 @@ apply Service "jardin-revision-pharmacopée-jardin" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "JARDIN" ]
|
||||
notes = "Vérification du stock de soins pour végétaux"
|
||||
vars.instructions_url = "/life-noc/item/jardin/revision-pharmacopée-jardin"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -101,5 +110,6 @@ apply Service "jardin-revision-armoire-produits-jardin" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "JARDIN" ]
|
||||
notes = "Vérification et ordre de l'armoire des produits pour végétaux"
|
||||
vars.instructions_url = "/life-noc/item/jardin/revision-armoire-produits-jardin"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "maison-remplacement-filtre-fournaise" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Remplacer le filtre de la fournaise"
|
||||
vars.instructions_url = "/life-noc/item/maison/remplacement-filtre-fournaise"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "maison-inspection-fournaise" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Inspection générale de la fournaise avant saison froide"
|
||||
vars.instructions_url = "/life-noc/item/maison/inspection-fournaise"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "maison-inspection-thermopompe" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Inspection et entretien de la thermopompe"
|
||||
vars.instructions_url = "/life-noc/item/maison/inspection-thermopompe"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "maison-nettoyage-unites-exterieures" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Nettoyer les unités extérieures et vérifier le dégagement"
|
||||
vars.instructions_url = "/life-noc/item/maison/nettoyage-unites-exterieures"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "maison-inspection-toiture" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Inspection annuelle de la toiture"
|
||||
vars.instructions_url = "/life-noc/item/maison/inspection-toiture"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +66,7 @@ apply Service "maison-inspection-gouttieres" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Inspection et nettoyage des gouttières"
|
||||
vars.instructions_url = "/life-noc/item/maison/inspection-gouttieres"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +77,7 @@ apply Service "maison-inspection-fondation" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Inspection de la fondation et des fissures"
|
||||
vars.instructions_url = "/life-noc/item/maison/inspection-fondation"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +88,7 @@ apply Service "maison-verification-drainage-terrain" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Vérification du drainage autour de la maison"
|
||||
vars.instructions_url = "/life-noc/item/maison/verification-drainage-terrain"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +99,7 @@ apply Service "maison-test-detecteurs-fumee" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Test des détecteurs de fumée"
|
||||
vars.instructions_url = "/life-noc/item/maison/test-detecteurs-fumee"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -101,6 +110,7 @@ apply Service "maison-test-detecteurs-co" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Test des détecteurs de monoxyde de carbone"
|
||||
vars.instructions_url = "/life-noc/item/maison/test-detecteurs-co"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -111,6 +121,7 @@ apply Service "maison-remplacement-piles-detecteurs" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Remplacement préventif des piles des détecteurs"
|
||||
vars.instructions_url = "/life-noc/item/maison/remplacement-piles-detecteurs"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -121,6 +132,7 @@ apply Service "maison-verification-plomberie-visible" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Vérification visuelle de la plomberie accessible"
|
||||
vars.instructions_url = "/life-noc/item/maison/verification-plomberie-visible"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -131,6 +143,7 @@ apply Service "maison-inspection-sump-pump" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Vérification de la pompe de puisard si applicable"
|
||||
vars.instructions_url = "/life-noc/item/maison/inspection-sump-pump"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -141,6 +154,7 @@ apply Service "maison-verification-calfetrage" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Vérification du calfeutrage portes et fenêtres"
|
||||
vars.instructions_url = "/life-noc/item/maison/verification-calfetrage"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -151,6 +165,7 @@ apply Service "maison-inspection-portes-garage" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Vérification mécanique et sécurité des portes de garage"
|
||||
vars.instructions_url = "/life-noc/item/maison/inspection-portes-garage"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -161,5 +176,6 @@ apply Service "maison-verification-extincteurs" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "MAISON" ]
|
||||
notes = "Vérification des extincteurs"
|
||||
vars.instructions_url = "/life-noc/item/maison/verification-extincteurs"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "obligations-chezlepro-verification-registraire-entreprise" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-CHEZLEPRO" ]
|
||||
notes = "Vérifier les obligations au Registraire des entreprises"
|
||||
vars.instructions_url = "/life-noc/item/obligations-chezlepro/verification-registraire-entreprise"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "obligations-chezlepro-verification-declarations-taxes" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-CHEZLEPRO" ]
|
||||
notes = "Vérifier les obligations de taxes de l'entreprise si applicables"
|
||||
vars.instructions_url = "/life-noc/item/obligations-chezlepro/verification-declarations-taxes"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "obligations-chezlepro-verification-dossier-comptable-entreprise"
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-CHEZLEPRO" ]
|
||||
notes = "Vérifier l'ordre du dossier comptable Chezlepro"
|
||||
vars.instructions_url = "/life-noc/item/obligations-chezlepro/verification-dossier-comptable-entreprise"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "obligations-chezlepro-verification-facturation-clients" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-CHEZLEPRO" ]
|
||||
notes = "Vérifier la facturation et son suivi"
|
||||
vars.instructions_url = "/life-noc/item/obligations-chezlepro/verification-facturation-clients"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "obligations-chezlepro-verification-paiements-fournisseurs" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-CHEZLEPRO" ]
|
||||
notes = "Vérifier les paiements fournisseurs"
|
||||
vars.instructions_url = "/life-noc/item/obligations-chezlepro/verification-paiements-fournisseurs"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +66,7 @@ apply Service "obligations-chezlepro-verification-contrats-ententes" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-CHEZLEPRO" ]
|
||||
notes = "Vérifier contrats, ententes et obligations associées"
|
||||
vars.instructions_url = "/life-noc/item/obligations-chezlepro/verification-contrats-ententes"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +77,7 @@ apply Service "obligations-chezlepro-verification-assurances-entreprise" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-CHEZLEPRO" ]
|
||||
notes = "Vérifier les assurances de l'entreprise"
|
||||
vars.instructions_url = "/life-noc/item/obligations-chezlepro/verification-assurances-entreprise"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -81,5 +88,6 @@ apply Service "obligations-chezlepro-archivage-documents-entreprise" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-CHEZLEPRO" ]
|
||||
notes = "Archiver les documents administratifs et financiers de l'entreprise"
|
||||
vars.instructions_url = "/life-noc/item/obligations-chezlepro/archivage-documents-entreprise"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "obligations-legales-personnelles-verification-testament" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-LEGALES-PERSONNELLES" ]
|
||||
notes = "Vérifier la pertinence et l'actualité du testament"
|
||||
vars.instructions_url = "/life-noc/item/obligations-legales-personnelles/verification-testament"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "obligations-legales-personnelles-verification-mandat-inaptitude"
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-LEGALES-PERSONNELLES" ]
|
||||
notes = "Vérifier le mandat de protection et documents connexes"
|
||||
vars.instructions_url = "/life-noc/item/obligations-legales-personnelles/verification-mandat-inaptitude"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "obligations-legales-personnelles-verification-directives-medicale
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-LEGALES-PERSONNELLES" ]
|
||||
notes = "Vérifier les directives médicales anticipées"
|
||||
vars.instructions_url = "/life-noc/item/obligations-legales-personnelles/verification-directives-medicales"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "obligations-legales-personnelles-verification-papiers-identite" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-LEGALES-PERSONNELLES" ]
|
||||
notes = "Vérifier l'expiration des papiers d'identité"
|
||||
vars.instructions_url = "/life-noc/item/obligations-legales-personnelles/verification-papiers-identite"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -60,6 +64,7 @@ apply Service "obligations-legales-personnelles-renouvellement-permis-conduire"
|
|||
vars.life_noc_threshold_critical_lt = "7"
|
||||
vars.life_noc_on_error = "critical"
|
||||
notes = "Vérifier la proximité de l’échéance du permis"
|
||||
vars.instructions_url = "/life-noc/item/obligations-legales-personnelles/renouvellement-permis-conduire"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -70,6 +75,7 @@ apply Service "obligations-legales-personnelles-verification-carte-assurance-mal
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-LEGALES-PERSONNELLES" ]
|
||||
notes = "Vérifier l'expiration de la carte d'assurance maladie"
|
||||
vars.instructions_url = "/life-noc/item/obligations-legales-personnelles/verification-carte-assurance-maladie"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -80,5 +86,6 @@ apply Service "obligations-legales-personnelles-verification-passeport" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OBLIGATIONS-LEGALES-PERSONNELLES" ]
|
||||
notes = "Vérifier l'expiration du passeport"
|
||||
vars.instructions_url = "/life-noc/item/obligations-legales-personnelles/verification-passeport"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "outils-et-equipements-entretien-outils-jardin" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OUTILS-ET-EQUIPEMENTS" ]
|
||||
notes = "Nettoyage et entretien des outils de jardin"
|
||||
vars.instructions_url = "/life-noc/item/outils-et-equipements/entretien-outils-jardin"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "outils-et-equipements-inspection-outils-electriques" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OUTILS-ET-EQUIPEMENTS" ]
|
||||
notes = "Vérification des outils électriques"
|
||||
vars.instructions_url = "/life-noc/item/outils-et-equipements/inspection-outils-electriques"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "outils-et-equipements-verification-rallonges-et-connecteurs" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OUTILS-ET-EQUIPEMENTS" ]
|
||||
notes = "Vérification des rallonges et connecteurs"
|
||||
vars.instructions_url = "/life-noc/item/outils-et-equipements/verification-rallonges-et-connecteurs"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "outils-et-equipements-verification-compresseur-et-accessoires" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OUTILS-ET-EQUIPEMENTS" ]
|
||||
notes = "Vérification du compresseur et accessoires"
|
||||
vars.instructions_url = "/life-noc/item/outils-et-equipements/verification-compresseur-et-accessoires"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,5 +55,6 @@ apply Service "outils-et-equipements-revision-inventaire-outillage" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "OUTILS-ET-EQUIPEMENTS" ]
|
||||
notes = "Revue de l'inventaire d'outillage"
|
||||
vars.instructions_url = "/life-noc/item/outils-et-equipements/revision-inventaire-outillage"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "projets-revision-life-noc" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "PROJETS" ]
|
||||
notes = "Révision du projet Life-NOC"
|
||||
vars.instructions_url = "/life-noc/item/projets/revision-life-noc"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "projets-revision-alliance-boreale" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "PROJETS" ]
|
||||
notes = "Révision du projet Alliance Boréale"
|
||||
vars.instructions_url = "/life-noc/item/projets/revision-alliance-boreale"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "projets-revision-erplibre" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "PROJETS" ]
|
||||
notes = "Révision du projet ERPLibre"
|
||||
vars.instructions_url = "/life-noc/item/projets/revision-erplibre"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "projets-revision-semence-numerique" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "PROJETS" ]
|
||||
notes = "Révision du projet semence numérique"
|
||||
vars.instructions_url = "/life-noc/item/projets/revision-semence-numerique"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "projets-revision-ortrux-1" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "PROJETS" ]
|
||||
notes = "Révision du système Ortrux-1"
|
||||
vars.instructions_url = "/life-noc/item/projets/revision-ortrux-1"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,5 +66,6 @@ apply Service "projets-revision-district16" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "PROJETS" ]
|
||||
notes = "Révision du projet DISTRICT16"
|
||||
vars.instructions_url = "/life-noc/item/projets/revision-district16"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "reseau-chezlepro-verification-firewalls" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESEAU-CHEZLEPRO" ]
|
||||
notes = "Vérification des firewalls"
|
||||
vars.instructions_url = "/life-noc/item/reseau-chezlepro/verification-firewalls"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "reseau-chezlepro-verification-vpn-openvpn" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESEAU-CHEZLEPRO" ]
|
||||
notes = "Vérification des tunnels OpenVPN"
|
||||
vars.instructions_url = "/life-noc/item/reseau-chezlepro/verification-vpn-openvpn"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "reseau-chezlepro-verification-crl-certificats" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESEAU-CHEZLEPRO" ]
|
||||
notes = "Vérification de la CRL et des certificats"
|
||||
vars.instructions_url = "/life-noc/item/reseau-chezlepro/verification-crl-certificats"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "reseau-chezlepro-verification-switches" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESEAU-CHEZLEPRO" ]
|
||||
notes = "Vérification des switches et uplinks"
|
||||
vars.instructions_url = "/life-noc/item/reseau-chezlepro/verification-switches"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "reseau-chezlepro-verification-vlans-segmentation" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESEAU-CHEZLEPRO" ]
|
||||
notes = "Vérification de la segmentation réseau"
|
||||
vars.instructions_url = "/life-noc/item/reseau-chezlepro/verification-vlans-segmentation"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +66,7 @@ apply Service "reseau-chezlepro-verification-dns" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESEAU-CHEZLEPRO" ]
|
||||
notes = "Vérification DNS interne et externe"
|
||||
vars.instructions_url = "/life-noc/item/reseau-chezlepro/verification-dns"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +77,7 @@ apply Service "reseau-chezlepro-verification-dynamic-dns" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESEAU-CHEZLEPRO" ]
|
||||
notes = "Vérification du DNS dynamique si utilisé"
|
||||
vars.instructions_url = "/life-noc/item/reseau-chezlepro/verification-dynamic-dns"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +88,7 @@ apply Service "reseau-chezlepro-audit-regles-firewall" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESEAU-CHEZLEPRO" ]
|
||||
notes = "Audit périodique des règles de firewall"
|
||||
vars.instructions_url = "/life-noc/item/reseau-chezlepro/audit-regles-firewall"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +99,7 @@ apply Service "reseau-chezlepro-verification-geoblocking" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESEAU-CHEZLEPRO" ]
|
||||
notes = "Vérifier le geoblocking et son effet attendu"
|
||||
vars.instructions_url = "/life-noc/item/reseau-chezlepro/verification-geoblocking"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -101,5 +110,6 @@ apply Service "reseau-chezlepro-verification-certificats-publics" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESEAU-CHEZLEPRO" ]
|
||||
notes = "Vérifier les expirations de certificats publics"
|
||||
vars.instructions_url = "/life-noc/item/reseau-chezlepro/verification-certificats-publics"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "resilience-test-generatrice-propane" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESILIENCE" ]
|
||||
notes = "Test mensuel de la génératrice au propane"
|
||||
vars.instructions_url = "/life-noc/item/resilience/test-generatrice-propane"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "resilience-verification-carburant-generatrice" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESILIENCE" ]
|
||||
notes = "Vérification de l'approvisionnement propane lié à la génératrice"
|
||||
vars.instructions_url = "/life-noc/item/resilience/verification-carburant-generatrice"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "resilience-verification-procedure-bascule" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESILIENCE" ]
|
||||
notes = "Réviser la procédure de bascule en mode secours"
|
||||
vars.instructions_url = "/life-noc/item/resilience/verification-procedure-bascule"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "resilience-verification-stock-lampes-piles" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESILIENCE" ]
|
||||
notes = "Vérification des lampes, piles et éclairage d'urgence"
|
||||
vars.instructions_url = "/life-noc/item/resilience/verification-stock-lampes-piles"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "resilience-verification-trousses-urgence" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESILIENCE" ]
|
||||
notes = "Vérification des trousses d'urgence"
|
||||
vars.instructions_url = "/life-noc/item/resilience/verification-trousses-urgence"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +66,7 @@ apply Service "resilience-revision-plan-urgence" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESILIENCE" ]
|
||||
notes = "Réviser le plan d'urgence domestique"
|
||||
vars.instructions_url = "/life-noc/item/resilience/revision-plan-urgence"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +77,7 @@ apply Service "resilience-test-autonomie-base" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESILIENCE" ]
|
||||
notes = "Vérifier l'autonomie énergétique minimale attendue"
|
||||
vars.instructions_url = "/life-noc/item/resilience/test-autonomie-base"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -81,5 +88,6 @@ apply Service "resilience-verification-moyens-cuisson-secours" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "RESILIENCE" ]
|
||||
notes = "Vérification des moyens de cuisson de secours"
|
||||
vars.instructions_url = "/life-noc/item/resilience/verification-moyens-cuisson-secours"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ apply Service "revue-revue-quotidienne-life-noc" {
|
|||
vars.life_noc_threshold_critical_gte = "3"
|
||||
vars.life_noc_on_error = "critical"
|
||||
notes = "Vérifier le tableau de bord Life-NOC"
|
||||
vars.instructions_url = "/life-noc/item/revue/revue-quotidienne-life-noc"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -39,6 +40,7 @@ apply Service "revue-revue-hebdomadaire-priorites" {
|
|||
vars.life_noc_threshold_critical_gte = "10"
|
||||
vars.life_noc_on_error = "critical"
|
||||
notes = "Revoir les priorités de la semaine"
|
||||
vars.instructions_url = "https://chezlepro.ca/life-noc/test-instructions"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -49,6 +51,7 @@ apply Service "revue-revue-mensuelle-systeme-vie" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "REVUE" ]
|
||||
notes = "Revue mensuelle de l'ensemble du système Life-NOC"
|
||||
vars.instructions_url = "/life-noc/item/revue/revue-mensuelle-systeme-vie"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -59,5 +62,6 @@ apply Service "revue-revue-trimestrielle-orientation" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "REVUE" ]
|
||||
notes = "Revue trimestrielle des orientations de vie et de Chezlepro"
|
||||
vars.instructions_url = "/life-noc/item/revue/revue-trimestrielle-orientation"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "sante-verification-trousse-premiers-soins" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "SANTE" ]
|
||||
notes = "Vérification de la trousse de premiers soins"
|
||||
vars.instructions_url = "/life-noc/item/sante/verification-trousse-premiers-soins"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "sante-verification-expiration-medicaments" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "SANTE" ]
|
||||
notes = "Vérification des dates d'expiration des médicaments"
|
||||
vars.instructions_url = "/life-noc/item/sante/verification-expiration-medicaments"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "sante-revision-rendez-vous-medicaux" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "SANTE" ]
|
||||
notes = "Revoir les rendez-vous médicaux requis"
|
||||
vars.instructions_url = "/life-noc/item/sante/revision-rendez-vous-medicaux"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "sante-verification-lunettes-prescriptions" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "SANTE" ]
|
||||
notes = "Vérifier les prescriptions et besoins de renouvellement"
|
||||
vars.instructions_url = "/life-noc/item/sante/verification-lunettes-prescriptions"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,5 +55,6 @@ apply Service "sante-verification-dossier-sante" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "SANTE" ]
|
||||
notes = "Vérifier l'ordre et l'accessibilité des documents de santé"
|
||||
vars.instructions_url = "/life-noc/item/sante/verification-dossier-sante"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "securite-chezlepro-verification-mises-a-jour-securite" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "SECURITE-CHEZLEPRO" ]
|
||||
notes = "Vérification des mises à jour de sécurité"
|
||||
vars.instructions_url = "/life-noc/item/securite-chezlepro/verification-mises-a-jour-securite"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "securite-chezlepro-audit-comptes-acces" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "SECURITE-CHEZLEPRO" ]
|
||||
notes = "Audit des comptes et accès privilégiés"
|
||||
vars.instructions_url = "/life-noc/item/securite-chezlepro/audit-comptes-acces"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "securite-chezlepro-verification-ids-snort" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "SECURITE-CHEZLEPRO" ]
|
||||
notes = "Vérification des IDS et de leur état"
|
||||
vars.instructions_url = "/life-noc/item/securite-chezlepro/verification-ids-snort"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "securite-chezlepro-revue-pki-privee" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "SECURITE-CHEZLEPRO" ]
|
||||
notes = "Revue de la PKI privée et des autorités intermédiaires"
|
||||
vars.instructions_url = "/life-noc/item/securite-chezlepro/revue-pki-privee"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "securite-chezlepro-revue-politiques-securite" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "SECURITE-CHEZLEPRO" ]
|
||||
notes = "Revue des politiques et pratiques de sécurité numérique"
|
||||
vars.instructions_url = "/life-noc/item/securite-chezlepro/revue-politiques-securite"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,5 +66,6 @@ apply Service "securite-chezlepro-verification-sauvegardes-configuration" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "SECURITE-CHEZLEPRO" ]
|
||||
notes = "Vérifier les sauvegardes des configurations critiques"
|
||||
vars.instructions_url = "/life-noc/item/securite-chezlepro/verification-sauvegardes-configuration"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "stock-alimentaire-rotation-nourriture-seche" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "STOCK-ALIMENTAIRE" ]
|
||||
notes = "Rotation des stocks de nourriture sèche"
|
||||
vars.instructions_url = "/life-noc/item/stock-alimentaire/rotation-nourriture-seche"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "stock-alimentaire-verification-reserve-eau" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "STOCK-ALIMENTAIRE" ]
|
||||
notes = "Vérification de la réserve d'eau potable"
|
||||
vars.instructions_url = "/life-noc/item/stock-alimentaire/verification-reserve-eau"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "stock-alimentaire-verification-mylar-absorbeurs" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "STOCK-ALIMENTAIRE" ]
|
||||
notes = "Vérifier l'intégrité des emballages Mylar et absorbeurs"
|
||||
vars.instructions_url = "/life-noc/item/stock-alimentaire/verification-mylar-absorbeurs"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "stock-alimentaire-revue-inventaire-conserves" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "STOCK-ALIMENTAIRE" ]
|
||||
notes = "Revue des conserves et dates de rotation"
|
||||
vars.instructions_url = "/life-noc/item/stock-alimentaire/revue-inventaire-conserves"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "stock-alimentaire-revue-inventaire-farine-riz-pates" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "STOCK-ALIMENTAIRE" ]
|
||||
notes = "Vérification des gros stocks alimentaires de base"
|
||||
vars.instructions_url = "/life-noc/item/stock-alimentaire/revue-inventaire-farine-riz-pates"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +66,7 @@ apply Service "stock-alimentaire-verification-bacs-legumes-racines" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "STOCK-ALIMENTAIRE" ]
|
||||
notes = "Vérification des bacs de stockage de légumes racines"
|
||||
vars.instructions_url = "/life-noc/item/stock-alimentaire/verification-bacs-legumes-racines"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -71,5 +77,6 @@ apply Service "stock-alimentaire-revue-supplements-vitamines" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "STOCK-ALIMENTAIRE" ]
|
||||
notes = "Vérification du stock de suppléments et dates utiles"
|
||||
vars.instructions_url = "/life-noc/item/stock-alimentaire/revue-supplements-vitamines"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ apply Service "voiture-verification-huile-moteur" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "VOITURE" ]
|
||||
notes = "Vérification de l'huile moteur"
|
||||
vars.instructions_url = "/life-noc/item/voiture/verification-huile-moteur"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ apply Service "voiture-inspection-freins" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "VOITURE" ]
|
||||
notes = "Inspection des freins"
|
||||
vars.instructions_url = "/life-noc/item/voiture/inspection-freins"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ apply Service "voiture-verification-pneus" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "VOITURE" ]
|
||||
notes = "Vérification usure, pression et permutation des pneus"
|
||||
vars.instructions_url = "/life-noc/item/voiture/verification-pneus"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +44,7 @@ apply Service "voiture-ajustement-valves" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "VOITURE" ]
|
||||
notes = "Vérification et ajustement des valves Honda Accord"
|
||||
vars.instructions_url = "/life-noc/item/voiture/ajustement-valves"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +55,7 @@ apply Service "voiture-verification-timing-belt" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "VOITURE" ]
|
||||
notes = "Vérification de la courroie de distribution et pompe à eau"
|
||||
vars.instructions_url = "/life-noc/item/voiture/verification-timing-belt"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +66,7 @@ apply Service "voiture-verification-batterie-voiture" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "VOITURE" ]
|
||||
notes = "Vérification de l'état de la batterie automobile"
|
||||
vars.instructions_url = "/life-noc/item/voiture/verification-batterie-voiture"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +77,7 @@ apply Service "voiture-verification-balais-essuie-glace" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "VOITURE" ]
|
||||
notes = "Vérification des essuie-glaces"
|
||||
vars.instructions_url = "/life-noc/item/voiture/verification-balais-essuie-glace"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +88,7 @@ apply Service "voiture-verification-liquides" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "VOITURE" ]
|
||||
notes = "Vérification des liquides de la voiture"
|
||||
vars.instructions_url = "/life-noc/item/voiture/verification-liquides"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +99,7 @@ apply Service "voiture-verification-eclairage" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "VOITURE" ]
|
||||
notes = "Vérification de l'éclairage et des phares"
|
||||
vars.instructions_url = "/life-noc/item/voiture/verification-eclairage"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
||||
|
|
@ -101,5 +110,6 @@ apply Service "voiture-verification-immatriculation-assurance" {
|
|||
vars.mock_message = "Sous contrôle"
|
||||
groups = [ "VOITURE" ]
|
||||
notes = "Vérification papiers d'assurance et immatriculation"
|
||||
vars.instructions_url = "/life-noc/item/voiture/verification-immatriculation-assurance"
|
||||
assign where host.name == "life-noc"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from pathlib import Path
|
|||
import yaml
|
||||
|
||||
INPUTS_DIR = Path("data/inputs")
|
||||
DOMAINS_FILE = Path("domains.yaml")
|
||||
|
||||
|
||||
def utc_now_iso() -> str:
|
||||
|
|
@ -68,3 +69,76 @@ def set_item(domain: str, item_key: str, value: str, origin: str = "manual") ->
|
|||
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -1,260 +0,0 @@
|
|||
#!/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é."
|
||||
|
|
@ -1,283 +0,0 @@
|
|||
#!/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 "checks/check_life_noc_probe.py"
|
||||
need_file "icinga/commands/check_life_noc_probe.conf"
|
||||
need_file "scripts/generate_services.py"
|
||||
need_file "domains.yaml"
|
||||
|
||||
echo "==> Sauvegarde"
|
||||
mkdir -p "$ROOT/.patch-backup-days-until-due"
|
||||
cp -a "$ROOT/checks/check_life_noc_probe.py" "$ROOT/.patch-backup-days-until-due/check_life_noc_probe.py.bak"
|
||||
cp -a "$ROOT/icinga/commands/check_life_noc_probe.conf" "$ROOT/.patch-backup-days-until-due/check_life_noc_probe.conf.bak"
|
||||
cp -a "$ROOT/scripts/generate_services.py" "$ROOT/.patch-backup-days-until-due/generate_services.py.bak"
|
||||
cp -a "$ROOT/domains.yaml" "$ROOT/.patch-backup-days-until-due/domains.yaml.bak"
|
||||
|
||||
echo "==> Réécriture de checks/check_life_noc_probe.py"
|
||||
cat > "$ROOT/checks/check_life_noc_probe.py" <<'PYEOF'
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
import yaml
|
||||
|
||||
|
||||
def exit_with(code: int, text: str) -> None:
|
||||
print(text)
|
||||
raise SystemExit(code)
|
||||
|
||||
|
||||
def parse_date(value: str) -> datetime:
|
||||
return datetime.strptime(value, "%Y-%m-%d").replace(tzinfo=timezone.utc)
|
||||
|
||||
|
||||
def load_input_value(inputs_file: str, item_key: str) -> str:
|
||||
path = Path(inputs_file)
|
||||
if not path.exists():
|
||||
raise ValueError(f"inputs file introuvable: {inputs_file}")
|
||||
|
||||
data = yaml.safe_load(path.read_text(encoding="utf-8"))
|
||||
if not isinstance(data, dict):
|
||||
raise ValueError(f"inputs file invalide: {inputs_file}")
|
||||
|
||||
if item_key not in data:
|
||||
raise ValueError(f"item_key introuvable dans le store: {item_key}")
|
||||
|
||||
item = data[item_key]
|
||||
if not isinstance(item, dict):
|
||||
raise ValueError(f"entrée invalide pour item_key: {item_key}")
|
||||
|
||||
if "value" not in item:
|
||||
raise ValueError(f"champ 'value' absent pour item_key: {item_key}")
|
||||
|
||||
return str(item["value"]).strip()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--probe-type", required=True)
|
||||
ap.add_argument("--source-type", required=True)
|
||||
ap.add_argument("--source-value")
|
||||
ap.add_argument("--inputs-file")
|
||||
ap.add_argument("--item-key")
|
||||
ap.add_argument("--unit", required=True)
|
||||
|
||||
ap.add_argument("--unknown-lt", type=float)
|
||||
ap.add_argument("--unknown-gte", type=float)
|
||||
|
||||
ap.add_argument("--ok-gte", type=float)
|
||||
ap.add_argument("--ok-lt", type=float)
|
||||
|
||||
ap.add_argument("--warning-gte", type=float)
|
||||
ap.add_argument("--warning-lt", type=float)
|
||||
|
||||
ap.add_argument("--critical-gte", type=float)
|
||||
ap.add_argument("--critical-lt", type=float)
|
||||
|
||||
ap.add_argument("--on-error", default="critical")
|
||||
ap.add_argument("--label", default="life-noc")
|
||||
args = ap.parse_args()
|
||||
|
||||
try:
|
||||
if args.source_type != "manual_date":
|
||||
exit_with(2, f"CRITICAL - source_type non supporté: {args.source_type}")
|
||||
|
||||
if args.unit != "days":
|
||||
exit_with(2, f"CRITICAL - unité non supportée: {args.unit}")
|
||||
|
||||
if args.inputs_file and args.item_key:
|
||||
source_value = load_input_value(args.inputs_file, args.item_key)
|
||||
elif args.source_value:
|
||||
source_value = args.source_value
|
||||
else:
|
||||
raise ValueError("aucune source fournie: inputs-file/item-key ou source-value requis")
|
||||
|
||||
dt = parse_date(source_value)
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
if args.probe_type == "elapsed_time":
|
||||
metric = (now - dt).total_seconds() / 86400.0
|
||||
|
||||
if args.critical_gte is not None and metric >= args.critical_gte:
|
||||
exit_with(2, f"CRITICAL - {args.label}: {metric:.1f} jours")
|
||||
if args.warning_gte is not None and metric >= args.warning_gte:
|
||||
exit_with(1, f"WARNING - {args.label}: {metric:.1f} jours")
|
||||
if args.ok_gte is not None and metric >= args.ok_gte:
|
||||
exit_with(0, f"OK - {args.label}: {metric:.1f} jours")
|
||||
if args.unknown_lt is not None and metric < args.unknown_lt:
|
||||
exit_with(3, f"UNKNOWN - {args.label}: {metric:.1f} jours")
|
||||
|
||||
exit_with(2, f"CRITICAL - {args.label}: seuils incohérents")
|
||||
|
||||
elif args.probe_type == "days_until_due":
|
||||
metric = (dt - now).total_seconds() / 86400.0
|
||||
|
||||
if args.critical_lt is not None and metric < args.critical_lt:
|
||||
exit_with(2, f"CRITICAL - {args.label}: {metric:.1f} jours restants")
|
||||
if args.warning_lt is not None and metric < args.warning_lt:
|
||||
exit_with(1, f"WARNING - {args.label}: {metric:.1f} jours restants")
|
||||
if args.ok_lt is not None and metric < args.ok_lt:
|
||||
exit_with(0, f"OK - {args.label}: {metric:.1f} jours restants")
|
||||
if args.unknown_gte is not None and metric >= args.unknown_gte:
|
||||
exit_with(3, f"UNKNOWN - {args.label}: {metric:.1f} jours restants")
|
||||
|
||||
exit_with(2, f"CRITICAL - {args.label}: seuils incohérents")
|
||||
|
||||
else:
|
||||
exit_with(2, f"CRITICAL - probe_type non supporté: {args.probe_type}")
|
||||
|
||||
except Exception as exc:
|
||||
if args.on_error == "critical":
|
||||
exit_with(2, f"CRITICAL - erreur sonde: {exc}")
|
||||
exit_with(3, f"UNKNOWN - erreur sonde: {exc}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
PYEOF
|
||||
chmod +x "$ROOT/checks/check_life_noc_probe.py"
|
||||
|
||||
echo "==> Réécriture de icinga/commands/check_life_noc_probe.conf"
|
||||
cat > "$ROOT/icinga/commands/check_life_noc_probe.conf" <<'CONFEOF'
|
||||
object CheckCommand "check_life_noc_probe" {
|
||||
command = [ PluginDir + "/check_life_noc_probe.py" ]
|
||||
|
||||
arguments = {
|
||||
"--probe-type" = "$life_noc_probe_type$"
|
||||
"--source-type" = "$life_noc_source_type$"
|
||||
"--source-value" = "$life_noc_source_value$"
|
||||
"--inputs-file" = "$life_noc_inputs_file$"
|
||||
"--item-key" = "$life_noc_item_key$"
|
||||
"--unit" = "$life_noc_metric_unit$"
|
||||
|
||||
"--unknown-lt" = "$life_noc_threshold_unknown_lt$"
|
||||
"--unknown-gte" = "$life_noc_threshold_unknown_gte$"
|
||||
|
||||
"--ok-gte" = "$life_noc_threshold_ok_gte$"
|
||||
"--ok-lt" = "$life_noc_threshold_ok_lt$"
|
||||
|
||||
"--warning-gte" = "$life_noc_threshold_warning_gte$"
|
||||
"--warning-lt" = "$life_noc_threshold_warning_lt$"
|
||||
|
||||
"--critical-gte" = "$life_noc_threshold_critical_gte$"
|
||||
"--critical-lt" = "$life_noc_threshold_critical_lt$"
|
||||
|
||||
"--on-error" = "$life_noc_on_error$"
|
||||
"--label" = "$life_noc_label$"
|
||||
}
|
||||
}
|
||||
CONFEOF
|
||||
|
||||
echo "==> Patch de scripts/generate_services.py"
|
||||
python3 - "$ROOT/scripts/generate_services.py" <<'PYEOF'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
path = Path(sys.argv[1])
|
||||
text = path.read_text(encoding="utf-8")
|
||||
|
||||
old = ' if "critical_gte" in thresholds:\n lines.append(f\' vars.life_noc_threshold_critical_gte = "{icinga_escape(str(thresholds["critical_gte"]))}"\')\n'
|
||||
new = old + ' 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 old not in text:
|
||||
raise SystemExit("Bloc seuils introuvable dans generate_services.py")
|
||||
text = text.replace(old, new, 1)
|
||||
|
||||
old2 = ' probe_type = str(probe.get("type", "")).strip()\n if probe_type not in {"elapsed_time"}:\n raise ValueError("seul probe.type=elapsed_time est supporté en v1")\n'
|
||||
new2 = ' probe_type = str(probe.get("type", "")).strip()\n if probe_type not in {"elapsed_time", "days_until_due"}:\n raise ValueError("seuls probe.type=elapsed_time et days_until_due sont supportés")\n'
|
||||
if old2 in text:
|
||||
text = text.replace(old2, new2, 1)
|
||||
else:
|
||||
old3 = ' probe_type = str(probe.get("type", "")).strip()\n if probe_type not in {"elapsed_time", "days_until_due"}:\n raise ValueError("seuls probe.type=elapsed_time et days_until_due sont supportés")\n'
|
||||
if old3 not in text:
|
||||
raise SystemExit("Bloc validate_probe introuvable ou inattendu dans generate_services.py")
|
||||
|
||||
path.write_text(text, encoding="utf-8")
|
||||
print("generate_services.py patché")
|
||||
PYEOF
|
||||
|
||||
echo "==> Création du store data/inputs/obligations-legales-personnelles.yaml"
|
||||
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 dans domains.yaml")
|
||||
|
||||
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"
|
||||
echo
|
||||
echo "Test utile ensuite :"
|
||||
echo " python3 scripts/life_noc_input.py set obligations-legales-personnelles renouvellement-permis-conduire 2026-03-20"
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
#!/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-v2"
|
||||
cp -a "$ROOT/scripts/generate_services.py" "$ROOT/.patch-backup-days-until-due-v2/generate_services.py.bak"
|
||||
cp -a "$ROOT/domains.yaml" "$ROOT/.patch-backup-days-until-due-v2/domains.yaml.bak"
|
||||
|
||||
echo "==> Patch de scripts/generate_services.py"
|
||||
python3 - "$ROOT/scripts/generate_services.py" <<'PYEOF'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
path = Path(sys.argv[1])
|
||||
text = path.read_text(encoding="utf-8")
|
||||
|
||||
# 1) Ajouter les seuils *_lt / unknown_gte si absents
|
||||
needle = ' if "critical_gte" in thresholds:\n lines.append(f\' vars.life_noc_threshold_critical_gte = "{icinga_escape(str(thresholds["critical_gte"]))}"\')\n'
|
||||
addition = (
|
||||
' 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 'vars.life_noc_threshold_unknown_gte' not in text:
|
||||
if needle not in text:
|
||||
raise SystemExit("Impossible de trouver le bloc des seuils dans generate_services.py")
|
||||
text = text.replace(needle, needle + addition, 1)
|
||||
|
||||
# 2) Élargir validate_probe aux deux types
|
||||
old_variants = [
|
||||
' probe_type = str(probe.get("type", "")).strip()\n if probe_type not in {"elapsed_time"}:\n raise ValueError("seul probe.type=elapsed_time est supporté en v1")\n',
|
||||
' probe_type = str(probe.get("type", "")).strip()\n if probe_type not in {"elapsed_time"}:\n raise ValueError("seul probe.type=elapsed_time est supporté en v1")\r\n',
|
||||
]
|
||||
new_block = ' probe_type = str(probe.get("type", "")).strip()\n if probe_type not in {"elapsed_time", "days_until_due"}:\n raise ValueError("seuls probe.type=elapsed_time et days_until_due sont supportés")\n'
|
||||
|
||||
replaced = False
|
||||
for old in old_variants:
|
||||
if old in text:
|
||||
text = text.replace(old, new_block, 1)
|
||||
replaced = True
|
||||
break
|
||||
|
||||
if not replaced:
|
||||
# si déjà patché, on accepte
|
||||
if new_block.strip() not in text:
|
||||
raise SystemExit("Bloc validate_probe introuvable ou déjà trop différent dans generate_services.py")
|
||||
|
||||
path.write_text(text, encoding="utf-8")
|
||||
print("generate_services.py patché")
|
||||
PYEOF
|
||||
|
||||
echo "==> Création du store data/inputs/obligations-legales-personnelles.yaml"
|
||||
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"
|
||||
echo
|
||||
echo "Test utile ensuite :"
|
||||
echo " python3 scripts/life_noc_input.py set obligations-legales-personnelles renouvellement-permis-conduire 2026-03-20"
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
#!/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"
|
||||
|
|
@ -79,6 +79,9 @@ def render_mock_service(domain: str, group_name: str, item: dict) -> str:
|
|||
date = str(item["date"]).strip()
|
||||
notes = item.get("notes", "").strip()
|
||||
notes_url = item.get("notes_url", "").strip()
|
||||
instructions_url = item.get("instructions_url", "").strip()
|
||||
if not instructions_url:
|
||||
instructions_url = f"/life-noc/item/{domain}/{name}"
|
||||
action_url = item.get("action_url", "").strip()
|
||||
mock_state = normalize_mock_state(item.get("mock_state", DEFAULT_MOCK_STATE))
|
||||
mock_message = item.get("mock_message", DEFAULT_MOCK_MESSAGE).strip() or DEFAULT_MOCK_MESSAGE
|
||||
|
|
@ -98,6 +101,8 @@ def render_mock_service(domain: str, group_name: str, item: dict) -> str:
|
|||
lines.append(f' notes = "{icinga_escape(notes)}"')
|
||||
if notes_url:
|
||||
lines.append(f' notes_url = "{icinga_escape(notes_url)}"')
|
||||
if instructions_url:
|
||||
lines.append(f' vars.instructions_url = "{icinga_escape(instructions_url)}"')
|
||||
if action_url:
|
||||
lines.append(f' action_url = "{icinga_escape(action_url)}"')
|
||||
|
||||
|
|
@ -112,6 +117,9 @@ def render_probe_service(domain: str, group_name: str, item: dict) -> str:
|
|||
name = item["name"].strip()
|
||||
notes = item.get("notes", "").strip()
|
||||
notes_url = item.get("notes_url", "").strip()
|
||||
instructions_url = item.get("instructions_url", "").strip()
|
||||
if not instructions_url:
|
||||
instructions_url = f"/life-noc/item/{domain}/{name}"
|
||||
action_url = item.get("action_url", "").strip()
|
||||
probe = item["probe"]
|
||||
|
||||
|
|
@ -160,6 +168,8 @@ def render_probe_service(domain: str, group_name: str, item: dict) -> str:
|
|||
lines.append(f' notes = "{icinga_escape(notes)}"')
|
||||
if notes_url:
|
||||
lines.append(f' notes_url = "{icinga_escape(notes_url)}"')
|
||||
if instructions_url:
|
||||
lines.append(f' vars.instructions_url = "{icinga_escape(instructions_url)}"')
|
||||
if action_url:
|
||||
lines.append(f' action_url = "{icinga_escape(action_url)}"')
|
||||
|
||||
|
|
|
|||
307
scripts/generate_services.py.bak
Normal file
307
scripts/generate_services.py.bak
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
INPUT_FILE = Path("domains.yaml")
|
||||
OUTPUT_DIR = Path("icinga/services")
|
||||
SERVICEGROUPS_DIR = Path("icinga/servicegroups")
|
||||
SERVICEGROUPS_FILE = SERVICEGROUPS_DIR / "life-noc.conf"
|
||||
HOST_NAME = "life-noc"
|
||||
SERVICE_TEMPLATE = "service_echeance"
|
||||
PROBE_TEMPLATE = "service_life_noc_probe"
|
||||
DEFAULT_MOCK_STATE = "OK"
|
||||
DEFAULT_MOCK_MESSAGE = "Sous contrôle"
|
||||
|
||||
|
||||
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 icinga_escape(value: str) -> str:
|
||||
return value.replace("\\", "\\\\").replace('"', '\\"')
|
||||
|
||||
|
||||
def normalize_mock_state(value: str) -> str:
|
||||
state = str(value).strip().upper()
|
||||
allowed = {"OK", "WARNING", "CRITICAL"}
|
||||
if state not in allowed:
|
||||
raise ValueError(
|
||||
f"mock_state invalide: {value}. Valeurs permises: {', '.join(sorted(allowed))}"
|
||||
)
|
||||
return state
|
||||
|
||||
|
||||
def render_mock_service(domain: str, group_name: str, item: dict) -> str:
|
||||
name = item["name"].strip()
|
||||
date = str(item["date"]).strip()
|
||||
notes = item.get("notes", "").strip()
|
||||
notes_url = item.get("notes_url", "").strip()
|
||||
action_url = item.get("action_url", "").strip()
|
||||
mock_state = normalize_mock_state(item.get("mock_state", DEFAULT_MOCK_STATE))
|
||||
mock_message = item.get("mock_message", DEFAULT_MOCK_MESSAGE).strip() or DEFAULT_MOCK_MESSAGE
|
||||
|
||||
service_name = f"{domain}-{name}"
|
||||
|
||||
lines = [
|
||||
f'apply Service "{icinga_escape(service_name)}" {{',
|
||||
f' import "{SERVICE_TEMPLATE}"',
|
||||
f' vars.date_echeance = "{icinga_escape(date)}"',
|
||||
f' vars.mock_state = "{icinga_escape(mock_state)}"',
|
||||
f' vars.mock_message = "{icinga_escape(mock_message)}"',
|
||||
f' groups = [ "{icinga_escape(group_name)}" ]',
|
||||
]
|
||||
|
||||
if notes:
|
||||
lines.append(f' notes = "{icinga_escape(notes)}"')
|
||||
if notes_url:
|
||||
lines.append(f' notes_url = "{icinga_escape(notes_url)}"')
|
||||
if action_url:
|
||||
lines.append(f' action_url = "{icinga_escape(action_url)}"')
|
||||
|
||||
lines.append(f' assign where host.name == "{HOST_NAME}"')
|
||||
lines.append("}")
|
||||
lines.append("")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def render_probe_service(domain: str, group_name: str, item: dict) -> str:
|
||||
name = item["name"].strip()
|
||||
notes = item.get("notes", "").strip()
|
||||
notes_url = item.get("notes_url", "").strip()
|
||||
action_url = item.get("action_url", "").strip()
|
||||
probe = item["probe"]
|
||||
|
||||
probe_type = str(probe["type"]).strip()
|
||||
source = probe["source"]
|
||||
metric = probe["metric"]
|
||||
thresholds = probe["thresholds"]
|
||||
policy = probe.get("policy", {})
|
||||
|
||||
service_name = f"{domain}-{name}"
|
||||
|
||||
lines = [
|
||||
f'apply Service "{icinga_escape(service_name)}" {{',
|
||||
f' import "{PROBE_TEMPLATE}"',
|
||||
f' vars.life_noc_probe_type = "{icinga_escape(probe_type)}"',
|
||||
f' vars.life_noc_source_type = "{icinga_escape(str(source["type"]).strip())}"',
|
||||
f' vars.life_noc_source_value = "{icinga_escape(str(source.get("value", "")).strip())}"',
|
||||
f' vars.life_noc_inputs_file = "{icinga_escape(str(source.get("inputs_file", "")).strip())}"',
|
||||
f' vars.life_noc_item_key = "{icinga_escape(str(source.get("item_key", name)).strip())}"',
|
||||
f' vars.life_noc_metric_unit = "{icinga_escape(str(metric["unit"]).strip())}"',
|
||||
f' vars.life_noc_label = "{icinga_escape(name)}"',
|
||||
f' groups = [ "{icinga_escape(group_name)}" ]',
|
||||
]
|
||||
|
||||
if "unknown_lt" in thresholds:
|
||||
lines.append(f' vars.life_noc_threshold_unknown_lt = "{icinga_escape(str(thresholds["unknown_lt"]))}"')
|
||||
if "ok_gte" in thresholds:
|
||||
lines.append(f' vars.life_noc_threshold_ok_gte = "{icinga_escape(str(thresholds["ok_gte"]))}"')
|
||||
if "warning_gte" in thresholds:
|
||||
lines.append(f' vars.life_noc_threshold_warning_gte = "{icinga_escape(str(thresholds["warning_gte"]))}"')
|
||||
if "critical_gte" in thresholds:
|
||||
lines.append(f' vars.life_noc_threshold_critical_gte = "{icinga_escape(str(thresholds["critical_gte"]))}"')
|
||||
if "unknown_gte" in thresholds:
|
||||
lines.append(f' vars.life_noc_threshold_unknown_gte = "{icinga_escape(str(thresholds["unknown_gte"]))}"')
|
||||
if "ok_lt" in thresholds:
|
||||
lines.append(f' vars.life_noc_threshold_ok_lt = "{icinga_escape(str(thresholds["ok_lt"]))}"')
|
||||
if "warning_lt" in thresholds:
|
||||
lines.append(f' vars.life_noc_threshold_warning_lt = "{icinga_escape(str(thresholds["warning_lt"]))}"')
|
||||
if "critical_lt" in thresholds:
|
||||
lines.append(f' vars.life_noc_threshold_critical_lt = "{icinga_escape(str(thresholds["critical_lt"]))}"')
|
||||
|
||||
on_error = str(policy.get("on_error", "critical")).strip()
|
||||
lines.append(f' vars.life_noc_on_error = "{icinga_escape(on_error)}"')
|
||||
|
||||
if notes:
|
||||
lines.append(f' notes = "{icinga_escape(notes)}"')
|
||||
if notes_url:
|
||||
lines.append(f' notes_url = "{icinga_escape(notes_url)}"')
|
||||
if action_url:
|
||||
lines.append(f' action_url = "{icinga_escape(action_url)}"')
|
||||
|
||||
lines.append(f' assign where host.name == "{HOST_NAME}"')
|
||||
lines.append("}")
|
||||
lines.append("")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
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")
|
||||
|
||||
|
||||
def render_servicegroup(group_name: str) -> str:
|
||||
return "\n".join([
|
||||
f'object ServiceGroup "{icinga_escape(group_name)}" {{',
|
||||
f' display_name = "{icinga_escape(group_name)}"',
|
||||
"}",
|
||||
"",
|
||||
])
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if not INPUT_FILE.exists():
|
||||
print(f"Erreur: fichier introuvable: {INPUT_FILE}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
with INPUT_FILE.open("r", encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f)
|
||||
|
||||
if not isinstance(data, dict) or "domains" not in data:
|
||||
print("Erreur: le YAML doit contenir une clé racine 'domains'.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
domains = data["domains"]
|
||||
if not isinstance(domains, dict):
|
||||
print("Erreur: 'domains' doit être un objet YAML.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
SERVICEGROUPS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for existing_conf in OUTPUT_DIR.glob("*.conf"):
|
||||
existing_conf.unlink()
|
||||
|
||||
if SERVICEGROUPS_FILE.exists():
|
||||
SERVICEGROUPS_FILE.unlink()
|
||||
|
||||
generated_files = []
|
||||
servicegroup_content = [
|
||||
"/*",
|
||||
" AUTO-GENERATED FILE - SERVICE GROUPS",
|
||||
" Ne pas modifier manuellement.",
|
||||
" Source: domains.yaml",
|
||||
"*/",
|
||||
"",
|
||||
]
|
||||
|
||||
for raw_domain, services in domains.items():
|
||||
domain = slugify(str(raw_domain))
|
||||
group_name = aliasify(str(raw_domain))
|
||||
|
||||
if not isinstance(services, list):
|
||||
print(f"Erreur: le domaine '{raw_domain}' doit contenir une liste.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
output_file = OUTPUT_DIR / f"{domain}.conf"
|
||||
content = [
|
||||
"/*",
|
||||
f" AUTO-GENERATED FILE - DOMAIN: {raw_domain}",
|
||||
" Ne pas modifier manuellement.",
|
||||
" Source: domains.yaml",
|
||||
"*/",
|
||||
"",
|
||||
]
|
||||
|
||||
servicegroup_content.append(render_servicegroup(group_name))
|
||||
|
||||
for idx, item in enumerate(services, start=1):
|
||||
if not isinstance(item, dict):
|
||||
print(f"Erreur: entrée invalide dans '{raw_domain}' à la position {idx}.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
missing = [key for key in ("name", "date", "notes") if key not in item]
|
||||
if missing:
|
||||
print(
|
||||
f"Erreur: dans le domaine '{raw_domain}', entrée {idx}, champs manquants: {', '.join(missing)}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
try:
|
||||
if "probe" in item:
|
||||
validate_probe(item)
|
||||
content.append(render_probe_service(domain, group_name, item))
|
||||
else:
|
||||
content.append(render_mock_service(domain, group_name, item))
|
||||
except ValueError as exc:
|
||||
print(f"Erreur dans '{raw_domain}', entrée {idx}: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
output_file.write_text("\n".join(content).rstrip() + "\n", encoding="utf-8")
|
||||
generated_files.append(str(output_file))
|
||||
|
||||
SERVICEGROUPS_FILE.write_text("\n".join(servicegroup_content).rstrip() + "\n", encoding="utf-8")
|
||||
generated_files.append(str(SERVICEGROUPS_FILE))
|
||||
|
||||
print("Fichiers générés :")
|
||||
for file_path in generated_files:
|
||||
print(f" - {file_path}")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
|
|
@ -5,14 +5,22 @@ from __future__ import annotations
|
|||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi import FastAPI, HTTPException, Form
|
||||
from fastapi.responses import HTMLResponse, RedirectResponse
|
||||
from pydantic import BaseModel
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from lib.life_noc_inputs import list_items, get_item, set_item, complete_item # noqa: E402
|
||||
from lib.life_noc_inputs import ( # noqa: E402
|
||||
list_items,
|
||||
get_item,
|
||||
set_item,
|
||||
complete_item,
|
||||
get_defined_service,
|
||||
compute_state_for_item,
|
||||
)
|
||||
|
||||
|
||||
class SetInputRequest(BaseModel):
|
||||
|
|
@ -27,6 +35,31 @@ class CompleteInputRequest(BaseModel):
|
|||
app = FastAPI(title="Life-NOC Input API", version="1.0.0")
|
||||
|
||||
|
||||
def html_escape(value: str) -> str:
|
||||
return (
|
||||
str(value)
|
||||
.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace('"', """)
|
||||
)
|
||||
|
||||
|
||||
def link_row(label: str, url: str) -> str:
|
||||
if not url:
|
||||
return ""
|
||||
u = html_escape(url)
|
||||
l = html_escape(label)
|
||||
return f'<li><a href="{u}" target="_blank" rel="noopener">{l}</a></li>'
|
||||
|
||||
|
||||
def resolve_instructions_url(domain: str, item_key: str, service: dict) -> str:
|
||||
explicit = str(service.get("instructions_url", "")).strip()
|
||||
if explicit:
|
||||
return explicit
|
||||
return f"/life-noc/item/{domain}/{item_key}"
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
def health() -> dict:
|
||||
return {"status": "ok"}
|
||||
|
|
@ -59,3 +92,191 @@ def api_complete_input(domain: str, item_key: str, req: CompleteInputRequest | N
|
|||
origin = "manual" if req is None else req.origin
|
||||
item = complete_item(domain, item_key, origin=origin)
|
||||
return {"domain": domain, "item_key": item_key, **item}
|
||||
|
||||
|
||||
@app.get("/life-noc/item/{domain}/{item_key}", response_class=HTMLResponse)
|
||||
def page_item(domain: str, item_key: str) -> HTMLResponse:
|
||||
try:
|
||||
service = get_defined_service(domain, item_key)
|
||||
current_input = get_item(domain, item_key)
|
||||
state = compute_state_for_item(domain, item_key)
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="item introuvable")
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc))
|
||||
|
||||
title = service.get("title") or service.get("display_name") or item_key.replace("-", " ").capitalize()
|
||||
summary = service.get("summary", "")
|
||||
notes = service.get("notes", "")
|
||||
instructions = service.get("instructions", "")
|
||||
notes_url = service.get("notes_url", "")
|
||||
instructions_url = resolve_instructions_url(domain, item_key, service)
|
||||
action_url = service.get("action_url", "")
|
||||
probe_type = service.get("probe", {}).get("type", "unknown")
|
||||
ui = service.get("ui", {}) if isinstance(service.get("ui", {}), dict) else {}
|
||||
form_mode = ui.get("form_mode", "")
|
||||
allow_complete = bool(ui.get("allow_complete", probe_type == "elapsed_time"))
|
||||
allow_manual_edit = bool(ui.get("allow_manual_edit", True))
|
||||
|
||||
links_html = ""
|
||||
for fragment in [
|
||||
link_row("Notes", notes_url),
|
||||
link_row("Instructions", instructions_url),
|
||||
link_row("Action", action_url),
|
||||
]:
|
||||
if fragment:
|
||||
links_html += fragment
|
||||
|
||||
summary_html = ""
|
||||
if summary:
|
||||
summary_html = f'<p><strong>Résumé :</strong> {html_escape(summary)}</p>'
|
||||
|
||||
instructions_html = ""
|
||||
if instructions:
|
||||
instructions_html = f"""
|
||||
<section class="card">
|
||||
<h2>Instructions</h2>
|
||||
<pre style="white-space: pre-wrap; font-family: Arial, sans-serif;">{html_escape(instructions)}</pre>
|
||||
</section>
|
||||
"""
|
||||
|
||||
manual_form_html = ""
|
||||
if allow_manual_edit and form_mode == "complete_date":
|
||||
manual_form_html = f"""
|
||||
<section class="card">
|
||||
<h2>Mettre à jour la date</h2>
|
||||
<form method="post" action="/life-noc/item/{html_escape(domain)}/{html_escape(item_key)}/set">
|
||||
<input type="date" name="value" value="{html_escape(current_input.get("value", ""))}" required>
|
||||
<input type="hidden" name="origin" value="manual">
|
||||
<button type="submit">Enregistrer</button>
|
||||
</form>
|
||||
</section>
|
||||
"""
|
||||
|
||||
complete_form_html = ""
|
||||
if allow_complete:
|
||||
complete_form_html = f"""
|
||||
<section class="card">
|
||||
<h2>Action rapide</h2>
|
||||
<form method="post" action="/life-noc/item/{html_escape(domain)}/{html_escape(item_key)}/complete">
|
||||
<button type="submit">Compléter</button>
|
||||
</form>
|
||||
</section>
|
||||
"""
|
||||
|
||||
html = f"""<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Life-NOC — {html_escape(title)}</title>
|
||||
<style>
|
||||
body {{
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
line-height: 1.45;
|
||||
}}
|
||||
.card {{
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 10px;
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}}
|
||||
.state {{
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
}}
|
||||
button {{
|
||||
font-size: 1rem;
|
||||
padding: 0.9rem 1.2rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #444;
|
||||
cursor: pointer;
|
||||
}}
|
||||
input[type="date"] {{
|
||||
font-size: 1rem;
|
||||
padding: 0.7rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #666;
|
||||
margin-right: 0.5rem;
|
||||
}}
|
||||
ul {{
|
||||
padding-left: 1.25rem;
|
||||
}}
|
||||
code {{
|
||||
background: #f3f3f3;
|
||||
padding: 0.1rem 0.3rem;
|
||||
border-radius: 4px;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<section class="card">
|
||||
<h1>{html_escape(title)}</h1>
|
||||
<p class="state">État actuel : {html_escape(state)}</p>
|
||||
<p><strong>Type de sonde :</strong> {html_escape(probe_type)}</p>
|
||||
{summary_html}
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>Dernier intrant</h2>
|
||||
<p><strong>Valeur :</strong> {html_escape(current_input.get("value", ""))}</p>
|
||||
<p><strong>Capturé le :</strong> {html_escape(current_input.get("captured_at", ""))}</p>
|
||||
<p><strong>Origine :</strong> {html_escape(current_input.get("origin", ""))}</p>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>Contexte</h2>
|
||||
<p><strong>Domaine :</strong> {html_escape(domain)}</p>
|
||||
<p><strong>Item key :</strong> <code>{html_escape(item_key)}</code></p>
|
||||
<p><strong>Notes :</strong> {html_escape(notes)}</p>
|
||||
</section>
|
||||
|
||||
{instructions_html}
|
||||
|
||||
<section class="card">
|
||||
<h2>Liens utiles</h2>
|
||||
<ul>
|
||||
{links_html}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
{manual_form_html}
|
||||
{complete_form_html}
|
||||
</main>
|
||||
</body>
|
||||
</html>"""
|
||||
return HTMLResponse(content=html)
|
||||
|
||||
|
||||
@app.post("/life-noc/item/{domain}/{item_key}/set")
|
||||
def page_set_item(domain: str, item_key: str, value: str = Form(...), origin: str = Form(default="manual")) -> RedirectResponse:
|
||||
try:
|
||||
set_item(domain, item_key, value=value, origin=origin)
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="item introuvable")
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc))
|
||||
|
||||
return RedirectResponse(
|
||||
url=f"/life-noc/item/{domain}/{item_key}",
|
||||
status_code=303,
|
||||
)
|
||||
|
||||
|
||||
@app.post("/life-noc/item/{domain}/{item_key}/complete")
|
||||
def page_complete_item(domain: str, item_key: str, origin: str = Form(default="manual")) -> RedirectResponse:
|
||||
try:
|
||||
complete_item(domain, item_key, origin=origin)
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="item introuvable")
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc))
|
||||
|
||||
return RedirectResponse(
|
||||
url=f"/life-noc/item/{domain}/{item_key}",
|
||||
status_code=303,
|
||||
)
|
||||
|
|
|
|||
227
scripts/life_noc_input_api.py.bak
Normal file
227
scripts/life_noc_input_api.py.bak
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
from fastapi import FastAPI, HTTPException, Form
|
||||
from fastapi.responses import HTMLResponse, RedirectResponse
|
||||
from pydantic import BaseModel
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from lib.life_noc_inputs import ( # noqa: E402
|
||||
list_items,
|
||||
get_item,
|
||||
set_item,
|
||||
complete_item,
|
||||
get_defined_service,
|
||||
compute_state_for_item,
|
||||
)
|
||||
|
||||
|
||||
class SetInputRequest(BaseModel):
|
||||
value: str
|
||||
origin: str = "manual"
|
||||
|
||||
|
||||
class CompleteInputRequest(BaseModel):
|
||||
origin: str = "manual"
|
||||
|
||||
|
||||
app = FastAPI(title="Life-NOC Input API", version="1.0.0")
|
||||
|
||||
|
||||
def html_escape(value: str) -> str:
|
||||
return (
|
||||
str(value)
|
||||
.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace('"', """)
|
||||
)
|
||||
|
||||
|
||||
def link_row(label: str, url: str) -> str:
|
||||
if not url:
|
||||
return ""
|
||||
u = html_escape(url)
|
||||
l = html_escape(label)
|
||||
return f'<li><a href="{u}" target="_blank" rel="noopener">{l}</a></li>'
|
||||
|
||||
def resolve_instructions_url(domain: str, item_key: str, service: dict) -> str:
|
||||
explicit = str(service.get("instructions_url", "")).strip()
|
||||
if explicit:
|
||||
return explicit
|
||||
return f"/life-noc/item/{domain}/{item_key}"
|
||||
|
||||
@app.get("/health")
|
||||
def health() -> dict:
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
@app.get("/inputs/{domain}")
|
||||
def api_list_inputs(domain: str) -> dict:
|
||||
return {"domain": domain, "items": list_items(domain)}
|
||||
|
||||
|
||||
@app.get("/inputs/{domain}/{item_key}")
|
||||
def api_get_input(domain: str, item_key: str) -> dict:
|
||||
try:
|
||||
item = get_item(domain, item_key)
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="item introuvable")
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc))
|
||||
return {"domain": domain, "item_key": item_key, **item}
|
||||
|
||||
|
||||
@app.post("/inputs/{domain}/{item_key}")
|
||||
def api_set_input(domain: str, item_key: str, req: SetInputRequest) -> dict:
|
||||
item = set_item(domain, item_key, req.value, origin=req.origin)
|
||||
return {"domain": domain, "item_key": item_key, **item}
|
||||
|
||||
|
||||
@app.post("/inputs/{domain}/{item_key}/complete")
|
||||
def api_complete_input(domain: str, item_key: str, req: CompleteInputRequest | None = None) -> dict:
|
||||
origin = "manual" if req is None else req.origin
|
||||
item = complete_item(domain, item_key, origin=origin)
|
||||
return {"domain": domain, "item_key": item_key, **item}
|
||||
|
||||
|
||||
@app.get("/life-noc/item/{domain}/{item_key}", response_class=HTMLResponse)
|
||||
def page_item(domain: str, item_key: str) -> HTMLResponse:
|
||||
try:
|
||||
service = get_defined_service(domain, item_key)
|
||||
current_input = get_item(domain, item_key)
|
||||
state = compute_state_for_item(domain, item_key)
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="item introuvable")
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc))
|
||||
|
||||
title = service.get("title") or service.get("display_name") or item_key.replace("-", " ").capitalize()
|
||||
summary = service.get("summary", "")
|
||||
notes = service.get("notes", "")
|
||||
instructions = service.get("instructions", "")
|
||||
notes_url = service.get("notes_url", "")
|
||||
instructions_url = resolve_instructions_url(domain, item_key, service)
|
||||
action_url = service.get("action_url", "")
|
||||
probe_type = service.get("probe", {}).get("type", "unknown")
|
||||
ui = service.get("ui", {}) if isinstance(service.get("ui", {}), dict) else {}
|
||||
form_mode = ui.get("form_mode", "")
|
||||
allow_complete = bool(ui.get("allow_complete", probe_type == "elapsed_time"))
|
||||
allow_manual_edit = bool(ui.get("allow_manual_edit", True))
|
||||
html = f"""<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Life-NOC — {html_escape(title)}</title>
|
||||
<style>
|
||||
body {{
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
line-height: 1.45;
|
||||
}}
|
||||
.card {{
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 10px;
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}}
|
||||
.state {{
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
}}
|
||||
button {{
|
||||
font-size: 1rem;
|
||||
padding: 0.9rem 1.2rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #444;
|
||||
cursor: pointer;
|
||||
}}
|
||||
ul {{
|
||||
padding-left: 1.25rem;
|
||||
}}
|
||||
code {{
|
||||
background: #f3f3f3;
|
||||
padding: 0.1rem 0.3rem;
|
||||
border-radius: 4px;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<section class="card">
|
||||
<h1>{html_escape(title)}</h1>
|
||||
<p class="state">État actuel : {html_escape(state)}</p>
|
||||
<p><strong>Type de sonde :</strong> {html_escape(probe_type)}</p>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>Dernier intrant</h2>
|
||||
<p><strong>Valeur :</strong> {html_escape(current_input.get("value", ""))}</p>
|
||||
<p><strong>Capturé le :</strong> {html_escape(current_input.get("captured_at", ""))}</p>
|
||||
<p><strong>Origine :</strong> {html_escape(current_input.get("origin", ""))}</p>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>Contexte</h2>
|
||||
<p><strong>Domaine :</strong> {html_escape(domain)}</p>
|
||||
<p><strong>Item key :</strong> <code>{html_escape(item_key)}</code></p>
|
||||
<p><strong>Notes :</strong> {html_escape(notes)}</p>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>Liens utiles</h2>
|
||||
<ul>
|
||||
{link_row("Notes", notes_url)}
|
||||
{link_row("Instructions", instructions_url)}
|
||||
{link_row("Action", action_url)}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>Action</h2>
|
||||
<form method="post" action="/life-noc/item/{html_escape(domain)}/{html_escape(item_key)}/complete">
|
||||
<button type="submit">Compléter</button>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>"""
|
||||
return HTMLResponse(content=html)
|
||||
|
||||
@app.post("/life-noc/item/{domain}/{item_key}/set")
|
||||
def page_set_item(domain: str, item_key: str, value: str = Form(...), origin: str = Form(default="manual")) -> RedirectResponse:
|
||||
try:
|
||||
set_item(domain, item_key, value=value, origin=origin)
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="item introuvable")
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc))
|
||||
|
||||
return RedirectResponse(
|
||||
url=f"/life-noc/item/{domain}/{item_key}",
|
||||
status_code=303,
|
||||
)
|
||||
|
||||
@app.post("/life-noc/item/{domain}/{item_key}/complete")
|
||||
def page_complete_item(domain: str, item_key: str, origin: str = Form(default="manual")) -> RedirectResponse:
|
||||
try:
|
||||
complete_item(domain, item_key, origin=origin)
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="item introuvable")
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc))
|
||||
|
||||
return RedirectResponse(
|
||||
url=f"/life-noc/item/{domain}/{item_key}",
|
||||
status_code=303,
|
||||
)
|
||||
Loading…
Reference in a new issue