ajoute le stock chaud, la correction automatique et les nouveaux essais de création de stack
Stock de stacks prêtes par lab dans Redis (prise atomique en Lua, ménage
par comparaison avec Heat, disjoncteur), files gérées par Horizon, séances
planifiables. Correcteur Go sur l'hyperviseur : socket Unix, commandes lues
dans le lab.yaml uniquement, exécution par l'agent invité QEMU. Une création
de stack ratée est supprimée et réessayée deux fois, puis la session passe
en échec, visible du prof.
Corrige aussi trois défauts des étapes précédentes : la console se coupait
à la première frappe d'un navigateur (trames texte), l'élève ne pouvait pas
rejoindre une séance, la déconnexion n'avait pas de jeton CSRF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:52:16 +02:00
# Runbook — Labs, stock chaud et correction (étapes 10 et 11)
2026-10-08 10:14:24 +02:00
## Où sont les choses
| Élément | Emplacement |
|---|---|
| Source éditoriale des labs | `paillasse-contenus/` (dépôt de contenu, pas de code) |
ajoute le stock chaud, la correction automatique et les nouveaux essais de création de stack
Stock de stacks prêtes par lab dans Redis (prise atomique en Lua, ménage
par comparaison avec Heat, disjoncteur), files gérées par Horizon, séances
planifiables. Correcteur Go sur l'hyperviseur : socket Unix, commandes lues
dans le lab.yaml uniquement, exécution par l'agent invité QEMU. Une création
de stack ratée est supprimée et réessayée deux fois, puis la session passe
en échec, visible du prof.
Corrige aussi trois défauts des étapes précédentes : la console se coupait
à la première frappe d'un navigateur (trames texte), l'élève ne pouvait pas
rejoindre une séance, la déconnexion n'avait pas de jeton CSRF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:52:16 +02:00
| Copie de travail lue par le portail et le correcteur | `labs/` à la racine de ce dépôt → synchronisée vers `/opt/labs` sur le serveur |
| Catalogue (table `labs` ) | `php artisan labs:synchroniser` , lancé par Ansible après chaque synchronisation de `labs/` |
2026-10-08 10:14:24 +02:00
| Lecture d'un `lab.yaml` | `portail/app/Services/Labs/DefinitionLab.php` |
| Traduction lab → gabarit Heat | `portail/app/Services/OpenStack/GenerateurTemplateHeat.php` |
ajoute le stock chaud, la correction automatique et les nouveaux essais de création de stack
Stock de stacks prêtes par lab dans Redis (prise atomique en Lua, ménage
par comparaison avec Heat, disjoncteur), files gérées par Horizon, séances
planifiables. Correcteur Go sur l'hyperviseur : socket Unix, commandes lues
dans le lab.yaml uniquement, exécution par l'agent invité QEMU. Une création
de stack ratée est supprimée et réessayée deux fois, puis la session passe
en échec, visible du prof.
Corrige aussi trois défauts des étapes précédentes : la console se coupait
à la première frappe d'un navigateur (trames texte), l'élève ne pouvait pas
rejoindre une séance, la déconnexion n'avait pas de jeton CSRF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:52:16 +02:00
| Construction d'une stack (3 essais) | `portail/app/Services/OpenStack/FabriqueStack.php` |
| Authentification OpenStack | `portail/app/Services/OpenStack/KeystoneAuth.php` (mot de passe — [ADR 0002 ](../adr/0002-mot-de-passe-pour-heat.md ), rotation : [compte-service-openstack.md ](compte-service-openstack.md )) |
| Stock chaud | `portail/app/Services/Labs/StockChaud.php` , job `CreerStackStock` , commande `labs:remplir-stock` chaque minute — [ADR 0003 ](../adr/0003-stock-chaud-et-horizon.md ) |
| Admission (stock ou construction) | `SeanceController::admettre` → `CreerStackLab` si le stock est vide |
| Suppression et expiration | `SupprimerStackLab` , commande `labs:expirer-sessions` chaque minute |
| Files de jobs | Laravel Horizon, service systemd `portail-horizon` : superviseurs `sessions` (4 processus) et `stock` (2), `config/horizon.php` |
| Correcteur | service systemd `correcteur` (Go, `correcteur/` , binaire `/usr/local/sbin/correcteur` ), socket `/run/correcteur/correcteur.sock` (`0660 root:www-data` ) |
| Correction côté portail | `ClientCorrecteur` , `CorrigerSession` , table `corrections` |
| Tests du parcours réel | `portail/tests/Reels/` (préparation + parcours prof/élève) |
## États d'une session de lab
`en_attente` → (prof : Admettre) → `actif` tout de suite si le stock a une
stack, sinon `admis` puis `actif` quand `CreerStackLab` a fini → `expire` ou
`termine` . Après 3 essais ratés : `echec` , la raison est affichée au prof
qui peut cliquer « Réessayer » (retour à `admis` ).
2026-10-08 10:14:24 +02:00
## Ajouter un nouveau lab
ajoute le stock chaud, la correction automatique et les nouveaux essais de création de stack
Stock de stacks prêtes par lab dans Redis (prise atomique en Lua, ménage
par comparaison avec Heat, disjoncteur), files gérées par Horizon, séances
planifiables. Correcteur Go sur l'hyperviseur : socket Unix, commandes lues
dans le lab.yaml uniquement, exécution par l'agent invité QEMU. Une création
de stack ratée est supprimée et réessayée deux fois, puis la session passe
en échec, visible du prof.
Corrige aussi trois défauts des étapes précédentes : la console se coupait
à la première frappe d'un navigateur (trames texte), l'élève ne pouvait pas
rejoindre une séance, la déconnexion n'avait pas de jeton CSRF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:52:16 +02:00
1. Le lab existe dans `paillasse-contenus/{id}/lab.yaml` . L'ordre des réseaux d'une machine décide de l'ordre des interfaces (`ens3` , `ens4` …). Les vérifications dont l'id commence par `bonus-` ne comptent pas pour « réussi ».
2. Le copier dans `labs/{id}/lab.yaml` de ce dépôt.
3. Vérifier que les images et flavors existent (`openstack image list` , `openstack flavor list` ) et que l'image a `hw_qemu_guest_agent=yes` (sinon le correcteur répond `agent_injoignable` ).
4. Déployer : `cd ansible && script -q /dev/null ansible-playbook correcteur.yml -i inventory.ini` (portail + correcteur). Le lab entre au catalogue, et son stock se remplit dans la minute.
5. Tester le parcours : `portail/tests/Reels/` (voir l'en-tête des deux scripts), puis supprimer les données de test.
## Stock chaud
```
ssh paillasse "cd /var/www/portail & & sudo -u www-data HOME=/tmp php8.3 artisan labs:remplir-stock"
```
Affiche, par lab : cible, prêtes, en construction, commandées, retirées,
disjoncteur. Réglages (`.env` du portail, sinon valeurs de `config/labs.php` ) :
2026-10-08 10:14:24 +02:00
ajoute le stock chaud, la correction automatique et les nouveaux essais de création de stack
Stock de stacks prêtes par lab dans Redis (prise atomique en Lua, ménage
par comparaison avec Heat, disjoncteur), files gérées par Horizon, séances
planifiables. Correcteur Go sur l'hyperviseur : socket Unix, commandes lues
dans le lab.yaml uniquement, exécution par l'agent invité QEMU. Une création
de stack ratée est supprimée et réessayée deux fois, puis la session passe
en échec, visible du prof.
Corrige aussi trois défauts des étapes précédentes : la console se coupait
à la première frappe d'un navigateur (trames texte), l'élève ne pouvait pas
rejoindre une séance, la déconnexion n'avait pas de jeton CSRF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:52:16 +02:00
- `LABS_CAPACITE_VM` (15) : plafond de VM `eleve.petit` , sessions et stock compris ;
- `LABS_STOCK_TAILLE` (1) : stacks prêtes par lab hors séance.
Disjoncteur ouvert (« oui ») : 3 échecs définitifs de suite sur ce lab. Lire
`storage/logs/laravel.log` (`CreerStackStock` ), corriger la cause (image,
flavor, quota…), puis le réarmer sans attendre ses 30 min :
2026-10-08 10:14:24 +02:00
```
ajoute le stock chaud, la correction automatique et les nouveaux essais de création de stack
Stock de stacks prêtes par lab dans Redis (prise atomique en Lua, ménage
par comparaison avec Heat, disjoncteur), files gérées par Horizon, séances
planifiables. Correcteur Go sur l'hyperviseur : socket Unix, commandes lues
dans le lab.yaml uniquement, exécution par l'agent invité QEMU. Une création
de stack ratée est supprimée et réessayée deux fois, puis la session passe
en échec, visible du prof.
Corrige aussi trois défauts des étapes précédentes : la console se coupait
à la première frappe d'un navigateur (trames texte), l'élève ne pouvait pas
rejoindre une séance, la déconnexion n'avait pas de jeton CSRF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:52:16 +02:00
sudo -u www-data HOME=/tmp php8.3 artisan tinker --execute='Illuminate\Support\Facades\Redis::del("stock:echecs:{lab}");'
2026-10-08 10:14:24 +02:00
```
ajoute le stock chaud, la correction automatique et les nouveaux essais de création de stack
Stock de stacks prêtes par lab dans Redis (prise atomique en Lua, ménage
par comparaison avec Heat, disjoncteur), files gérées par Horizon, séances
planifiables. Correcteur Go sur l'hyperviseur : socket Unix, commandes lues
dans le lab.yaml uniquement, exécution par l'agent invité QEMU. Une création
de stack ratée est supprimée et réessayée deux fois, puis la session passe
en échec, visible du prof.
Corrige aussi trois défauts des étapes précédentes : la console se coupait
à la première frappe d'un navigateur (trames texte), l'élève ne pouvait pas
rejoindre une séance, la déconnexion n'avait pas de jeton CSRF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:52:16 +02:00
Vider le stock d'un lab (les stacks seront supprimées par le ménage) : passer
`LABS_STOCK_TAILLE=0` puis attendre une minute, ou supprimer la clé
`stock:pretes:{lab}` (le ménage supprime alors les stacks orphelines après 10 min).
## Correcteur
```
systemctl status correcteur
journalctl -u correcteur -f # une ligne par vérification : instance, lab, id, résultat, durée
```
Il n'accepte que `{"instance": uuid, "lab": id, "verification": id}` , refuse
tout champ en plus, et n'exécute que la commande du `lab.yaml` , en root dans
la VM, par `guest-exec` (10 s maximum). Avant d'exécuter, il vérifie dans les
métadonnées libvirt que la VM appartient au projet `paillasse` et porte le
nom de la machine visée. Codes d'erreur : `requete_invalide` , `lab_inconnu` ,
`verification_inconnue` , `machine_non_conforme` , `agent_injoignable` ,
`delai_depasse` .
## Inspecter les stacks sur le serveur
2026-10-08 10:14:24 +02:00
```
sudo -i
export PATH=/opt/kolla-venv/bin:$PATH
ajoute le stock chaud, la correction automatique et les nouveaux essais de création de stack
Stock de stacks prêtes par lab dans Redis (prise atomique en Lua, ménage
par comparaison avec Heat, disjoncteur), files gérées par Horizon, séances
planifiables. Correcteur Go sur l'hyperviseur : socket Unix, commandes lues
dans le lab.yaml uniquement, exécution par l'agent invité QEMU. Une création
de stack ratée est supprimée et réessayée deux fois, puis la session passe
en échec, visible du prof.
Corrige aussi trois défauts des étapes précédentes : la console se coupait
à la première frappe d'un navigateur (trames texte), l'élève ne pouvait pas
rejoindre une séance, la déconnexion n'avait pas de jeton CSRF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:52:16 +02:00
export OS_CLIENT_CONFIG_FILE=/etc/kolla/clouds-paillasse.yaml OS_CLOUD=paillasse-service
openstack stack list # lab-session-{id}-e{n} : sessions ; stock-{lab}-{xxxxxx}-e{n} : stock
2026-10-08 10:14:24 +02:00
openstack server list
```
## Pièges rencontrés
ajoute le stock chaud, la correction automatique et les nouveaux essais de création de stack
Stock de stacks prêtes par lab dans Redis (prise atomique en Lua, ménage
par comparaison avec Heat, disjoncteur), files gérées par Horizon, séances
planifiables. Correcteur Go sur l'hyperviseur : socket Unix, commandes lues
dans le lab.yaml uniquement, exécution par l'agent invité QEMU. Une création
de stack ratée est supprimée et réessayée deux fois, puis la session passe
en échec, visible du prof.
Corrige aussi trois défauts des étapes précédentes : la console se coupait
à la première frappe d'un navigateur (trames texte), l'élève ne pouvait pas
rejoindre une séance, la déconnexion n'avait pas de jeton CSRF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:52:16 +02:00
- **Heat refuse une application credential** (`Delegated tokens cannot manage trusts` ), même `--unrestricted` : voir [ADR 0002 ](../adr/0002-mot-de-passe-pour-heat.md ).
- **Horizon garde le code et la configuration en mémoire** : le rôle Ansible le redémarre après chaque synchronisation de code ou changement de `.env` .
- **Timeouts emboîtés** : job (280 s) < superviseur Horizon ( 300 s ) < `REDIS_QUEUE_RETRY_AFTER` ( 330 s ). Sinon Redis redonne un job encore en cours à un autre processus , et deux stacks sont construites .
- **Console muette après la première touche** : `nova-serialproxy` ferme la connexion à la première trame WebSocket texte. Le proxy Go envoie tout en binaire — voir [post-mortem du 2026-10-08 ](../postmortems/2026-10-08-console-trames-texte.md ).
- `sudo -u www-data php artisan ...` exige `HOME=/tmp` (pas de `$HOME` inscriptible pour `www-data` ).
- Une stack appartient à une session (un élève, une tentative) ; une stack du stock n'y retourne jamais après avoir été donnée.