auto-backup-Mimik steht

This commit is contained in:
Hartmut Bauer committed 2025-03-22 00:36:45 +01:00
1 parent 1fcdb5669a
commit 22d9442b42
17 files changed
+223 -738

No files matched your search

+1
View File
@@ -12,3 +12,4 @@
# Built Visual Studio Code Extensions # Built Visual Studio Code Extensions
*.vsix *.vsix
._server-backup.code-workspace
+18 -1
View File
@@ -9,5 +9,22 @@ Scripte für
Um möglichst wenige Abhängigkeiten zu erzeugen, werden primär Bordmittel verwendet (tar, gpg, find, rsync, etc.). Das sollte auch die Pflege vereinfachen. Um möglichst wenige Abhängigkeiten zu erzeugen, werden primär Bordmittel verwendet (tar, gpg, find, rsync, etc.). Das sollte auch die Pflege vereinfachen.
Gesichert wird vom Server das Verzeichnis ```/var```, wobei ```/var/docker``` und ```/var/docker/vol``` gesondert behandelt werden. Von der NAS werden die Daten-Shares, sowie die Bücher- und Musik-Verzeichnisse gesichert. Die Serien- und Video-Verzeichnisse werden hin und wieder auf externe Datenträger kopiert. Täglich gesichert wird von den Servern das Verzeichnis ```/var``` (für nathan werden ```/var/docker``` und ```/var/docker/vol``` gesondert behandelt). Von der NAS werden die Daten-Shares (z.Zt. ```data``` uns ```nfs```) täglich gesichert, sowie die Bücher- und Musik-Verzeichnisse wöchentlich. Die Serien- und Video-Verzeichnisse werden im Zug des Exports auf externe Datenträger kopiert.
Das gibt auf der NAS unter ```/volume1/nfs/backups``` die folgende Struktur (1 = MO):
```
daily/nathan/backup.1 20GB/ 0:40h
...
backup.7
hamiller/backup.1 35GB/ 0:35h
...
backup.7
synology/backup.1/data \
nfs / 60GB/ 1:40h
...
backup.7/data
backup.7/nfs
weekly/synology 320GB/ 9:30h
logs/<hostname>/
```
+22 -56
View File
@@ -1,46 +1,9 @@
### tar
``` ### TODOs
#!/bin/bash
date
cd /var/docker
for f in *; do
sudo tar -c -z -v --numeric-owner --one-file-system -f /var/docker/tmp/$(basename $f).tar.gz $f
done
date
```
### gpg
```
passphrase=$(head -n 1 /var/secret.key)
gpg --symmetric --batch --yes --passphrase $passphrase --output some.gpg toEncrypt.txt
# oder
gpg --batch -c --passphrase-file /var/secret.key -o some.gpg toencrypt.txt
# oder
gpg --batch --symmetric --passphrase 1234567890 test.txt # -> test.txt.gpg
gpg --batch --decrypt --passphrase 1234567890 -o test.txt test.txt.gpg # ohne -o to stdout
```
### ssh
auf nathan
je Server ssh -mount-point-/Server/bin/backup/cron.sh -mount-point-/Server/log/backup/-server-/backup.x.log
### TODO
nextcloud: nextcloud:
- vol/nextcloud/data/data/hb zeigt auf NAS-share - (x) vol/nextcloud/data/data/hb zeigt auf NAS-share
-> alles auf NAS, bzw. alles auf Server? -> alles auf Server
-> oder symlink in NFS-Share?
-> falls auf NAS, per NFS?
backup MAC backup MAC
- ccc 2x 2TB intern (weekly) - ccc 2x 2TB intern (weekly)
@@ -49,20 +12,28 @@ backup MAC
- TODO: Kalendereintrag für wöchentlichen backup - TODO: Kalendereintrag für wöchentlichen backup
nas-backup daily nas-backup daily
- tar, gpg to nas - (x) tar, gpg to nas
- server: /var dir to file (evtl. /var/docker + /var/docker/vol extra - tar-Syntax?) - (x) server: /var dir to file (evtl. /var/docker + /var/docker/vol extra - tar-Syntax?)
- nas: //data, //nfs, //nextcloud(?) dir to file - (x) nas: //data, //nfs, //nextcloud(?) dir to file
- auf nas unter //backup sammeln - (x) auf nas unter //backup sammeln
- TODO: tar syntax (find | py) - (x) TODO: tar syntax (find | py)
- TODO: gpg syntax - (x) TODO: gpg syntax
- TODO: file handling - (x) TODO: file handling
- TODO: script (python?) - (x) TODO: script (python?)
nas-backup weekly 1 nas-backup weekly 1
- media/books, media/music/_all + _hoerspiel -> tar, gpg nach //backup (x) media/books, media/music/_all + _hoerspiel -> tar, gpg nach //backup
- TODO: s. nas-backup daily (x) TODO: s. nas-backup daily
backup server+nas logging
- TODO: wo speichern?
- TODO: ggf. lokal und auf NAS kopieren
- TODO: full für alles (taugt nur für auto backup, also ggf. noch ein log)
- TODO: Übersichtliches für die Mail -> Error-Handling!
- TODO: wo und wie sammeln für Mail
- TODO: Mail aus py-script übernehmen
backup server+nas extern
- rsync nas-backup 2x HDD intern (weekly) (5TB?) - rsync nas-backup 2x HDD intern (weekly) (5TB?)
- TODO: script (python?) mit HD-Erkennung - TODO: script (python?) mit HD-Erkennung
- TODO: zusätzliche HDD - TODO: zusätzliche HDD
@@ -79,8 +50,3 @@ export serien
export video export video
- rsync dir 1x 5TB HDD extern - rsync dir 1x 5TB HDD extern
- TODO: s. export serien - TODO: s. export serien
**script**
tar: wo beginnen?, Schleife für dirs
+1 -1
View File
@@ -19,4 +19,4 @@ LOG="$1"
shift shift
HERE=$(dirname "$0") HERE=$(dirname "$0")
$HERE/main.sh -a "$@" >"$LOG" 2>&1 & $HERE/main.sh "$@" >"$LOG" 2>&1 &
+23 -40
View File
@@ -1,51 +1,34 @@
#!/usr/bin/eval bash #!/usr/bin/eval bash
# TODO: cmd line handling
# fn für div. Aktionen (gemeinsame?)
NAS_ROOT=/var/srv/nas/backups
BACKUP_ROOT=/var/docker/tmp BACKUP_ROOT=/var/docker/tmp
NAS_TARGET="$NAS_ROOT/daily/$HOST_NAME/backup.$DAY"
backup_data() { #
TARGET_DIR="$BACKUP_ROOT/backup.$DAY" # ACHTUNG: BACKUP_TARGET wird für jeden Lauf _daily1, 2, usw. geköscht,
# es muss sich also für alle _daily?, bzw. _weekly? unterscheiden
#
NAS_ROOT=/var/srv/nas/backups backup_daily1() {
BACKUP_SOURCE="/var"
LOG_FILE="$NAS_ROOT/log/$HOST_NAME-backup.log" BACKUP_TARGET="$BACKUP_ROOT"
BACKUP_EXCLUDE_DIRS=()
log INFO "*** *** Begin hamiller server backup"
delete_dir $TARGET_DIR
check_directory $TARGET_DIR
# TODO: docker down
backup_all_dirs "/var" "$TARGET_DIR" # docker
# backup_all_dirs "/var/docker" "$TARGET_DIR" vol tmp
# backup_all_dirs "/var/docker/vol" "$TARGET_DIR"
# TODO: docker up
# TODO: copy backup files to NAS
log INFO "*** End of hamiller server backup"
list_archives $BACKUP_ROOT
} }
# TODO: restore fn
copy_to_nas() {
# ins NAS-Verzeichnis verschieben
delete_dir "$NAS_TARGET"
check_dir "$NAS_TARGET"
sudo mv "$BACKUP_ROOT/*" "$NAS_TARGET"
}
while :; do before_backup() {
case $1 in run_docker down
--daily) }
backup_data
break
;;
--restore)
# TODO
break
;;
*) # Default case: No more options, so break out of the loop.
break
esac
shift after_backup() {
done run_docker up -d
copy_to_nas
}
+40 -1
View File
@@ -5,6 +5,14 @@ PASSPHRASE=1234567890
EXT=tgz.gpg EXT=tgz.gpg
LIST_EXT=txt LIST_EXT=txt
# docker compose ausführen
#
# $1 ff. - compose parameter, z.B. up -d
#
run_docker() {
/usr/bin/docker compose -f /var/docker/run/docker-compose.yml --ansi never $@
}
# check if function $1 exists # check if function $1 exists
# #
# returns true/false # returns true/false
@@ -105,10 +113,10 @@ backup_file_prefix() {
backup_all_dirs() { backup_all_dirs() {
local root=$1 local root=$1
local target=$2 local target=$2
shift 2
local prefix=$(backup_file_prefix $root) local prefix=$(backup_file_prefix $root)
local tar_file local tar_file
local dir local dir
shift 2
for dir in $(iterate_dirs_in "$root" "$@"); do for dir in $(iterate_dirs_in "$root" "$@"); do
tar_file="$target/$prefix-$dir.$EXT" tar_file="$target/$prefix-$dir.$EXT"
@@ -138,6 +146,37 @@ backup_dir() {
fi fi
} }
##
# auto backup handling
#
# hostname-scripte setzen vars und definieren Funktionen backup_daily1, 2, usw. und backup_weekly1, 2, usw.
# in den Funktionen werden die vars für den einzelnen backup gesetzt (target, excludes, usw.)
# hier wird dann dass hostname-script gesourced (s.o.) und in einer Schleife werden die
# entsprechenden backup_*-Funktionen aufgerufen
#
do_auto_backup() {
local func=$1
local count=1
before_backup
while [ $(isFunction $func$count) ]; do
func$count
# vars defined in $func$count in $HOST_NAME.sh
delete_dir "$BACKUP_TARGET" # bei Fehler werden die Dateien hoffentlich überschrieben
check_directory "$BACKUP_TARGET"
backup_all_dirs "$BACKUP_SOURCE" "$BACKUP_TARGET" "${BACKUP_EXCLUDE_DIRS[@]}"
let "count += 1"
done
after_backup
}
# TODO LOG_FILE="$NAS_ROOT/log/$HOST_NAME-backup-media.log"
backup_daily() {
do_auto_backup backup_daily
}
backup_weekly() {
do_auto_backuo backup_weekly
}
# Inhalt des Archivs in eine Textdatei ausgeben. # Inhalt des Archivs in eine Textdatei ausgeben.
# #
# $1 - Archiv # $1 - Archiv
+42 -18
View File
@@ -3,27 +3,45 @@
# entrypoint for all actions # entrypoint for all actions
# #
HERE=$(dirname "$0")
. $HERE/main.inc.sh
show_help() { show_help() {
echo "usage: $0 options" echo "usage: $0 options"
echo " -a, --auto start nightly backup on local machine" echo " -d, --daily start daily backup on local machine"
echo " -w, --weekly start weekly backup on local machine"
echo " --list list archives" echo " --list list archives"
echo ' --content <archive> ' echo ' --content <archive> '
echo " show contents of archive" echo " show contents of archive"
echo ' -r, --restore <archive> <file(s)> ' echo ' -r, --restore <archive> <file(s)> '
echo " restore files from archive to pwd" echo " restore files from archive to pwd"
echo " -h, -?. --help show this help" echo " -h, -?. --help show this help"
echo " "
echo " Script muss auf dem jeweiligen Server ausgeführt werden (ggf. via ssh)."
echo " "
} }
echo " ### main.sh" HERE=$(dirname "$0")
if [ -f $HERE/main.inc.sh ]; then
. $HERE/main.inc.sh
else
echo "**"
echo "** ERROR: Datei \"$HERE/main.inc.sh\" nicht gefunden. "
echo "** Script wird abgebrochen"
echo "**"
show_help
exit 1
fi
if [ -f $HERE/$HOST_NAME.sh ]; then
. $HERE/$HOST_NAME.sh
else
echo "**"
echo "** ERROR: Datei \"$HOST_NAME.sh\" nicht gefunden (falscher Rechner?). "
echo "** Script wird abgebrochen."
echo "**"
show_help
exit 2
fi
# Initialize all the option variables.
# This ensures we are not contaminated by variables from the environment.
file= file=
archive= archive=
@@ -33,18 +51,24 @@ while :; do
show_help # Display a usage synopsis. show_help # Display a usage synopsis.
exit 0 exit 0
;; ;;
-a|--auto) -d|--daily)
shift backup_daily
. $HERE/$HOST_NAME.sh "$@" # >$LOGF 2>&1 break
break # exit kehrt nicht zu run.sh zurück ;;
-w|--weekly)
backup_weekly
break
;; ;;
--list) --list)
. $HERE/$HOST_NAME.sh -l list_archives "$NAS_ROOT/daily/$HOST_NAME"
if [ -d "$NAS_ROOT/weekly/$HOST_NAME" ]; then
list_archives "$NAS_ROOT/weekly/$HOST_NAME"
fi
break; break;
;; ;;
--content) --content)
if [ "$2" ]; then if [ "$2" ]; then
. $HERE/$HOST_NAME.sh -c $2 list_archive_content "$NAS_ROOT" "$2"
else else
echo 'ERROR: "--content" requires a non-empty option argument.' echo 'ERROR: "--content" requires a non-empty option argument.'
fi fi
@@ -52,10 +76,9 @@ while :; do
;; ;;
-r|--restore) -r|--restore)
if [ "$2" ]; then if [ "$2" ]; then
echo "not yet implemented"
archive=$2 archive=$2
shift shift
#. $HERE/$HOST_NAME.sh -r $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
@@ -94,3 +117,4 @@ while :; do
shift shift
done done
exit 0
+40 -42
View File
@@ -1,51 +1,49 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# TODO: cmd line handling NAS_ROOT=/var/srv/nas/backups
# fn für div. Aktionen (gemeinsame?)
BACKUP_ROOT=/var/docker/tmp BACKUP_ROOT=/var/docker/tmp
NAS_TARGET="$NAS_ROOT/daily/$HOST_NAME/backup.$DAY"
backup_data() { #
TARGET_DIR="$BACKUP_ROOT/backup.$DAY" # ACHTUNG: BACKUP_TARGET wird für jeden Lauf _daily1, 2, usw. geköscht,
# es muss sich also für alle _daily?, bzw. _weekly? unterscheiden
#
NAS_ROOT=/var/srv/nas/backups backup_daily1() {
BACKUP_SOURCE="/var"
LOG_FILE="$NAS_ROOT/log/$HOST_NAME-backup.log" BACKUP_TARGET="$BACKUP_ROOT/var"
BACKUP_EXCLUDE_DIRS=(docker)
log INFO "*** *** Begin nathan server backup"
delete_dir "$TARGET_DIR"
check_directory "$TARGET_DIR"
# TODO: docker down
backup_all_dirs "/var" "$TARGET_DIR" docker
backup_all_dirs "/var/docker" "$TARGET_DIR" vol tmp
backup_all_dirs "/var/docker/vol" "$TARGET_DIR"
# TODO: docker up
# TODO: copy backup files to NAS
log INFO "*** End of nathan server backup"
list_archives $BACKUP_ROOT
} }
# TODO: restore fn
backup_daily2() {
BACKUP_SOURCE="/var/docker"
BACKUP_TARGET="$BACKUP_ROOT/docker"
BACKUP_EXCLUDE_DIRS=(vol tmp)
}
while :; do backup_daily3() {
case $1 in BACKUP_SOURCE="/var/docker/vol"
--daily) BACKUP_TARGET="$BACKUP_ROOT/vol"
backup_data BACKUP_EXCLUDE_DIRS=()
break }
;;
--restore)
# TODO
break
;;
*) # Default case: No more options, so break out of the loop.
break
esac
shift copy_to_nas() {
done local dir
# einzelne backups iin einem Verzeichnis sammeln
for dir in $(iterate_dirs_in "$BACKUP_ROOT" "$@"); do
sudo mv "$BACKUP_ROOT/$dir/*" .. && rmdir "$BACKUP_ROOT/$dir"
done
# ins NAS-Verzeichnis verschieben
delete_dir "$NAS_TARGET"
check_dir "$NAS_TARGET"
sudo mv "$BACKUP_ROOT/*" "$NAS_TARGET"
}
before_backup() {
run_docker down
}
after_backup() {
run_docker up -d
copy_to_nas
}
+8
View File
@@ -0,0 +1,8 @@
{
"folders": [
{
"path": "."
}
],
"settings": {}
}
-63
View File
@@ -1,63 +0,0 @@
#!/bin/bash
# ex33.sh: Exercising getopts and OPTIND
# Script modified 10/09/03 at the suggestion of Bill Gradwohl.
# Here we observe how 'getopts' processes command-line arguments to script.
# The arguments are parsed as "options" (flags) and associated arguments.
# Try invoking this script with:
# 'scriptname -mn'
# 'scriptname -oq qOption' (qOption can be some arbitrary string.)
# 'scriptname -qXXX -r'
#
# 'scriptname -qr'
#+ - Unexpected result, takes "r" as the argument to option "q"
# 'scriptname -q -r'
#+ - Unexpected result, same as above
# 'scriptname -mnop -mnop' - Unexpected result
# (OPTIND is unreliable at stating where an option came from.)
#
# If an option expects an argument ("flag:"), then it will grab
#+ whatever is next on the command-line.
NO_ARGS=0
E_OPTERROR=85
if [ $# -eq "$NO_ARGS" ] # Script invoked with no command-line args?
then
echo "Usage: `basename $0` options (-mnopqrs)"
exit $E_OPTERROR # Exit and explain usage.
# Usage: scriptname -options
# Note: dash (-) necessary
fi
while getopts ":mnopq:rs" Option
do
case $Option in
m ) echo "$OPTIND -$Option ($OPTARG)";;
n | o ) echo "$OPTIND -$Option ($OPTARG)";;
p ) echo "$OPTIND -$Option ($OPTARG)";;
q ) echo "$OPTIND -$Option ($OPTARG)";;
# Note that option 'q' must have an associated argument,
#+ otherwise it falls through to the default.
r | s ) echo "$OPTIND -$Option ($OPTARG)";;
* ) echo "Unimplemented option chosen.";; # Default.
esac
done
shift $(($OPTIND - 1))
echo "Rest $@"
# Decrements the argument pointer so it points to next argument.
# $1 now references the first non-option item supplied on the command-line
#+ if one exists.
exit $?
# As Bill Gradwohl states,
# "The getopts mechanism allows one to specify: scriptname -mnop -mnop
#+ but there is no reliable way to differentiate what came
#+ from where by using OPTIND."
# There are, however, workarounds.
+23 -86
View File
@@ -1,96 +1,33 @@
#!/usr/bin/eval bash #!/usr/bin/eval bash
# TODO: cmd line handling
# fn für div. Aktionen (gemeinsame?)
NAS_ROOT=/volume1/nfs/backups NAS_ROOT=/volume1/nfs/backups
backup_media() { #
TARGET_DIR="$NAS_ROOT/weekly/$HOST_NAME" # ACHTUNG: BACKUP_TARGET wird für jeden Lauf _daily1, 2, usw. geköscht,
# es muss sich also für alle _daily?, bzw. _weekly? unterscheiden
LOG_FILE="$NAS_ROOT/log/$HOST_NAME-backup-media.log" #
log INFO "*** *** Begin NAS backup (media/books, media/music)"
EXCLUDE_DIRS=("@eaDir" "Temporary Items" "lost+found" serien tmp video "video.archive")
check_directory $TARGET_DIR
# media/books media/music
backup_all_dirs "/volume1/media" "$TARGET_DIR" "${EXCLUDE_DIRS[@]}"
log INFO "*** End of NAS backup"
list_archives $TARGET_DIR
backup_daily1() {
BACKUP_SOURCE="/volume1/data"
BACKUP_TARGET="$NAS_ROOT/daily/$HOST_NAME/backup.$DAY/data"
BACKUP_EXCLUDE_DIRS=("@eaDir" "Temporary Items" "lost+found")
}
backup_daily2() {
BACKUP_SOURCE="/volume1/nfs"
BACKUP_TARGET="$NAS_ROOT/daily/$HOST_NAME/backup.$DAY/nfs"
BACKUP_EXCLUDE_DIRS=("@eaDir" "Temporary Items" "lost+found" backups)
} }
backup_data() { backup_weekly1() {
BACKUP_SOURCE="/volume1/media"
TARGET_DIR="$NAS_ROOT/daily/$HOST_NAME/backup.$DAY" BACKUP_TARGET="$NAS_ROOT/weekly/$HOST_NAME"
BACKUP_EXCLUDE_DIRS=("@eaDir" "Temporary Items" "lost+found" serien tmp video "video.archive")
LOG_FILE="$NAS_ROOT/log/$HOST_NAME-backup.log"
log INFO "*** *** Begin NAS backup (data, nfs)"
EXCLUDE_DIRS=("@eaDir" "Temporary Items" "lost+found")
delete_dir $TARGET_DIR # bei Fehler werden die Dateien hoffentlich überschrieben
check_directory $TARGET_DIR
# data
backup_all_dirs "/volume1/data" "$TARGET_DIR" "${EXCLUDE_DIRS[@]}"
EXCLUDE_DIRS=("@eaDir" "Temporary Items" "lost+found" backups)
# nfs
backup_all_dirs "/volume1/nfs" "$TARGET_DIR" "${EXCLUDE_DIRS[@]}"
log INFO "*** End of NAS backup"
list_archives $TARGET_DIR
} }
# TODO: restore fn before_backup() {
# nothing to do
}
after_backup() {
## # nothing to do
# auto backup handling }
#
# hostname-scripte setzen vars und definieren Funktionen backup_daily1, 2, usw. und backup_weekly1, 2, usw.
# in den Funktionen werden die vars für den einzelnen backuü gesetzt (target, excludes, usw.)
# im main-script wird dann dass hostname-script gesourced und in einer Schleife werden die
# entsprechenden backup_*-Funktionen aufgerufen
#
# count=1
# while [ $(isFunction backup_daily$count) ]; do
# backup_daily$count # setzt die nötigen vars für den backup
# do_backup "daily"
# let "count += 1"
# done
#
while :; do
case $1 in
--daily)
backup_data
break
;;
--weekly)
backup_media
break
;;
-l|--list)
list_archives "$NAS_ROOT"
break;
;;
-c|--content)
if [ "$2" ]; then
list_archive_content "$NAS_ROOT" "$2"
else
echo 'ERROR: "--content" requires a non-empty option argument.'
fi
break
;;
--restore)
# TODO
break
;;
*) # Default case: No more options, so break out of the loop.
break
esac
shift
done
+5 -303
View File
@@ -1,274 +1,11 @@
#!/usr/bin/env bash #!/usr/bin/env bash
HOST_NAME=$(hostname)
DAY=$(date +%u)
HERE=$(dirname "$0") HERE=$(dirname "$0")
PASSPHRASE=1234567890 . $HERE/main.inc.sh
EXT=tgz.gpg
# nicht auf calvados
# Log-Datei schreiben. #. $HERE/$HOST_NAME
#
# Die Ausgabe geht auch auf STDOUT, dadurch kann die vollständige Ausgabe,
# einschließlich Status- und Fehlermeldungen der Programme in ein erweitertes
# Log für die Fehlersuche umgeleitet werden.
#
# $1 - Typ, z.B. INFO, WARN, ERROR, etc.
# $2 ff. - die Meldung, die ins Log geschreiben wird
#
log() {
local type=$1
if [ "$type" == "ERROR" ]; then ERROR=0; fi
shift 1
echo "$(date '+%d.%m.%Y %H:%M:%S') - $type $@" | sudo tee -a $LOG_FILE
}
# Ist $1 in der Liste der restlichen args $2, $3 ...
#
# zB. if is_in "foo" "foo" "bar" "foo bar" ; then ...
# Leere Liste liefert immer false
#
is_in() {
local search="$1"
shift 1
local e
for e in "$@"; do [[ "$e" == "$search" ]] && return 0; done
return 1
}
# Alle Verzechnisnamen in einem Verzeichnis holen.
#
# $1 - Verzeichnis in dem gesucht wird als absoluter Pfad
# $2 ff. - auszuschliessende Verzeichnisse (kann leer bleiben)
#
iterate_dirs_in() {
local dirname
local root=$1
shift 1
for dir in $(sudo find "$root" -maxdepth 1 -type d \! -wholename "$root"); do
dirname=$(basename $dir)
if ! is_in "$dirname" "$@"; then
echo "$dirname"
fi
done
}
# create directory if it not exists
#
# $1 - dir to check
#
check_directory() {
local dir=$1
if [ -d "$1" ]; then
return 0
else
mkdir -p "$1" && return 0
sudo mkdir -p "$1" && return 0
log ERROR "### could not create directory $1!"
# no chance to recover
exit 1
fi
}
# Verzeichnis löschen
#
# Im Fehlerfall wird rc=1 zurückgegeben
#
# $1 - zu löschendes Verzeichnis
#
delete_dir() {
local dir=$1
sudo rm -rf "$dir" && return 0
log ERROR "### could not delete directory $1!"
# return error, so caller can decide what to do
return 1
}
# Slashes "/" im Pfadnamen durch Dashes "-" ersetzen, so dass der String als Dateiname verwendet werden kann.
#
# $1 - path
backup_file_prefix() {
echo "$1" | sed -E 's/^\///' | sed -E 's/\//-/g'
}
# Verzeichnise in .tgz.gpg-Dateien sichern.
#
# $1 - Verzeichnis, das gesichert wird: alle Verzeichnisse darunter werden einzeln als .tgz.gpg-Datei gesichert
# $2 - Zielverzeichnis für .tgz.gpg-Dateien
# $3 ff. - Verzeichnisse, die nicht gesichert werden sollen (kann leer bleiben)
#
backup_all_dirs() {
local root=$1
local target=$2
local prefix=$(backup_file_prefix $root)
local tar_file
local dir
shift 2
for dir in $(iterate_dirs_in "$root" "$@"); do
tar_file="$target/$prefix-$dir.$EXT"
backup_dir "$root" "$tar_file" "$dir"
create_list "$tar_file" "$dir"
test_integrity "$tar_file"
done
}
# Einzelnes Verzeichnis sichern.
#
# $1 - Pfad um Verzeichnis, das gesichert werden soll
# $2 - Zielpfad und -name für das Archiv
# $2 - zu sicherndes Verzeichnis
#
backup_dir() {
local root=$1
local archive=$2
local dir=$3
log INFO "--- Backup $root/$dir -> $archive"
sudo tar -c -z --numeric-owner --one-file-system --exclude "@eaDir" -C "$root" "$dir" | sudo gpg --batch -c --passphrase $PASSPHRASE -o "$archive"
local rc=$?
if [ "$rc" == "0" ] ; then
log INFO "*** success"
else
log ERROR "### see full log"
fi
}
# Inhalt des Archivs in eine Textdatei ausgeben.
#
# $1 - Archiv
#
create_list() {
local archive=$1
log INFO "--- List $archive"
sudo gpg --batch --decrypt --passphrase $PASSPHRASE "$archive" | sudo tar -tzv | sudo tee $archive.txt >/dev/null
local rc=$?
if [ "$rc" == "0" ] ; then
log INFO "*** success"
else
log ERROR "### see full log"
fi
}
# Integrität des Archivs testen, indem es entschlüsselt, entpackt
# und der Inhalt auf /dev/null ausgegeben wird.
#
# $1 - Archiv
#
test_integrity() {
local archive=$1
log INFO "--- Check integrity of $archive"
sudo gpg --batch --decrypt --passphrase $PASSPHRASE "$archive" | sudo tar -xzO >/dev/null
local rc=$?
if [ "$rc" == "0" ] ; then
log INFO "*** success"
else
log ERROR "### see full log"
fi
}
# Restore aus Archiv
#
# Wird nach pwd ausgegeben!
#
# $1 - Archiv, ggf. mit Pfad
# $2 ff. - zurückzusichernde Dateien/Verzeichnisse
#
restore() {
local archive=$1
shift 1
sudo gpg --batch --decrypt --passphrase $PASSPHRASE "$archive" | sudo tar -xzv $@ >/dev/null
local rc=$?
if [ "$rc" == "0" ] ; then
log INFO "*** success"
else
log ERROR "### see full log"
fi
}
# Liste der Archives auf stdout ausgeben
#
# Zeigt alle Archive incl. des letzten Verzeichnisses an
#
# z.B.
# backup.7/volume1-data-Web.tgz.gpg
# media/volume1-media-books.tgz.gpg
#
# $1 - root path i.d.R. ein Verzeichnis oberhalb, damit alle täglichen Backups angezeigt werden
#
list_archives() {
local target=$1
local targ=${target//\//\\\/} # slashes escapen
echo "#$targ#"
sudo find "$target" -type f -name "*.gpg" | sed -E "s/^$targ//"
}
# *** NAS Test ***
nas_test() {
LOG_FILE="/volume1/nfs/Server/tmp/backup.log"
log INFO "*** *** Begin NAS backup (data, nfs, media/books, media/music)"
TARGET_DIR="/volume1/nfs/backups/tmp/backup.$DAY"
EXCLUDE_DIRS=("@eaDir" "Temporary Items" "lost+found")
delete_dir $TARGET_DIR # bei Fehler werden die Dateien hoffentlich überschrieben
check_directory $TARGET_DIR
# data
backup_all_dirs "/volume1/data" "$TARGET_DIR" "${EXCLUDE_DIRS[@]}"
EXCLUDE_DIRS=("@eaDir" "Temporary Items" "lost+found" backups)
# nfs
backup_all_dirs "/volume1/nfs" "$TARGET_DIR" "${EXCLUDE_DIRS[@]}"
BACKUP_ROOT=/volume1/nfs/backups/tmp
TARGET_DIR="$BACKUP_ROOT/media"
EXCLUDE_DIRS=("@eaDir" "Temporary Items" "lost+found" serien tmp video "video.archive")
check_directory $TARGET_DIR
# media/books media/music
backup_all_dirs "/volume1/media" "$TARGET_DIR" "${EXCLUDE_DIRS[@]}"
log INFO "*** End of NAS backup"
list_archives $BACKUP_ROOT
}
# *** NATHAN Test ***
nathan_test() {
LOG_FILE=/var/docker/tmp/backup.log
log INFO "*** *** Begin nathan server backup"
BACKUP_ROOT=/var/docker/tmp
TARGET_DIR="$BACKUP_ROOT/backup.$DAY"
delete_dir $TARGET_DIR
check_directory $TARGET_DIR
backup_all_dirs "/var" "$TARGET_DIR" docker
backup_all_dirs "/var/docker" "$TARGET_DIR" vol tmp
backup_all_dirs "/var/docker/vol" "$TARGET_DIR"
log INFO "*** End of nathan server backup"
list_archives $BACKUP_ROOT
}
# *** HANILLER Test ***
hamiller_test() {
LOG_FILE=/var/docker/tmp/backup.log
log INFO "*** *** Begin hamiller server backup"
BACKUP_ROOT=/var/docker/tmp
TARGET_DIR="$BACKUP_ROOT/backup.$DAY"
delete_dir $TARGET_DIR
check_directory $TARGET_DIR
backup_all_dirs "/var" "$TARGET_DIR" # docker
# backup_all_dirs "/var/docker" "$TARGET_DIR" vol tmp
# backup_all_dirs "/var/docker/vol" "$TARGET_DIR"
log INFO "*** End of hamiller server backup"
list_archives $BACKUP_ROOT
}
test() { test() {
for i in "$@"; do echo "$i"; done for i in "$@"; do echo "$i"; done
@@ -296,42 +33,7 @@ list2() {
#for i in "${a[@]}"; do echo "$i"; done #for i in "${a[@]}"; do echo "$i"; done
} }
EXC=()
count=1 iterate_dirs_in "." ${EXC[@]}
isFunction list4
while [ $(isFunction list$count) ]; do
list$count
for i in "${EXCL[@]}"; do echo "$i"; done
echo "$count: one = ${ONE} / two = ${TWO}"
let "count += 1"
done
exit exit
TARGET_DIR=/var/docker/tmp/two
echo "#"
echo "### gpg ###################################################"
echo "#"
date +%H:%M:%S.%N
echo "--- tar -c ------------------------------------------------"
cd $RUN_DIR
sudo tar -c -z --numeric-owner --one-file-system "$BACKUP_DIR/$SOURCE" | sudo gpg --batch -c --passphrase $PASSPHRASE -o "$TARGET_DIR/$SOURCE.tgz.gpg"
date +%H:%M:%S.%N
echo "--- tar -t ------------------------------------------------"
cd $TARGET_DIR
sudo gpg --batch --decrypt --passphrase $PASSPHRASE "$TARGET_DIR/$SOURCE.tgz.gpg" 2>/dev/null | sudo tar -tz | sudo tee tar_list.txt >/dev/null
date +%H:%M:%S.%N
echo "--- tar -x ------------------------------------------------"
sudo gpg --batch --decrypt --passphrase $PASSPHRASE "$TARGET_DIR/$SOURCE.tgz.gpg" 2>/dev/null | sudo tar -xzv $RESTORE >/dev/null
date +%H:%M:%S.%N
-8
View File
@@ -1,8 +0,0 @@
INC=include
HOST_NAME=$(hostname)
testfunc() {
echo "testfunc() works!"
}
-88
View File
@@ -1,88 +0,0 @@
#!/usr/bin/env bash
show_help() {
echo "usage: $0 options"
echo " -a, --auto start nightly backup"
echo " -l, --list list archives"
echo ' -c, --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 " ### main.sh"
# Initialize all the option variables.
# This ensures we are not contaminated by variables from the environment.
file=
archive=
while :; do
case $1 in
-h|-\?|--help)
show_help # Display a usage synopsis.
exit 0
;;
-a|--auto)
shift
. $HERE/$HOST_NAME.sh "$@" >$LOGF 2>&1
break # exit kehrt nicht zu run.sh zurück
;;
-l|--list)
. $HERE/$HOST_NAME.sh -l
break;
;;
-c|--content)
if [ "$2" ]; then
echo "not yet implemented"
#. $HERE/$HOST_NAME.sh -c $2
else
echo 'ERROR: "--content" requires a non-empty option argument.'
fi
break
;;
-r|--restore)
if [ "$2" ]; then
echo "not yet implemented"
archive=$2
shift
#. $HERE/$HOST_NAME.sh -r $archive $@
else
echo 'ERROR: "--restore" requires a non-empty option argument.'
fi
break
;;
# --- example -> https://mywiki.wooledge.org/BashFAQ/035
-f|--file) # Takes an option argument; ensure it has been specified.
if [ "$2" ]; then
file=$2
shift
else
die 'ERROR: "--file" requires a non-empty option argument.'
fi
;;
--file=?*)
file=${1#*=} # Delete everything up to "=" and assign the remainder.
;;
--file=) # Handle the case of an empty --file=
die 'ERROR: "--file" requires a non-empty option argument.'
;;
--) # End of all options.
shift
break
;;
-?*)
echo "WARN: Unknown option (ignored): $1"
echo
show_help
exit
;;
*) # Default case: No more options, so break out of the loop.
break
esac
shift
done
-10
View File
@@ -1,10 +0,0 @@
#!/usr/bin/env bash
echo " *** nathan.sh"
for i in "$@"; do echo "param: $i"; done
echo " include=$INC"
echo " host=$HOST_NAME"
testfunc
echo " *** nathan.sh end"
-11
View File
@@ -1,11 +0,0 @@
#!/usr/bin/env bash
HERE=$(dirname "$0")
. $HERE/main.inc
LOGF=$HERE/t1.log
echo "--- run.sh"
. $HERE/main.sh "$@"
echo "--- run.sh end"
-10
View File
@@ -1,10 +0,0 @@
testfunc() works!
### main.sh
usage: ./run.sh options
-a, --auto start nightly backup
-l, --list list archives
-c, --content <archive>
show contents of archive
-r, --restore <archive> <file(s)>
restore files from archive to pwd
-h, -?. --help show this help