bash: Eine praktische Einführung
Wenn man einen Server verwaltet fallen früher oder später Routineaufgaben an. Dabei kann es sich um einfache Aufräumarbeiten oder Standardaufgaben wie Backups handeln. Alle diese Aufgaben werden massiv erleichtert wenn man sie mit Hilfe von Bash-Scripten (oder wie Borat sagen würde Bash-Apps) selbst automatisieren kann.
In diesem Artikel möchte ich einige Lösungen für dabei auftretende Probleme vorstellen.## Generische Scripte dank Config-Files ##
if [ -f /root/backup/backup_config ]; then
while read line; do
if [ ! -z "$line" ]; then
case $line in
\#*) /bin/true;;
remount*) remount=${line#remount=};;
backup_dir*) backup_dir=${line#backup_dir=};;
daily*) daily=${line#daily=};;
device_id*) device_id=${line#device_id=};;
mysqlpw*) mysqlpw=${line#mysqlpw=};;
init_backup*) $line;;
ldap_backup*) $line;;
mysql_backup*) $line;;
postgres_backup*) $line;;
rsnapshot_backup*) $line;;
file_backup*) $line;;
finish_backup*) $line;;
*) log "Error: Unknown command \"$line\"";;
esac
fi
done < "/root/backup/backup_config"
else
chk 997 "backup_config not found" 1
fi
In der ersten Zeile wird geprüft ob die Konfigurationsdatei /root/backup/backup_config
existiert. Falls ja wird diese von while
eingelesen (Zeile 2 und 21). Sofern die eingelesene Zeile nicht leer ist (Zeile 3) wird per case
nach bestimmten Werten gesucht. Beginnt eine Zeile mit einer `# wird der Befehl
/bin/trueausgeführt. Beginnt die Zeile mit
remountwird die Umgebungsvariable
remount` gesetzt. Der entsprechende Wert für die Variable kommt aus der Konfigurationsdatei.
So geht es immer weiter, beginnt eine Zeile mit ldap_backup
wird die gleichnamige Funktion des Backup-Scriptes ausgeführt. Im Zweifel mit zusätzlichen Parametern aus der Konfigurationsdatei.
Hier eine Beispielkonfiguration:
# Am Ende der Datei muss sich eine Leerzeile befinden.
# Ziel für das Backup
backup_dir=/backup
# Wenn daily "true" ist wird ein 7-Tage Backup erzeugt.
daily=false
# Wenn remount "true" ist wird das Backuplaufwerk rw/ro gemountet.
remount=false
init_backup
mysql_backup $password
postgres_backup
#rsnapshot_backup
file_backup /var/www/
file_backup /home/
file_backup /opt/
finish_backup
Wie man sehen kann werden diverse Variablen vorbereitet und dann die Backupfunktionen ausgeführt. rsnapshot_backup
ist auskommentiert und wird daher nicht verwendet.## Funktionen ##
Über Funktionen können gleichartige Befehle, über Parameter angesteuert, zentralisiert werden.
log() {
# Write to logfile
/usr/bin/logger -t "backup" "$hostname: $1";
echo $1
}
chk() {
# Check if there was an error during the backup
if [ "$1" -ne "0" ]; then
# Something went wrong
log "ERROR #$1: $2";
warning=true;
log "[FAIL]";
else
# Everything was fine
log "[ok]";
fi
if [ "$3" eq "1" ]; then
echo "[FATAL] Error $1: $2"
exit $3
fi
}
Die hier definierte Funktion log
erwartet mindestens einen Parameter $1
. Außerdem muss im Script die Variable $hostname
gesetzt werden. Die Funktion kann mit log "Nachricht"
aus dem Script heraus aufgerufen werden. Sie ruft dann die Funktion logger
auf. Hierdurch wird eine Nachricht im Syslog erzeugt. Sie lautet: backup $hostname: Nachricht
. Außerdem wird "Nachricht" auf STDOUT
ausgegeben.
Die Funktion chk
bekommt als Parameter zwei Werte übergeben: $1
und $2
Der Wert $1
enthält den Rückgabewert eines zuvor ausgeführten Befehls. $2
enthält eine beliebige Nachricht. Wenn der übergebene Rückgabewert ($1
) nicht 0
ist wird ein Fehler ins Logfile geschrieben (über die Funktion log
). Außerdem wird die Variable warning
auf true
gestellt. Ist der Rückgabewert 0
wird ein ok
ins Logfile geschrieben.## If-Abfragen ##
Über if
-Abfragen kann man Entscheidungen im Scriptablauf herbeiführen:
init_backup() {
if (( `id -u` != 0 )); then
chk 1000 "Are you root?" 1
fi
if [ -e "/var/lock/daily_backup.lock" ]; then
log "Checking for Lock-File";
chk 1000 "Lock-file exists, backup already running? Stopping..." 1
fi
log "INFO: Starting Backup `date`";
log "Writing Lock-File";
touch /var/lock/daily_backup.lock
chk $? "Writing Lock-File failed" 1
if [ $daily == true ]; then
backup_dir=$backup_dir/`date +%w`
fi
if [ $remount == true ]; then
log "Mounting (rw) Backup-Device"
mount -o remount,rw $device_id
chk $? "Mount failed ($device_id)" 1
fi
log "INFO: Target $backup_dir";
if [ ! -d "$backup_dir" ]; then
log "Creating Backup-Dir";
mkdir -p "$backup_dir"
chk $? "mkdir failed ($backup_dir)" 1
fi
}
Die Funktion init_backup
bereitet das eigentlich Backup vor. Zunächst wird aber geprüft ob der aufrufende Benutzer überhaupt berechtigt ist das Backup durchzuführen (id -u
). Wenn das Script nicht mit root
-Rechten gestartet wird beendet es sich.
Anschließend wird geprüft ob die Datei /var/lock/daily_backup.log
existiert. Falls ja wird davon ausgegangen, dass bereits eine andere Backup-Instanz aktiv ist und das Backup wird ebenfalls beendet.
Existiert keine Lock-Datei werden einige Angaben in das Syslog geschrieben und die Lock-Datei erzeugt. Schlägt dies fehl wird ebenfalls abgebrochen.
Ist der Parameter daily
auf true
gestellt wird dies mit einer entsprechenden Variablen quittiert. Der Parameter remount
entscheidet darüber ob das Backupziel neu gemountet werden muss oder nicht.
Abschließend wird der Backupordner erstellt, sofern er nicht bereits existiert. Klappt das nicht wird das Backup beendet.