Bestand aus ~/ansible-schule uebernehmen (Push-Setup, Stand Feb 2026)

Playbooks, Inventory, update-ips.sh, first-boot-setup.sh und Doku
unveraendert aus dem alten git-losen Ordner uebernommen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-13 13:11:24 +02:00
commit bd4384c36f
12 changed files with 706 additions and 0 deletions

110
ANLEITUNG_NACH_KLONEN.md Normal file
View File

@@ -0,0 +1,110 @@
# Anleitung: Nach dem Klonen
Diese Anleitung gilt NACHDEM du:
- Das Image mit Clonezilla aufgespielt hast
- Das First-Boot-Script ausgefuehrt hast (`sudo ~/ansible-schule/files/first-boot-setup.sh laptopXX`)
---
## Auf dem Controller (laptop03)
### Schritt 1: IPs aktualisieren
```bash
cd ~/ansible-schule
./update-ips.sh
```
Das Script findet automatisch alle eingeschalteten Laptops im Netzwerk und traegt ihre IPs in die inventory.yml ein.
**Erwartete Ausgabe:**
```
=== 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
ansible all -m ping
```
**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
- [ ] Image mit Clonezilla aufgespielt
- [ ] First-Boot-Script: `sudo ~/ansible-schule/files/first-boot-setup.sh laptopXX`
- [ ] Auf Controller: `./update-ips.sh`
- [ ] Testen: `ansible laptopXX -m ping`

99
CLONEZILLA_AUTOMATISCH.md Normal file
View File

@@ -0,0 +1,99 @@
# Clonezilla Automatisiert - USB + Externe Festplatte
## Setup
- **USB-Stick:** CLONEZILLA (7,6 GB) - enthält Clonezilla Live
- **Externe Festplatte:** DEZNTRSICHERUNG (1,8 TB) - enthält das Image
- **Image-Name:** `schule-laptop`
## Boot-Menü
Beim Booten vom USB-Stick erscheinen zwei Hauptoptionen:
```
>>> IMAGE AUFSPIELEN (Laptop bespielen) <<< [Standard]
>>> IMAGE ERSTELLEN (Laptop sichern) <<<
```
**Nach der Auswahl läuft alles automatisch** - keine weitere Eingabe nötig!
Der Computer fährt nach Abschluss automatisch herunter.
## Workflow
### 1. Master-Image erstellen (einmalig)
1. Master-Laptop (laptop03) vorbereiten und testen
2. USB-Stick und externe Festplatte anschließen
3. Von USB booten (F12)
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
sudo ~/ansible-schule/files/first-boot-setup.sh laptop05
```
## Technische Details
### Clonezilla-Parameter für Image erstellen
```
ocs-sr -q2 -c -j2 -z5p -i 4096 -sfsck -senc -p poweroff savedisk schule-laptop sda
```
- `-q2` - Priorität: partclone > partimage > dd
- `-z5p` - Kompression mit zstd (schnell, gut)
- `-i 4096` - Splitgröße 4GB
- `-sfsck` - Filesystem-Check überspringen (schneller)
- `-p poweroff` - Nach Abschluss herunterfahren
### Clonezilla-Parameter für Image aufspielen
```
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
- **Clonezilla manuell** - Alle Optionen, für Experten
- **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" für externe Festplatte
- 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)
- Erst "IMAGE ERSTELLEN" auf dem Master-Laptop ausführen
- Prüfen ob Ordner `schule-laptop` auf der externen Festplatte existiert
### 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 |

144
README.md Normal file
View File

@@ -0,0 +1,144 @@
# Ansible Setup - Schul-Laptops
12 Linux Mint Laptops verwalten mit Ansible + Clonezilla Backup.
## Erstes Setup (einmalig auf diesem Rechner)
### 1. Passwordless Sudo einrichten
Damit Ansible ohne Passwort arbeiten kann:
```bash
sudo visudo
```
Am Ende hinzufuegen:
```
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
nano ~/ansible-schule/inventory.yml
```
## Workflow: Image auf andere Rechner spielen
### Schritt 1: Image erstellen (Clonezilla)
1. Clonezilla Live USB-Stick erstellen
2. Von USB booten
3. "device-image" → "savedisk" waehlen
4. Image auf externen Datentraeger speichern
### Schritt 2: Image auf Clients aufspielen
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
```
~/ansible-schule/
├── ansible.cfg # Ansible-Konfiguration
├── inventory.yml # Liste aller Laptops mit IPs
├── README.md # Diese Datei
├── playbooks/
│ ├── ping.yml # Erreichbarkeit testen
│ ├── update.yml # System-Updates
│ ├── install-software.yml
│ ├── reboot.yml
│ └── set-hostname.yml
└── files/
└── first-boot-setup.sh # Nach Klonen ausfuehren
```
## Problemloesungen
### "Permission denied" bei SSH
```bash
# SSH-Key manuell kopieren
ssh-copy-id puettmann@192.168.1.105
```
### 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

12
ansible.cfg Normal file
View File

@@ -0,0 +1,12 @@
[defaults]
inventory = ./inventory.yml
remote_user = puettmann
host_key_checking = False
retry_files_enabled = False
stdout_callback = yaml
[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False

61
files/first-boot-setup.sh Executable file
View File

@@ -0,0 +1,61 @@
#!/bin/bash
#
# First-Boot Setup fuer geklonte Rechner
#
# Dieses Script nach dem Klonen EINMAL ausfuehren auf jedem Rechner:
# sudo ~/ansible-schule/files/first-boot-setup.sh laptop05
#
# Es macht:
# 1. Neuen Hostnamen setzen
# 2. Neue SSH-Host-Keys generieren (wichtig!)
# 3. Neue Machine-ID generieren
#
set -e
# Farben
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo -e "${GREEN}=== First-Boot Setup ===${NC}"
# Hostname als Parameter oder interaktiv
if [ -n "$1" ]; then
NEW_HOSTNAME="$1"
else
read -p "Neuer Hostname (z.B. laptop05): " NEW_HOSTNAME
fi
if [ -z "$NEW_HOSTNAME" ]; then
echo -e "${RED}Fehler: Kein Hostname angegeben${NC}"
exit 1
fi
echo -e "${YELLOW}Setze Hostname auf: $NEW_HOSTNAME${NC}"
# 1. Hostname setzen
hostnamectl set-hostname "$NEW_HOSTNAME"
sed -i "s/127.0.1.1.*/127.0.1.1\t$NEW_HOSTNAME/" /etc/hosts
# 2. Neue SSH-Host-Keys generieren
echo -e "${YELLOW}Generiere neue SSH-Host-Keys...${NC}"
rm -f /etc/ssh/ssh_host_*
ssh-keygen -A
# 3. Neue Machine-ID generieren
echo -e "${YELLOW}Generiere neue Machine-ID...${NC}"
rm -f /etc/machine-id /var/lib/dbus/machine-id
dbus-uuidgen --ensure=/etc/machine-id
cp /etc/machine-id /var/lib/dbus/machine-id
# 4. SSH-Dienst neustarten
systemctl restart ssh
echo ""
echo -e "${GREEN}=== Setup abgeschlossen ===${NC}"
echo -e "Hostname: ${GREEN}$NEW_HOSTNAME${NC}"
echo ""
echo "Optional: Rechner neustarten mit 'sudo reboot'"
echo ""

62
inventory.yml Normal file
View File

@@ -0,0 +1,62 @@
# Ansible Inventory - Schul-Laptops
#
# IPs werden automatisch aktualisiert mit ./update-ips.sh
# Das Script fragt hostname.local via mDNS ab
#
all:
children:
schul_laptops:
hosts:
laptop01:
ansible_host: 0.0.0.0
laptop02:
ansible_host: 0.0.0.0
laptop03:
ansible_host: 192.168.1.78
laptop04:
ansible_host: 0.0.0.0
laptop05:
ansible_host: 0.0.0.0
laptop06:
ansible_host: 0.0.0.0
laptop07:
ansible_host: 0.0.0.0
laptop08:
ansible_host: 0.0.0.0
laptop09:
ansible_host: 0.0.0.0
laptop10:
ansible_host: 192.168.178.68
laptop11:
ansible_host: 0.0.0.0
laptop12:
ansible_host: 0.0.0.0
laptop13:
ansible_host: 0.0.0.0
laptop14:
ansible_host: 0.0.0.0
laptop15:
ansible_host: 0.0.0.0
laptop16:
ansible_host: 0.0.0.0
vars:
ansible_python_interpreter: /usr/bin/python3
# Gruppe ohne den Controller (fuer Remote-Updates)
clients:
hosts:
laptop01:
laptop02:
laptop04:
laptop05:
laptop06:
laptop07:
laptop08:
laptop09:
laptop10:
laptop11:
laptop12:
laptop13:
laptop14:
laptop15:
laptop16:

View File

@@ -0,0 +1,37 @@
# Software auf allen Rechnern installieren
#
# Verwendung:
# ansible-playbook playbooks/install-software.yml
#
# Oder einzelnes Paket:
# ansible-playbook playbooks/install-software.yml -e "packages=['firefox','vlc']"
#
---
- name: Software installieren
hosts: clients
become: yes
vars:
# Standard-Pakete die installiert werden sollen
packages:
- htop
- git
- curl
- vim
# Weitere Pakete hier hinzufuegen
tasks:
- name: APT Cache aktualisieren
apt:
update_cache: yes
cache_valid_time: 3600
- name: Pakete installieren
apt:
name: "{{ packages }}"
state: present
register: install_result
- name: Installierte Pakete anzeigen
debug:
msg: "Installiert: {{ packages | join(', ') }}"

17
playbooks/ping.yml Normal file
View File

@@ -0,0 +1,17 @@
# Test-Playbook: Pruefen ob alle Rechner erreichbar sind
---
- name: Ping alle Laptops
hosts: schul_laptops
gather_facts: no
tasks:
- name: Ping
ping:
- name: Zeige Hostname
command: hostname
register: result
changed_when: false
- name: Ausgabe
debug:
msg: "{{ inventory_hostname }} antwortet als {{ result.stdout }}"

27
playbooks/reboot.yml Normal file
View File

@@ -0,0 +1,27 @@
# Neustart aller Clients
#
# Verwendung:
# ansible-playbook playbooks/reboot.yml
#
# Nur bestimmte Rechner:
# ansible-playbook playbooks/reboot.yml --limit laptop05,laptop06
#
---
- name: Rechner neustarten
hosts: clients
become: yes
tasks:
- name: Neustart durchfuehren
reboot:
reboot_timeout: 300
msg: "Neustart durch Ansible"
- name: Warten bis Rechner wieder erreichbar
wait_for_connection:
delay: 10
timeout: 300
- name: Bestaetigung
debug:
msg: "{{ inventory_hostname }} ist wieder online"

View File

@@ -0,0 +1,24 @@
# Hostname setzen
#
# Verwendung:
# ansible-playbook playbooks/set-hostname.yml --limit laptop05 -e "new_hostname=laptop05"
#
---
- name: Hostname setzen
hosts: all
become: yes
tasks:
- name: Hostname setzen
hostname:
name: "{{ new_hostname | default(inventory_hostname) }}"
- name: /etc/hosts aktualisieren
lineinfile:
path: /etc/hosts
regexp: '^127\.0\.1\.1'
line: "127.0.1.1\t{{ new_hostname | default(inventory_hostname) }}"
- name: Neuer Hostname
debug:
msg: "Hostname gesetzt auf: {{ new_hostname | default(inventory_hostname) }}"

31
playbooks/update.yml Normal file
View File

@@ -0,0 +1,31 @@
# System-Update auf allen Rechnern
---
- name: System Update
hosts: clients # Ohne den Controller
become: yes
tasks:
- name: APT Cache aktualisieren
apt:
update_cache: yes
cache_valid_time: 3600
- name: Alle Pakete upgraden
apt:
upgrade: safe
register: upgrade_result
- name: Zeige aktualisierte Pakete
debug:
msg: "{{ upgrade_result.stdout_lines | default(['Keine Updates']) }}"
when: upgrade_result.stdout_lines is defined
- name: Pruefen ob Neustart noetig
stat:
path: /var/run/reboot-required
register: reboot_required
- name: Hinweis wenn Neustart noetig
debug:
msg: "ACHTUNG: {{ inventory_hostname }} benoetigt einen Neustart!"
when: reboot_required.stat.exists

82
update-ips.sh Executable file
View File

@@ -0,0 +1,82 @@
#!/bin/bash
#
# Aktualisiert die IP-Adressen in inventory.yml via mDNS (hostname.local)
#
# Ausfuehren aus ~/ansible-schule:
# ./update-ips.sh
#
INVENTORY="$(dirname "$0")/inventory.yml"
# Farben
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo "=== IP-Adressen aktualisieren ==="
echo ""
# Alle Hostnamen aus inventory.yml extrahieren (Zeilen mit "laptop" am Anfang)
HOSTNAMES=$(grep -E '^\s+laptop[0-9]+:$' "$INVENTORY" | sed 's/://g' | tr -d ' ')
if [ -z "$HOSTNAMES" ]; then
echo -e "${RED}Keine Laptops in inventory.yml gefunden${NC}"
exit 1
fi
UPDATED=0
FAILED=0
CURRENT_HOSTNAME=$(hostname)
for HOST in $HOSTNAMES; do
printf "%-12s " "$HOST:"
IP=""
# Wenn es der lokale Rechner ist, eigene IPv4 verwenden
if [ "$HOST" = "$CURRENT_HOSTNAME" ]; then
IP=$(hostname -I | awk '{print $1}')
if [ -n "$IP" ]; then
echo -e "${GREEN}$IP${NC} (localhost)"
fi
else
# Methode 1: getent hosts (nur IPv4 filtern)
IP=$(getent hosts "${HOST}.local" 2>/dev/null | grep -E '^[0-9]+\.' | awk '{print $1}')
# Methode 2: avahi-resolve mit IPv4
if [ -z "$IP" ]; then
IP=$(avahi-resolve -4 -n "${HOST}.local" 2>/dev/null | awk '{print $2}')
fi
# Methode 3: ping (extrahiert IP aus Antwort)
if [ -z "$IP" ]; then
IP=$(ping -4 -c 1 -W 2 "${HOST}.local" 2>/dev/null | grep -oP '(\d+\.){3}\d+' | head -1)
fi
if [ -n "$IP" ]; then
echo -e "${GREEN}$IP${NC}"
fi
fi
if [ -n "$IP" ]; then
# IP in inventory.yml aktualisieren
sed -i "/${HOST}:$/,/ansible_host:/ s/ansible_host:.*/ansible_host: $IP/" "$INVENTORY"
((UPDATED++))
else
echo -e "${RED}nicht erreichbar${NC}"
((FAILED++))
fi
done
echo ""
echo "=== Fertig ==="
echo -e "Aktualisiert: ${GREEN}$UPDATED${NC}"
echo -e "Nicht erreichbar: ${RED}$FAILED${NC}"
if [ $UPDATED -gt 0 ]; then
echo ""
echo "Inventory testen:"
echo " ansible all -m ping"
fi