+++ /dev/null
-#!/bin/bash
-
-errlog()
-{
- local lastexit=$?
- local msg="$1"
-
- echo "❌ ERROR: $msg"
- echo "🛑 EXIT $lastexit"
- return $lastexit
-}
-
-get_backup_type()
-{
- local typ="none"
-
- [ -f "$backup_path/day" ] && typ="day"
- [ -f "$backup_path/week" ] && typ="week"
- [ -f "$backup_path/month" ] && typ="month"
-
- echo "$typ"
-}
-
-write_current_date()
-{
- local backup_path="$1"
- local current_date=
- local typ=
- current_date="$(date +%F)"
- typ=$(get_backup_type)
-
- mkdir --parents "history"
-
- echo "$current_date" > "$backup_path/$typ"
- echo "$current_date" > "history/$typ"
-}
-
-rotate_history()
-{
- local history_file="$1"
-
- [ -f "$history_file" ] || return 0
-
- history_lines=$(wc --lines "$history_file" | awk '{print $1}')
- echo "ℹ️ INFO: $history_file has $history_lines lines"
- [ "$history_lines" -ge 100 ] \
- && savelog -c 10 -l "$history_file" \
- && echo "ℹ️ INFO: $history_file rotated"
-}
-
-write_history_entry()
-{
- local msg="$1"
- local current_date=
- local typ=
- current_date=$(date --iso-8601=seconds)
- typ=$(get_backup_type)
-
- mkdir --parents "history"
- rotate_history "history/history"
-
- echo "ℹ️ INFO: $current_date $typ $msg"
- echo "$current_date $typ $msg" >> "history/history"
-}
-
-get_backup_dir()
-{
- local backup_path="$1"
- local backup_name="$2"
- local last_backup_number="$3"
- local date=
- date=$(date +%F)
-
- local backup_dir=
- local number=
- for number in $(seq --format "%02g" "$last_backup_number" 99); do
- backup_dir="$date"_"$number"_"$backup_name"
- [ -d "$backup_path/$backup_dir" ] || break;
- done
-
- echo "$backup_dir"
-}
-
-get_last_backup_dir_path()
-{
- local backup_path="$1"
- local backup_name="$2"
- local last_backup_dir_path=
-
- last_backup_dir_path=$(find "$backup_path" \
- -maxdepth 1 \
- -type d \
- -name "*_""$backup_name" \
- | sort \
- | tail --lines=1)
-
- echo "$last_backup_dir_path"
-}
-
-print_line()
-{
- printf "#%.0s" {1..80}
- printf "\n"
-}
-
-backup_remote_pathes()
-{
- local backup_path="$1"
- local machine="$2"
- local last_backup_dir_path="$3"
- local remote_user=
- local host=
- local port=
- local pathes=
- local excludes=
- local YELLOW="\e[0;33m"
- local LIGHTPURPLE="\e[1;35m"
- local RESET="\e[0m"
- local rsyncargs=()
-
- remote_user=$(yq \
- --raw-output ".machines.\"$machine\".remote_user" config.yaml)
- [ -n "$remote_user" ] && [ "$remote_user" != "null" ] \
- || errlog "config.yaml missing remote_user for $machine" \
- || return $?
- host=$(yq --raw-output ".machines.\"$machine\".host" config.yaml)
- [ -n "$host" ] && [ "$host" != "null" ] \
- || errlog "config.yaml missing host for $machine" \
- || return $?
- port=$(yq --raw-output ".machines.\"$machine\".port" config.yaml)
- [ -n "$port" ] && [ "$port" != "null" ] \
- || errlog "config.yaml missing port for $machine" \
- || return $?
- pathes=$(yq --raw-output ".machines.\"$machine\".pathes[]" config.yaml)
- [ -n "$pathes" ] \
- || errlog "config.yaml missing pathes for $machine" \
- || return $?
- excludes=$(yq --raw-output ".machines.\"$machine\".excludes[]" \
- config.yaml \
- 2> /dev/null)
-
-
- local path=
- for path in $pathes; do
- print_line
- printf "ℹ️ INFO: machine ${LIGHTPURPLE}%s${RESET}; " "$machine"
- printf "path ${YELLOW}%s${RESET}\n\n" "$path"
-
- rsyncargs=("--archive"
- "--verbose"
- "--sparse"
- "--acls"
- "--hard-links"
- "--relative"
- "--human-readable")
-
- if [ "$excludes" != "null" ]; then
- local exclude=
- for exclude in $excludes; do
- rsyncargs+=("--exclude=$exclude")
- done
- fi
- rsyncargs+=("--rsh=ssh -p $port")
-
- [ -n "$last_backup_dir_path" ] \
- && rsyncargs+=("--link-dest=$last_backup_dir_path/$machine")
-
- local hostpath="$remote_user@$host:$path"
- [ "$host" == "localhost" ] && local hostpath="$path"
- rsyncargs+=("$hostpath")
- rsyncargs+=("$backup_path/$machine")
-
- rsync "${rsyncargs[@]}" \
- || errlog "could not backup $machine with path $path" \
- || return $?
-
- print_line
- done
-}
-
-backup_remotes()
-{
- local backup_path="$1"
- local last_backup_dir_path="$2"
- local machines=
- machines=$(yq --raw-output '.machines | keys[]' config.yaml)
- [ -n "$machines" ] \
- || errlog "config.yaml no machines" \
- || return $?
-
- local machine=
- for machine in $machines; do
- echo "ℹ️ INFO: create directory $backup_path/$machine"
- mkdir --parents "$backup_path/$machine" \
- || errlog "could not create directory $backup_path/$machine" \
- || return $?
-
- backup_remote_pathes "$backup_path" \
- "$machine" \
- "$last_backup_dir_path" \
- || return $?
- done
-}
-
-remove_backup_dir()
-{
- local backup_path="$1"
- local backup_name="$2"
- local delete_count=$3
- local backups=
-
- backups=$(find "$backup_path" -maxdepth 1 -name "*_${backup_name}" \
- | sort \
- | head --lines "$delete_count")
-
- local backup=
- for backup in $backups; do
- echo "🗑️ DELETE: $backup"
- rm --recursive "$backup"
- write_history_entry "deleted ${backup##*/}"
- done
-}
-
-cleanup_backups()
-{
- local backup_path="$1"
- local backup_name="$2"
- local backup_count="$3"
- local backup_counted=
-
- backup_counted=$(find "$backup_path" -maxdepth 1 -type d \
- | grep "_$backup_name" \
- | sort \
- | wc --lines)
- local delete_count=$(( backup_counted - backup_count ))
-
- print_line
- echo
- echo "ℹ️ INFO: backup count: $backup_counted"
-
- if [ "$backup_counted" -gt "$backup_count" ]; then
- echo "ℹ️ INFO: delete backup count: $delete_count"
- echo
- remove_backup_dir "$backup_path" "$backup_name" "$delete_count"
- fi
-
- echo
- print_line
-}
-
-is_backup_old()
-{
- local backup_typ="$1"
- local backup_date="$2"
- local backup_month=
- local now_month=
- local diff=
- backup_month=$(date --date="$backup_date" '+%Y-%m')
- now_month=$(date '+%Y-%m')
- diff=$(( ($(date --date="$backup_date" +%s) - $(date +%s)) / 86400 ))
-
- case "$backup_typ" in
- "day") [ $diff -ge 0 ] || return 1 ;;
- "week") [ $diff -ge -6 ] || return 1 ;;
- "month") [ "$backup_month" == "$now_month" ] || return 1 ;;
- *) return 0;;
- esac
-}
-
-check_backup_date()
-{
- local LIGHTRED="\e[1;31m"
- local LIGHTGREEN="\e[1;32m"
- local RESET="\e[0m"
- local color=$LIGHTGREEN
- local history_path="history"
-
- print_line
- echo
- local typ=
- for typ in day week month; do
- if [ -f "$history_path/$typ" ]; then
- color=$LIGHTGREEN
- is_backup_old "$typ" "$(cat $history_path/$typ)" \
- || color=$LIGHTRED
- printf "${color}last backup %s " "$typ"
- printf "am %s$RESET\n" "$(cat $history_path/$typ)"
- else
- printf "${LIGHTRED}no backup %s " $typ
- printf "%s$RESET\n" "exists"
- fi
- done
- echo
- print_line
-}
-
-main()
-{
- local only_check="$1"
- local last_backup_dir_path=
- local today_date=
- local backup_dir=
-
- [ "$only_check" == "check" ] && check_backup_date && return 0
-
- echo "⭐ START: backup"
-
- command -v yq > /dev/null \
- || errlog "command yq not found" \
- || return $?
- command -v rsync > /dev/null \
- || errlog "command rsync not found" \
- || return $?
- command -v ssh > /dev/null \
- || errlog "command ssh not found" \
- || return $?
- [ -f "config.yaml" ] \
- || errlog "file config.yaml not found" \
- || return $?
-
- backup_path=$(yq --raw-output '.backup_path' config.yaml)
- backup_name=$(yq --raw-output '.backup_name' config.yaml)
- backup_count=$(yq --raw-output '.backup_count' config.yaml)
-
- [ -n "$backup_path" ] && [ "$backup_path" != "null" ] \
- || errlog "config.yaml missing backup_path" \
- || return $?
- [ -d "$backup_path" ] \
- || errlog "directory $backup_path not exists" \
- || return $?
- echo "ℹ️ INFO: backup path $backup_path"
- [ -n "$backup_name" ] && [ "$backup_name" != "null" ] \
- || errlog "config.yaml missing backup_name" \
- || return $?
- echo "ℹ️ INFO: backup name $backup_name"
- [ -n "$backup_count" ] && [ "$backup_count" != "null" ] \
- || errlog "config.yaml missing backup_count" \
- || return $?
- echo "ℹ️ INFO: backup count $backup_count"
-
- last_backup_dir_path=$(get_last_backup_dir_path \
- "$backup_path" \
- "$backup_name")
- echo "ℹ️ INFO: last backup dir path $last_backup_dir_path"
-
- today_date=$(date +%F)
- local last_backup_number=1
- [[ "$last_backup_dir_path" =~ $today_date ]] \
- && last_backup_number=${last_backup_dir_path##*/} \
- && last_backup_number=${last_backup_number:11:2}
- backup_dir=$(get_backup_dir \
- "$backup_path" \
- "$backup_name" \
- "$last_backup_number")
-
- echo "ℹ️ INFO: backup folder $backup_dir"
- local backup_full_path=$backup_path/$backup_dir
- echo "ℹ️ INFO: create folder $backup_full_path"
-
- backup_remotes \
- "$backup_full_path" \
- "$last_backup_dir_path" \
- || return $?
- write_current_date "$backup_path" \
- || return $?
- write_history_entry "created $backup_dir" \
- || return $?
- cleanup_backups \
- "$backup_path" \
- "$backup_name" \
- "$backup_count" \
- || return $?
- check_backup_date \
- || return $?
-
- echo "✅ SUCCESS: backup"
-}
-
-main "$@"