Jahres-Reimage: Boot-Check, GRUB-Eintrag, Clonezilla-Batch-Skript
reimage-check erkennt die Platte DEZNTRSICHERUNG mit neuerem Image und bootet in den GRUB-Eintrag Schul-Neuinstallation (Clonezilla toram). schul-reimage.sh: Mini-Menue (AUFSPIELEN auto nach 20 s / IMAGE ERSTELLEN / Abbrechen), ocs-sr im Batch-Modus ohne Nachpruefung (E-004), Hostname bleibt erhalten, Admin-Key nur auf laptop03 (E-005). local.yml haelt alles per Pull aktuell. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
9
files/clonezilla/grub-custom.cfg
Normal file
9
files/clonezilla/grub-custom.cfg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Wird von GRUB (41_custom) zur Boot-Zeit gelesen — kein update-grub noetig.
|
||||||
|
# Ziel von "grub-reboot Schul-Neuinstallation" (reimage-check.service).
|
||||||
|
# Bootet Clonezilla-Live aus /boot/clonezilla komplett ins RAM (toram),
|
||||||
|
# damit die eigene Platte ueberschrieben werden kann.
|
||||||
|
menuentry "Schul-Neuinstallation" {
|
||||||
|
search --no-floppy --file --set=root /boot/clonezilla/vmlinuz
|
||||||
|
linux /boot/clonezilla/vmlinuz boot=live union=overlay username=user config components noswap edd=on noprompt nosplash live-media-path=/boot/clonezilla toram=filesystem.squashfs locales=de_DE.UTF-8 keyboard-layouts=de ocs_live_batch="yes" ocs_live_run="bash /run/live/medium/boot/clonezilla/schul-reimage.sh"
|
||||||
|
initrd /boot/clonezilla/initrd.img
|
||||||
|
}
|
||||||
118
files/clonezilla/schul-reimage.sh
Normal file
118
files/clonezilla/schul-reimage.sh
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Laeuft in der Clonezilla-Live-Umgebung (via ocs_live_run, toram).
|
||||||
|
# Eigenes Mini-Menue statt Clonezilla-TUI, alle Sicherheitsschranken aus (E-004):
|
||||||
|
#
|
||||||
|
# AUFSPIELEN - neuestes Image von der Platte, Hostname bleibt erhalten
|
||||||
|
# (vorausgewaehlt, startet nach 20 s automatisch)
|
||||||
|
# IMAGE ERSTELLEN - sichert diesen Rechner als schule-laptop-<Datum>
|
||||||
|
# ABBRECHEN - Neustart ins normale System
|
||||||
|
#
|
||||||
|
set -u
|
||||||
|
|
||||||
|
DISK="sda"
|
||||||
|
ROOT_PART="/dev/sda2" # 12x identische Hardware: UEFI, sda1=EFI, sda2=System
|
||||||
|
LABEL="DEZNTRSICHERUNG"
|
||||||
|
IMG_MNT="/home/partimag" # Clonezilla-Standardpfad fuer Images
|
||||||
|
VERSION_FILE="/etc/schul-image-version"
|
||||||
|
|
||||||
|
rot() { echo -e "\033[0;31m$*\033[0m"; }
|
||||||
|
gruen(){ echo -e "\033[0;32m$*\033[0m"; }
|
||||||
|
gelb() { echo -e "\033[1;33m$*\033[0m"; }
|
||||||
|
|
||||||
|
# ---------- Image-Platte einbinden ----------
|
||||||
|
mkdir -p "$IMG_MNT"
|
||||||
|
if ! mountpoint -q "$IMG_MNT"; then
|
||||||
|
DEV=$(blkid -L "$LABEL" 2>/dev/null)
|
||||||
|
if [ -z "$DEV" ] || ! mount "$DEV" "$IMG_MNT"; then
|
||||||
|
rot "Platte '$LABEL' nicht gefunden — Neustart in 15 s."
|
||||||
|
sleep 15; reboot; exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
NEWEST=$(find "$IMG_MNT" -maxdepth 1 -name 'schule-laptop-*' -type d -printf '%f\n' | sort | tail -1)
|
||||||
|
|
||||||
|
# ---------- Hostname aus dem alten System retten ----------
|
||||||
|
OLD_HOSTNAME=""
|
||||||
|
mkdir -p /mnt/altes-system
|
||||||
|
if mount -o ro "$ROOT_PART" /mnt/altes-system 2>/dev/null; then
|
||||||
|
OLD_HOSTNAME=$(cat /mnt/altes-system/etc/hostname 2>/dev/null | tr -d '[:space:]')
|
||||||
|
umount /mnt/altes-system
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---------- Mini-Menue ----------
|
||||||
|
clear
|
||||||
|
gruen "==============================================="
|
||||||
|
gruen " SCHUL-LAPTOPS — IMAGE-STATION"
|
||||||
|
gruen "==============================================="
|
||||||
|
echo "Rechner: ${OLD_HOSTNAME:-unbekannt}"
|
||||||
|
echo "Neuestes Image: ${NEWEST:-KEINES GEFUNDEN}"
|
||||||
|
echo
|
||||||
|
echo " [a] AUFSPIELEN (Standard, startet automatisch)"
|
||||||
|
echo " [i] IMAGE ERSTELLEN (diesen Rechner sichern)"
|
||||||
|
echo " [x] Abbrechen (Neustart ins normale System)"
|
||||||
|
echo
|
||||||
|
gelb "AUFSPIELEN startet in 20 Sekunden ..."
|
||||||
|
WAHL="a"
|
||||||
|
read -t 20 -n 1 -r WAHL_INPUT && WAHL="${WAHL_INPUT:-a}"
|
||||||
|
echo
|
||||||
|
|
||||||
|
case "$WAHL" in
|
||||||
|
i|I)
|
||||||
|
NEU="schule-laptop-$(date +%Y-%m-%d)"
|
||||||
|
gelb "Erstelle Image '$NEU' von /dev/$DISK ..."
|
||||||
|
# Batch, zstd-Kompression, KEINE Nachpruefung des Images (-scs, E-004)
|
||||||
|
/usr/sbin/ocs-sr -q2 -j2 -z5p -i 4096 -sfsck -senc -scs -batch -p true savedisk "$NEU" "$DISK"
|
||||||
|
# Eigene Versionsdatei nachziehen: der gesicherte Rechner ist damit "aktuell"
|
||||||
|
# und bespielt sich nicht beim naechsten Boot selbst mit dem eigenen Image.
|
||||||
|
if mount "$ROOT_PART" /mnt/altes-system 2>/dev/null; then
|
||||||
|
echo "$NEU" > /mnt/altes-system$VERSION_FILE
|
||||||
|
umount /mnt/altes-system
|
||||||
|
fi
|
||||||
|
gruen "Image '$NEU' erstellt — Rechner faehrt herunter."
|
||||||
|
sleep 5; poweroff
|
||||||
|
;;
|
||||||
|
x|X)
|
||||||
|
gelb "Abgebrochen — Neustart."
|
||||||
|
sleep 3; reboot
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ -z "$NEWEST" ]; then
|
||||||
|
rot "Kein Image auf der Platte — Neustart in 15 s."
|
||||||
|
sleep 15; reboot; exit 1
|
||||||
|
fi
|
||||||
|
gelb "Spiele '$NEWEST' auf /dev/$DISK auf ..."
|
||||||
|
# Batch, KEINE Bestaetigungen, KEINE Nachpruefung (-scr), Groessencheck aus (E-004)
|
||||||
|
/usr/sbin/ocs-sr -g auto -e1 auto -e2 -r -j2 -icds -k1 -scr -batch -p true restoredisk "$NEWEST" "$DISK"
|
||||||
|
|
||||||
|
# ---------- Frisches System personalisieren ----------
|
||||||
|
gelb "Personalisiere frisches System (${OLD_HOSTNAME:-laptopXX}) ..."
|
||||||
|
mkdir -p /mnt/neues-system
|
||||||
|
if mount "$ROOT_PART" /mnt/neues-system; then
|
||||||
|
if [ -n "$OLD_HOSTNAME" ]; then
|
||||||
|
echo "$OLD_HOSTNAME" > /mnt/neues-system/etc/hostname
|
||||||
|
sed -i "s/127.0.1.1.*/127.0.1.1\t$OLD_HOSTNAME/" /mnt/neues-system/etc/hosts
|
||||||
|
fi
|
||||||
|
# Neue SSH-Host-Keys + Machine-ID (jeder Klon muss eindeutig sein)
|
||||||
|
rm -f /mnt/neues-system/etc/ssh/ssh_host_*
|
||||||
|
chroot /mnt/neues-system ssh-keygen -A
|
||||||
|
rm -f /mnt/neues-system/etc/machine-id /mnt/neues-system/var/lib/dbus/machine-id
|
||||||
|
chroot /mnt/neues-system dbus-uuidgen --ensure=/etc/machine-id
|
||||||
|
cp /mnt/neues-system/etc/machine-id /mnt/neues-system/var/lib/dbus/machine-id
|
||||||
|
# Versionsdatei: dieses Image ist jetzt installiert
|
||||||
|
echo "$NEWEST" > /mnt/neues-system$VERSION_FILE
|
||||||
|
# Privater Gitea-Admin-Key gehoert nur auf laptop03 (E-005)
|
||||||
|
if [ "$OLD_HOSTNAME" != "laptop03" ]; then
|
||||||
|
rm -f /mnt/neues-system/home/puettmann/.ssh/id_ed25519 \
|
||||||
|
/mnt/neues-system/home/puettmann/.ssh/id_ed25519.pub
|
||||||
|
fi
|
||||||
|
umount /mnt/neues-system
|
||||||
|
gruen "Fertig: ${OLD_HOSTNAME:-unbenannt} mit Image '$NEWEST'."
|
||||||
|
else
|
||||||
|
rot "Konnte frisches System nicht mounten — Personalisierung uebersprungen!"
|
||||||
|
rot "Bitte von Hand: first-boot-setup.sh ausfuehren."
|
||||||
|
sleep 15
|
||||||
|
fi
|
||||||
|
sleep 5; poweroff
|
||||||
|
;;
|
||||||
|
esac
|
||||||
11
files/reimage-check.service
Normal file
11
files/reimage-check.service
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Schul-Laptops: Pruefen ob ein neues Image aufgespielt werden soll
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
# USB-Platte braucht einen Moment, bis sie erkannt ist
|
||||||
|
ExecStartPre=/bin/sleep 5
|
||||||
|
ExecStart=/usr/local/bin/reimage-check.sh
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
37
files/reimage-check.sh
Normal file
37
files/reimage-check.sh
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Prueft beim Boot, ob die Image-Platte (DEZNTRSICHERUNG) angeschlossen ist
|
||||||
|
# und ein neueres Image traegt als das installierte. Wenn ja: einmaliger
|
||||||
|
# Reboot in den GRUB-Eintrag "Schul-Neuinstallation" (Clonezilla, toram).
|
||||||
|
#
|
||||||
|
# Sicherungen gegen Fehlausloesung:
|
||||||
|
# - laptop03 (Master) bespielt sich nie selbst (E-004)
|
||||||
|
# - Versionsvergleich verhindert Reimage-Schleifen bei steckender Platte
|
||||||
|
#
|
||||||
|
set -u
|
||||||
|
|
||||||
|
LABEL="DEZNTRSICHERUNG"
|
||||||
|
VERSION_FILE="/etc/schul-image-version"
|
||||||
|
GRUB_ENTRY="Schul-Neuinstallation"
|
||||||
|
|
||||||
|
# Der Master ist tabu — doppelte Absicherung zusaetzlich zum deaktivierten Service
|
||||||
|
[ "$(hostname)" = "laptop03" ] && exit 0
|
||||||
|
|
||||||
|
DEV=$(blkid -L "$LABEL" 2>/dev/null) || exit 0
|
||||||
|
[ -n "$DEV" ] || exit 0
|
||||||
|
|
||||||
|
MNT=$(mktemp -d)
|
||||||
|
mount -o ro "$DEV" "$MNT" 2>/dev/null || { rmdir "$MNT"; exit 0; }
|
||||||
|
NEWEST=$(find "$MNT" -maxdepth 1 -name 'schule-laptop-*' -type d -printf '%f\n' 2>/dev/null | sort | tail -1)
|
||||||
|
umount "$MNT"
|
||||||
|
rmdir "$MNT"
|
||||||
|
|
||||||
|
[ -n "$NEWEST" ] || exit 0
|
||||||
|
INSTALLED=$(cat "$VERSION_FILE" 2>/dev/null || echo "0")
|
||||||
|
|
||||||
|
if [ "$NEWEST" \> "$INSTALLED" ]; then
|
||||||
|
echo "Neues Image '$NEWEST' gefunden (installiert: '$INSTALLED') — Neuinstallation beim naechsten Boot."
|
||||||
|
grub-reboot "$GRUB_ENTRY" && systemctl reboot
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
69
local.yml
69
local.yml
@@ -50,6 +50,75 @@
|
|||||||
enabled: yes
|
enabled: yes
|
||||||
state: started
|
state: started
|
||||||
|
|
||||||
|
# --- Jahres-Reimage: Boot-Check + GRUB-Eintrag aktuell halten ---
|
||||||
|
|
||||||
|
- name: reimage-check-Script installieren
|
||||||
|
copy:
|
||||||
|
src: files/reimage-check.sh
|
||||||
|
dest: /usr/local/bin/reimage-check.sh
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: reimage-check.service installieren
|
||||||
|
copy:
|
||||||
|
src: files/reimage-check.service
|
||||||
|
dest: /etc/systemd/system/reimage-check.service
|
||||||
|
mode: "0644"
|
||||||
|
register: reimage_unit
|
||||||
|
|
||||||
|
- name: systemd neu laden, falls reimage-Unit geaendert
|
||||||
|
systemd:
|
||||||
|
daemon_reload: yes
|
||||||
|
when: reimage_unit.changed
|
||||||
|
|
||||||
|
- name: reimage-check aktivieren (alle ausser Master laptop03)
|
||||||
|
systemd:
|
||||||
|
name: reimage-check.service
|
||||||
|
enabled: "{{ 'no' if ansible_hostname == 'laptop03' else 'yes' }}"
|
||||||
|
|
||||||
|
- name: GRUB auf gespeicherten Default umstellen (fuer grub-reboot)
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/default/grub
|
||||||
|
regexp: '^GRUB_DEFAULT='
|
||||||
|
line: 'GRUB_DEFAULT=saved'
|
||||||
|
register: grub_default
|
||||||
|
|
||||||
|
- name: update-grub ausfuehren, falls GRUB-Konfig geaendert
|
||||||
|
command: update-grub
|
||||||
|
when: grub_default.changed
|
||||||
|
|
||||||
|
- name: Normalen Boot als gespeicherten Default setzen
|
||||||
|
command: grub-set-default 0
|
||||||
|
args:
|
||||||
|
creates: /boot/grub/grubenv
|
||||||
|
|
||||||
|
- name: GRUB-Eintrag Schul-Neuinstallation installieren
|
||||||
|
copy:
|
||||||
|
src: files/clonezilla/grub-custom.cfg
|
||||||
|
dest: /boot/grub/custom.cfg
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Verzeichnis /boot/clonezilla anlegen
|
||||||
|
file:
|
||||||
|
path: /boot/clonezilla
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Reimage-Skript nach /boot/clonezilla verteilen
|
||||||
|
copy:
|
||||||
|
src: files/clonezilla/schul-reimage.sh
|
||||||
|
dest: /boot/clonezilla/schul-reimage.sh
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Pruefen ob Clonezilla-Live-Dateien vorhanden sind
|
||||||
|
stat:
|
||||||
|
path: /boot/clonezilla/filesystem.squashfs
|
||||||
|
register: clonezilla_live
|
||||||
|
|
||||||
|
- name: Hinweis falls Clonezilla-Live-Dateien fehlen
|
||||||
|
debug:
|
||||||
|
msg: "HINWEIS: /boot/clonezilla ohne Live-Dateien (vmlinuz, initrd.img, filesystem.squashfs) — Reimage ohne Stick nicht moeglich."
|
||||||
|
when: not clonezilla_live.stat.exists
|
||||||
|
|
||||||
# --- Status melden ---
|
# --- Status melden ---
|
||||||
|
|
||||||
- name: Pruefen ob ein Neustart noetig ist
|
- name: Pruefen ob ein Neustart noetig ist
|
||||||
|
|||||||
Reference in New Issue
Block a user