Compare commits
7 Commits
9cd471d66e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| aa5a1fcf0a | |||
| f81dbd8d54 | |||
| 313cfae828 | |||
| 72d0b11647 | |||
| 78b8e68f9f | |||
| d349595aec | |||
| 22bb3ccec9 |
@@ -1,110 +1,36 @@
|
|||||||
# Anleitung: Nach dem Klonen
|
# Anleitung: Nach dem Klonen
|
||||||
|
|
||||||
Diese Anleitung gilt NACHDEM du:
|
Gilt fuer die **Erstinstallation per USB-Stick** (Weg 3 in
|
||||||
- Das Image mit Clonezilla aufgespielt hast
|
`CLONEZILLA_AUTOMATISCH.md`). Beim automatischen Jahres-Reimage von der
|
||||||
- Das First-Boot-Script ausgefuehrt hast (`sudo ~/ansible-schule/files/first-boot-setup.sh laptopXX`)
|
externen Platte ist NICHTS davon noetig — dort passiert alles von selbst.
|
||||||
|
|
||||||
---
|
## Auf dem frisch geklonten Laptop (einmalig)
|
||||||
|
|
||||||
## Auf dem Controller (laptop03)
|
|
||||||
|
|
||||||
### Schritt 1: IPs aktualisieren
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/ansible-schule
|
sudo ~/projekte/schul-laptops/files/first-boot-setup.sh laptopXX
|
||||||
./update-ips.sh
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Das Script findet automatisch alle eingeschalteten Laptops im Netzwerk und traegt ihre IPs in die inventory.yml ein.
|
Das Script setzt Hostname, SSH-Host-Keys und Machine-ID, entfernt den
|
||||||
|
Admin-Key (ausser auf laptop03) und aktiviert den ansible-pull-Timer.
|
||||||
|
**Das war's** — ab jetzt holt sich der Laptop alle 30 Minuten selbst
|
||||||
|
Updates und Konfiguration aus Gitea, egal in welchem Netz er haengt.
|
||||||
|
|
||||||
**Erwartete Ausgabe:**
|
## Kontrolle (optional)
|
||||||
```
|
|
||||||
=== IP-Adressen aktualisieren ===
|
|
||||||
|
|
||||||
laptop01: 192.168.x.x
|
|
||||||
laptop02: nicht erreichbar
|
|
||||||
laptop03: 192.168.x.x
|
|
||||||
...
|
|
||||||
|
|
||||||
=== Fertig ===
|
|
||||||
Aktualisiert: 5
|
|
||||||
Nicht erreichbar: 11
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Schritt 2: Verbindung testen
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ansible all -m ping
|
systemctl list-timers ansible-pull* # Timer aktiv?
|
||||||
|
journalctl -u ansible-pull -n 30 # letzter Pull-Lauf ok?
|
||||||
|
cat /etc/schul-image-version # installiertes Image
|
||||||
```
|
```
|
||||||
|
|
||||||
**Erfolg sieht so aus:**
|
|
||||||
```
|
|
||||||
laptop03 | SUCCESS => { "ping": "pong" }
|
|
||||||
laptop10 | SUCCESS => { "ping": "pong" }
|
|
||||||
```
|
|
||||||
|
|
||||||
**Fehler ignorieren** fuer Laptops die nicht eingeschaltet sind - das ist normal.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Schritt 3: Updates auf alle erreichbaren Laptops
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook playbooks/update.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
Oder nur auf bestimmte:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook playbooks/update.yml --limit laptop10,laptop11
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Schnellreferenz
|
|
||||||
|
|
||||||
| Was | Befehl |
|
|
||||||
|-----|--------|
|
|
||||||
| IPs aktualisieren | `./update-ips.sh` |
|
|
||||||
| Alle pingen | `ansible all -m ping` |
|
|
||||||
| System-Update | `ansible-playbook playbooks/update.yml` |
|
|
||||||
| Software installieren | `ansible-playbook playbooks/install-software.yml -e "packages=['vlc']"` |
|
|
||||||
| Neustarten | `ansible-playbook playbooks/reboot.yml` |
|
|
||||||
| Nur bestimmte Rechner | `--limit laptop05,laptop06` |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Problemloesungen
|
|
||||||
|
|
||||||
### "nicht erreichbar" bei update-ips.sh
|
|
||||||
|
|
||||||
- Ist der Laptop eingeschaltet?
|
|
||||||
- Ist er im gleichen Netzwerk (WLAN/Kabel)?
|
|
||||||
- Wurde das First-Boot-Script ausgefuehrt?
|
|
||||||
|
|
||||||
### SSH-Fehler "Host key verification failed"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ssh-keygen -R 192.168.x.x
|
|
||||||
```
|
|
||||||
|
|
||||||
(Die IP durch die tatsaechliche IP ersetzen)
|
|
||||||
|
|
||||||
### Ansible findet inventory nicht
|
|
||||||
|
|
||||||
Immer aus dem richtigen Verzeichnis ausfuehren:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/ansible-schule
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Checkliste neuer Laptop
|
## Checkliste neuer Laptop
|
||||||
|
|
||||||
- [ ] Image mit Clonezilla aufgespielt
|
- [ ] Image per Stick aufgespielt (nimmt automatisch das neueste)
|
||||||
- [ ] First-Boot-Script: `sudo ~/ansible-schule/files/first-boot-setup.sh laptopXX`
|
- [ ] `sudo files/first-boot-setup.sh laptopXX` ausgefuehrt
|
||||||
- [ ] Auf Controller: `./update-ips.sh`
|
- [ ] `journalctl -u ansible-pull` zeigt einen erfolgreichen Lauf
|
||||||
- [ ] Testen: `ansible laptopXX -m ping`
|
|
||||||
|
## Legacy: Push-Betrieb im Heimnetz
|
||||||
|
|
||||||
|
Nur noetig, wenn du aktiv per Push arbeiten willst (funktioniert nicht im
|
||||||
|
Schul-WLAN) — siehe README.md, Abschnitt „Legacy“ (`update-ips.sh`,
|
||||||
|
`ansible-playbook playbooks/...`).
|
||||||
|
|||||||
19
CHANGELOG.md
19
CHANGELOG.md
@@ -1,5 +1,24 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-07-13 — Umbau umgesetzt (Teile A–C)
|
||||||
|
|
||||||
|
- **Server:** DNS `git.lehrstun.de` (A-Record via Server-Token angelegt),
|
||||||
|
Nginx-vHost mit Let's-Encrypt-Zertifikat → Gitea; Read-only-Deploy-Key
|
||||||
|
`ansible-pull-deploy` am Repo, privater Key unter `/root/.ssh/` auf laptop03.
|
||||||
|
Beide Pull-Wege (HTTPS + SSH 2222) Ende-zu-Ende getestet.
|
||||||
|
- **Pull-Mechanik:** `local.yml`, `schul-pull.sh`, systemd-Timer (Boot + 30 min)
|
||||||
|
— laeuft auf laptop03, verwaltet sich selbst per Pull.
|
||||||
|
- **Jahres-Reimage:** `reimage-check.service` (auf laptop03 deaktiviert),
|
||||||
|
GRUB-Eintrag „Schul-Neuinstallation“ (custom.cfg, GRUB_DEFAULT=saved),
|
||||||
|
`schul-reimage.sh` mit Mini-Menue und ocs-sr-Batch-Aufrufen. Per Pull verteilt.
|
||||||
|
- **Doku:** README, CLONEZILLA_AUTOMATISCH, ANLEITUNG_NACH_KLONEN auf den neuen
|
||||||
|
Ablauf umgestellt.
|
||||||
|
- **Offen:** Live-Dateien vom Stick, Image umbenennen, Stick-Update,
|
||||||
|
Reimage-Test (siehe [[CLAUDE]]).
|
||||||
|
- **Sitzungsende:** Weiter am 2026-07-15. Erster Schritt dann: Herb prueft
|
||||||
|
laptop03 auf Image-Reife (was soll geklont werden?) — erst danach
|
||||||
|
Master-Image. Reihenfolge steht unmissverstaendlich in [[CLAUDE]].
|
||||||
|
|
||||||
## 2026-07-13 — Projektgruendung & Kurswechsel auf Pull
|
## 2026-07-13 — Projektgruendung & Kurswechsel auf Pull
|
||||||
|
|
||||||
- Alter git-loser Ordner `~/ansible-schule` (Jan/Feb 2026) nach
|
- Alter git-loser Ordner `~/ansible-schule` (Jan/Feb 2026) nach
|
||||||
|
|||||||
39
CLAUDE.md
39
CLAUDE.md
@@ -1,6 +1,6 @@
|
|||||||
# schul-laptops — Projektstatus
|
# schul-laptops — Projektstatus
|
||||||
|
|
||||||
Status: aktiv · Stand: 2026-07-13
|
Status: aktiv · Stand: 2026-07-13 · Pull-Mechanik LAEUFT auf laptop03, Reimage-Skripte verteilt — es fehlt nur noch der Hardware-Teil (Stick/Platte)
|
||||||
|
|
||||||
## Worum es geht
|
## Worum es geht
|
||||||
|
|
||||||
@@ -31,15 +31,38 @@ Benutzer auf den Laptops: `puettmann` (Admin, passwordless sudo), `schueler` (oh
|
|||||||
|
|
||||||
## Blocker
|
## Blocker
|
||||||
|
|
||||||
- Keine.
|
- Keine Software-Blocker. Es fehlt nur Hardware am laptop03:
|
||||||
|
CLONEZILLA-Stick + Platte DEZNTRSICHERUNG (siehe naechste Schritte).
|
||||||
|
|
||||||
## Naechste Schritte
|
## Naechste Schritte — GENAU IN DIESER REIHENFOLGE (naechste Sitzung: 2026-07-15)
|
||||||
|
|
||||||
- [ ] Teil A: Server — DNS `git.lehrstun.de`, Nginx-vHost, Deploy-Key
|
**Als Erstes, BEVOR irgendein Image erstellt wird:**
|
||||||
- [ ] Teil B: Pull-Mechanik (local.yml, schul-pull.sh, systemd-Units, first-boot)
|
|
||||||
- [ ] Teil C: Jahres-Reimage (Clonezilla lokal, Boot-Check, Mini-Menue)
|
1. [ ] **Herb prueft laptop03 auf Image-Reife.** Herb will kontrollieren, ob
|
||||||
- [ ] Teil D: Aktivierung auf laptop03 + Verifikation
|
alles auf diesem Rechner ist, was geklont werden soll (Software, Einstellungen,
|
||||||
- [ ] Master-Image erstellen, Rollout auf laptop01–16 (auch laptop10 neu)
|
schueler-Account). Die naechste Instanz soll ihn dabei aktiv unterstuetzen:
|
||||||
|
installierte Programme durchgehen, Home-Verzeichnisse auf Muell/Privates
|
||||||
|
pruefen (z.B. `~/RS41ng` bleibt — ist ok, wird mitgeklont), offene Fragen stellen.
|
||||||
|
**Kein Master-Image erstellen, bevor Herb das freigegeben hat!**
|
||||||
|
|
||||||
|
**Danach (Stick + Platte muessen an laptop03 stecken):**
|
||||||
|
|
||||||
|
2. [ ] Clonezilla-Live-Dateien vom Stick (Ordner `/live/`: vmlinuz, initrd.img,
|
||||||
|
filesystem.squashfs) nach `/boot/clonezilla/` kopieren
|
||||||
|
3. [ ] Bestandsimage auf der Platte umbenennen: `schule-laptop` →
|
||||||
|
`schule-laptop-2026-02-01` (Datums-Schema, neuestes gewinnt)
|
||||||
|
4. [ ] Stick-Menue (syslinux.cfg + grub.cfg auf dem Stick) auf
|
||||||
|
„neuestes Image“-Logik + `files/clonezilla/schul-reimage.sh` umstellen
|
||||||
|
5. [ ] Reimage-Kette TROCKEN testen (auf laptop03 nur den Check, nie den Restore:
|
||||||
|
`sudo /usr/local/bin/reimage-check.sh` mit angesteckter Platte ausfuehren —
|
||||||
|
wegen Hostname-Schutz muss er ohne Aktion beenden; Logik ggf. mit
|
||||||
|
ueberschriebenem Hostname-Check auf einer Wegwerf-Kopie pruefen)
|
||||||
|
6. [ ] Neues Master-Image erstellen: laptop03 neu starten, GRUB-Eintrag
|
||||||
|
„Schul-Neuinstallation“ → Taste `i` (IMAGE ERSTELLEN)
|
||||||
|
7. [ ] ECHTER Reimage-Test auf laptop10 (Opfer-Laptop): Platte dran, einschalten,
|
||||||
|
warten — muss sich danach als laptop10 mit neuem Image melden
|
||||||
|
8. [ ] Rollout auf laptop01–16 (Erstinstallation per Stick, Weg 3 in
|
||||||
|
`CLONEZILLA_AUTOMATISCH.md`)
|
||||||
|
|
||||||
## Hinweise
|
## Hinweise
|
||||||
|
|
||||||
|
|||||||
@@ -1,99 +1,82 @@
|
|||||||
# Clonezilla Automatisiert - USB + Externe Festplatte
|
# Clonezilla — Images erstellen & aufspielen
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
- **USB-Stick:** CLONEZILLA (7,6 GB) - enthält Clonezilla Live
|
- **Externe Festplatte:** `DEZNTRSICHERUNG` (1,8 TB) — traegt die Images
|
||||||
- **Externe Festplatte:** DEZNTRSICHERUNG (1,8 TB) - enthält das Image
|
- **Images:** Ordner `schule-laptop-JJJJ-MM-TT` — es koennen mehrere liegen,
|
||||||
- **Image-Name:** `schule-laptop`
|
**das neueste (Datumsname) gewinnt immer**
|
||||||
|
- **USB-Stick:** `CLONEZILLA` — nur noch fuer die **Erstinstallation** und als
|
||||||
|
Rettung, falls ein Laptop gar nicht mehr bootet
|
||||||
|
- Jeder Laptop merkt sich sein installiertes Image in `/etc/schul-image-version`
|
||||||
|
|
||||||
## Boot-Menü
|
## Weg 1: Jahres-Reimage OHNE Stick (der Normalfall)
|
||||||
|
|
||||||
Beim Booten vom USB-Stick erscheinen zwei Hauptoptionen:
|
1. Platte `DEZNTRSICHERUNG` an den Laptop anstecken
|
||||||
|
2. Laptop einschalten — mehr nicht
|
||||||
|
3. Der Laptop erkennt beim Boot, dass ein neueres Image auf der Platte liegt,
|
||||||
|
und startet automatisch in die Image-Station (Clonezilla aus `/boot/clonezilla`,
|
||||||
|
laeuft komplett im RAM)
|
||||||
|
4. Mini-Menue erscheint:
|
||||||
|
- **AUFSPIELEN** — vorausgewaehlt, startet nach 20 s von selbst
|
||||||
|
- **IMAGE ERSTELLEN** — diesen Rechner als neues Image sichern
|
||||||
|
- **Abbrechen** — normaler Neustart
|
||||||
|
5. Beim Aufspielen bleibt der **Hostname erhalten** (laptop11 bleibt laptop11);
|
||||||
|
SSH-Host-Keys, Machine-ID und Versionsdatei werden automatisch neu gesetzt.
|
||||||
|
Danach: Poweroff. Fertig — kein first-boot-Script noetig.
|
||||||
|
|
||||||
```
|
Steckt die Platte beim naechsten Boot noch, passiert nichts mehr
|
||||||
>>> IMAGE AUFSPIELEN (Laptop bespielen) <<< [Standard]
|
(Versionsvergleich). **laptop03 (Master) bespielt sich nie selbst** —
|
||||||
>>> IMAGE ERSTELLEN (Laptop sichern) <<<
|
dort ist der Boot-Check deaktiviert.
|
||||||
```
|
|
||||||
|
|
||||||
**Nach der Auswahl läuft alles automatisch** - keine weitere Eingabe nötig!
|
## Weg 2: Neues Master-Image erstellen (auf laptop03)
|
||||||
Der Computer fährt nach Abschluss automatisch herunter.
|
|
||||||
|
|
||||||
## Workflow
|
1. Platte anstecken, laptop03 neu starten
|
||||||
|
2. Im GRUB-Menue **„Schul-Neuinstallation“** waehlen (Eintrag ist im normalen
|
||||||
|
Boot nicht sichtbar, ggf. `Esc`/`Shift` beim Boot halten)
|
||||||
|
3. Im Mini-Menue **„IMAGE ERSTELLEN“** (Taste `i`) — Image heisst automatisch
|
||||||
|
`schule-laptop-<heutiges Datum>` und ist damit sofort das neueste
|
||||||
|
4. Rechner faehrt herunter, wenn fertig
|
||||||
|
|
||||||
### 1. Master-Image erstellen (einmalig)
|
## Weg 3: Erstinstallation per USB-Stick
|
||||||
|
|
||||||
1. Master-Laptop (laptop03) vorbereiten und testen
|
1. Stick `CLONEZILLA` **und** Platte anstecken, per `F12` vom Stick booten
|
||||||
2. USB-Stick und externe Festplatte anschließen
|
2. „IMAGE AUFSPIELEN“ waehlen — nimmt automatisch das neueste Image
|
||||||
3. Von USB booten (F12)
|
3. Nach dem Poweroff booten und einmalig den Namen vergeben:
|
||||||
4. **"IMAGE ERSTELLEN"** wählen
|
|
||||||
5. Warten bis Computer herunterfährt
|
|
||||||
6. Image liegt dann auf der externen Festplatte als Ordner `schule-laptop`
|
|
||||||
|
|
||||||
### 2. Image auf andere Laptops aufspielen
|
|
||||||
|
|
||||||
1. USB-Stick und externe Festplatte anschließen
|
|
||||||
2. Von USB booten (F12)
|
|
||||||
3. **"IMAGE AUFSPIELEN"** wählen (ist bereits vorausgewählt)
|
|
||||||
4. Warten bis Computer herunterfährt (~5-10 Min mit SSD)
|
|
||||||
5. First-Boot-Script ausführen:
|
|
||||||
```bash
|
```bash
|
||||||
sudo ~/ansible-schule/files/first-boot-setup.sh laptop05
|
sudo ~/projekte/schul-laptops/files/first-boot-setup.sh laptop05
|
||||||
```
|
```
|
||||||
|
Ab dann laeuft ansible-pull und der Laptop haelt sich selbst aktuell.
|
||||||
|
|
||||||
## Technische Details
|
## Technische Details
|
||||||
|
|
||||||
### Clonezilla-Parameter für Image erstellen
|
- Alle `ocs-sr`-Aufrufe laufen im **Batch-Modus ohne Sicherheitsabfragen und
|
||||||
```
|
ohne Nachpruefung** (`-batch -scs/-scr -icds -sfsck`, Entscheidung E-004 —
|
||||||
ocs-sr -q2 -c -j2 -z5p -i 4096 -sfsck -senc -p poweroff savedisk schule-laptop sda
|
12x identische Hardware, Fehlerfaelle macht Herb von Hand)
|
||||||
```
|
- Restore: `ocs-sr -g auto -e1 auto -e2 -r -j2 -icds -k1 -scr -batch -p true restoredisk <image> sda`
|
||||||
- `-q2` - Priorität: partclone > partimage > dd
|
- Save: `ocs-sr -q2 -j2 -z5p -i 4096 -sfsck -senc -scs -batch -p true savedisk <image> sda`
|
||||||
- `-z5p` - Kompression mit zstd (schnell, gut)
|
- Menue/Ablauf: `files/clonezilla/schul-reimage.sh` (liegt auf jedem Laptop
|
||||||
- `-i 4096` - Splitgröße 4GB
|
unter `/boot/clonezilla/`, wird per ansible-pull aktuell gehalten)
|
||||||
- `-sfsck` - Filesystem-Check überspringen (schneller)
|
- GRUB-Eintrag: `files/clonezilla/grub-custom.cfg` → `/boot/grub/custom.cfg`
|
||||||
- `-p poweroff` - Nach Abschluss herunterfahren
|
- Boot-Check: `files/reimage-check.sh` + `.service`
|
||||||
|
|
||||||
### Clonezilla-Parameter für Image aufspielen
|
## Voraussetzung: Clonezilla-Live-Dateien im Image
|
||||||
```
|
|
||||||
ocs-sr -g auto -e1 auto -e2 -r -j2 -icds -k1 -p poweroff restoredisk schule-laptop sda
|
|
||||||
```
|
|
||||||
- `-g auto` - Geometrie automatisch
|
|
||||||
- `-e1 auto -e2` - MBR/Partitionstabelle wiederherstellen
|
|
||||||
- `-r` - Partitionsgrößen anpassen
|
|
||||||
- `-icds` - Bestätigung überspringen
|
|
||||||
- `-k1` - Partitionstabelle der Zielfestplatte erstellen
|
|
||||||
- `-p poweroff` - Nach Abschluss herunterfahren
|
|
||||||
|
|
||||||
## Weitere Boot-Optionen
|
`/boot/clonezilla/` braucht einmalig `vmlinuz`, `initrd.img` und
|
||||||
|
`filesystem.squashfs` vom Clonezilla-Stick (Ordner `/live/`). Sie sind zu gross
|
||||||
|
fuer git und kommen ueber das Master-Image auf alle Laptops. Fehlen sie, meldet
|
||||||
|
der Pull-Lauf einen Hinweis im Journal.
|
||||||
|
|
||||||
- **Clonezilla manuell** - Alle Optionen, für Experten
|
## Problemloesungen
|
||||||
- **Von Festplatte starten** - Normaler Boot
|
|
||||||
- **Erweiterte Optionen:**
|
|
||||||
- Image aufspielen (in RAM) - USB kann nach Start entfernt werden
|
|
||||||
- Failsafe-Modus - Bei Boot-Problemen
|
|
||||||
- Memtest - RAM-Test
|
|
||||||
|
|
||||||
## Problemlösungen
|
- **„Mount failed“ / Platte nicht gefunden:** Label pruefen:
|
||||||
|
`sudo ntfslabel /dev/sdX1 DEZNTRSICHERUNG`
|
||||||
|
- **Kein Image gefunden:** Liegt ein Ordner `schule-laptop-*` auf der Platte?
|
||||||
|
- **Laptop bootet nach Reimage nicht:** Stick benutzen (Weg 3) — der Stick ist
|
||||||
|
die Rettungsleine und funktioniert immer
|
||||||
|
|
||||||
### "Mount failed" für externe Festplatte
|
## Zeiten (12x gleiche Hardware, SSD + USB 3.0)
|
||||||
- Prüfen ob Festplatte das Label "DEZNTRSICHERUNG" hat
|
|
||||||
- Festplatte neu formatieren und Label setzen:
|
|
||||||
```bash
|
|
||||||
sudo ntfslabel /dev/sdX1 DEZNTRSICHERUNG
|
|
||||||
```
|
|
||||||
|
|
||||||
### Image existiert nicht (beim Aufspielen)
|
| Aktion | Dauer |
|
||||||
- Erst "IMAGE ERSTELLEN" auf dem Master-Laptop ausführen
|
|---|---|
|
||||||
- Prüfen ob Ordner `schule-laptop` auf der externen Festplatte existiert
|
| Image erstellen | ~10–15 Min |
|
||||||
|
| Image aufspielen | ~5–10 Min |
|
||||||
### Falsches Device (nicht sda)
|
|
||||||
- Manuellen Modus verwenden und Device anpassen
|
|
||||||
- Oder Konfiguration auf USB-Stick anpassen:
|
|
||||||
- BIOS: `/syslinux/syslinux.cfg`
|
|
||||||
- UEFI: `/boot/grub/grub.cfg`
|
|
||||||
|
|
||||||
## Zeiten (geschätzt)
|
|
||||||
|
|
||||||
| Aktion | SSD + USB 3.0 | HDD + USB 2.0 |
|
|
||||||
|--------|---------------|---------------|
|
|
||||||
| Image erstellen | ~10-15 Min | ~30-45 Min |
|
|
||||||
| Image aufspielen | ~5-10 Min | ~20-30 Min |
|
|
||||||
|
|||||||
178
README.md
178
README.md
@@ -1,144 +1,78 @@
|
|||||||
# Ansible Setup - Schul-Laptops
|
# schul-laptops
|
||||||
|
|
||||||
12 Linux Mint Laptops verwalten mit Ansible + Clonezilla Backup.
|
12–16 Linux-Mint-Laptops verwalten: **ansible-pull** (laufende Updates) +
|
||||||
|
**Clonezilla** (Komplett-Image ~1×/Jahr). Ueberblick: `COCKPIT.md` · Status:
|
||||||
|
`CLAUDE.md` · Architektur: `docs/architektur.md`.
|
||||||
|
|
||||||
## Erstes Setup (einmalig auf diesem Rechner)
|
## So funktioniert es (Normalfall)
|
||||||
|
|
||||||
### 1. Passwordless Sudo einrichten
|
Jeder Laptop zieht sich alle 30 Minuten (und bei jedem Boot) selbst dieses Repo
|
||||||
|
von `https://git.lehrstun.de/admin/schul-laptops.git` und fuehrt `local.yml` aus.
|
||||||
|
Es gibt keinen Push mehr — das Schul-WLAN laesst das nicht zu.
|
||||||
|
|
||||||
Damit Ansible ohne Passwort arbeiten kann:
|
**Aenderung ausrollen:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo visudo
|
cd ~/projekte/schul-laptops
|
||||||
|
# z.B. Paket ergaenzen in group_vars/all.yml oder Task in local.yml
|
||||||
|
git add -A && git commit -m "..." && git push
|
||||||
|
# fertig — die Laptops holen es sich beim naechsten Timer-Lauf
|
||||||
```
|
```
|
||||||
|
|
||||||
Am Ende hinzufuegen:
|
**Auf einem Laptop nachsehen:**
|
||||||
```
|
|
||||||
puettmann ALL=(ALL) NOPASSWD: ALL
|
|
||||||
```
|
|
||||||
|
|
||||||
Speichern mit `Ctrl+X`, dann `Y`, dann `Enter`.
|
|
||||||
|
|
||||||
### 2. Inventory anpassen
|
|
||||||
|
|
||||||
Bearbeite `inventory.yml` und trage die richtigen IP-Adressen ein:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nano ~/ansible-schule/inventory.yml
|
systemctl list-timers ansible-pull* # laeuft der Timer?
|
||||||
|
journalctl -u ansible-pull -n 50 # letztes Pull-Log
|
||||||
|
sudo systemctl start ansible-pull.service # sofort ziehen statt warten
|
||||||
```
|
```
|
||||||
|
|
||||||
## Workflow: Image auf andere Rechner spielen
|
## Komplett-Image (~1×/Jahr, nach den Ferien)
|
||||||
|
|
||||||
### Schritt 1: Image erstellen (Clonezilla)
|
Details in `CLONEZILLA_AUTOMATISCH.md`. Kurzfassung:
|
||||||
|
|
||||||
1. Clonezilla Live USB-Stick erstellen
|
- **Erstinstallation:** Clonezilla-USB-Stick + externe Platte `DEZNTRSICHERUNG`,
|
||||||
2. Von USB booten
|
danach einmalig `sudo files/first-boot-setup.sh laptopXX` (vergibt den Namen).
|
||||||
3. "device-image" → "savedisk" waehlen
|
- **Danach ohne Stick:** Platte anstecken, Laptop einschalten. Ist das neueste
|
||||||
4. Image auf externen Datentraeger speichern
|
Image auf der Platte neuer als das installierte, bespielt sich der Laptop
|
||||||
|
selbst neu — der Hostname bleibt erhalten.
|
||||||
### Schritt 2: Image auf Clients aufspielen
|
- **Neues Master-Image:** auf laptop03 im GRUB-Menue „Schul-Neuinstallation“
|
||||||
|
waehlen → „IMAGE ERSTELLEN“.
|
||||||
1. Von Clonezilla USB booten
|
|
||||||
2. "device-image" → "restoredisk" waehlen
|
|
||||||
3. Image auswaehlen, auf Festplatte spielen
|
|
||||||
|
|
||||||
### Schritt 3: First-Boot Setup (auf jedem geklonten Rechner)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo ~/ansible-schule/files/first-boot-setup.sh laptop05
|
|
||||||
```
|
|
||||||
|
|
||||||
(Ersetze `laptop05` durch den jeweiligen Hostnamen)
|
|
||||||
|
|
||||||
## Ansible Befehle
|
|
||||||
|
|
||||||
Alle Befehle aus dem Verzeichnis `~/ansible-schule` ausfuehren:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/ansible-schule
|
|
||||||
```
|
|
||||||
|
|
||||||
### Alle Rechner pingen
|
|
||||||
```bash
|
|
||||||
ansible-playbook playbooks/ping.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
### System-Update auf allen Clients
|
|
||||||
```bash
|
|
||||||
ansible-playbook playbooks/update.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
### Software installieren
|
|
||||||
```bash
|
|
||||||
# Standard-Pakete (in der Datei definiert)
|
|
||||||
ansible-playbook playbooks/install-software.yml
|
|
||||||
|
|
||||||
# Bestimmte Pakete
|
|
||||||
ansible-playbook playbooks/install-software.yml -e "packages=['firefox','vlc','gimp']"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Nur bestimmte Rechner
|
|
||||||
```bash
|
|
||||||
ansible-playbook playbooks/update.yml --limit laptop05,laptop06
|
|
||||||
```
|
|
||||||
|
|
||||||
### Alle Clients neustarten
|
|
||||||
```bash
|
|
||||||
ansible-playbook playbooks/reboot.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
### Schnelle Befehle ohne Playbook
|
|
||||||
```bash
|
|
||||||
# Shell-Befehl auf allen Clients
|
|
||||||
ansible clients -m shell -a "df -h"
|
|
||||||
|
|
||||||
# Paket installieren
|
|
||||||
ansible clients -m apt -a "name=htop state=present" --become
|
|
||||||
|
|
||||||
# Datei kopieren
|
|
||||||
ansible clients -m copy -a "src=./files/test.txt dest=/tmp/"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Verzeichnisstruktur
|
## Verzeichnisstruktur
|
||||||
|
|
||||||
```
|
```
|
||||||
~/ansible-schule/
|
~/projekte/schul-laptops/
|
||||||
├── ansible.cfg # Ansible-Konfiguration
|
├── local.yml # DAS Playbook (laeuft per ansible-pull auf jedem Laptop)
|
||||||
├── inventory.yml # Liste aller Laptops mit IPs
|
├── group_vars/all.yml # Paketliste u.a. Variablen
|
||||||
├── README.md # Diese Datei
|
├── files/
|
||||||
├── playbooks/
|
│ ├── schul-pull.sh # Pull-Wrapper (HTTPS, SSH-Fallback)
|
||||||
│ ├── ping.yml # Erreichbarkeit testen
|
│ ├── ansible-pull.service # systemd-Units
|
||||||
│ ├── update.yml # System-Updates
|
│ ├── ansible-pull.timer
|
||||||
│ ├── install-software.yml
|
│ └── first-boot-setup.sh # einmalig nach Erstinstallation
|
||||||
│ ├── reboot.yml
|
├── docs/ # Architektur, Entscheidungslog
|
||||||
│ └── set-hostname.yml
|
└── playbooks/, inventory.yml, update-ips.sh, ansible.cfg # LEGACY, s.u.
|
||||||
└── files/
|
|
||||||
└── first-boot-setup.sh # Nach Klonen ausfuehren
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Legacy: Push-Betrieb (nur Heimnetz)
|
||||||
|
|
||||||
|
Das alte Push-Setup funktioniert weiterhin, aber **nur wenn die Laptops im
|
||||||
|
eigenen WLAN haengen** (Schul-WLAN blockiert SSH/mDNS zwischen Geraeten):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./update-ips.sh # IPs per mDNS einsammeln
|
||||||
|
ansible-playbook playbooks/ping.yml # Erreichbarkeit
|
||||||
|
ansible-playbook playbooks/update.yml # Updates pushen
|
||||||
|
ansible clients -m shell -a "df -h" # Ad-hoc-Befehl
|
||||||
|
```
|
||||||
|
|
||||||
|
Voraussetzung auf neuen Controllern: passwordless sudo fuer `puettmann`
|
||||||
|
(`sudo visudo` → `puettmann ALL=(ALL) NOPASSWD: ALL`).
|
||||||
|
|
||||||
## Problemloesungen
|
## Problemloesungen
|
||||||
|
|
||||||
### "Permission denied" bei SSH
|
- **Laptop zieht nichts:** `journalctl -u ansible-pull` — HTTPS blockiert? Dann
|
||||||
```bash
|
greift automatisch der SSH-Fallback (Port 2222, Deploy-Key unter /root/.ssh).
|
||||||
# SSH-Key manuell kopieren
|
- **Pull sofort ausloesen:** `sudo systemctl start ansible-pull.service`
|
||||||
ssh-copy-id puettmann@192.168.1.105
|
- **Push: Permission denied:** `ssh-copy-id puettmann@<IP>`;
|
||||||
```
|
Host-Key-Warnung: `ssh-keygen -R <IP>`
|
||||||
|
|
||||||
### Rechner nicht erreichbar
|
|
||||||
```bash
|
|
||||||
# Einzelnen Rechner testen
|
|
||||||
ansible laptop05 -m ping -vvv
|
|
||||||
```
|
|
||||||
|
|
||||||
### Host-Key Warnung
|
|
||||||
Ist in ansible.cfg deaktiviert. Falls es trotzdem auftritt:
|
|
||||||
```bash
|
|
||||||
ssh-keygen -R 192.168.1.105
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tipps
|
|
||||||
|
|
||||||
1. **Bandbreite sparen:** Updates nachts oder gestaffelt ausfuehren
|
|
||||||
2. **Grosse Aenderungen:** Besser per Clonezilla-Image
|
|
||||||
3. **Kleine Aenderungen:** Ansible (schneller, kein Neustart)
|
|
||||||
4. **Testen:** Erst mit `--limit laptop05` auf einem Rechner testen
|
|
||||||
|
|||||||
8
files/ansible-pull.service
Normal file
8
files/ansible-pull.service
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Schul-Laptops: Konfiguration per ansible-pull aktualisieren
|
||||||
|
Wants=network-online.target
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/schul-pull.sh
|
||||||
11
files/ansible-pull.timer
Normal file
11
files/ansible-pull.timer
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Schul-Laptops: regelmaessiger ansible-pull (Boot + alle 30 min)
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnBootSec=2min
|
||||||
|
OnUnitActiveSec=30min
|
||||||
|
RandomizedDelaySec=5min
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
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
|
||||||
@@ -3,12 +3,19 @@
|
|||||||
# First-Boot Setup fuer geklonte Rechner
|
# First-Boot Setup fuer geklonte Rechner
|
||||||
#
|
#
|
||||||
# Dieses Script nach dem Klonen EINMAL ausfuehren auf jedem Rechner:
|
# Dieses Script nach dem Klonen EINMAL ausfuehren auf jedem Rechner:
|
||||||
# sudo ~/ansible-schule/files/first-boot-setup.sh laptop05
|
# sudo ~/projekte/schul-laptops/files/first-boot-setup.sh laptop05
|
||||||
#
|
#
|
||||||
# Es macht:
|
# Es macht:
|
||||||
# 1. Neuen Hostnamen setzen
|
# 1. Neuen Hostnamen setzen
|
||||||
# 2. Neue SSH-Host-Keys generieren (wichtig!)
|
# 2. Neue SSH-Host-Keys generieren (wichtig!)
|
||||||
# 3. Neue Machine-ID generieren
|
# 3. Neue Machine-ID generieren
|
||||||
|
# 4. Privaten Admin-Key entfernen (ausser auf laptop03, siehe docs/decisions.md E-005)
|
||||||
|
# 5. Image-Versionsdatei setzen (falls nicht vorhanden)
|
||||||
|
# 6. ansible-pull-Timer aktivieren und ersten Lauf anstossen
|
||||||
|
#
|
||||||
|
# Beim automatischen Reimage von der externen Platte uebernimmt das
|
||||||
|
# Clonezilla-Restore-Skript diese Schritte — dieses Script ist nur fuer
|
||||||
|
# die Erstinstallation per USB-Stick gedacht.
|
||||||
#
|
#
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
@@ -53,9 +60,30 @@ cp /etc/machine-id /var/lib/dbus/machine-id
|
|||||||
# 4. SSH-Dienst neustarten
|
# 4. SSH-Dienst neustarten
|
||||||
systemctl restart ssh
|
systemctl restart ssh
|
||||||
|
|
||||||
|
# 5. Privaten Admin-Key entfernen — der Gitea-Admin-Key gehoert nur auf laptop03.
|
||||||
|
# Der Read-only-Deploy-Key unter /root/.ssh bleibt (wird fuer den Pull-Fallback gebraucht).
|
||||||
|
if [ "$NEW_HOSTNAME" != "laptop03" ]; then
|
||||||
|
echo -e "${YELLOW}Entferne privaten Admin-Key...${NC}"
|
||||||
|
rm -f /home/puettmann/.ssh/id_ed25519 /home/puettmann/.ssh/id_ed25519.pub
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 6. Image-Versionsdatei: "0" ist aelter als jeder Image-Name, d.h. das naechste
|
||||||
|
# angesteckte Image wuerde ein Reimage ausloesen — das Restore-Skript schreibt
|
||||||
|
# hier den echten Image-Namen hinein.
|
||||||
|
if [ ! -f /etc/schul-image-version ]; then
|
||||||
|
echo "0" > /etc/schul-image-version
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 7. ansible-pull aktivieren: ab jetzt holt sich der Laptop alles selbst.
|
||||||
|
echo -e "${YELLOW}Aktiviere ansible-pull-Timer...${NC}"
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now ansible-pull.timer
|
||||||
|
systemctl start --no-block ansible-pull.service
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${GREEN}=== Setup abgeschlossen ===${NC}"
|
echo -e "${GREEN}=== Setup abgeschlossen ===${NC}"
|
||||||
echo -e "Hostname: ${GREEN}$NEW_HOSTNAME${NC}"
|
echo -e "Hostname: ${GREEN}$NEW_HOSTNAME${NC}"
|
||||||
|
echo "Der erste ansible-pull-Lauf wurde gestartet (Log: journalctl -u ansible-pull)."
|
||||||
echo ""
|
echo ""
|
||||||
echo "Optional: Rechner neustarten mit 'sudo reboot'"
|
echo "Optional: Rechner neustarten mit 'sudo reboot'"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
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
|
||||||
24
files/schul-pull.sh
Normal file
24
files/schul-pull.sh
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Zieht das schul-laptops-Repo und fuehrt local.yml aus.
|
||||||
|
# HTTPS zuerst (funktioniert auch im Schulnetz), SSH mit Deploy-Key als Fallback.
|
||||||
|
# Wird vom systemd-Timer (ansible-pull.timer) als root aufgerufen.
|
||||||
|
#
|
||||||
|
set -u
|
||||||
|
|
||||||
|
HTTPS_URL="https://git.lehrstun.de/admin/schul-laptops.git"
|
||||||
|
SSH_URL="ssh://git@46.225.114.15:2222/admin/schul-laptops.git"
|
||||||
|
DEPLOY_KEY="/root/.ssh/ansible-pull-deploy"
|
||||||
|
CHECKOUT="/var/lib/schul-laptops"
|
||||||
|
|
||||||
|
run_pull() {
|
||||||
|
ansible-pull -U "$1" -d "$CHECKOUT" -c local -i localhost, local.yml
|
||||||
|
}
|
||||||
|
|
||||||
|
if run_pull "$HTTPS_URL"; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "HTTPS fehlgeschlagen, versuche SSH-Fallback (Port 2222) ..." >&2
|
||||||
|
export GIT_SSH_COMMAND="ssh -i $DEPLOY_KEY -p 2222 -o BatchMode=yes"
|
||||||
|
run_pull "$SSH_URL"
|
||||||
9
group_vars/all.yml
Normal file
9
group_vars/all.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
# Software, die auf allen Schul-Laptops installiert sein soll.
|
||||||
|
# Paket hier ergaenzen + pushen = wird auf allen Laptops installiert.
|
||||||
|
schul_pakete:
|
||||||
|
- htop
|
||||||
|
- git
|
||||||
|
- curl
|
||||||
|
- vim
|
||||||
|
- ansible
|
||||||
132
local.yml
Normal file
132
local.yml
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
---
|
||||||
|
# Wird per ansible-pull auf jedem Laptop lokal ausgefuehrt (via schul-pull.sh).
|
||||||
|
# Aenderungen hier verteilen sich beim naechsten Timer-Lauf auf alle Laptops.
|
||||||
|
- name: Schul-Laptop konfigurieren
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
become: true
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: APT-Cache aktualisieren
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
cache_valid_time: 3600
|
||||||
|
|
||||||
|
- name: System-Updates installieren (safe upgrade)
|
||||||
|
apt:
|
||||||
|
upgrade: safe
|
||||||
|
|
||||||
|
- name: Standard-Software installieren
|
||||||
|
apt:
|
||||||
|
name: "{{ schul_pakete }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
# --- Selbstverwaltung: haelt die Pull-Mechanik auf allen Laptops aktuell ---
|
||||||
|
|
||||||
|
- name: Pull-Script installieren
|
||||||
|
copy:
|
||||||
|
src: files/schul-pull.sh
|
||||||
|
dest: /usr/local/bin/schul-pull.sh
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: systemd-Units fuer ansible-pull installieren
|
||||||
|
copy:
|
||||||
|
src: "files/{{ item }}"
|
||||||
|
dest: "/etc/systemd/system/{{ item }}"
|
||||||
|
mode: "0644"
|
||||||
|
loop:
|
||||||
|
- ansible-pull.service
|
||||||
|
- ansible-pull.timer
|
||||||
|
register: units
|
||||||
|
|
||||||
|
- name: systemd neu laden, falls Units geaendert
|
||||||
|
systemd:
|
||||||
|
daemon_reload: yes
|
||||||
|
when: units.changed
|
||||||
|
|
||||||
|
- name: ansible-pull.timer aktivieren
|
||||||
|
systemd:
|
||||||
|
name: ansible-pull.timer
|
||||||
|
enabled: yes
|
||||||
|
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 ---
|
||||||
|
|
||||||
|
- name: Pruefen ob ein Neustart noetig ist
|
||||||
|
stat:
|
||||||
|
path: /var/run/reboot-required
|
||||||
|
register: reboot_required
|
||||||
|
|
||||||
|
- name: Neustart-Hinweis ins Log schreiben
|
||||||
|
debug:
|
||||||
|
msg: "ACHTUNG: Neustart erforderlich (wird nicht automatisch ausgefuehrt)."
|
||||||
|
when: reboot_required.stat.exists
|
||||||
Reference in New Issue
Block a user