# Post-mortem — Panne provoquée : VM figée, réparation automatique **Date** : 2026-10-12. **Gravité** : aucune (panne provoquée volontairement, sur le serveur réel, pour valider le self-healing du bloc A, semaine 6). **Impact réel** : nul — une seule VM de test, aucun élève. ## Scénario Une VM d'élève (3 machines du lab 08, prises du stock chaud et attribuées à une session de test) est gelée avec `virsh suspend`, qui simule un noyau planté ou un blocage matériel : le processeur virtuel s'arrête, l'agent invité ne répond plus, mais la VM reste en mémoire (état libvirt `paused`). ## Déroulé observé | Heure (locale) | Événement | |---|---| | 21:08:00 | VM `pc-a` mise en pause (`virsh suspend`) ; `routeur` et `pc-b` intactes | | 21:08–21:10 | Sondes automatiques (`labs:surveiller-vm`, chaque minute) : `pc-a` muette, `routeur`/`pc-b` répondent | | ≈ 21:10 | 3 sondes ratées de suite atteintes : Nova reçoit l'ordre de redémarrage forcé (`reboot --hard`) sur `pc-a` ; `routeur` et `pc-b` jamais touchées | | + quelques secondes | `pc-a` repasse de `paused` à `running` ; la sonde suivante la trouve de nouveau vivante | | — | `lab_session_machines.sante` = `relancee`, horodatée ; les deux autres machines restent `null` | **Aucune intervention humaine entre la mise en pause et la réparation.** ## Preuve ``` # Avant : pc-a « running » # Panne : virsh suspend → domstate « paused » 3 VM sondées, 1 muettes ; élèves : 1 VM relancée(s), 0 irréparable(s) # Après : domstate « running » 3 VM sondées, 0 muettes ; élèves : 0 VM relancée(s), 0 irréparable(s) sante = "relancee", sante_a = 2026-10-12 19:08:11 ``` ## Ce qui a bien fonctionné - La sonde (correcteur) distingue bien une VM gelée (`paused`) d'une VM éteinte (`shut off`) et d'une VM saine : seule `pc-a` a été touchée, les deux autres machines de la même session n'ont jamais reçu d'action. - Le redémarrage forcé a suffi : pas besoin de reconstruire la stack Heat ni de perdre le travail de l'élève sur les deux autres machines. - Le compteur de relances par heure a empêché une boucle : si la VM était restée muette, elle serait passée « irréparable » après 2 tentatives, pas redémarrée indéfiniment. ## Ce qui a été découvert pendant le test (pas un défaut, une leçon) Le scheduler Laravel tourne **chaque minute en continu**, y compris pendant qu'on teste à la main : les appels manuels de `labs:surveiller-vm` se sont mélangés avec les passages automatiques du cron. Le seuil de 3 sondes ratées a donc été atteint plus vite qu'en comptant seulement les commandes tapées à la main. **À refaire** : pour un test reproductible au chronomètre, désactiver temporairement le cron du scheduler (ou observer uniquement les métriques, sans lancer la commande soi-même) — noté pour le prochain test (montée en charge, panne générale). Un piège trouvé **avant** ce test, pendant le déploiement : le correcteur n'avait pas encore été recompilé avec la sonde quand le nouveau code Laravel a commencé à l'appeler (cron déjà actif après `ansible-playbook portail.yml`, avant `ansible-playbook correcteur.yml`). Les VM sont apparues « muettes » quelques minutes à tort (erreur `requete_invalide` de l'ancien binaire, pas une vraie panne). **Correction pour la suite** : toujours déployer `correcteur.yml` avant `portail.yml` quand les deux changent ensemble (le contraire de l'ordre suivi cette fois). ## Comprendre Un self-healing qui ne distingue pas « cette VM précise est malade » de « tout l'hôte est en panne » ferait plus de mal que de bien : redémarrer en boucle 20 VM parce que l'hyperviseur lui-même est surchargé n'aiderait en rien, et ajouterait de la charge au pire moment. La règle « toutes muettes à la fois → aucune action » (vérifiée mais non provoquée pendant ce test, seulement en test Pest) existe pour cette raison. L'autre leçon, plus générale, rejoint celle de l'étape 7 : un service qui tourne en tâche de fond (ici le scheduler, chaque minute) continue de tourner pendant qu'on observe à la main — il faut en tenir compte en testant, pas le découvrir après coup.