construit l'image paillasse-debian, crée le projet OpenStack et teste la console série

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Adam Belkacemi 2026-10-07 16:14:06 +02:00
parent 21c9de6d10
commit 44384847e5
8 changed files with 331 additions and 1 deletions

View file

@ -0,0 +1,81 @@
#!/bin/bash
# Construit l'image Glance `paillasse-debian`, à lancer sur le serveur Syllabus
# (a besoin d'Internet pour télécharger l'image cloud officielle et les
# paquets, et de /dev/kvm pour que virt-customize aille vite).
#
# Usage : sudo bash construire-paillasse-debian.sh
#
# Ne supprime jamais une image existante toute seule (règle 3 : suppression =
# accord explicite d'Adam) : s'arrête si `paillasse-debian` existe déjà.
set -euo pipefail
DOSSIER_SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# lycee.sql est copié ici par Ansible (ansible/roles/images/), à côté du
# script, pour ne pas avoir besoin d'un clone complet du dépôt sur le serveur.
LYCEE_SQL="$DOSSIER_SCRIPT/lycee.sql"
URL_BASE="https://cloud.debian.org/images/cloud/bookworm/latest"
IMAGE_BASE="debian-12-genericcloud-amd64.qcow2"
export OS_CLIENT_CONFIG_FILE=/etc/kolla/clouds.yaml
export OS_CLOUD=kolla-admin
export PATH=/opt/kolla-venv/bin:$PATH
if openstack image show paillasse-debian >/dev/null 2>&1; then
echo "L'image « paillasse-debian » existe déjà dans Glance." >&2
echo "Supprime-la toi-même si tu veux la reconstruire (openstack image delete paillasse-debian) : Claude ne le fait pas automatiquement." >&2
exit 1
fi
TRAVAIL=$(mktemp -d)
trap 'rm -rf "$TRAVAIL"' EXIT
echo "== Téléchargement de l'image cloud Debian 12 officielle =="
curl -fsSL -o "$TRAVAIL/SHA512SUMS" "$URL_BASE/SHA512SUMS"
curl -fsSL -o "$TRAVAIL/$IMAGE_BASE" "$URL_BASE/$IMAGE_BASE"
echo "== Vérification de la somme SHA512 =="
(cd "$TRAVAIL" && grep " $IMAGE_BASE\$" SHA512SUMS | sha512sum -c -)
IMAGE_TRAVAIL="$TRAVAIL/paillasse-debian.qcow2"
cp "$TRAVAIL/$IMAGE_BASE" "$IMAGE_TRAVAIL"
echo "== Préparation des fichiers à copier dans l'image =="
mkdir -p "$TRAVAIL/copie/labs/07" "$TRAVAIL/copie/paquets"
cp "$LYCEE_SQL" "$TRAVAIL/copie/labs/07/lycee.sql"
echo "== Téléchargement du paquet tree (lab 02 : installation hors ligne) =="
apt-get update -qq
(cd "$TRAVAIL/copie/paquets" && apt-get download tree)
echo "== Personnalisation avec virt-customize =="
# Remarque sur `tree` : volontairement absent de --install. Le lab 02 demande
# à l'élève de l'installer lui-même depuis /opt/paquets/ ; il serait sans
# intérêt pédagogique s'il était déjà présent (contrairement à ce que
# suggérait une première lecture de paillasse-contenus/README.md).
#
# cloud-init est retiré : les réseaux de lab n'ont ni DHCP ni service de
# métadonnées joignable (pas de routeur), donc cloud-init ne ferait
# qu'attendre inutilement à chaque démarrage. La correction automatique passe
# par l'agent QEMU (guest-exec), pas par cloud-init/user-data.
virt-customize -a "$IMAGE_TRAVAIL" \
--install sudo,qemu-guest-agent,iproute2,iputils-ping,traceroute,tcpdump,dnsutils,curl,netcat-openbsd,openssl,nano,vim,htop,nginx,mariadb-server,frr \
--run-command 'useradd -m -s /bin/bash -G sudo eleve' \
--password 'eleve:password:eleve' \
--run-command 'systemctl enable serial-getty@ttyS0.service' \
--run-command 'systemctl disable nginx mariadb frr' \
--run-command 'apt-get purge -y cloud-init && rm -rf /etc/cloud /var/lib/cloud' \
--run-command 'mkdir -p /opt/labs/07' \
--copy-in "$TRAVAIL/copie/labs/07/lycee.sql:/opt/labs/07" \
--copy-in "$TRAVAIL/copie/paquets:/opt"
echo "== Import dans Glance =="
openstack image create "paillasse-debian" \
--disk-format qcow2 --container-format bare \
--property hw_qemu_guest_agent=yes \
--property hw_rng_model=virtio \
--property os_type=linux \
--file "$IMAGE_TRAVAIL"
openstack image show paillasse-debian -c id -c status -c size -c properties
echo "== Terminé =="

View file

@ -0,0 +1,57 @@
#!/usr/bin/env python3
"""Test manuel de la console série Nova (étape 6 du déploiement).
Usage : python3 test-console-serie.py <url-ws> <commande-a-taper>
"""
import sys
import time
import websocket
url = sys.argv[1]
commande = sys.argv[2] if len(sys.argv) > 2 else "echo bonjour-syllabus"
ws = websocket.create_connection(url, subprotocols=["binary"], timeout=10)
def lire(duree=3):
fin = time.time() + duree
sortie = b""
while time.time() < fin:
ws.settimeout(max(0.2, fin - time.time()))
try:
morceau = ws.recv()
except websocket.WebSocketTimeoutException:
break
except websocket.WebSocketConnectionClosedException:
print("[connexion fermée par le serveur]")
break
if isinstance(morceau, str):
morceau = morceau.encode()
if not morceau:
break
sortie += morceau
return sortie
print("=== lecture initiale (vide la file, y compris un essai précédent) ===")
sys.stdout.buffer.write(lire(5))
sys.stdout.flush()
print("\n=== connexion : eleve ===")
ws.send_binary(b"eleve\r")
sys.stdout.buffer.write(lire(2))
sys.stdout.flush()
print("\n=== mot de passe ===")
ws.send_binary(b"eleve\r")
sys.stdout.buffer.write(lire(2))
sys.stdout.flush()
print(f"\n=== envoi de la commande : {commande} ===")
ws.send_binary((commande + "\r").encode())
sys.stdout.buffer.write(lire(3))
sys.stdout.flush()
ws.close()
print("\n=== fin ===")