feat: using a more unified structure for the different Backup options
This commit is contained in:
parent
0a6c6bb70d
commit
f4aca9b1a0
1 changed files with 133 additions and 171 deletions
|
|
@ -20,6 +20,9 @@ PV_BIN="@PV_BIN@"
|
||||||
DU_BIN="@DU_BIN@"
|
DU_BIN="@DU_BIN@"
|
||||||
BZIP2_BIN="@BZIP2_BIN@"
|
BZIP2_BIN="@BZIP2_BIN@"
|
||||||
XZ_BIN="@XZ_BIN@"
|
XZ_BIN="@XZ_BIN@"
|
||||||
|
WC_BIN="@WC_BIN@"
|
||||||
|
FIND_BIN="@FIND_BIN@"
|
||||||
|
|
||||||
|
|
||||||
# Convenience wrappers
|
# Convenience wrappers
|
||||||
rsync_cmd="$RSYNC_BIN"
|
rsync_cmd="$RSYNC_BIN"
|
||||||
|
|
@ -35,11 +38,29 @@ pv_cmd="$PV_BIN"
|
||||||
du_cmd="$DU_BIN"
|
du_cmd="$DU_BIN"
|
||||||
bzip2_cmd="$BZIP2_BIN"
|
bzip2_cmd="$BZIP2_BIN"
|
||||||
xz_cmd="$XZ_BIN"
|
xz_cmd="$XZ_BIN"
|
||||||
|
wc_cmd="$WC_BIN"
|
||||||
|
find_cmd="$FIND_BIN"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# PATH extension
|
# PATH extension
|
||||||
# (only figured that out later if you add it here it can actually just use the bin)
|
# (only figured that out later if you add it here it can actually just use the bin)
|
||||||
# So you can easily just switch out the "*_cmd" with the "normal" name
|
# So you can easily just switch out the "*_cmd" with the "normal" name
|
||||||
export PATH="$(dirname "$GZIP_BIN")":"$(dirname "$ZSTD_BIN")":"$(dirname "$PV_BIN")":"$(dirname "$DU_BIN")":"$(dirname "$BZIP2_BIN")":"$(dirname "$XZ_BIN")":"$PATH"
|
# Extend PATH with all injected binaries so we can call them directly
|
||||||
|
for bin in \
|
||||||
|
"$GZIP_BIN" \
|
||||||
|
"$ZSTD_BIN" \
|
||||||
|
"$PV_BIN" \
|
||||||
|
"$DU_BIN" \
|
||||||
|
"$BZIP2_BIN" \
|
||||||
|
"$XZ_BIN" \
|
||||||
|
"$WC_BIN" \
|
||||||
|
"$FIND_BIN"
|
||||||
|
do
|
||||||
|
export PATH="$(dirname "$bin"):$PATH"
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Defaults
|
# Defaults
|
||||||
REBOOT=false
|
REBOOT=false
|
||||||
|
|
@ -49,15 +70,17 @@ DESTINATION="/srv/minecraft/backups/unknown"
|
||||||
PURE=false
|
PURE=false
|
||||||
FORMAT="tar"
|
FORMAT="tar"
|
||||||
COMPRESSION="gzip"
|
COMPRESSION="gzip"
|
||||||
|
PROGRESS_INTERVAL=5 # default to 5 seconds
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
usage() {
|
usage() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Usage: $0 [--reboot] [--sleep <seconds>] [--full] [--destination <path>] [--pure]
|
Usage: $0 [--reboot] [--sleep <seconds>] [--full] [--destination <path>] [--pure]
|
||||||
[--format <tar|zip>] [--compression <gzip|bzip2|xz|zstd>]
|
[--format <tar|zip>] [--compression <gzip|bzip2|xz|zstd>] [--progressInterval <seconds>]
|
||||||
|
|
||||||
--reboot Stop server before backup and start afterwards [DOES NOT WORK]
|
--reboot Stop server before backup and start afterwards [DOES NOT WORK]
|
||||||
--sleep N Wait N seconds with countdown announcements
|
--sleep N Wait N seconds with countdown announcements
|
||||||
|
--progressInterval N Wait N seconds with interval announcements (default: 5)
|
||||||
--full Backup entire server directory (default: world only)
|
--full Backup entire server directory (default: world only)
|
||||||
--destination X Backup target directory (default: /srv/minecraft/backups/unknown)
|
--destination X Backup target directory (default: /srv/minecraft/backups/unknown)
|
||||||
--pure Use rsync to copy files (no compression, symlinks resolved)
|
--pure Use rsync to copy files (no compression, symlinks resolved)
|
||||||
|
|
@ -78,6 +101,7 @@ while [[ $# -gt 0 ]]; do
|
||||||
--pure) echo "[DEBUG] Flag: --pure"; PURE=true; shift ;;
|
--pure) echo "[DEBUG] Flag: --pure"; PURE=true; shift ;;
|
||||||
--format) echo "[DEBUG] Flag: --format $2"; FORMAT="$2"; shift 2 ;;
|
--format) echo "[DEBUG] Flag: --format $2"; FORMAT="$2"; shift 2 ;;
|
||||||
--compression) echo "[DEBUG] Flag: --compression $2"; COMPRESSION="$2"; shift 2 ;;
|
--compression) echo "[DEBUG] Flag: --compression $2"; COMPRESSION="$2"; shift 2 ;;
|
||||||
|
--progressInterval) echo "[DEBUG] Flag: --progressInterval $2"; PROGRESS_INTERVAL="$2"; shift 2 ;;
|
||||||
--help) usage ;;
|
--help) usage ;;
|
||||||
*) echo "[ERROR] Unknown option: $1"; usage ;;
|
*) echo "[ERROR] Unknown option: $1"; usage ;;
|
||||||
esac
|
esac
|
||||||
|
|
@ -170,215 +194,155 @@ countdown() {
|
||||||
|
|
||||||
|
|
||||||
do_backup() {
|
do_backup() {
|
||||||
#echo "[DEBUG] Entering do_backup with args: $*"
|
local backup_source=""
|
||||||
local source=""
|
local backup_destination=""
|
||||||
local destination=""
|
local backup_compression="gzip"
|
||||||
local compression="gzip"
|
local backup_format="tar"
|
||||||
local format="tar"
|
local backup_pure=false
|
||||||
local pure=false
|
local progress_interval=$PROGRESS_INTERVAL
|
||||||
|
|
||||||
# parse args
|
# Parse args
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--source) source="$2"; shift 2 ;;
|
--source) backup_source="$2"; shift 2 ;;
|
||||||
--destination) destination="$2"; shift 2 ;;
|
--destination) backup_destination="$2"; shift 2 ;;
|
||||||
--compression) compression="$2"; shift 2 ;;
|
--compression) backup_compression="$2"; shift 2 ;;
|
||||||
--format) format="$2"; shift 2 ;;
|
--format) backup_format="$2"; shift 2 ;;
|
||||||
--pure) pure=true; shift ;;
|
--pure) backup_pure=true; shift ;;
|
||||||
|
|
||||||
*) echo "[ERROR] Unknown option to do_backup: $1"; return 1 ;;
|
*) echo "[ERROR] Unknown option to do_backup: $1"; return 1 ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [[ -z "$backup_source" || -z "$backup_destination" ]]; then
|
||||||
if [[ -z "$source" || -z "$destination" ]]; then
|
|
||||||
echo "[ERROR] Missing --source or --destination"
|
echo "[ERROR] Missing --source or --destination"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local timestamp="$(date +%Y%m%d-%H%M%S)"
|
local timestamp="$(date +%Y%m%d-%H%M%S)"
|
||||||
local full_source="$DATA_DIR/$source"
|
local full_source_path="$DATA_DIR/$backup_source"
|
||||||
local basename="$(basename "$source")"
|
local source_basename="$(basename "$backup_source")"
|
||||||
local archive=""
|
local archive_path=""
|
||||||
local ext=""
|
local archive_ext=""
|
||||||
|
|
||||||
|
if [[ ! -d "$full_source_path" ]]; then
|
||||||
if [[ ! -d "$full_source" ]]; then
|
echo "[ERROR] Source directory not found: $full_source_path"
|
||||||
echo "[ERROR] Source directory not found: $full_source"
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$destination"
|
mkdir -p "$backup_destination"
|
||||||
|
|
||||||
if [[ "$pure" == true ]]; then
|
# PURE (rsync) backup
|
||||||
local target_dir="$destination/${basename}-${timestamp}"
|
if [[ "$backup_pure" == true ]]; then
|
||||||
echo "[INFO] Performing pure rsync backup to $target_dir"
|
local target_path="$backup_destination/${source_basename}-${timestamp}"
|
||||||
echo "#####"
|
echo "[INFO] Performing pure rsync backup to $target_path"
|
||||||
|
|
||||||
local last_percentage=-1
|
local progress_last_percent=-1
|
||||||
|
local progress_last_time=$(date +%s)
|
||||||
|
|
||||||
"$rsync_cmd" -rptgoDL --delete --info=progress2 --stats \
|
"$rsync_cmd" -rptgoDL --delete --info=progress2 --stats \
|
||||||
"$full_source/" "$target_dir/" 2>&1 | \
|
"$full_source_path/" "$target_path/" 2>&1 | \
|
||||||
while IFS= read -r -d $'\r' chunk; do
|
while IFS= read -r -d $'\r' chunk; do
|
||||||
# Extract percentage
|
|
||||||
if [[ $chunk =~ ([0-9]{1,3})% ]]; then
|
if [[ $chunk =~ ([0-9]{1,3})% ]]; then
|
||||||
current_percentage=${BASH_REMATCH[1]}
|
local progress_percent=${BASH_REMATCH[1]}
|
||||||
# Print only if percentage changed
|
local now=$(date +%s)
|
||||||
if [[ $current_percentage -ne $last_percentage ]]; then
|
if [[ $progress_percent -ne $progress_last_percent ]] && \
|
||||||
echo -e "Progress: ${current_percentage}%\r" | say "$@"
|
(( now - progress_last_time >= progress_interval )); then
|
||||||
last_percentage=$current_percentage
|
say "Progress: ${progress_percent}%"
|
||||||
|
progress_last_percent=$progress_percent
|
||||||
|
progress_last_time=$now
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#echo "[DEBUG] Using archive mode: format=$format compression=$compression"
|
# ARCHIVE backup
|
||||||
# Archive/compression backup
|
case "$backup_format" in
|
||||||
|
|
||||||
case "$format" in
|
|
||||||
tar)
|
tar)
|
||||||
# Map compression → extension and tar invocation (using only *_cmd vars)
|
case "$backup_compression" in
|
||||||
case "$compression" in
|
none) archive_ext="tar"; tar_create=( "$tar_cmd" -cvf ) ;;
|
||||||
none)
|
gzip) archive_ext="tar.gz"; tar_create=( "$tar_cmd" --use-compress-program="$gzip_cmd" -cvf ) ;;
|
||||||
ext="tar"
|
bzip2) archive_ext="tar.bz2";tar_create=( "$tar_cmd" --use-compress-program="$bzip2_cmd" -cvf ) ;;
|
||||||
tar_create=( "$tar_cmd" -cvf )
|
xz) archive_ext="tar.xz"; tar_create=( "$tar_cmd" --use-compress-program="$xz_cmd" -cvf ) ;;
|
||||||
;;
|
zstd) archive_ext="tar.zst";tar_create=( "$tar_cmd" --use-compress-program="$zstd_cmd" -cvf ) ;;
|
||||||
gzip)
|
*) echo "[ERROR] Unsupported tar compression: $backup_compression" >&2; return 1 ;;
|
||||||
ext="tar.gz"
|
|
||||||
tar_create=( "$tar_cmd" --use-compress-program="$gzip_cmd" -cvf )
|
|
||||||
;;
|
|
||||||
bzip2)
|
|
||||||
ext="tar.bz2"
|
|
||||||
tar_create=( "$tar_cmd" --use-compress-program="$bzip2_cmd" -cvf )
|
|
||||||
;;
|
|
||||||
xz)
|
|
||||||
ext="tar.xz"
|
|
||||||
tar_create=( "$tar_cmd" --use-compress-program="$xz_cmd" -cvf )
|
|
||||||
;;
|
|
||||||
zstd)
|
|
||||||
ext="tar.zst"
|
|
||||||
tar_create=( "$tar_cmd" --use-compress-program="$zstd_cmd" -cvf )
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "[ERROR] Unsupported tar compression: $compression" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
archive="$destination/${basename}-${timestamp}.${ext}"
|
archive_path="$backup_destination/${source_basename}-${timestamp}.${archive_ext}"
|
||||||
sources=( $source )
|
echo "[INFO] Creating tar archive $archive_path"
|
||||||
for s in "${sources[@]}"; do
|
|
||||||
if [[ ! -e "$DATA_DIR/$s" ]]; then
|
|
||||||
echo "[ERROR] Source not found under DATA_DIR: $DATA_DIR/$s" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Count total items for progress (files + dirs)
|
local progress_total=$(find "$full_source_path" | wc -l)
|
||||||
total_items=0
|
local progress_done=0
|
||||||
for s in "${sources[@]}"; do
|
local progress_last_percent=-1
|
||||||
count=$(find "$DATA_DIR/$s" | wc -l)
|
local progress_last_time=$(date +%s)
|
||||||
total_items=$(( total_items + count ))
|
|
||||||
done
|
|
||||||
current=0
|
|
||||||
|
|
||||||
echo "[INFO] Creating $archive"
|
|
||||||
|
|
||||||
last_percent=-1
|
|
||||||
last_info_time=$(date +%s)
|
|
||||||
# seconds between info logs
|
|
||||||
interval=2
|
|
||||||
|
|
||||||
(
|
(
|
||||||
"${tar_create[@]}" "$archive" -C "$DATA_DIR" "${sources[@]}"
|
"${tar_create[@]}" "$archive_path" -C "$DATA_DIR" "$backup_source"
|
||||||
) 2>&1 | while read -r line; do
|
) 2>&1 | while read -r line; do
|
||||||
if [[ -n "$line" ]]; then
|
if [[ -n "$line" ]]; then
|
||||||
current=$(( current + 1 ))
|
progress_done=$(( progress_done + 1 ))
|
||||||
if (( total_items > 0 )); then
|
if (( progress_total > 0 )); then
|
||||||
percent=$(( current * 100 / total_items ))
|
local progress_percent=$(( progress_done * 100 / progress_total ))
|
||||||
|
local now=$(date +%s)
|
||||||
# echo full percent:
|
if (( progress_percent != progress_last_percent )) && \
|
||||||
#echo "[DEBUG] Progress: ${percent}%"
|
(( now - progress_last_time >= progress_interval )); then
|
||||||
now=$(date +%s)
|
say "Progress: ${progress_percent}%"
|
||||||
if (( percent != last_percent )) && (( now - last_info_time >= interval )); then
|
progress_last_percent=$progress_percent
|
||||||
#echo "[INFO] Progress: ${percent}%"
|
progress_last_time=$now
|
||||||
say "Progress: ${percent}%"
|
|
||||||
last_percent=$percent
|
|
||||||
last_info_time=$now
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Ensure 100% gets printed once at the end
|
[[ $progress_last_percent -lt 100 ]] && say "Progress: 100%"
|
||||||
if (( last_percent < 100 )); then
|
echo "[INFO] Tar archive created: $archive_path"
|
||||||
#echo "[INFO] Progress: 100%"
|
|
||||||
say "Progress: 100%"
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "[INFO] Tar archive created: $archive"
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
zip)
|
zip)
|
||||||
ext="zip"
|
archive_path="$backup_destination/${source_basename}-${timestamp}.zip"
|
||||||
archive="$destination/${basename}-${timestamp}.${ext}"
|
echo "[INFO] Creating zip archive $archive_path"
|
||||||
echo "[INFO] Creating zip archive $archive"
|
|
||||||
|
|
||||||
# Count both files and directories
|
local progress_total=$(find "$full_source_path" | wc -l)
|
||||||
total_items=$(find "$DATA_DIR/$source" | wc -l)
|
local progress_done=0
|
||||||
current=0
|
local progress_last_percent=-1
|
||||||
|
local progress_last_time=$(date +%s)
|
||||||
last_percent=-1
|
|
||||||
last_info_time=$(date +%s)
|
|
||||||
interval=2 # seconds between info logs
|
|
||||||
|
|
||||||
(
|
(
|
||||||
cd "$DATA_DIR"
|
cd "$DATA_DIR"
|
||||||
"$zip_cmd" -r "$archive" "$source"
|
"$zip_cmd" -r "$archive_path" "$backup_source"
|
||||||
) 2>&1 | while read -r line; do
|
) 2>&1 | while read -r line; do
|
||||||
if [[ $line =~ adding: ]]; then
|
if [[ $line =~ adding: ]]; then
|
||||||
current=$((current+1))
|
progress_done=$(( progress_done + 1 ))
|
||||||
if (( total_items > 0 )); then
|
if (( progress_total > 0 )); then
|
||||||
percent=$(( current * 100 / total_items ))
|
local progress_percent=$(( progress_done * 100 / progress_total ))
|
||||||
|
local now=$(date +%s)
|
||||||
#echo "[DEBUG] Progress: ${percent}%"
|
if (( progress_percent != progress_last_percent )) && \
|
||||||
|
(( now - progress_last_time >= progress_interval )); then
|
||||||
now=$(date +%s)
|
say "Progress: ${progress_percent}%"
|
||||||
if (( percent != last_percent )) && (( now - last_info_time >= interval )); then
|
progress_last_percent=$progress_percent
|
||||||
#echo "[INFO] Progress: ${percent}%"
|
progress_last_time=$now
|
||||||
say "Progress: ${percent}%"
|
|
||||||
last_percent=$percent
|
|
||||||
last_info_time=$now
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Ensure 100% gets printed once at the end
|
[[ $progress_last_percent -lt 100 ]] && say "Progress: 100%"
|
||||||
if (( last_percent < 100 )); then
|
echo "[INFO] Zip archive created: $archive_path"
|
||||||
#echo "[INFO] Progress: 100%"
|
|
||||||
say "Progress: 100%"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "[INFO] Zip archive created: $archive"
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
echo "[ERROR] Unsupported format: $format"
|
echo "[ERROR] Unsupported format: $backup_format"
|
||||||
return 1
|
return 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
echo "[INFO] Backup completed: $archive"
|
echo "[INFO] Backup completed: $archive_path"
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# MAIN
|
# MAIN
|
||||||
|
|
||||||
#echo "[DEBUG] FULL=$FULL"
|
#echo "[DEBUG] FULL=$FULL"
|
||||||
|
|
@ -400,7 +364,6 @@ if (( SLEEP_TIME > 0 )); then
|
||||||
countdown "$SLEEP_TIME"
|
countdown "$SLEEP_TIME"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
mkdir -p "$DESTINATION"
|
mkdir -p "$DESTINATION"
|
||||||
|
|
||||||
echo "[INFO] Running backup of $BACKUP_MODE to $DESTINATION..."
|
echo "[INFO] Running backup of $BACKUP_MODE to $DESTINATION..."
|
||||||
|
|
@ -416,5 +379,4 @@ else
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
say "Backup ($BACKUP_MODE) completed successfully."
|
say "Backup ($BACKUP_MODE) completed successfully."
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue