Um festzustlelen, welche Clients derzeit noch online sind, kann man das tool fping benutzen. Dafür nehme ich die workstations-Datei, filtere mit grep alle Zeilen heraus, die auf 0 oder 0; enden, schneide mit cut die IP-Spalte heraus und gebe das Ergebnis an fping weiter. Der Paramter -a zeigt nur die IPs der Rechner, die derzeit erreichbar sind.
cat /etc/linuxmuster/workstations | grep -v '0;$\|0$' | cut -d ";" -f 5 | fping -a 2> /dev/null # IP-basiert cat /etc/linuxmuster/workstations | grep -v '0;$\|0$' | cut -d ";" -f 2 | fping -a 2> /dev/null # hostbasiert
Man kann über das Testen offener Ports versuchen, das laufende Betriebssystems festzustellen. Das ist im allgemeinen zwar keine sichere Methode, da ich aber im Schulnetz die Dienste kenne und gezielt ein- und ausschalten kann, sollte das in der Regel eine solide Erkennung ermöglichen. Um das für das eigene Netz zu planen, kann man mit
nmap $hostname
verschiedene Clients auf offene bzw. geschlossene Ports untersuchen. Dies sollte relativ schnell einen geeigneten Port-Test-Plan ergeben, der zuverlässig zwischen Windows und Linux unterscheidet. Geeignete Ports sind z.B.:
Port | Dienst | OS |
2222 | SSH | Linbo |
135 | RPC-Dienst | Windows |
631 | Cups | Linux |
Der Befehl zum gezielten Testen eines Ports mit nmap lautet
nmap 10.16.1.2 -p 22 | sed -n 6p bzw nmap hostname -p 22 | sed -n 7p
sed filtert hier die Zeile heraus, die die Rückmeldung über den abgefragten Port enthält. Wenn man mit Hostnamen arbeitet, gibt es eine zusätzliche Zeile mit dem DNS-Eintrag, daher das 7p. Daraus kann man nun eine einfache Bedingung bauen:
nmap 10.16.1.5 -p 22 | sed -n 6p | grep -c "open" > /dev/null && echo OFFEN || echo GESCHLOSSEN
Es wird also einfach gezählt (grep -c), wie oft das Wort „open“ vorkommt - das Ergebnis ist 0 oder 1. && (und bzw. wenn) || (oder bzw. wenn nicht) verknüpfen den Test mit Befehlen.
Für manche Skripte kann es hilfreich sein, sich die Liste aller Räume ausgeben zu lassen - das ist mit folgender Zeile möglich:
cat /etc/linuxmuster/workstations | grep -v "0$\|0;$\" | cut -d ";" -f 1 | sed '$!N; /^\(.*\)\n\1$/!P; D'
sed ist ein wirkliches Wunderwerkzeug - der letzte Befehl entfernt Duplikate aus der Liste. In den grep-Befehl kann man weitere auszuschließende Räume packen:
cat /etc/linuxmuster/workstations | grep -v "0$\|0;$\|^raum1\|^raum2\|^raum7" | cut -d ";" -f 1 | sed '$!N; /^\(.*\)\n\1$/!P; D' Um diese Räume in einem Skript abzuarbeiten, kann man das Ergebnis auch in einem **Array** speichern: <code> rooms=( $(cat /etc/linuxmuster/workstations | grep -v "0$\|0;$\|^raum1\|^raum2\|^raum7" | cut -d ";" -f 1 | sed '$!N; /^\(.*\)\n\1$/!P; D') )
echo ${rooms[@]}
zeigt nun alle Räume, ein
for room in $rooms ...
arbeitet die Räume ab.
Wenn ein Rechner per ssh erreichbar ist, kann man direkt per ssh einen Befehl übergeben.
ssh administrator@$host shutdown /t 0 /s
Falls man keinen passwortlosen Zugang zu den Clients eingerichtet hat, kann man sshpass nutzen, um ein Passwort zu übergeben. Die Option StrictHostKeyChecking no verhindert bei neuen Clients den Abbruch wegen unbekanntem Hosts. Ein kompletter Befehl könnte also heißen:
sshpass -p "<passwort>" ssh -o "StrictHostKeyChecking no" administrator@$host shutdown /t 0 /s && echo "shutdown windows/linux on $host"
Bei passwortlosem Zugang (hier z.B. Linbo) lautet der Befehl:
ssh -o "StrictHostKeyChecking no" -p 2222 $host poweroff && echo "shutdown linbo on $host"
Dies klappt sogar, wenn wie derzeit unter Linbo kein Login auf der Shell möglich ist.
Manchmal geht beim längeren linbo-remote-Aufgaben etwas schief. Da linbo-remote die start.conf-Dateien verändert, bleiben dann evtl. die falschen Dateien zurück und der Benutzer sieht nur ausgegraute Linbo-Buttons und kann nichts tun. Das folgende Skript behebt diese fehlerhaften Verlinkungen
#/bin/bash # Zurückschreiben etwaiger Linbo-Remote-Verknüpfungen test linbo-remote -l | wc-l && exit 0 # Sicherstellen, dass kein linbo-remote mehr läuft cd /var/linbo for f in $(ls start.conf-* 2>/dev/null); do if ! [[ $(echo $f | cut -d "." -f "6") -eq "" ]]; then echo "Setze $f zurück auf $(echo $f | cut -d "." -f "1-5")" mv -f $f $(echo $f | cut -d "." -f "1-5") fi done
Die bisherigen Überleungen lassen sich zu einem Einzeiler zusammenfassen, der alle eingeschalteten Rechner samt Betriebssystem ausgibg:
for host in $(cat /etc/linuxmuster/workstations | grep -v '0;$\|0$' | cut -d ";" -f 2 | fping -a 2> /dev/null); do nmap $host -p 2222 | sed -n 7p | grep -c "open" > /dev/null && echo "Auf $host läuft LINBO" || nmap $host -p 135 | sed -n 7p | grep -c "open" > /dev/null && echo "Auf $host läuft WINDOWS" || echo "Auf $host läuft LINUX"; done;
Damit lässt sich das Herunterfahren aller Rechner als Einzeiler realisieren (z.B. als abendlicher cron-job):
for host in $(cat /etc/linuxmuster/workstations | grep -v '0;$\|0$' | cut -d ";" -f 2 | fping -a 2> /dev/null); do nmap $host -p 2222 | sed -n 7p | grep -c "open" > /dev/null && <linbo-shutdown> || nmap $host -p 135 | sed -n 7p | grep -c "open" > /dev/null && <windows-shutdown> || <linux-shutdown>; done;
Möchte man einzelne Rechner auslassen, kann man sie in den ersten grep-Befehl einbauen (z.B. grep -v '0;$\|0$\|admin01\|backupserver' - hier werden die Rechner admin01 und backupserver ausgelassen, \| ist das oder von grep).
Danach kann dann Raum für Raum synchronisiert werden (hier 2 Betriebssysteme):
for room in ( raum1 raum2 raum3 ) do linbo-remote -r $room -w 45 -c partition,initcache,sync:1,sync:2,halt sleep 1h done
Das folgende Skript lässt einzelne oder alle Räume synchronisieren und verbindet das mit ein wenig Logging - dann hat man am Morgen gleich eine Liste der Rechner, von man „nachhelfen“ bzw. nachforschen muss. Für die Einschränkung auf einzelne Räume wird ein zusätzliches grep eingefügt, welches nach dem Raumnamen am Anfang der Zeile sucht (grep „^<raumname>„).
#!/bin/bash # Dieses Skript fährt Rechner einer Gruppe per ssh herunter, # synchronisiert danach und loggt fehlerhafte Rechner log=yosync.log logfail=yosyncfail.log echo "Log-Datei: groupsync $1 ( $(date) )" | tee $log if [ "$1" == "all" ]; then rooms=( $(cat /etc/linuxmuster/workstations | grep -v "0$\|0;$" | cut -d ";" -f 1 | sed '$!N; /^\(.*\)\n\1$/!P; D') ) else rooms=$1 fi for room in ${rooms[@]}; do echo "Shutdown $room" | tee -a $log for host in $(cat /etc/linuxmuster/workstations | grep -v '0;$\|0$' | grep "^$room" | cut -d ";" -f 2 | fping -a 2> /dev/null); do nmap $host -p 2222 | sed -n 7p | grep -c "open" > /dev/null && ssh -o "StrictHostKeyChecking no" -p 2222 $host poweroff || nmap $host -p 135 | sed -n 7p | grep -c "open" > /dev/null && sshpass -p "<ssh-pwd>" ssh -o "StrictHostKeyChecking no" <ssh-usr>@$host shutdown /t 0 /s || sshpass -p "<ssh-pwd>" ssh -o "StrictHostKeyChecking no" <ssh-usr>@$host shutdown /t 0 /s; done; echo "Sync $room" | tee -a $log linbo-remote -r $room -w 45 -c partition,initcache,sync:1,sync:2,halt | tee -a $log echo "--- fertig - warte eine Stunde" | tee -a $log sleep 1h done echo "ListFailCliens -> FailLog" | tee -a $log while read line; do grep $(echo $line | cut -d " " -f 1) /etc/linuxmuster/workstations | cut -d ";" -f 1-3,5) > $logfail done < <(grep "Failed" $log)