Files
system_update/docs/design/tache2/10-templates-apt.md
T
gilles 0fbca06d3d docs: roadmap tâches 1.9-8 (briefs, gates de validation, designs tâche 2) + plans d'implémentation
Cartographie complète (liste_taches/coherence_taches), briefs tacheN + gates
validation_tacheN, design tâche 2 (docs/design/tache2/), specs/plans jalon 1-2
et tâche 1.9/2 (Phase 1, Phase 2, SJ-0→3). Validations consignées (1.9 , 2-8 🟡).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 19:50:25 +02:00

12 KiB

10 — Templates APT : inventaire, sémantique et pseudo-shell

Axe A + livrables §4.1 et §4.2. Cohérent avec templates/apt/check.sh.tpl, full-upgrade.sh.tpl, reboot.sh.tpl existants, la convention ===SU:XXX===, LC_ALL=C, DEBIAN_FRONTEND=noninteractive, exécution sous sudo -S (server/ssh/client.ts).


1. Sémantique APT clarifiée (manpage apt-get)

Commande Effet Peut supprimer ? Peut installer du nouveau ?
apt-get update Resynchronise les index de paquets. Ne modifie aucun paquet installé. non non
apt-get -s upgrade Simulation : installe les nouvelles versions des paquets installés sans jamais supprimer ni installer de nouveaux paquets. Les paquets dont l'upgrade exigerait une suppression/installation restent held back. non non
apt-get -s dist-upgrade / full-upgrade Simulation : gère intelligemment les changements de dépendances, peut installer de nouveaux paquets et en supprimer pour satisfaire les dépendances. oui oui
apt-get autoremove Retire les dépendances automatiquement installées et devenues inutiles. oui non
apt-get clean Vide le cache local /var/cache/apt/archives. N'affecte pas l'état des paquets. non non

apt full-upgrade (commande apt) ≡ apt-get dist-upgrade (commande apt-get). On utilise toujours apt-get en script (non interactif, stable), jamais apt (UI humaine). L'UI parle d'« full-upgrade » comme alias convivial ; la commande système est apt-get dist-upgrade.

Lignes documentées parsées : Inst <pkg> [<cur>] (<target> <origin> [<arch>]), Conf <pkg>, Remv <pkg>. Le log brut complet reste archivé ; seules ces lignes + E:/W:/dpkg:/reboot-required alimentent Hermes.

Sources : apt-get https://manpages.debian.org/apt-get · dpkg https://manpages.debian.org/dpkg · dpkg-query https://manpages.debian.org/dpkg-query · apt-listchanges https://manpages.debian.org/bookworm/apt-listchanges/apt-listchanges.1.en.html · needrestart https://manpages.debian.org/bookworm/needrestart/needrestart.1.en.html


2. Inventaire des templates APT

Template Action (ActionType) Rôle Type OS ciblés Destructif ? Marqueurs
apt/update-analyze.sh.tpl apt_update_analyze Refresh index + simulation upgrade et dist-upgrade + reboot-check. Tâche de fond, non destructif. Remplace/étend l'actuel check.sh.tpl. snapshot tous non ===SU:APT_UPDATE===, ===SU:APT_SIM_UPGRADE===, ===SU:APT_SIM_DISTUPGRADE===, ===SU:APT_HELD===, ===SU:REBOOT===, ===SU:EXIT=N===
apt/upgrade.sh.tpl apt_upgrade Applique l'upgrade simple (sans suppression volontaire). Snapshot dpkg avant/après. action tous oui (modif paquets) ===SU:DPKG_BEFORE===, ===SU:APT_UPGRADE===, ===SU:DPKG_AFTER===, ===SU:REBOOT===, ===SU:EXIT=N===
apt/full-upgrade.sh.tpl apt_full_upgrade Applique apt-get dist-upgrade. Conserve l'existant (jalon 1) en l'enrichissant du diff dpkg. action tous oui (peut supprimer) idem upgrade + ===SU:APT_FULLUPGRADE===
apt/autoremove.sh.tpl apt_autoremove Retire les dépendances inutiles, avec simulation préalable affichée. action tous oui (supprime) ===SU:APT_SIM_AUTOREMOVE===, ===SU:DPKG_BEFORE===, ===SU:APT_AUTOREMOVE===, ===SU:DPKG_AFTER===, ===SU:EXIT=N===
apt/clean.sh.tpl apt_clean Vide le cache des paquets téléchargés. Action séparée, peu risquée. action tous non (cache only) ===SU:APT_CLEAN===, ===SU:EXIT=N===
apt/reboot-check.sh.tpl (intégré au refresh) Vérifie /run/reboot-required, /var/run/reboot-required, liste reboot-required.pkgs, état needrestart -b. snapshot tous non ===SU:REBOOT===
apt/reboot.sh.tpl reboot_verified Lit boot_id avant, planifie le reboot, émet un marqueur parsable avant coupure SSH. Conserve l'existant en ajoutant boot_id. action tous oui (reboot) ===SU:BOOT_ID_BEFORE===, ===SU:REBOOT_NOW===

Compatibilité jalon 1 : apt_full_upgrade et reboot restent des actions valides. check.sh.tpl n'est pas supprimé ; update-analyze.sh.tpl est son successeur enrichi (le refresh peut basculer dessus sans casser le parsing existant — voir §6 ci-dessous).


3. Variables de rendu (Mustache)

Étend TemplateVars (extension proposée, voir 40-contrats-json.md). Variables utilisées par les templates APT :

aptProxy          string|null   proxy apt-cacher-ng injecté à l'exécution (mode runtime)
osProfile         string        debian | ubuntu | proxmox | raspbian
machineKind       string        physical | vm | proxmox_host | lxc | raspberry_pi | workstation
confValues        bool          true => --force-confdef --force-confold (défaut)
inactivityTimeout int           secondes; 0 = désactivé (défaut 600)

Les sections Mustache {{#aptProxy}}…{{/aptProxy}} restent identiques à l'existant.


4. Pseudo-shell des templates clés

4.1 apt/update-analyze.sh.tpl (refresh + analyse, non destructif)

#!/bin/sh
# Refresh index + simulations upgrade/dist-upgrade + reboot-check.
# Exécuté entier sous sudo par la couche SSH. Non destructif.
export LC_ALL=C
export DEBIAN_FRONTEND=noninteractive
{{#aptProxy}}export http_proxy="{{aptProxy}}"; export https_proxy="{{aptProxy}}"
{{/aptProxy}}

echo "===SU:APT_UPDATE==="
apt-get update -qq 2>&1
UPD=$?

echo "===SU:APT_SIM_UPGRADE==="
apt-get -s -y upgrade 2>&1

echo "===SU:APT_SIM_DISTUPGRADE==="
apt-get -s -y dist-upgrade 2>&1

echo "===SU:APT_HELD==="
# Paquets retenus (held back) : présents en dist-upgrade mais pas en upgrade.
apt-mark showhold 2>/dev/null

echo "===SU:REBOOT==="
if [ -f /run/reboot-required ] || [ -f /var/run/reboot-required ]; then
  echo "REBOOT_REQUIRED=1"
  [ -f /var/run/reboot-required.pkgs ] && sed 's/^/PKG=/' /var/run/reboot-required.pkgs
else
  echo "REBOOT_REQUIRED=0"
fi
# needrestart en mode batch/list si présent (jamais interactif).
command -v needrestart >/dev/null 2>&1 && needrestart -b 2>/dev/null | grep -E '^NEEDRESTART-(KSTA|SVC)' || true

echo "===SU:EXIT=${UPD}==="

Le backend parse :

  • section APT_SIM_UPGRADE → liste upgrade (paquets Inst),
  • section APT_SIM_DISTUPGRADE → liste dist-upgrade (inclut Inst nouveaux + Remv suppressions),
  • held = APT_HELD (et/ou paquets présents en dist-upgrade absents d'upgrade),
  • REBOOT_REQUIRED + PKG= → reboot requis + paquets concernés.

Statut snapshot APT : ok si rien ; updates_available si Inst non vides ; warning si dist-upgrade implique des Remv ou des held ; error si APT_UPDATE échoue (dépôt injoignable, clé GPG…).

4.2 apt/full-upgrade.sh.tpl (application, avec diff dpkg)

#!/bin/sh
export LC_ALL=C
export DEBIAN_FRONTEND=noninteractive
{{#aptProxy}}export http_proxy="{{aptProxy}}"; export https_proxy="{{aptProxy}}"
{{/aptProxy}}

echo "===SU:DPKG_BEFORE==="
dpkg-query -W -f='${binary:Package}\t${Version}\t${Architecture}\n' 2>/dev/null

echo "===SU:APT_FULLUPGRADE==="
apt-get -y \
  -o Dpkg::Options::=--force-confdef \
  -o Dpkg::Options::=--force-confold \
  dist-upgrade 2>&1
CODE=$?

echo "===SU:DPKG_AFTER==="
dpkg-query -W -f='${binary:Package}\t${Version}\t${Architecture}\n' 2>/dev/null

echo "===SU:REBOOT==="
if [ -f /run/reboot-required ] || [ -f /var/run/reboot-required ]; then echo "REBOOT_REQUIRED=1"; else echo "REBOOT_REQUIRED=0"; fi

echo "===SU:EXIT=${CODE}==="

Le backend compare DPKG_BEFORE et DPKG_AFTER (clé = package+arch) → installed / upgraded / removed / unchanged, versions finales réelles. L'exit code seul ne suffit pas : un paquet annoncé en simulation mais resté inchangé est signalé comme anomalie.

Politique non interactive justifiée : --force-confdef+--force-confold conservent les fichiers de config locaux quand dpkg ne peut pas trancher, pour ne pas écraser une configuration distante. Les prompts (conffile, debconf, apt-listchanges, needrestart) sont traités comme risques de blocage à détecter (timeout d'inactivité), pas comme dialogues à exposer. Voir 50-erreurs.md (human_interaction_required).

4.3 apt/autoremove.sh.tpl

#!/bin/sh
export LC_ALL=C
export DEBIAN_FRONTEND=noninteractive
echo "===SU:APT_SIM_AUTOREMOVE==="
apt-get -s -y autoremove 2>&1     # prévisualisation des Remv
echo "===SU:DPKG_BEFORE==="
dpkg-query -W -f='${binary:Package}\t${Version}\t${Architecture}\n' 2>/dev/null
echo "===SU:APT_AUTOREMOVE==="
apt-get -y autoremove 2>&1
CODE=$?
echo "===SU:DPKG_AFTER==="
dpkg-query -W -f='${binary:Package}\t${Version}\t${Architecture}\n' 2>/dev/null
echo "===SU:EXIT=${CODE}==="

Confirmation UI explicite requise (action qui supprime des paquets).

4.4 apt/clean.sh.tpl

#!/bin/sh
export LC_ALL=C
echo "===SU:APT_CLEAN==="
BEFORE=$(du -sb /var/cache/apt/archives 2>/dev/null | awk '{print $1}')
apt-get clean 2>&1
AFTER=$(du -sb /var/cache/apt/archives 2>/dev/null | awk '{print $1}')
echo "FREED_BYTES=$((BEFORE - AFTER))"
echo "===SU:EXIT=0==="

4.5 apt/reboot.sh.tpl (reboot vérifié — capture boot_id)

#!/bin/sh
export LC_ALL=C
echo "===SU:BOOT_ID_BEFORE==="
cat /proc/sys/kernel/random/boot_id 2>/dev/null
echo "===SU:REBOOT_NOW==="
# Reboot différé pour laisser le canal SSH se fermer proprement.
nohup sh -c 'sleep 2; reboot' >/dev/null 2>&1 &
echo "reboot planifié"

Le backend orchestre la vérification (hors template) : il a lu boot_id avant, attend la coupure SSH, retente la connexion (délai adaptatif), relit boot_id via runPlain (cat /proc/sys/kernel/random/boot_id). Reboot ok seulement si la machine revient ET boot_id a changé. Statuts d'échec : reboot_command_failed, ssh_never_went_down, machine_did_not_return, boot_id_unchanged, timeout. Champs résultat : beforeBootId, afterBootId, requestedAt, sshWentDownAt, sshCameBackAt, waitedSeconds, status, errors. Délai adaptatif par machine : lastRebootDurationSecondsnextRecommendedWaitSeconds (avec marge). Voir 40-contrats-json.md (RebootResult).


5. Spécificités par profil OS (détail dans 60-profils-os-machine.md)

  • Debian : avant de proposer firmware/drivers propriétaires, vérifier la présence des composants contrib, non-free, non-free-firmware (template apt/check-components.sh.tpl, lecture seule). Pas d'activation automatique.
  • Ubuntu : ubuntu-drivers devices (lecture) pour proposer des drivers (NVIDIA/GPU) — proposition uniquement, jamais installé par défaut.
  • Proxmox : profil dédié. Vérifier dépôts PVE (pve-no-subscription vs enterprise), meta-package proxmox-ve, kernel PVE, Ceph éventuel, puis apt-get dist-upgrade. Ne jamais traiter comme une Debian générique.
  • Raspberry Pi OS : profil dédié. Attention firmware/kernel, vérifier l'espace disque avant upgrade, utiliser full-upgrade.

Le template le plus spécifique disponible sous templates/<profil>/<commande>.sh.tpl est choisi, sinon fallback templates/apt/<commande>.sh.tpl (profil base).


6. Compatibilité et migration (non-régression jalon 1)

  • L'actuel check.sh.tpl produit ===SU:UPDATE=== / ===SU:SIMULATE=== / ===SU:REBOOT=== / ===SU:END===. Le nouveau update-analyze.sh.tpl ajoute des sections sans supprimer la sémantique : le parsing actuel (extractSection(raw, "===SU:SIMULATE===", "===SU:REBOOT===")) peut être conservé en parallèle pendant la migration.
  • Recommandation MVP : introduire update-analyze.sh.tpl comme nouveau template et faire pointer le refresh dessus dans un sous-jalon dédié, en gardant check.sh.tpl jusqu'à bascule validée. Aucune rupture du flux prouvé en prod.
  • full-upgrade.sh.tpl et reboot.sh.tpl existants restent fonctionnels ; on ajoute les sections DPKG_BEFORE/AFTER et BOOT_ID_BEFORE (extension, pas remplacement de marqueurs).