Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Praktische Anwendungen (Showcase)
    4. [Vorlage] Synchronisation / Backup von Fileserver in Cloud und Erfolgsanzeige in VIS

    NEWS

    • [erledigt] 15. 05. Wartungsarbeiten am ioBroker Forum

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Monatsrückblick - April 2025

    [Vorlage] Synchronisation / Backup von Fileserver in Cloud und Erfolgsanzeige in VIS

    This topic has been deleted. Only users with topic management privileges can see it.
    • Mic
      Mic Developer last edited by

      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:

      1. 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.

      2. 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:
      6940_back1.png

      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.
      6940_back2.png

      Das "smarte" an der ganzen Sache ist:

      Im VIS wird nur dann "Backup erfolgreich" angezeigt, wenn

      1. 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".

      1 Reply Last reply Reply Quote 1
      • ruhr70
        ruhr70 last edited by

        Wow! Super durchdacht und schön gelöst.

        Danke fürs teilen und der ausführlichen Beschreibung!

        1 Reply Last reply Reply Quote 0
        • Mic
          Mic Developer last edited by

          Gern geschehen und danke für Dein Feedback ruhr70!

          Hab oben im JavaScript übrigens noch einen Fehler behoben.

          1 Reply Last reply Reply Quote 0
          • First post
            Last post

          Support us

          ioBroker
          Community Adapters
          Donate

          755
          Online

          31.6k
          Users

          79.5k
          Topics

          1.3m
          Posts

          2
          3
          861
          Loading More Posts
          • Oldest to Newest
          • Newest to Oldest
          • Most Votes
          Reply
          • Reply as topic
          Log in to reply
          Community
          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
          The ioBroker Community 2014-2023
          logo