Navaria
Anmeldungsdatum: 30. Dezember 2006
Beiträge: 117
Wohnort: Hannover
|
Hi Leute, ich brauch mal wieder Hilfe in Sachen Scripte. Mein Server macht mehrfach die Woche ein per crontab gestartetes Backup, die er in einen Verzeichnis /backup unter einem Namen wie "backupData_2023-09-15_040001.tar.gz" ablegt (Dateiname + Timestamp also). Das Backup-Script löscht dabei automatisch alle Backups älter als 14 Tage, damit das Verzeichnis nicht überläuft. So, und jetzt würde ich diese Backups gerne per AndreaFabrizi's "dropbox_uploader" Script (https://github.com/andreafabrizi/Dropbox-Uploader) in meine Dropbox synchronisieren. Es ist alles vorbereitet, ich habe in Dropbox eine neue App angelegt, einen API Key generiert, und das Hochladen von Dateien in die Dropbox funktioniert wunderbar, das Löschen auch. Bisher starte ich die Scripte noch manuell, aber das soll natürlich dann auch per crontab automatisiert werden. Mein Problem ist folgendes:
Man muss das dropbox_uploader Script entweder mit einer Option wie "upload", "list", "download" oder "delete" aufrufen. Mein Problem ist, dass ich zwar problemlos alle neuen Backup-Dateien in die Dropbox hochladen kann, aber wie sorge ich dafür, dass alle Dateien, die mein Backup-Script aufgeräumt hat (Löschen aller Backups älter als 14 Tage, siehe oben), dann auch mithilfe des dropbox_uploader Scripts gelöscht werden? Ich muss dem Script ja ganz genau die Dateinamen im Ziel vorgeben, die gelöscht werden sollen. Hat jemand eine Idee?
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13211
|
Kannst Du nicht einfach die Backusp in einen Ordner legen, der von Dropbox synchronisiert wird? Dann hast Du damit nix zu tun.
|
Navaria
(Themenstarter)
Anmeldungsdatum: 30. Dezember 2006
Beiträge: 117
Wohnort: Hannover
|
Das ist nen Server, ich hab da keine GUI laufen ☺ Und daher auch keinen Dropbox Client.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13211
|
Dann würde ich das so machen. setzte zwei Skripte mit inotifywait -r -m ... auf - der eine wartet auf Event "close_write", der andere auf "delete". Du liest jeweils in einer Schleife von Stdin und startest Dein Skript mit den entsprechenden Parametern. Grob: | inotifywait -m -r -q --format '%w%f' -e close_write backup/dir | while read -r file; do
[ -f "$file" ] && dropbox_uploader upload "$file"
done
|
Option -r brauchst Du nicht, wenn es nur um Dateien in dem einen Verzeichnis geht. Der Test auf die Existenz muss dann bei "delete" natürlich wegfallen oder umgekehrt aussehen. | inotifywait -m -r -q --format '%w%f' -e delete backup/dir | while read -r file; do
[ -e "$file" ] || dropbox_uploader delete "$file"
done
|
|
shiro
Supporter
Anmeldungsdatum: 20. Juli 2020
Beiträge: 1274
|
Hallo Navaria, wenn ich dich richtig verstanden habe, willst du auf dem Dropbox Server alle .tar.gz Dateien löschen, die gemäß Datum des Dateinamens älter als 14 Tage sind. Statt eines "dropbox_uploader.sh delete $f" Befehls habe ich in meinem Beispiel ein "echo $f delete" geschrieben.
$ file=backupData_2023-09-01_000001.tar.gz
$ dropbox_uploader.sh upload $file $file
$ file=backupData_2023-09-15_040001.tar.gz
$ dropbox_uploader.sh upload $file $file
$ dropbox_uploader.sh list >$$
$ cat $$
> Listing "/"... DONE
[F] 0 backupData_2023-09-01_000001.tar.gz
[F] 0 backupData_2023-09-15_040001.tar.gz
$ dt=$(echo $file | sed -E 's/^.*_([0-9-]*)_(..)(..)(..).*$/\1 \2:\3:\4/')
$ tbd="backupData_$(date -d "$dt 14 days ago" +%Y-%m-%d_%H%M%S).tar.gz"
$ cat $$ | sed 1d | cut -d\ -f4- | while read f; do if [[ "$f" < "$tbd" ]]; then echo "$f delete"; else echo "$f keep"; fi; done
backupData_2023-09-01_000001.tar.gz delete
backupData_2023-09-15_040001.tar.gz keep
$ rm $$
Könnte es sein, dass du diese Aufgabe lösen willst?
|
Navaria
(Themenstarter)
Anmeldungsdatum: 30. Dezember 2006
Beiträge: 117
Wohnort: Hannover
|
Jein shiro, nicht ganz. Hab mich wahrscheinlich blöd ausgedrückt. Mein Backup-Script läuft regelmäßig per crontab gesteuert und sichert Daten. Dabei löscht es am Ende des Scriptes alle Dateien älter als 14 Tage weg: | echo Alte Backups werden entfernt... >>$LOGFILE
find $BACKUP_DIR/*.tar.gz -type f -mtime +14 -exec rm -v '{}' >> $LOGFILE \;
|
Blick ins Backup-Verzeichnis: QUELLE
| markus@pi:~/foundry/backup/vtt1/data$ ll
insgesamt 6577956
drwxrwxr-x 2 markus markus 4096 Sep 5 04:03 ./
drwxrwxr-x 4 markus markus 4096 Jan 15 2023 ../
-rw-rw-r-- 1 markus markus 1680069732 Aug 22 04:02 backupData_2023-08-22_040001.tar.gz
-rw-rw-r-- 1 markus markus 1681503086 Aug 29 04:02 backupData_2023-08-29_040001.tar.gz
-rw-rw-r-- 1 markus markus 1698234267 Sep 5 04:03 backupData_2023-09-05_040001.tar.gz
|
Bisher habe ich dieses Quell-Verzeichnis per Samba-Freigabe als Netzlaufwerk auf meinem Mac eingebunden und lasse 1x täglich diesen Ordner mit dem Dropbox-Ordner abgleichen. Ich verwende dazu Carbon Copy Cloner, und habe den so eingestellt, dass alle neuen und geänderten Dateien der Quelle in den Dropbox Ordner kopiert werden und Dateien, die auf der Quelle gelöscht wurden, auch im Ziel (Dropbox) gelöscht werden. Also im Grunde ein Unidirektionaler Sync. Nur halt ganz schön umständlich durch den Umweg über den Mac. Ich würde mir aber gerne den Umweg über meinen Mac ersparen und den Pi-Server die Daten direkt mit der Dropbox syncen. Gleiche Vorgabe wie bisher: Neue und geänderten Daten ins Ziel hochladen, auf der Quelle gelöschte Daten in der Dropbox ebenfalls löschen. Das dropbox_uploader Script arbeitet wunderbar in Sachen Upload. Ich gebe das Verzeichnis vor, und alle neuen / geänderten Daten werden hochgeladen. Aber ich müsste das Script ein zweites Mal starten mit dem Befehl die in der Quelle nicht mehr vorhandenen Daten auch in der Dropbox zu löschen. Im Gegensatz zum Upload, wo ich nur ein Verzeichnis angeben kann, und das Script erkennt selbstständig, welche Dateien hochzuladen sind, muss ich beim Delete exakte Dateinamen, die löschen sind, vorgeben. Ich muss also meinem Backup-Script irgendwie ein "Gedächtnis" einbauen, welche Dateien (älter 14 Tage) gelöscht wurden, um diese dann auch in der Dropbox zu löschen. Oder umgekehrt, dass zunächst bestimmt wird, welche Daten älter als 14 Tage sind, diese in der Dropbox löschen und dann auch auf der Quelle. Die Reihenfolge ist nicht so wichtig. Am Ende muss nur der Dropbox Ordner den gleichen Inhalt haben wie die Quelle. Natürlich müssen das nicht zwei Scripte sein, ich könnte den Upload in die Dropbox und das Löschen in der Dropbox mit in das Backup-Script mit aufnehmen.
|
shiro
Supporter
Anmeldungsdatum: 20. Juli 2020
Beiträge: 1274
|
Am Ende muss nur der Dropbox Ordner den gleichen Inhalt haben wie die Quelle.
Aber das bedeutet ja, dass du die .tar.gz Dateien 2 mal hast (lokal=QUELLE und remote=DROPBOX)! Wenn diese meine Interpretation richtig ist, dann frage ich mich allerdings, warum du "dropbox_update.sh" verwendest. Normalerweise würde man für diese Aufgabe das Paket "thunar-dropbox-plugin" installieren, was automatisch auch das Paket "nautilus-dropbox" mit installiert. Du hast dann auf einem gemounteten Filesystem dein "Spiegelverzeichnis" von Dropbox, in das du deine .tar.gz Dateien ablegst. Der Dropbox-service synchronisiert dann automatisch bidirektion das Spiegelverzeichnis (mit den Unterordnern) mit dem von Dropbox (siehe "man dropbox" → dropbox autostart y). Dabei werden dann automatisch auch die Dateien auf dem Dropbox Server gelöscht, die du lokal gelöscht hast. Wenn du das nicht automatisch machen lassen willst, kannst du mit "dropbox start" und "dropbox stop" den Zeitraum festlegen, in dem gesynched werden soll.
|
Navaria
(Themenstarter)
Anmeldungsdatum: 30. Dezember 2006
Beiträge: 117
Wohnort: Hannover
|
Ja deine Interpretation ist vollkommen richtig, ich möchte sie 2x haben. Einmal lokal auf dem Server und aus Sicherheitsgründen in einem zweiten Speicherort (Dropbox). Was das von dir erwähnte thunar-dropbox-plugin und nautilus-dropbox angeht:
Ich habe Ubuntu Server auf dem Pi laufen, ohne GUI. Ich habe zwar eine GUI (Budgie) installiert, doch standardmäßig wird die nicht gestartet (multi-user.target). Wenn ich das richtig verstehe, lösen diese Pakete mein Problem nur, wenn ich die GUI vom Server starte (was ich aus Performance-Gründen nicht möchte). Oder siehst du einen anderen Weg, rein auf Kommandozeile, einen Dropbox-Sync zu realisieren, den ich nicht sehe? Kann ja sein ☺ Und ich möchte ja auch gar nicht den ganzen Dropbox Ordner synchronisieren, sondern nur diesen einen Ordner und nur in eine Richtung. Dafür habe ich mir in Dropbox eine Developer App und einen API-Key eingerichtet. Das sorgt dafür, dass die Daten dieser "App" einen separaten eigenen Space bekommen, um die Daten abzulegen.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13211
|
Navaria schrieb:
Ich muss also meinem Backup-Script irgendwie ein "Gedächtnis" einbauen, welche Dateien (älter 14 Tage) gelöscht wurden, um diese dann auch in der Dropbox zu löschen. Oder umgekehrt, dass zunächst bestimmt wird, welche Daten älter als 14 Tage sind, diese in der Dropbox löschen und dann auch auf der Quelle. Die Reihenfolge ist nicht so wichtig. Am Ende muss nur der Dropbox Ordner den gleichen Inhalt haben wie die Quelle.
Oder Du lässt einen Betriebssystemmechanismus wie inotify das erledigen.
Natürlich müssen das nicht zwei Scripte sein, ich könnte den Upload in die Dropbox und das Löschen in der Dropbox mit in das Backup-Script mit aufnehmen.
Ich finde inotofy genau den richtigen Mechanismus dafür. Ich habe noch mal eine Variante gebaut, die in einem Skript beide Ereignisse (Datei geschrieben, Datei gelöscht) erledigt. Das ist ressourcensparender (weniger Watches) und erhält die Reihenfolge der Ereignisse (kann bedeutsam sein, wenn eine Datei mehrfach geschrieben und gelöscht wird). | #!/bin/sh
inotifywait -m -r -q --format '%e %w%f' -e delete,close_write "$1" | while read -r event file; do
case "$event" in
CLOSE_WRITE*) dropbox_uploader upload "$file";;
DELETE) dropbox_uploader delete "$file";;
*) echo "WARNIN: ignoring event $event" >&2;;
esac
done
|
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13211
|
Ach, ich denke wieder zu umständlich. Wenn Dein Backup-Skript in der bash läuft, kannst Du das einfach mit einem Array lösen: | backup_dir=.
vorher=("$backup_dir"/*)
echo 'Backups...'
for f in "${vorher[@]}"; do
[ -e "$f" ] || dropbox_upload delete "$f"
done
|
Und wenn man das noch kombiniert mit der Behandlung der neuen: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | #!/bin/bash
# prep
ts=$(date +%s)
backup_dir=.
vorher=("$backup_dir"/*)
# backups
echo 'Backups...'
# dropbox sync
for f in "${vorher[@]}"; do
[ -e "$f" ] || echo drop delete "$f"
done
for f in "$backup_dir"/*; do
[ $(date +%s -r "$f") -ge $ts ] && echo dropbox_upload upload
done
|
So braucht man das inotify-Gehampel nicht. ☺
|
shiro
Supporter
Anmeldungsdatum: 20. Juli 2020
Beiträge: 1274
|
Navaria schrieb: Oder siehst du einen anderen Weg, rein auf Kommandozeile, einen Dropbox-Sync zu realisieren, den ich nicht sehe? Kann ja sein
Das CLI Interface von dropbox wird durch das Paket "nautilus-dropbox" bereits gestellt (siehe "apt-file list nautilus-dropbox"). Das eigentliche "dropbox" Kit wird dabei eh von der dropbox-Webseite (http://www.dropbox.com/downloading) im Hintergrund geladen (siehe "man dropbox" → update). Wenn du das Ubuntu Paket nicht installieren willst, kannst du die Kernsoftware auch von der o.g. Webseite laden (.deb) oder aus den dort abrufbaren Quellen bilden.
Letztendlich wird das Programm über "~/.dropbox-dist/dropboxd" gestartet. Das Ubuntu Paket liefert dir nur eine CLI Bedienoberfläche, die auch mit den grafischen Dateimanagern zusammen genutzt werden kann (nicht erforderlich).
Wenn ich das richtig verstehe, lösen diese Pakete mein Problem nur, wenn ich die GUI vom Server starte
Nein. Der "dropbox" Befehl wird über Terminal oder Script gestartet.
Und ich möchte ja auch gar nicht den ganzen Dropbox Ordner synchronisieren, sondern nur diesen einen Ordner und nur in eine Richtung.
Du musst nicht das komplette Dropbox-Verzeichnis synchronisieren sondern kannst über die "selektive Synchronisierung" die (Sub-)Ordner auswählen, die nicht synchronisiert werden sollen. Die somit "verborgenen Ordner" sind nur über die Weboberfläche (dropbox.com) erreichbar (siehe auch "man dropbox" → exclude add/list usw).
|
Navaria
(Themenstarter)
Anmeldungsdatum: 30. Dezember 2006
Beiträge: 117
Wohnort: Hannover
|
rklm schrieb: | #!/bin/sh
inotifywait -m -r -q --format '%e %w%f' -e delete,close_write "$1" | while read -r event file; do
case "$event" in
CLOSE_WRITE*) dropbox_uploader upload "$file";;
DELETE) dropbox_uploader delete "$file";;
*) echo "WARNIN: ignoring event $event" >&2;;
esac
done
|
Ok 😮 Wow, ähm da brauche ich etwas Erläuterung. Ich hab mal im Wiki unter inotify nachgelesen und was ich aus deinem Script herauslese, ist, dass es scheinbar dauerhaft (Im Hintergrund? Wie gestartet?) läuft, und wenn das Event delete oder close_write (Wo wird das Verzeichnis, dass zu überwachen ist angegeben?) auftritt, dann wird das dropbox_uploader Script entweder mit Option upload oder delete gefolgt vom Dateinamen aufgerufen. Die echo-Zeile verstehe ich nicht vollständig, es gibt ne Warnung aus, wenn ein Ereignis ignoriert wird, aber >&2 sagt mir nichts. Und was macht esac? Kannst du mir die Lösung noch etwas umfassender erklären bitte, damit ich verstehe, wie ich das implementieren muss? Danke ☺
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13211
|
Navaria schrieb:
Ok 😮 Wow, ähm da brauche ich etwas Erläuterung. Ich hab mal im Wiki unter inotify nachgelesen und was ich aus deinem Script herauslese, ist, dass es scheinbar dauerhaft (Im Hintergrund? Wie gestartet?) läuft,
Genau. Könnte man als Systemd-Unit anlegen, die beim Booten gestartet wird.
und wenn das Event delete oder close_write (Wo wird das Verzeichnis, dass zu überwachen ist angegeben?)
Das ist in $1 , also dem ersten Argument beim Skriptaufruf. Du kannst es natürlich anders setzen.
auftritt, dann wird das dropbox_uploader Script entweder mit Option upload oder delete gefolgt vom Dateinamen aufgerufen.
Korrekt.
Die echo-Zeile verstehe ich nicht vollständig, es gibt ne Warnung aus, wenn ein Ereignis ignoriert wird, aber >&2 sagt mir nichts.
Das ist die Umleitung der Ausgabe nach Stderr, wo Fehlermeldungen üblicherweise landen.
Und was macht esac?
Das schließt case .
Mittlerweile denke ich aber, die Lösung innerhalb des Skriptes ist besser, weil weniger kompliziert.
|
Navaria
(Themenstarter)
Anmeldungsdatum: 30. Dezember 2006
Beiträge: 117
Wohnort: Hannover
|
Sorry für die späte Antwort, hatte den ganzen Tag über keine Zeit. Also ich bin kein Programmierer, sondern eher Integrator 😀 Will sagen, ich verstehe den Vorschlag nicht so ganz. Aber ich hab mich einfach mal versucht, mit einem Test-Verzeichnis: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | #!/bin/bash
DATE=$(date +"%Y-%m-%d_%H%M%S")
BACKUP_DIR="$HOME/foundry/backup/vtt1/testdata" # Variable gab es bereits. rklm: Funktioniert das hier auch in deinem Vorschlag?
DELFILE=("$BACKUP_DIR"/*) # neue Variable gem. Vorschlag rklm
DATA_DIR="$HOME/foundry/server/vtt1/foundrydata"
LOG_DIR="$HOME/foundry/logs/vtt1/backuplogs"
LOGFILE="$HOME/foundry/logs/vtt1/backuplogs/backupData_$DATE.log"
# Variablen ausgeben, fuer Debug Zwecke
echo Backup Dir: $BACKUP_DIR >>$LOGFILE
echo DelFile: $DELFILE >> $LOGFILE
echo UsrDat Dir: $DATA_DIR >>$LOGFILE
echo Log Dir: $LOG_DIR >>$LOGFILE
echo Logfile: $LOGFILE >>$LOGFILE
# Backup erstellen
tar -czvf $BACKUP_DIR/backupData_$DATE.tar.gz "$DATA_DIR" "$(realpath --relative-to ../dummy $DATA_DIR)" >>$LOGFILE
# Alte Backups entfernen
echo Alte Backups werden entfernt... >>$LOGFILE
find $BACKUP_DIR/*.tar.gz -type f -mtime +14 -exec rm -v '{}' >> $LOGFILE \;
# Vorschlag rklm fuer das Loeschen in der Dropbox
# Hier erst mal nur Ausgabe, was das Script loeschen wuerde
for f in "${DELFILE[@]}"; do
[ -e "$f" ] || echo Delete file "$f" >>$LOGFILE
# hier kommt dann das Loeschen in der Dropbox rein
done
# Alte Backup-Logs entfernen
echo Alte Backup-Logs werden entfernt... >>$LOGFILE
find $LOG_DIR/backupData*.log -type f -mtime +14 -exec rm -v '{}' >> $LOGFILE \;
|
Ausgabe des Logs, gekürzt auf das Wesentliche:
1
2
3
4
5
6
7
8
9
10
11
12
13 | Backup Dir: /home/markus/foundry/backup/vtt1/testdata
DelFile: /home/markus/foundry/backup/vtt1/testdata/backupData_2023-08-15_040001.tar.gz
UsrDat Dir: /home/markus/foundry/server/vtt1/foundrydata
Log Dir: /home/markus/foundry/logs/vtt1/backuplogs
Logfile: /home/markus/foundry/logs/vtt1/backuplogs/backupData_2023-09-17_205355.log
...
...
...
Alte Backups werden entfernt...
Alte Backup-Logs werden entfernt...
'/home/markus/foundry/logs/vtt1/backuplogs/backupData_2023-08-15_040001.log' wurde entfernt
'/home/markus/foundry/logs/vtt1/backuplogs/backupData_2023-08-22_040001.log' wurde entfernt
'/home/markus/foundry/logs/vtt1/backuplogs/backupData_2023-08-29_040001.log' wurde entfernt
|
Es scheint, als ob deine Codezeilen gar keinen Effekt haben. Ich habe ja deine Zeile
| [ -e "$f" ] || dropbox_upload delete "$f"
|
durch
| [ -e "$f" ] || echo Delete file "$f" >>$LOGFILE
|
ersetzt in der Hoffnung, dass ich dann die Ausgabe sehe, welche Dateien er zu löschen gedenkt. Aber er gibt ja gar nichts aus. Muss $f nicht irgendwo deklariert werden?
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13211
|
Navaria schrieb:
ersetzt in der Hoffnung, dass ich dann die Ausgabe sehe, welche Dateien er zu löschen gedenkt. Aber er gibt ja gar nichts aus. Muss $f nicht irgendwo deklariert werden?
Zeile 25.
|