384 lines
15 KiB
Bash
384 lines
15 KiB
Bash
backupLabel="[Backup]"
|
|
|
|
# Creates archive-based backups for all OpenLiteSpeed virtual hosts.
|
|
# [$1] (path): destination directory.
|
|
# [$2] (type): archive type: zip or tar.
|
|
function cmdBackupSitesArchive() {
|
|
local path
|
|
path=$(backupPathGenerate "$1")
|
|
|
|
local type="${2:-$backupType}"
|
|
|
|
local error vhostList total
|
|
run vhostList error openlitespeedConfigVhostList || { printDanger "Failed get list of vhosts: $error"; return 1; }
|
|
total=$(grep -c . <<< "$vhostList")
|
|
|
|
printSection "Config"
|
|
printDotText "Target" "all ($total)"
|
|
printDotText "Type" "$type"
|
|
printDotText "Path" "$path"
|
|
|
|
printSection "Executing"
|
|
local domain label num i=0 lockFile tmpDir
|
|
maxJobs="${backupParallelJobs:-1}"
|
|
tmpDir=$(mktemp -d) || { printDanger "Failed to create temp directory"; return 1; }
|
|
lockFile="$tmpDir/.lock"
|
|
while read -r domain; do
|
|
((i++))
|
|
num=$(printf "%0${#total}d" "$i")
|
|
label="$num: $fontBlue$domain$fontReset"
|
|
|
|
while (( $(jobs -rp | wc -l) >= maxJobs )); do
|
|
wait -n 2>/dev/null || true
|
|
done
|
|
|
|
(
|
|
local jobError
|
|
if runError jobError backupSite "$domain" "$path" "$type"; then
|
|
{ flock 9; printDotText "$label" "$labelDone"; } 9>>"$lockFile"
|
|
else
|
|
touch "$tmpDir/$i"
|
|
{ flock 9; printDotText "$label" "$labelFail"; printDanger "$jobError"; } 9>>"$lockFile"
|
|
fi
|
|
) &
|
|
done < <(awk 'NF' <<< "$vhostList")
|
|
wait
|
|
|
|
local failed=0 f
|
|
for f in "$tmpDir"/[0-9]*; do
|
|
[[ -f "$f" ]] || break
|
|
((failed++))
|
|
done
|
|
rm -rf "$tmpDir"
|
|
|
|
printSection "Summary"
|
|
printDotText "Total" "$fontBlue$total$fontReset"
|
|
printDotText "Successful" "$fontGreen$((total-failed))$fontReset"
|
|
printDotText "Failed" "$fontRed$failed$fontReset"
|
|
}
|
|
|
|
# Creates rsync-based backups for all sites; first daily backup is full, later ones use hard links.
|
|
# [$1] (path): destination directory.
|
|
function cmdBackupSitesRsync() {
|
|
local path
|
|
path=$(backupPathGenerate "$1")
|
|
|
|
printSection "Config"
|
|
printDotText "Target" "all"
|
|
printDotText "Path" "$path"
|
|
|
|
local error vhostList
|
|
run vhostList error openlitespeedConfigVhostList || { printDanger "Failed get list of vhosts: $error"; return 1; }
|
|
|
|
printText "Files..."
|
|
if [[ "$path" == *"$backupFirstDir" ]]; then
|
|
runError error rsync -a --mkpath -- "$olsVhostsPath/" "$path" || printDanger "$error"
|
|
else
|
|
runError error rsync -a --link-dest="$backupDailyPath/$backupFirstDir" -- "$olsVhostsPath/" "$path" || printDanger "$error"
|
|
fi
|
|
|
|
printText "Databases..."
|
|
while read -r domain; do
|
|
runError error backupSiteDatabase "$domain" "$path/$domain.sql.tar.gz" || printDanger "$error"
|
|
done < <(awk 'NF' <<< "$vhostList")
|
|
|
|
printText "Configs..."
|
|
while read -r domain; do
|
|
runError error cp -p -- "$olsVhostsConfigPath/$domain.conf" "$path/$domain.conf" || printDanger "$error"
|
|
done < <(awk 'NF' <<< "$vhostList")
|
|
}
|
|
|
|
# Runs a backup for all sites using the configured or given backup type.
|
|
# [$1] (path): destination directory.
|
|
# [$2] (type): backup type: zip, tar, or rsync.
|
|
function cmdBackupSites() {
|
|
local path="$1"
|
|
path=$(backupPathGenerate "$path")
|
|
|
|
local type="${2:-$backupType}"
|
|
|
|
case "$type" in
|
|
zip|tar)
|
|
cmdBackupSitesArchive "$path" "$type" || return 1
|
|
;;
|
|
rsync)
|
|
cmdBackupSitesRsync "$path" || return 1
|
|
;;
|
|
*)
|
|
printSection "Config"
|
|
printDanger "Unknown backup type: $type"
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
function cmdBackupArchiveDispatch() {
|
|
printSection "Config"
|
|
[[ -n "$backupArchivePath" ]] || { printDotText "Path" "$labelNull"; return 1; }
|
|
printDotText "Path" "$backupArchivePath"
|
|
[[ -n "$backupArchiveInterval" ]] || { printDotText "Period" "$labelNull"; return 1; }
|
|
printDotText "Period" "$backupArchiveInterval"
|
|
[[ -n "$backupArchiveDirPattern" ]] || { printDotText "Pattern" "$labelNull"; return 1; }
|
|
printDotText "Pattern" "$backupArchiveDirPattern"
|
|
|
|
mkdir -p -- "$backupArchivePath" || { printDanger "Failed to create archive path"; return 1; }
|
|
|
|
local dirList archiveList dailyList error
|
|
run dirList error fileList "$backupArchivePath" d || { printDanger "$error"; return 1; }
|
|
archiveList=$(printf '%s\n' "$dirList" | grep -E -- "$backupArchiveDirPattern" | sort || true)
|
|
|
|
run dirList error fileList "$backupDailyPath" d || { printDanger "$error"; return 1; }
|
|
dailyList=$(printf '%s\n' "$dirList" | grep -E -- "$backupDailyDirPattern" | sort || true)
|
|
|
|
printSection "Directories found"
|
|
local archiveCount archiveRemoveCount i=0 num label dirDate dirDays archiveRemoveList=""
|
|
archiveCount=$(grep -c . <<< "$archiveList" || true)
|
|
if [[ "$archiveCount" -gt 0 ]]; then
|
|
while read -r dir; do
|
|
((++i))
|
|
num=$(printf "%0${#archiveCount}d" "$i")
|
|
label="$num: $fontBlue$dir$fontReset"
|
|
|
|
if (( i == archiveCount )); then
|
|
printDotText "$label" "${fontGreen}save$fontReset"
|
|
elif (( i == archiveCount - 1 )); then
|
|
dirDate="${dir%$backupArchiveSuffix}"
|
|
dirDays=$(( $(timeDiff "$dirDate" "$appDate") / 86400 ))
|
|
if (( dirDays >= backupArchiveInterval )); then
|
|
printDotText "$label" "${fontRed}delete$fontReset"
|
|
archiveRemoveList+=$'\n'"$dir"
|
|
else
|
|
printDotText "$label" "${fontGreen}save$fontReset"
|
|
fi
|
|
else
|
|
printDotText "$label" "${fontRed}delete$fontReset"
|
|
archiveRemoveList+=$'\n'"$dir"
|
|
fi
|
|
done < <(awk 'NF' <<< "$archiveList")
|
|
|
|
archiveRemoveCount=$(grep -c . <<< "$archiveRemoveList" || true)
|
|
if [[ "$archiveRemoveCount" -gt 0 ]]; then
|
|
printSection "Deleting Directories"
|
|
|
|
while read -r dir; do
|
|
label="$backupArchivePath/$dir"
|
|
if [[ -n "$dir" ]]; then
|
|
if rm -rf -- "$backupArchivePath/$dir" &>/dev/null; then
|
|
printDotText "$label" "$labelDone"
|
|
else
|
|
printDotText "$label" "$labelFail"
|
|
fi
|
|
fi
|
|
done < <(awk 'NF' <<< "$archiveRemoveList")
|
|
fi
|
|
fi
|
|
|
|
# Promote oldest daily (excluding today) to archive
|
|
run dirList error fileList "$backupArchivePath" d || { printDanger "$error"; return 1; }
|
|
archiveList=$(printf '%s\n' "$dirList" | grep -E -- "$backupArchiveDirPattern" | sort || true)
|
|
archiveCount=$(grep -c . <<< "$archiveList" || true)
|
|
if (( archiveCount < 2 )); then
|
|
local oldestDaily
|
|
oldestDaily=$(head -1 <<< "$dailyList" || true)
|
|
[[ -n "$oldestDaily" ]] || return 0
|
|
[[ "$oldestDaily" != "$appDate" ]] || return 0
|
|
|
|
printSection "Promote Directories"
|
|
mv -- "$backupDailyPath/$oldestDaily" "$backupArchivePath/${oldestDaily}$backupArchiveSuffix" || {
|
|
printDotText "$backupDailyPath/$oldestDaily" "$labelFail"
|
|
printDanger "Failed to promote daily to archive: $oldestDaily"
|
|
return 1
|
|
}
|
|
printDotText "$backupDailyPath/$oldestDaily" "$labelDone"
|
|
fi
|
|
}
|
|
|
|
function cmdBackupDailyDispatch() {
|
|
printSection "Config"
|
|
[[ -n "$backupDailyPath" ]] || { printDotText "Path" "$labelNull"; return 1; }
|
|
printDotText "Path" "$backupDailyPath"
|
|
[[ -n "$backupDailyKeep" ]] || { printDotText "Keep" "$labelNull"; return 1; }
|
|
printDotText "Keep" "$backupDailyKeep"
|
|
[[ -n "$backupDailyDirPattern" ]] || { printDotText "Pattern" "$labelNull"; return 1; }
|
|
printDotText "Pattern" "$backupDailyDirPattern"
|
|
|
|
mkdir -p -- "$backupDailyPath" || { printDanger "Failed to create archive path"; return 1; }
|
|
|
|
local dirList dailyList error
|
|
run dirList error fileList "$backupDailyPath" d || { printDanger "$error"; return 1; }
|
|
dailyList=$(printf '%s\n' "$dirList" | grep -v "$appDate" | grep -E -- "$backupDailyDirPattern" | sort || true)
|
|
|
|
printSection "Directories found"
|
|
local dailyCount dailyRemoveCount i=0 num label dailyRemoveList=""
|
|
dailyCount=$(grep -c . <<< "$dailyList" || true)
|
|
|
|
if [[ "$dailyCount" -gt 0 ]]; then
|
|
while read -r dir; do
|
|
((++i))
|
|
num=$(printf "%0${#dailyCount}d" "$i")
|
|
label="$num: $fontBlue$dir$fontReset"
|
|
|
|
if [[ "$dir" == "$appDate" ]]; then
|
|
printDotText "$label" "${fontGray}skipped$fontReset"
|
|
elif (( dailyCount - backupDailyKeep >= i )); then
|
|
printDotText "$label" "${fontRed}delete$fontReset"
|
|
dailyRemoveList+=$'\n'"$dir"
|
|
else
|
|
printDotText "$label" "${fontGreen}save$fontReset"
|
|
fi
|
|
done < <(awk 'NF' <<< "$dailyList")
|
|
|
|
dailyRemoveCount=$(grep -c . <<< "$dailyRemoveList" || true)
|
|
if [[ "$dailyRemoveCount" -gt 0 ]]; then
|
|
printSection "Deleting Directories"
|
|
while read -r dir; do
|
|
label="$backupDailyPath/$dir"
|
|
if [[ -n "$dir" ]]; then
|
|
if rm -rf -- "$backupDailyPath/$dir" &>/dev/null; then
|
|
printDotText "$label" "$labelDone"
|
|
else
|
|
printDotText "$label" "$labelFail"
|
|
fi
|
|
fi
|
|
done < <(awk 'NF' <<< "$dailyRemoveList")
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function cmdBackupDispatch() {
|
|
local second=0 interval=0
|
|
|
|
printText "$fontMagenta[Step 1 Processing of archive backups on external storage]$fontReset"
|
|
cmdStorageBackupArchiveDispatch
|
|
seconds=$(timeDiff "$appDate ${appTime//-/:}" "$(date +%Y-%m-%d) $(date +%H:%M:%S)")
|
|
printDotText "Complete" "$(date +%Y-%m-%d) $(date +%H:%M:%S) $fontBlue$((seconds-interval))s$fontReset"
|
|
interval="$seconds"
|
|
|
|
printRow
|
|
printText "$fontMagenta[Step 2 Processing of daily backups on external storage]$fontReset"
|
|
cmdStorageBackupDailyDispatch
|
|
seconds=$(timeDiff "$appDate ${appTime//-/:}" "$(date +%Y-%m-%d) $(date +%H:%M:%S)")
|
|
printDotText "Complete" "$(date +%Y-%m-%d) $(date +%H:%M:%S) $fontBlue$((seconds-interval))s$fontReset"
|
|
interval="$seconds"
|
|
|
|
printRow
|
|
printText "$fontMagenta[Step 3 Processing of archive backups on host (SKIP...)]$fontReset"
|
|
# cmdBackupArchiveDispatch
|
|
# seconds=$(timeDiff "$appDate ${appTime//-/:}" "$(date +%Y-%m-%d) $(date +%H:%M:%S)")
|
|
# printDotText "Complete" "$(date +%Y-%m-%d) $(date +%H:%M:%S) $fontBlue$((seconds-interval))s$fontReset"
|
|
# interval="$seconds"
|
|
|
|
printRow
|
|
printText "$fontMagenta[Step 4 Processing of daily backups on host]$fontReset"
|
|
cmdBackupDailyDispatch
|
|
seconds=$(timeDiff "$appDate ${appTime//-/:}" "$(date +%Y-%m-%d) $(date +%H:%M:%S)")
|
|
printDotText "Complete" "$(date +%Y-%m-%d) $(date +%H:%M:%S) $fontBlue$((seconds-interval))s$fontReset"
|
|
interval="$seconds"
|
|
|
|
printRow
|
|
printText "$fontMagenta[Step 5 Creating a full daily backup]$fontReset"
|
|
cmdBackupSites
|
|
seconds=$(timeDiff "$appDate ${appTime//-/:}" "$(date +%Y-%m-%d) $(date +%H:%M:%S)")
|
|
printDotText "Complete" "$(date +%Y-%m-%d) $(date +%H:%M:%S) $fontBlue$((seconds-interval))s$fontReset"
|
|
interval="$seconds"
|
|
|
|
printRow
|
|
printText "$fontMagenta[Step 6 Synchronization with external storage (daily backups)]$fontReset"
|
|
cmdStorageBackupDailySyncLast
|
|
seconds=$(timeDiff "$appDate ${appTime//-/:}" "$(date +%Y-%m-%d) $(date +%H:%M:%S)")
|
|
printDotText "Complete" "$(date +%Y-%m-%d) $(date +%H:%M:%S) $fontBlue$((seconds-interval))s$fontReset"
|
|
interval="$seconds"
|
|
|
|
printRow
|
|
printText "$fontMagenta[Step 7 Synchronization with external storage (archive backups) (SKIP...)]$fontReset"
|
|
# cmdStorageBackupArchiveSyncLast
|
|
# seconds=$(timeDiff "$appDate ${appTime//-/:}" "$(date +%Y-%m-%d) $(date +%H:%M:%S)")
|
|
# printDotText "Complete" "$(date +%Y-%m-%d) $(date +%H:%M:%S) $fontBlue$((seconds-interval))s$fontReset"
|
|
}
|
|
|
|
# Runs a backup for a single site or all sites.
|
|
# [$1] (target): site domain or "all".
|
|
# [$2] (path): destination directory.
|
|
# [$3] (type): backup type.
|
|
function cmdBackupRun() {
|
|
local target="$1"
|
|
[[ -n "$target" ]] || { printRow; printDanger "Target not specified"; return 1; }
|
|
|
|
local path="$2"
|
|
path=$(backupPathGenerate "$path")
|
|
|
|
local type="${3:-$backupType}"
|
|
|
|
if [[ "$target" == "all" ]]; then
|
|
cmdBackupSites "$path" "$type" || return 1
|
|
else
|
|
printSection "Config"
|
|
printDotText "Target" "$target"
|
|
printDotText "Type" "$type"
|
|
printDotText "Path" "$path"
|
|
|
|
printSection "Executing"
|
|
|
|
local label error
|
|
if runError error backupSite "$target" "$path" "$type"; then
|
|
printDotText "$target" "$labelDone"
|
|
else
|
|
printDotText "$target" "$labelFail"
|
|
printDanger "$error"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function cmdBackupList() {
|
|
printRow
|
|
|
|
local dirList archiveList dailyList backupList backupCount error
|
|
run dirList error fileList "$backupArchivePath" d || { printDanger "$error"; return 1; }
|
|
archiveList=$(printf '%s\n' "$dirList" | grep -E -- "$backupArchiveDirPattern" | sort || true)
|
|
|
|
run dirList error fileList "$backupDailyPath" d || { printDanger "$error"; return 1; }
|
|
dailyList=$(printf '%s\n' "$dirList" | grep -E -- "$backupDailyDirPattern" | sort || true)
|
|
|
|
backupList=$(printf '%s\n' "$archiveList" "$dailyList" | awk 'NF' | sort)
|
|
backupCount=$(grep -c . <<< "$backupList" || true)
|
|
local i=0 num dir label
|
|
while read -r dir; do
|
|
((++i))
|
|
num=$(printf "%0${#backupCount}d" "$i")
|
|
label="$num: $fontBlue$dir$fontReset"
|
|
|
|
if listContains "$dir" "$archiveList"; then
|
|
printDotText "$label" "${fontGreen}archive$fontReset"
|
|
elif listContains "$dir" "$dailyList"; then
|
|
printDotText "$label" "${fontGreen}daily$fontReset"
|
|
else
|
|
printDotText "$label" "$labelUnknown"
|
|
fi
|
|
done < <(awk 'NF' <<< "$backupList")
|
|
}
|
|
|
|
function cmdBackupSize() {
|
|
local dirList file size total=0 archiveList dailyList
|
|
|
|
printSection "Archive: $backupArchivePath"
|
|
run dirList error fileList "$backupArchivePath" d || { printDanger "$error"; return 1; }
|
|
archiveList=$(printf '%s\n' "$dirList" | grep -E -- "$backupArchiveDirPattern" | sort || true)
|
|
while IFS= read -r file; do
|
|
size=$(pathSize "$backupArchivePath/$file" "gb")
|
|
printDotText "$file" "$size Gb"
|
|
(( total += size ))
|
|
done <<< "$archiveList"
|
|
|
|
printSection "Daily: $backupDailyPath"
|
|
run dirList error fileList "$backupDailyPath" d || { printDanger "$error"; return 1; }
|
|
dailyList=$(printf '%s\n' "$dirList" | grep -E -- "$backupDailyDirPattern" | sort || true)
|
|
while IFS= read -r file; do
|
|
size=$(pathSize "$backupDailyPath/$file" "gb")
|
|
printDotText "$file" "$size Gb"
|
|
(( total += size ))
|
|
done <<< "$dailyList"
|
|
|
|
printRow
|
|
printDotText "total" "$total Gb"
|
|
}
|