Dienstag, 23. April 2019

Backup wenn der Server kommt

FHEM sichert ziemlich viel selbstständig, allerdings lokal innerhalb der Ordnerstruktur von FHEM. Geht beim Raspberry mal die SD Card kaputt, sollte man das Backup auf einem anderen System gesichert haben. Da bietet sich die NAS, der Windows Server oder was auch immer im lokalen Netzwerk an. Die Anbindung eines Windows/Samba Shares an den Raspberry hatte ich hier schon mal im Detail beschrieben.
Ich möchte zeigen, wie man bestimmte Ordner von FHEM auf ein temporäres Netzlaufwerk sichert und wie man diese Sicherung triggern kann.
Meine Codezeilen bauen aufeinander auf und ergeben in der Summe eine Art Setup Script. Damit ist das relativ zügig eingerichtet und auf mehreren Computer installiert. Die Einrichtung erfordert höhere Rechte, also bitte im Context sudo su ausführen!

Laufwerk verbinden

Auf dem Server1 existiert eine SMB Freigabe "Sicherung". In einem Unterverzeichnis fhem (muss noch nicht existieren) wird zukünftig die Sicherung des FHEM Server abgelegt.

# Konfiguration der Datei, Server, Ordnernamen und des Benutzerkontos
fcred='smbcredentials'
share='//Server1/Sicherung'
mdir=/media/Sicherung
# Benutzerkonto ablegen
echo 'username=UserName' > /usr/.$fcred
echo 'password=Userpassword' >> /usr/.$fcred
# fstab Eintrag anhängen
echo "$share $mdir cifs noauto,users,credentials=/usr/.$fcred 0 0" >> /etc/fstab
# Ordner erzeugen, Verbindung testen
mkdir $mdir
mount $mdir
mkdir ${mdir}/fhem
umount $mdir
Die letzte Sequenz testet gleichzeitig ob die Verbindung zum Server funktioniert und die Rechte zum Schreiben vorhanden sind. 

Das backup Script

Damit alles in einem "Rutsch" ohne großes Hin und her funktioniert, habe ich das Script zur Sicherung als Here Doc abgelegt. Dabei wird die Konfigurationsvariable $mdir aus dem ersten Schritt verwendet! Die anderen $Variablennamen sind deshalb mit \ geschützt und EOF steht nicht in ' '.
cat <<EOF > /opt/fhem/backupFhem.sh
qpath="/opt/fhem"
dpath=$mdir
LOG=backupFhem.log
if [ -d "log" ];then LOG="log/\$LOG";fi
# check if fhemcl exists
file=fhemcl.sh
{
date
if [ ! -e \$file ]
then
    echo "\$file is missing"
    wget https://raw.githubusercontent.com/heinz-otto/fhemcl/master/\$file
    chmod +x \$file
fi
# mount, sync 
mount "\$dpath"
bash fhemcl.sh 8083 "set BackupFhem gestartet"
if rsync -rut \${qpath}/backup \${qpath}/restoreDir \${dpath}/fhem/\$(hostname)
then
   bash fhemcl.sh 8083 "set BackupFhem gesichert"
else
   bash fhemcl.sh 8083 "set BackupFhem ERROR"
fi
umount "\$dpath"
} >> \$LOG 2>&1
EOF
Gesichert werden die beiden Pfade backup und restoreDir. Der gesamte Ablauf wird im FHEM gesteuert und geloggt. Zur Orientierung wird ein Startzeiteintrag ins Log geschrieben. Das Serverlaufwerk wird bewusst nur temporär gemountet.
Falls Fehler im Script auftreten wird eine Logdatei geschrieben. Der dazu notwendige HTTP Client wird, falls nicht vorhanden, von GitHub nachgeladen.

Steuerung über FHEM

In FHEM sind dazu zunächst mal ein Dummy und ein FileLog Device notwendig. Mit dem "fakelog" wird das Logfile vom Script zur Anzeige gebracht.
Man kann diese Codezeilen mit der Raw Definition oder auch mit dem FHEM HTTP Client direkt per Script in FHEM eingeben.
define BackupFhem dummy
attr BackupFhem room backup

define backupFhemlog FileLog ./log/backupFhem.log fakelog
attr backupFhemlog room backup
Für den automatischen Start gibt es mehrere Varianten/Ideen:

  • der SMB Server meldet an FHEM über ein Powershell Script das er gestartet ist.
  • der Start des Server wird mit einem Presence Device überwacht
    • mit einem Perl Script ermitteln das Port 445 / SMB aktiv ist
    • mit lan-ping  
In jedem Fall übernimmt z.B. ein DOIF den Start des Scripts backupFhem.sh.
define backupCopy DOIF ([Server1] eq "present") ("bash backupFhem.sh")
attr backupCopy room backup
Die Reaktion des Servers auf ein LAN Ping, stellt nicht zuverlässig sicher, dass das SMB Share schon erreichbar ist. In dem Fall kann man mit einem wait eine Wartepause vor der Ausführung einlegen.
attr backupCopy wait 120

Die Konfiguration für FHEM gibt es noch in einem Script, falls der FHEM HTTP Client im lokalen Pfad nicht vorhanden ist, wird er herunter geladen.
#file=fhemcl.sh
if [ ! -e $file ]
then
    echo "$file is missing"
    wget https://raw.githubusercontent.com/heinz-otto/fhemcl/master/$file
    chmod +x $file
fi
# ab hier wird der Code im (lokalen) FHEM Server erzeugt
cat <<EOF | bash fhemcl.sh 8083
define BackupFhem dummy
attr BackupFhem room backup
define backupFhemlog FileLog ./log/backupFhem.log fakelog
attr backupFhemlog room backup
define backupCopy DOIF ([Server1] eq "present") ("bash backupFhem.sh")
attr backupCopy room backup
attr backupCopy wait 120
EOF

Monitor für TCP Port

Mit dieser Perl Sub in der 99_myUtils.pm kann man gezielt einen bestimmten Port überwachen.
Achtung! Diese Sub wirkt blockierend.
sub ServiceMonitor($$)
# Usage: ServiceMonitor("Hostname","Portnummer")
# in Presence: function {ServiceMonitor("Hostname","Portnummer")}
{
    use Net::Ping;
    my ($host, $port)    = @_;
    my $status;
    
    # Create a new ping object
    my $p = Net::Ping->new("syn");
    $p->port_number($port);
    $p->ping($host,10);
    
    # perform the ping
    if ( $p->ack ) {
       $status = 1;
    }
    else{
       $status = 0;
    }
    
    # close our ping handle
    $p->close();
    return $status;
    
}

Alternativen zum SMB Server

Natürlich kann anstatt des SMB Servers auch ein anderes Server Laufwerk eingebunden werden. Es könnte z.B. auch ein Cloud Speicher über WebDav sein. Allerdings sollte man sich dazu überlegen, die Dateien zusätzlich zu verschlüsseln.
Hier noch ein komplettes Muster Script zum download. Dieses Script wird weiterentwickelt und es kann sein, dass der Stand nicht mehr dem hier geschilderten entspricht. Größere Änderungen werde ich aber hier dokumentieren.

Alte Backups aufräumen

Vor allem wenn man täglich backups macht erzeugt man schnell eine volle SD Card / HDD. Vor allem bei der SD bin ich nicht sicher, ob es für die Lebensdauer gut ist allzu oft zu löschen. Man kann von "Zeit zu Zeit" das backup Dir schrumpfen:
{
my $BackupDir = AttrVal("global", "backupdir", "backup");;
$BackupDir.="/FHEM-*.tar.gz";;
my $BackupsMax = 12;;
my $BackupsCurrent = qx(ls -A $BackupDir | wc -l);;
my $BackupsDelete = $BackupsCurrent - $BackupsMax;;
if ($BackupsDelete > 0)
  {
    my $FilesDel = join "|",split "\n",qx(ls -d $BackupDir | head -$BackupsDelete);; 
    my $BackupDelete = qx(ls -d $BackupDir | head -$BackupsDelete | xargs rm);;
    if ($BackupDelete eq "") {Log 1, "Es wurden $BackupsDelete alte Backupfiles gelöscht: $FilesDel"} else {Log 1, "Es trat ein Fehler auf $BackupDelete"};;
  }
}
Das Perl / Bash Script reduziert die Anzahl auf 12 Original FHEM Backup Dateien (Namensschema), alle anderen Dateien im Pfad bleiben unberührt. 
Man muss sich natürlich einen Automatismus einfallen lassen. Einmal im Monat/Jahr, wenn die SD Card 2/3 voll ist oder so etwas in der Art. Ich bin da noch am experimentieren.

Zum Schluss

Hier noch ein komplettes Muster Script zum download. Dieses Script wird weiterentwickelt und es kann sein, dass der Stand nicht mehr dem hier geschilderten entspricht. Größere Änderungen werde ich aber hier dokumentieren.
wget -O https://raw.githubusercontent.com/heinz-otto/raspberry/master/configBackupFhem2Cifs.sh


Keine Kommentare:

Kommentar veröffentlichen