tests/installer/vm_install_test.sh
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env bash
# Test d'installation de Lyra dans des VM propres (roadmap #44), pilote par les
# scripts vm-controller de fedora-agents (les memes que les outils MCP vm_*).
#
# Par VM : restauration du snapshot vierge, clone du depot au commit teste,
# installeur SANS interface (--headless), verifications, rapport date.
# Protocole et baselines : docs/user/VM_INSTALL_TESTS.md.
#
# tests/installer/vm_install_test.sh --dry-run # affiche le plan, ne lance rien
# tests/installer/vm_install_test.sh --ollama-host 192.0.2.1 # campagne reelle (Fedora + Ubuntu)
#
# Options : --vm NOM (repetable ; defaut fedora-base et ubuntu-base)
# --snapshot NOM (defaut installer-clean-20260926)
# --ref REF (defaut : commit courant, qui doit etre pousse)
# --repo URL --ollama-host HOTE --scripts-dir DIR --keep (ne pas re-restaurer)
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
VMS=()
SNAPSHOT="installer-clean-20260926"
REPO="https://github.com/amineutron/lyra.git"
REF=""
OLLAMA_HOST_ARG=""
SCRIPTS_DIR="${LYRA_SCRIPTS_DIR:-/usr/local/lib/lyra/scripts}/agents/vm-controller"
DRY_RUN=false
KEEP=false
usage() { sed -n '2,17p' "$0" | sed 's/^# \{0,1\}//'; }
while [ $# -gt 0 ]; do
case "$1" in
--vm) VMS+=("$2"); shift ;;
--snapshot) SNAPSHOT="$2"; shift ;;
--repo) REPO="$2"; shift ;;
--ref) REF="$2"; shift ;;
--ollama-host) OLLAMA_HOST_ARG="$2"; shift ;;
--scripts-dir) SCRIPTS_DIR="$2"; shift ;;
--dry-run) DRY_RUN=true ;;
--keep) KEEP=true ;;
-h|--help) usage; exit 0 ;;
*) echo "option inconnue : $1" >&2; usage >&2; exit 2 ;;
esac
shift
done
[ ${#VMS[@]} -gt 0 ] || VMS=(fedora-base ubuntu-base)
REF="${REF:-$(git -C "$ROOT" rev-parse HEAD)}"
if ! $DRY_RUN && [ -z "$OLLAMA_HOST_ARG" ]; then
echo "--ollama-host requis : les VM n'ont pas de GPU, Ollama tourne sur l'hote" >&2; exit 2
fi
STAMP="$(date +%Y-%m-%d)"
REPORT_DIR="$ROOT/docs/user/vm-install-reports"
# les VM testees dans le nom : deux campagnes separees du meme commit ne s'ecrasent plus
REPORT="$REPORT_DIR/$STAMP-${REF:0:7}-$(IFS=-; echo "${VMS[*]}").md"
# Une etape = une commande ; en --dry-run on l'affiche seulement.
step() {
if $DRY_RUN; then printf '[plan]'; printf ' %q' "$@"; printf '\n'; return 0; fi
"$@"
}
# Commande jouee DANS la VM (utilisateur de la baseline, sans mot de passe sudo)
install_cmd() {
local host_opt=""
[ -n "$OLLAMA_HOST_ARG" ] && host_opt="--ollama-host $OLLAMA_HOST_ARG"
printf '%s' "rm -rf ~/lyra && git clone --quiet $REPO ~/lyra && cd ~/lyra && git checkout --quiet $REF \
&& ./installer/install.sh --headless $host_opt"
}
CHECKS=(
"systemctl --user is-active lyra-daemon"
"test -f ~/lyra/config.yaml && echo config.yaml present"
# la commande la ou l'installeur la pose (et l'annonce) : ~/.local/bin/lyra
"cd ~ && .local/bin/lyra --version"
"cd ~ && timeout 120 .local/bin/lyra -y 'liste les taches'"
)
# Jusqu'a 3 min, un essai toutes les 10 s : apres restauration, ubuntu-base a mis plus
# de 2 min a retrouver le reseau (campagne du 2026-09-26) ; fedora-base ~15 s.
SSH_WAIT_S=180
ssh_ready() {
if $DRY_RUN; then step "$SCRIPTS_DIR/vm-exec.sh" "$1" "true" --timeout=30; return 0; fi
local deadline=$(( $(date +%s) + SSH_WAIT_S ))
while [ "$(date +%s)" -lt "$deadline" ]; do
"$SCRIPTS_DIR/vm-exec.sh" "$1" "true" --timeout=15 >/dev/null 2>&1 && return 0
sleep 10
done
return 1
}
# Horloge de la VM a l'heure de l'hote : agent invite QEMU (virsh domtime), sinon
# sudo date dans la VM. Echec si l'ecart reste superieur a 5 minutes.
sync_clock() {
local vm="$1" now
if $DRY_RUN; then step virsh -c qemu:///system domtime "$vm" --now; return 0; fi
virsh -c qemu:///system domtime "$vm" --now >/dev/null 2>&1 \
|| "$SCRIPTS_DIR/vm-exec.sh" "$vm" "sudo -n date -u -s @$(date +%s)" --timeout=30 >/dev/null 2>&1
now="$("$SCRIPTS_DIR/vm-exec.sh" "$vm" "date +%s" --timeout=30 2>/dev/null | grep -Eo '^[0-9]{9,}$' | head -1)"
[ -n "$now" ] && [ $(( $(date +%s) - now )) -lt 300 ] && [ $(( now - $(date +%s) )) -lt 300 ]
}
run_vm() {
local vm="$1" status=OK
echo "== $vm"
step "$SCRIPTS_DIR/vm-snapshot.sh" "$vm" restore "$SNAPSHOT" -y || return 1
step sleep 20 # reseau de la VM apres restauration (~15 s mesure)
# Acces SSH d'abord : une baseline qui ne connait pas la cle des VM faisait echouer
# toutes les etapes une par une (2026-09-26 : cle creee le 15/09, baseline du 24/08).
if ! ssh_ready "$vm"; then
echo "SSH refuse sur $vm : la baseline $SNAPSHOT doit autoriser la cle des VM (~/.ssh/config)" >&2
RESULTS+=("| $vm | acces SSH | ECHEC |"); SUMMARY+=("| $vm | ECHEC (SSH refuse) |")
$KEEP || step "$SCRIPTS_DIR/vm-snapshot.sh" "$vm" restore "$SNAPSHOT" -y
return 1
fi
# Un snapshot a chaud restaure aussi l'horloge de la VM (mars 2026 pour la baseline) :
# sans remise a l'heure, TLS refuse les certificats « pas encore valides » (git clone).
if ! sync_clock "$vm"; then
RESULTS+=("| $vm | remise a l'heure | ECHEC |"); SUMMARY+=("| $vm | ECHEC (horloge) |")
$KEEP || step "$SCRIPTS_DIR/vm-snapshot.sh" "$vm" restore "$SNAPSHOT" -y
return 1
fi
if ! step "$SCRIPTS_DIR/vm-exec.sh" "$vm" "$(install_cmd)" --timeout=3600; then status=ECHEC; fi
for check in "${CHECKS[@]}"; do
if step "$SCRIPTS_DIR/vm-exec.sh" "$vm" "$check" --timeout=180; then
RESULTS+=("| $vm | \`$check\` | ok |")
else
RESULTS+=("| $vm | \`$check\` | ECHEC |"); status=ECHEC
fi
done
$KEEP || step "$SCRIPTS_DIR/vm-snapshot.sh" "$vm" restore "$SNAPSHOT" -y
SUMMARY+=("| $vm | $status |")
}
if ! $DRY_RUN; then
for s in vm-snapshot.sh vm-exec.sh; do
[ -x "$SCRIPTS_DIR/$s" ] || { echo "introuvable : $SCRIPTS_DIR/$s (--scripts-dir)" >&2; exit 2; }
done
git -C "$ROOT" branch -r --contains "$REF" | grep -q . \
|| { echo "le commit $REF n'est pas pousse : les VM clonent depuis $REPO" >&2; exit 2; }
fi
RESULTS=(); SUMMARY=(); FAILED=0
for vm in "${VMS[@]}"; do run_vm "$vm" || FAILED=1; done
if $DRY_RUN; then echo "[plan] rapport : ${REPORT#"$ROOT"/}"; exit 0; fi
mkdir -p "$REPORT_DIR"
{
echo "# Test d'installation en VM : $STAMP"
echo
echo "- Commit : \`$REF\`"
echo "- Snapshot de depart : \`$SNAPSHOT\` ; Ollama : hote de la VM"
echo "- Script : \`tests/installer/vm_install_test.sh\` (installeur \`--headless\`)"
echo
echo "| VM | Resultat |"; echo "|---|---|"; printf '%s\n' "${SUMMARY[@]}"
echo
echo "| VM | Verification | Resultat |"; echo "|---|---|---|"; printf '%s\n' "${RESULTS[@]}"
} > "$REPORT"
echo "rapport : ${REPORT#"$ROOT"/}"
grep -q "ECHEC" "$REPORT" && FAILED=1
exit "$FAILED"