3 Commits
Author SHA1 Message Date
Hartmut Bauer 328936748e Restore, List Archives, Content 2025-04-13 02:36:47 +02:00
Hartmut Bauer ab61e0e916 Fix log+backup acls 2025-04-13 00:10:00 +02:00
Hartmut Bauer 80c5bb0ff0 Release 2.1.0 2025-04-11 23:03:47 +02:00
10 changed files with 170 additions and 101 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2025 hb Copyright (c) 2025 Hartmut Bauer
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-1
View File
@@ -24,5 +24,4 @@ daily/nathan/backup.1 20GB/ 0:40h
... ...
backup.7 backup.7
weekly/synology 320GB/ 9:30h weekly/synology 320GB/ 9:30h
logs/<hostname>/
``` ```
+35 -35
View File
@@ -1,26 +1,26 @@
### TODOs ### TODOs
- code cleanup (-> export!)
- test export
- Doku - Doku
- (x) code cleanup (-> export!)
- (x) test export
DB-Dump DB-Dump
(x) new for postgres - (x) new for postgres
(x) jede db einzeln? - (x) jede db einzeln?
(x) +mariadb - (x) +mariadb
(-) hooks für weitere - (-) hooks für weitere
nextcloud: nextcloud:
(x) vol/nextcloud/data/data/hb zeigt auf NAS-share - (x) vol/nextcloud/data/data/hb zeigt auf NAS-share
(x) -> alles auf Server - (x) -> alles auf Server
backup MAC backup MAC
(x) ccc 2x 2TB intern (weekly) - (x) ccc 2x 2TB intern (weekly)
(x) ccc 2x 2TB extern - (x) ccc 2x 2TB extern
(x) TODO: SSDs auf Verschlüsselung umstellen - (x) TODO: SSDs auf Verschlüsselung umstellen
(x) TODO: Kalendereintrag für wöchentlichen backup - (x) TODO: Kalendereintrag für wöchentlichen backup
nas-backup daily nas-backup daily
- (x) tar, gpg to nas - (x) tar, gpg to nas
@@ -33,36 +33,36 @@ nas-backup daily
- (x) TODO: script (python?) - (x) TODO: script (python?)
nas-backup weekly 1 nas-backup weekly 1
(x) media/books, media/music/_all + _hoerspiel -> tar, gpg nach //backup - (x) media/books, media/music/_all + _hoerspiel -> tar, gpg nach //backup
(x) TODO: s. nas-backup daily - (x) TODO: s. nas-backup daily
logging logging
(x) für auto-fns mail() - (x) für auto-fns mail()
(x) mail() loggt in extra Datei und ruft log(), für std log - (x) mail() loggt in extra Datei und ruft log(), für std log
(x) Name std log in mail() ausgeben - (x) Name std log in mail() ausgeben
(-) mail log lokal anlegen (wo?) - (-) mail log lokal anlegen (wo?)
(-) am Ende von auto mail log in mail und file löschen -> py-script - (-) am Ende von auto mail log in mail und file löschen -> py-script
(x) alle Programme müssen stdout/stderr auf std log umleiten - (x) alle Programme müssen stdout/stderr auf std log umleiten
(x) für jeden Lauf neue log datei (+date) - (x) für jeden Lauf neue log datei (+date)
(-) Name der log Datei bei !auto auf stderr ausgeben (damit stdout ggf. geparst werden kann, alt.: param --machine) - (-) Name der log Datei bei !auto auf stderr ausgeben (damit stdout ggf. geparst werden kann, alt.: param --machine)
(x) log file in nfs/backups/log/$HOST_NAME-$(date '+%Y-%m-%d_%H%M').log - (x) log file in nfs/backups/log/$HOST_NAME-$(date '+%Y-%m-%d_%H%M').log
(x) bei jedem Lauf alte logs löschen (7d?) -> wie? - (x) bei jedem Lauf alte logs löschen (7d?) -> wie?
(-) evtl. logs lokal ablegen und am Ende auf NAS kopieren - (-) evtl. logs lokal ablegen und am Ende auf NAS kopieren
backup server+nas extern backup server+nas extern
(x) rsync nas-backup 2x HDD intern (weekly) (5TB?) - (x) rsync nas-backup 2x HDD intern (weekly) (5TB?)
(x) TODO: script (python?) mit HD-Erkennung - (x) TODO: script (python?) mit HD-Erkennung
(x) TODO: zusätzliche HDD - (x) TODO: zusätzliche HDD
(x) TODO: Kalendereintrag, s. backup MAC - (x) TODO: Kalendereintrag, s. backup MAC
export backups export backups
(x) rsync nas-backup 2x 2TB HDD extern - (x) rsync nas-backup 2x 2TB HDD extern
(x) TODO: script, s. backup server+nas - (x) TODO: script, s. backup server+nas
export serien export serien
(x) rsync dir 1x 5TB HDD extern - (x) rsync dir 1x 5TB HDD extern
(x) TODO: vorhandenes script in neue Routine einbauen - (x) TODO: vorhandenes script in neue Routine einbauen
export video export video
(x) rsync dir 1x 5TB HDD extern - (x) rsync dir 1x 5TB HDD extern
(x) TODO: s. export serien - (x) TODO: s. export serien
+3
View File
@@ -0,0 +1,3 @@
#!/usr/bin/eval bash
#NAS_ROOT=/Users/hb/mnt/nas/backups
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/eval bash #!/usr/bin/eval bash
NAS_ROOT=/var/srv/nas/backups #NAS_ROOT=/var/srv/nas/backups
BACKUP_TARGET=/var/docker/tmp BACKUP_TARGET=/var/docker/tmp
NAS_TARGET="$NAS_ROOT/daily/$HOST_NAME/backup.$DAY" NAS_TARGET="$NAS_ROOT/daily/$HOST_NAME/backup.$DAY"
+83 -23
View File
@@ -1,6 +1,15 @@
HOST_NAME=$(hostname -s) HOST_NAME=$(hostname -s)
DAY=$(date +%u) # MO == 1 DAY=$(date +%u) # MO == 1
NAS_MOUNT_POINT="$(realpath $HERE/../../..)" # Server/bin/backup
NAS_ROOT="$NAS_MOUNT_POINT/backups"
LOG_FILE_PATH="$NAS_MOUNT_POINT/Server/log/backup"
log_file_name="$LOG_FILE_PATH/$HOST_NAME-$(date '+%Y-%m-%d_%H%M')"
LOG_FILE="${log_file_name}.log"
RESTORE_PATH="$NAS_MOUNT_POINT/Server/restore"
BACKUP_MASTER_CHECK="/var/docker/vol/proxy" BACKUP_MASTER_CHECK="/var/docker/vol/proxy"
NAS_HOSTNAME=synology NAS_HOSTNAME=synology
@@ -117,6 +126,19 @@ dump_postgresql() {
# ----- helper functions ----- # ----- helper functions -----
# Für Backup und Export muss das Script mit root-Rechten
# ausgeführt werden.
#
check_root() {
if [ "$(id -u)" -ne 0 ]; then
log $ERROR "$ERR script must be run as superuser."
echo "****"
echo "***** script must be run as superuser! *****"
echo "****"
exit 100
fi
}
start_docker() { start_docker() {
log $DEBUG "$DBG start_docker()" log $DEBUG "$DBG start_docker()"
log $DEBUG "$DBG > \$DOCKER up -d" log $DEBUG "$DBG > \$DOCKER up -d"
@@ -131,6 +153,17 @@ stop_docker() {
return $? return $?
} }
# Zugriffsrechte für Logs und Backups setzen
#
fix_acls() {
log $DEBUG "$DBG fix_acls()"
log $DEBUG "$DBG chmod -R a+r $NAS_ROOT"
chmod -R a+r $NAS_ROOT >>$LOG_FILE 2>&1
log $DEBUG "$DBG chmod -R a+r $LLOG_FILE_PATH"
chmod -R a+r $LLOG_FILE_PATH >>$LOG_FILE 2>&1
}
# Script per ssh auf Server $1 im Hintergrund starten # Script per ssh auf Server $1 im Hintergrund starten
# #
# ssh start in background # ssh start in background
@@ -419,6 +452,7 @@ backup_daily() {
is_error $? is_error $?
mail_log $INFO ">>>>>>>>>> end of auto backup" mail_log $INFO ">>>>>>>>>> end of auto backup"
fix_acls
send_mail_log "Daily Backup" send_mail_log "Daily Backup"
# ggf. weekly backup starten (z.ZT. nur auf NAS) # ggf. weekly backup starten (z.ZT. nur auf NAS)
@@ -437,6 +471,7 @@ backup_weekly() {
is_error $? is_error $?
mail_log $INFO ">>>>>>>>>> end of auto backup" mail_log $INFO ">>>>>>>>>> end of auto backup"
fix_acls
send_mail_log "Weekly Backup" send_mail_log "Weekly Backup"
} }
@@ -462,21 +497,50 @@ test_integrity() {
# Restore aus Archiv # Restore aus Archiv
# #
# Wird nach pwd ausgegeben! # Wird nach $RESTORE_PATH ausgegeben und mit root-Rechten
# auf der NAS ausgeführt.
# #
# $1 - Archiv, ggf. mit Pfad # $1 - Archiv, mit Pfad ab $NAS_ROOT
# $2 ff. - zurückzusichernde Dateien/Verzeichnisse # $2 ff. - zurückzusichernde Dateien/Verzeichnisse
# #
# returns 0 for success, 1 otherwise
#
restore() { restore() {
log $DEBUG "$DBG restore( $@ )" log $DEBUG "$DBG restore( $@ )"
local archive=$1 local archive=$1
shift 1 shift
log $DEBUG "$DBG > gpg --batch --decrypt --passphrase xxxx \"$archive\" | tar -xzv $@" echo "--- Restore ---"
gpg --batch --decrypt --passphrase $PASSPHRASE "$archive" 2>>$LOG_FILE | tar -xzv $@ >/dev/null 2>>$LOG_FILE echo "--- archive: $archive"
echo "--- files: $@"
echo "--- to: $RESTORE_PATH"
echo
echo "Restore runs on NAS, see e-mail"
echo
run_script_remote $NAS_IP "$NAS_SCRIPT --rx $archive $@"
}
# Restore
#
# Beim Restore einzelner Dateien wird nur die ownership der Datei
# restored, nicht die des Pfades zur Datei!
#
do_restore() {
if [ "$HOST_NAME" != "$NAS_HOSTNAME" ]; then
restore $@
exit
fi
local archive=$1
shift
mail_log $INFO ">>>>>>>>>> restore $VER for $HOST_NAME <<<<<<<<<<"
mail_log $INFO ">>> restore from: $archive"
mail_log $INFO ">>> files : $@"
mail_log $INFO ">>> restore to : $RESTORE_PATH"
mail_log $INFO ">>> log file : $LOG_FILE"
log $DEBUG "$DBG > gpg --batch --decrypt --passphrase xxxx \"$NAS_ROOT/${archive/#\//}\" | tar -xzv --directory $RESTORE_PATH $@"
gpg --batch --decrypt --passphrase $PASSPHRASE "$NAS_ROOT/${archive/#\//}" 2>>$LOG_FILE | tar -xzv --directory $RESTORE_PATH $@ >>$LOG_FILE 2>&1
check_pipe_rc ${PIPESTATUS[@]} check_pipe_rc ${PIPESTATUS[@]}
return $? is_error $?
mail_log $INFO ">>>>>>>>>> end of restore"
send_mail_log "Restore"
} }
# ----- archive content ------ # ----- archive content ------
@@ -498,41 +562,37 @@ create_list() {
# Liste der Archives auf stdout ausgeben # Liste der Archives auf stdout ausgeben
# #
# Zeigt alle Archive incl. Verzeichnis (ohne $1) an # Zeigt alle Archive incl. Verzeichnis (ohne $NAS_ROOT) an
# #
# z.B. # z.B.
# $1 = /volume1/nfs/backups # $NAS_ROOT = /volume1/nfs/backups
# ... # ...
# /daily/synology/backup.3/volume1-nfs-Server.tgz.gpg # /daily/synology/backup.3/volume1-nfs-Server.tgz.gpg
# /weekly/synology/volume1-media-books.tgz.gpg # /weekly/synology/volume1-media-books.tgz.gpg
# #
# $1 - Verzeichnis unter dem alle Backups liegen
#
# returns 0 for success, 1 otherwise # returns 0 for success, 1 otherwise
# #
list_archives() { list_archives() {
log $DEBUG "$DBG list_archives( $@ )" log $DEBUG "$DBG list_archives()"
local target=$1 local target=$1
local targ=${target//\//\\\/} # slashes escapen local targ=${NAS_ROOT//\//\\\/} # slashes escapen
log $DEBUG "$DBG > find \"$target\" -type f -name \"*.$EXT\" | grep \"${HOST_NAME}/\" | sed -E \"s/^$targ//\"" log $DEBUG "$DBG > find \"$NAS_ROOT\" -type f -name \"*.$EXT\" | sed -E \"s/^$targ//\""
find "$target" -type f -name "*.$EXT" 2>>$LOG_FILE | grep "${HOST_NAME}/" 2>>$LOG_FILE | sed -E "s/^$targ//" 2>>$LOG_FILE find "$NAS_ROOT" -type f -name "*.$EXT" 2>>$LOG_FILE | sed -E "s/^$targ//" 2>>$LOG_FILE
check_pipe_rc ${PIPESTATUS[@]} check_pipe_rc ${PIPESTATUS[@]}
return $? return $?
} }
# Inhalt des Archivs $2 auf stdout ausgeben # Inhalt des Archivs $1 auf stdout ausgeben
# #
# $1 - Verzeichnis unter dem alle Backups liegen # $1 - Archiv-Datei mit Pfad ab $NAS_ROOT
# $2 - Archiv-Datei mit Pfad ab $1
# #
# returns 0 for success, 1 otherwise # returns 0 for success, 1 otherwise
# #
list_archive_content() { list_archive_content() {
log $DEBUG "$DBG list_archive_content( $@ )" log $DEBUG "$DBG list_archive_content( $@ )"
local root=$1 local archive=$1
local archive=$2 log $DEBUG "$DBG > cat \"$NAS_ROOT/${archive/#\//}.$LIST_EXT\""
log $DEBUG "$DBG > cat \"$root/${archive/#\//}.$LIST_EXT\"" cat "$NAS_ROOT/${archive/#\//}.$LIST_EXT" 2>>$LOG_FILE
cat "$root/${archive/#\//}.$LIST_EXT" 2>>$LOG_FILE
} }
# ----- export ----- # ----- export -----
+33 -38
View File
@@ -3,37 +3,28 @@
# entrypoint for all actions # entrypoint for all actions
# #
VER="2.0.4" VER="2.1.2"
show_help() {
echo "usage: $0 options"
echo " -d, --daily start daily backup on local machine"
echo " -w, --weekly start weekly backup on local machine"
echo " --list list archives"
echo ' --content <archive> '
echo " show contents of archive"
echo ' -r, --restore <archive> <file(s)> '
echo " restore files from archive to pwd"
echo " -h, -?. --help show this help"
echo " "
echo " Script muss auf dem jeweiligen Server ausgeführt werden (ggf. via ssh)."
echo " "
}
#
# Script muss unter root bzw. sudo laufen, sonst gibt es jede Menge Probleme
# mit Zugriff auf die diversen Verzeichnisse.
#
if [ "$(id -u)" -ne 0 ]; then
echo "**"
echo "** ERROR: script has to be run as superuser!"
echo "**"
exit 100
fi
HERE=$(dirname "$0") HERE=$(dirname "$0")
THIS_SCRIPT=$0 THIS_SCRIPT=$0
show_help() {
echo "Server Backup $VER"
echo "usage: $0 options"
echo " -d, --daily start daily backup on local machine"
echo " -w, --weekly start weekly backup on local machine"
echo " -e, --export export backups to USB-HDD"
echo " -l, --list list archives"
echo ' -c, --content <archive> '
echo " show contents of archive (path from $NAS_ROOT)"
echo ' -r, --restore <archive> <file(s)> '
echo " restore files from archive to $RESTORE_PATH"
echo " -h, -?. --help show this help"
echo " "
echo " -d, -w, -e must be run as superuser."
echo " "
}
if [ -f $HERE/main.inc.sh ]; then if [ -f $HERE/main.inc.sh ]; then
. $HERE/main.inc.sh . $HERE/main.inc.sh
else else
@@ -56,9 +47,6 @@ else
exit 102 exit 102
fi fi
LOG_FILE_PATH="$(realpath $HERE/../../../log/backup)"
log_file_name="$LOG_FILE_PATH/$HOST_NAME-$(date '+%Y-%m-%d_%H%M')"
LOG_FILE="${log_file_name}.log"
file= file=
archive= archive=
@@ -71,29 +59,29 @@ while :; do
;; ;;
-d|--daily) -d|--daily)
MAIL_LOG_FILE="${log_file_name}.auto.log" MAIL_LOG_FILE="${log_file_name}.auto.log"
check_root
backup_daily backup_daily
break break
;; ;;
-w|--weekly) -w|--weekly)
MAIL_LOG_FILE="${log_file_name}.auto.log" MAIL_LOG_FILE="${log_file_name}.auto.log"
check_root
backup_weekly backup_weekly
break break
;; ;;
-e|--export) -e|--export)
MAIL_LOG_FILE="${log_file_name}.auto.log" MAIL_LOG_FILE="${log_file_name}.auto.log"
check_root
export_backups export_backups
break break
;; ;;
--list) -l|--list)
list_archives "$NAS_ROOT/daily/$HOST_NAME" list_archives
if [ -d "$NAS_ROOT/weekly/$HOST_NAME" ]; then
list_archives "$NAS_ROOT/weekly/$HOST_NAME"
fi
break; break;
;; ;;
--content) -c|--content)
if [ "$2" ]; then if [ "$2" ]; then
list_archive_content "$NAS_ROOT" "$2" list_archive_content "$2"
else else
echo 'ERROR: "--content" requires a non-empty option argument.' echo 'ERROR: "--content" requires a non-empty option argument.'
fi fi
@@ -102,13 +90,20 @@ while :; do
-r|--restore) -r|--restore)
if [ "$2" ]; then if [ "$2" ]; then
archive=$2 archive=$2
shift shift 2
restore "$archive" "$@" restore "$archive" "$@"
else else
echo 'ERROR: "--restore" requires a non-empty option argument.' echo 'ERROR: "--restore" requires a non-empty option argument.'
fi fi
break break
;; ;;
--rx)
MAIL_LOG_FILE="${log_file_name}.auto.log"
check_root
shift
do_restore $@
break
;;
--) # End of all options. --) # End of all options.
shift shift
break break
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
NAS_ROOT=/var/srv/nas/backups #NAS_ROOT=/var/srv/nas/backups
DOCKER_ROOT=/var/docker DOCKER_ROOT=/var/docker
BACKUP_TARGET=$DOCKER_ROOT/tmp BACKUP_TARGET=$DOCKER_ROOT/tmp
NAS_TARGET="$NAS_ROOT/daily/$HOST_NAME/backup.$DAY" NAS_TARGET="$NAS_ROOT/daily/$HOST_NAME/backup.$DAY"
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/eval bash #!/usr/bin/eval bash
NAS_ROOT=/volume1/nfs/backups #NAS_ROOT=/volume1/nfs/backups
HAS_WEEKLY=true HAS_WEEKLY=true
backup_daily1() { backup_daily1() {
+12
View File
@@ -1,5 +1,17 @@
#!/usr/bin/env bash #!/usr/bin/env bash
fn() {
echo "all: $@"
echo "#1: $1"
shift
echo "rest: $@"
}
fn eins zwei drei
exit
if [ "$(id -u)" -ne 0 ]; then if [ "$(id -u)" -ne 0 ]; then
echo "**" echo "**"
echo "** ERROR: script has to be run as superuser!" echo "** ERROR: script has to be run as superuser!"