NEWS
[Vorlage] Synchronisation / Backup von Fileserver in Cloud und Erfolgsanzeige in VIS
-
ACHTUNG: Man sollte für folgendes auf jeden Fall (Grund)kenntnisse von JavaScript und Shell-Programmierung und Linux mitbringen, sowie vorher ein Backup der Daten machen.
Hi,
ich bin noch nicht so lange in der Linux-Welt unterwegs, aber mag es, mit Scripts Dinge zu steuern
Daher möchte ich gerne mit der ioBroker-Community meine Vorgehensweise teilen. Sicherlich alles andere als perfekt, aber es läuft 8-)
Das ganze hat mich etwas Zeit gekostet, vor allem mich einzuarbeiten in Bash, wie Linux tickt, Proxmox, etc. Ist für mich ein nettes Hobby.
<size size="150">Ausgangssituation / Use Case:</size>
Auf einem Linux-Server (bei mir: Proxmox-Virtualisierung) liegen Dateien, die ich Nachts in die Cloud (bei mir: Microsoft OneDrive) synchronisieren möchte. In VIS möchte ich sehen, ob die Synchronisierung erfolgreich lief, also sichergestellt ist, dass ein Backup in die Cloud erfolgte.
<size size="150">Durchführung:</size>
Tools:
-
https://rclone.org/ - sehr mächtig und kann mit vielen Clouds umgehen.
-
https://github.com/ioBroker/ioBroker.simple-api/blob/master/README.md
Bei mir läuft auf einem Proxmox-Container ein Turnkey-Fileserver mit Samba. Im Endeffekt sollte hier eine typische Linux-Umgebung vorliegen.
Auf diesem Container habe ich rclone installiert und über die Kommandozeile entsprechend eingerichtet und die Cloud entsprechend konfiguriert.
Auf der Weboberfläche vom Turnkey-Fileserver habe ich dann entsprechende CronJobs eingerichtet, hier ein Bash-Script-Beispiel, das bei mir jede Nacht läuft. Das Script habe ich in eine Datei gepackt und auf dem Fileserver abgelegt und der CronJob führt es aus.
#!/bin/bash # Variablen DATENOW=`date '+%Y-%m-%d_%H-%M-%S'`; LOCKDIR="/_myshare/_my-cron-jobs/mylock_onedrive_crypto" # Um zu prüfen, dass das Script nicht zweimal gleichzeitig ausgeführt wird. LOGFILE="/_myshare/_my-cron-jobs/rclone_crypto_$DATENOW.log" # ioBroker-Datenpunkte # Achtung: Zum setzen ist der simple-api Adapter notwendig, damit dieser Browser-Kommandos empfangen kann. IOBROKERSTATUS=javascript.0.mic.vis-support.proxmoxBackup.cryptomatorSuccessful IBROKERLASTTIME=javascript.0.mic.vis-support.proxmoxBackup.cryptomatorLastDateTime # ioBroker-IP:Port (Port von simple-api Adapter) IPP=10.10.0.140:8087 # ################################################ # Script nicht 2mal ausführen, daher arbeiten wir mit Lock. # http://wiki.bash-hackers.org/howto/mutex # https://askubuntu.com/questions/142002/generic-solution-to-prevent-a-long-cron-job-from-running-in-parallel # ################################################## if mkdir "${LOCKDIR}"; then echo "Locking succeeded (script is not already running), so we can continue with our script" >&2 trap 'rm -rf "${LOCKDIR}"' EXIT # Lock dir deleted whenever script is exited, stopped, etc. else echo "Lock failed, script is already running - exit" >&2 exit 1 fi # Hier das eigentliche Kommando if rclone sync /_myshare/XYZ remote_OneDrive:XYZ --log-file "${LOGFILE}" --log-level "INFO" echo 'rclone successfully executed' DATENOWSUCC=`date '+%Y-%m-%dT%H:%M:%S'`; curl http://${IPP}/set/${IOBROKERSTATUS}?value=true curl http://${IPP}/set/${IBROKERLASTTIME}?value={$DATENOWSUCC} else echo 'rclone failed' DATENOWFAIL=`date '+%Y-%m-%dT%H:%M:%S'`; curl http://${IPP}/set/${IOBROKERSTATUS}?value=false curl http://${IPP}/set/${IBROKERLASTTIME}?value={$DATENOWFAIL} fi
Dieses Bash-Script macht folgendes:
-
Es führt die Synchronisierung des lokalen Verzeichnisses "/_myshare/XYZ" mit der Cloud im Verzeichnis "XYZ" durch. Das ganze ist "einweg", das heißt Änderungen in der Cloud werden nicht berücksichtigt. Also eine reine Backup-Lösung.
-
Der Erfolg (oder Misserfolg) der tagtäglichen Synchronisierung wird im ioBroker in Datenpunkte (dank ioBroker-Adapter simple-api) geschrieben.
ioBroker
Damit das ganze läuft, muss im ioBroker der simple-api-Adapter laufen.
Mit folgendem Script werden die benötigten Datenpunkte erstellt, die zum einen das obige Bash-Script füllt, und die zum anderen für die Anzeige im VIS dienen.
/****************************************************************************************** * --------------------------- * PROXMOX: Cloud-Backup mittels rclone: Datenpunkte erstellen und für VIS auswerten * --------------------------- * Diese werden direkt von den Bash-Scripts geschrieben (Fileserver: /_myshare/_my-cron-jobs) * * Siehe https://forum.iobroker.net/viewtopic.php?f=35&t=19004 * * Change Log * 0.2 Mic - Bug fix * 0.1 Mic - Initial release *******************************************************************************************/ const STATE_PATH = 'javascript.0.mic.vis-support.proxmoxBackup.'; // Die verschiedenen Backups // schedule: wann wird das Script ausgeführt. // noOfDays: innerhalb wie vielen Tagen muss das Backup gelaufen sein, damit "Successful"=true const CONF_BACKUP = [ {'name': 'keepass', 'schedule_hour': 5, 'schedule_minute': 15, 'noOfDays': 2}, {'name': 'cryptomator', 'schedule_hour': 5, 'schedule_minute': 20, 'noOfDays': 2}, ]; // Erweitertes Log const LOG_DEBUG = true; /******************************************************************************* * Ab hier nichts mehr ändern / Stop editing here! ******************************************************************************/ // Globale Variablen var G_ScheduleObjects = {}; // Contains the object for each schedule /******************************************************************************* * Executed on every script start. *******************************************************************************/ init(); function init() { // Create states createBackupStates(); // Main Script starten, 3s nach State-Generierung setTimeout(main, 3000); } /******************************************************************************* * Haupt-Skript *******************************************************************************/ function main() { for (let lpEntry of CONF_BACKUP) { var loopScheduleObjectId = lpEntry.name + '_schedule'; // ID for each schedule object. We define it here to be able to clear the schedule. /********************* * 1\. Execute once Backup was performed ********************/ on({id: STATE_PATH + lpEntry.name + 'LastDateTime', change: 'any'}, function(obj) { if (getState(STATE_PATH + lpEntry.name + 'Successful').val === true ) { setState(STATE_PATH + lpEntry.name + 'ForVIS_BackupSuccessful', true); } else { setState(STATE_PATH + lpEntry.name + 'ForVIS_BackupSuccessful', false); // Jetzt nicht unbedingt "within last x days", aber jedenfalls war Backup nicht erfolgreich! } }); // Gelbes Dreieck Kann man links ignorieren, wir brauchen hier die Funktion innerhalb der Schleife /********************* * 2\. Schedule for every day ********************/ if(LOG_DEBUG) log('Proxmox-Cloud-Backup: Setze Schedule für ' + lpEntry.name + ', gesetzt auf Stunde ' + lpEntry.schedule_hour + ' und Minute ' + lpEntry.schedule_minute); clearSchedule(loopScheduleObjectId); // Let's clear the schedule to make sure no former schedules are running. Not sure if we really need this, but just in case. G_ScheduleObjects[loopScheduleObjectId] = schedule({hour: lpEntry.schedule_hour, minute: lpEntry.schedule_minute}, function () { let strDateLastBackup = getState(STATE_PATH + lpEntry.name + 'LastDateTime').val; if (g_myIsValueEmptyNullUndefined(strDateLastBackup) === false) { // Date/Time of backup + X days -- from https://stackoverflow.com/questions/3674539/incrementing-a-date-in-javascript let noOfDaysToCheck = lpEntry.noOfDays; let dtLastBackupPlusXDays = new Date(strDateLastBackup); dtLastBackupPlusXDays = F_addDays(dtLastBackupPlusXDays, noOfDaysToCheck); // Current date let dtCurrentForCompare = new Date(); // Compare if (dtLastBackupPlusXDays > dtCurrentForCompare) { // Last Backup took place within last X days, so we set state to true setState(STATE_PATH + lpEntry.name + 'ForVIS_BackupSuccessful', true); } else { setState(STATE_PATH + lpEntry.name + 'ForVIS_BackupSuccessful', false); } } else { // Datenpunkt für letztes Backup nicht gesetzt, also setzen wir auf false (zur Sicherheit) setState(STATE_PATH + lpEntry.name + 'ForVIS_BackupSuccessful', false); } if(LOG_DEBUG) log('Proxmox-Cloud-Backup: Update Datenpunkt für ' + lpEntry.name + ' durchgeführt.'); }); // Gelbes Dreieck Kann man links ignorieren, wir brauchen hier die Funktion innerhalb der Schleife } // for } /******************************************************************************* * Create States *******************************************************************************/ function createBackupStates() { for (let lpEntry of CONF_BACKUP) { createState(STATE_PATH + lpEntry.name + 'Successful', {'name': lpEntry.name + ' Successful?', 'type':'boolean', 'read':true, 'write':true, 'role':'info', 'def':false }); createState(STATE_PATH + lpEntry.name + 'LastDateTime', {'name': lpEntry.name + ' Last Date/Time', 'type':'string', 'read':true, 'write':true, 'role':'info', 'def':'' }); createState(STATE_PATH + lpEntry.name + 'ForVIS_BackupSuccessful', {'name': lpEntry.name + ' Status For VIS: Performed Successfully?', 'type':'boolean', 'read':true, 'write':true, 'role':'info', 'def':false }); } } /******************************************************************************* * Function to add days to a given date/time. *******************************************************************************/ function F_addDays(startDateTime, numberOfDays) { return new Date(startDateTime.getTime() + (numberOfDays * 24 *60 * 60 * 1000)); }
Damit werden dann die entsprechenden Datenpunkte erzeugt, hier ein Auszug:
Zum Schluss kann man dann den Datenpunkt "javascript.0.mic.vis-support.XXXXBackup.cryptomatorForVIS_BackupSuccessful" entsprechend in VIS verwenden. Er gibt true/false zurück.
Das "smarte" an der ganzen Sache ist:
Im VIS wird nur dann "Backup erfolgreich" angezeigt, wenn
-
Der Cron-Job ausgeführt wurde
-
- Die Synchronisierung mit der Cloud erfolgreich war
-
- Die letzte erfolgreiche Ausführung innerhalb von X Tagen war (im JavaScript konfigurierbar, im Beispiel auf 2 Tage gesetzt, 'noOfDays': 2)
Schlussbemerkungen:
Die Installation und Einrichtung von rclone ist über den obigen Link und Google gut durchführbar.
Sämtliche Pfade müssen natürlich im Bash-Script und Javascript angepasst werden etc.
Bitte das ganze erst mal nur mit Test-Verzeichnissen durchführen, gerade das Tool rsync ist da gnadenlos und führt exakt das aus, was in den Parametern steht.
Für Verbesserungsvorschläge usw. bin ich natürlich sehr dankbar
P.S. Warum verwende ich Microsoft OneDrive? Nun, es bietet 1TB Speicherplatz in Verbindung mit dem MS-Office-Abo, daher aus meiner Sicht sehr günstig in dieser Kombination und mir ist ansonsten kein Cloud-Anbieter bekannt mit diesem guten Ratio aus "Euro pro GB Speicher".
-
-
Wow! Super durchdacht und schön gelöst.
Danke fürs teilen und der ausführlichen Beschreibung!
-
Gern geschehen und danke für Dein Feedback ruhr70!
Hab oben im JavaScript übrigens noch einen Fehler behoben.