Full-featured cPanel backup tool with SSH, S3, and Google Drive support. Includes WHM plugin with Tailwind/DaisyUI UI, multi-remote management, decoupled schedules, and account restore workflows. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
133 lines
4.4 KiB
Bash
133 lines
4.4 KiB
Bash
#!/usr/bin/env bash
|
|
# gniza/lib/verify.sh — Remote backup integrity checks
|
|
|
|
verify_account_backup() {
|
|
local user="$1"
|
|
local timestamp="${2:-}"
|
|
local errors=0
|
|
|
|
# Resolve timestamp
|
|
local ts; ts=$(resolve_snapshot_timestamp "$user" "$timestamp") || return 1
|
|
|
|
log_info "Verifying backup for $user (snapshot: $ts)..."
|
|
|
|
if _is_rclone_mode; then
|
|
local snap_subpath="accounts/${user}/snapshots/${ts}"
|
|
|
|
# Check .complete marker
|
|
if ! rclone_exists "${snap_subpath}/.complete"; then
|
|
log_error "Snapshot missing .complete marker: $snap_subpath"
|
|
return 1
|
|
fi
|
|
|
|
# Count files
|
|
local file_list; file_list=$(rclone_list_files "$snap_subpath" 2>/dev/null) || true
|
|
local file_count=0
|
|
[[ -n "$file_list" ]] && file_count=$(echo "$file_list" | wc -l)
|
|
if (( file_count == 0 )); then
|
|
log_warn "No files found in snapshot"
|
|
((errors++)) || true
|
|
else
|
|
log_info " files: $file_count file(s)"
|
|
fi
|
|
|
|
# Check homedir
|
|
if rclone_exists "${snap_subpath}/homedir/"; then
|
|
local size_json; size_json=$(rclone_size "${snap_subpath}/homedir" 2>/dev/null) || true
|
|
local bytes=0
|
|
if [[ -n "$size_json" ]]; then
|
|
bytes=$(echo "$size_json" | grep -oP '"bytes":\s*\K[0-9]+' || echo 0)
|
|
fi
|
|
log_info " homedir: $(human_size "$bytes")"
|
|
else
|
|
log_warn "homedir directory missing in snapshot"
|
|
fi
|
|
|
|
# Check latest.txt
|
|
local latest; latest=$(rclone_cat "accounts/${user}/snapshots/latest.txt" 2>/dev/null) || true
|
|
if [[ -n "$latest" ]]; then
|
|
log_info " latest -> $latest"
|
|
else
|
|
log_warn " latest.txt not set"
|
|
fi
|
|
else
|
|
local snap_dir; snap_dir=$(get_snapshot_dir "$user")
|
|
local snap_path="$snap_dir/$ts"
|
|
|
|
# Check snapshot directory exists
|
|
if ! remote_exec "test -d '$snap_path'" 2>/dev/null; then
|
|
log_error "Snapshot directory not found: $snap_path"
|
|
return 1
|
|
fi
|
|
|
|
# Detect old format (pkgacct/ subdir) vs new format (content at root)
|
|
local pkgacct_base="$snap_path"
|
|
if remote_exec "test -d '$snap_path/pkgacct'" 2>/dev/null; then
|
|
pkgacct_base="$snap_path/pkgacct"
|
|
fi
|
|
|
|
# Check for expected pkgacct files
|
|
local file_count; file_count=$(remote_exec "find '$pkgacct_base' -maxdepth 1 -type f | wc -l" 2>/dev/null)
|
|
if [[ "$file_count" -eq 0 ]]; then
|
|
log_warn "No pkgacct files found in snapshot"
|
|
((errors++)) || true
|
|
else
|
|
log_info " pkgacct: $file_count file(s)"
|
|
fi
|
|
|
|
# Check for SQL files
|
|
local sql_count; sql_count=$(remote_exec "find '$pkgacct_base/mysql' -name '*.sql.gz' 2>/dev/null | wc -l" 2>/dev/null)
|
|
log_info " databases: $sql_count compressed SQL file(s)"
|
|
|
|
# Check homedir directory
|
|
if ! remote_exec "test -d '$snap_path/homedir'" 2>/dev/null; then
|
|
log_warn "homedir directory missing in snapshot"
|
|
else
|
|
local homedir_size; homedir_size=$(remote_exec "du -sb '$snap_path/homedir' | cut -f1" 2>/dev/null)
|
|
log_info " homedir: $(human_size "${homedir_size:-0}")"
|
|
fi
|
|
|
|
# Check latest symlink
|
|
local base; base=$(get_remote_account_base "$user")
|
|
local latest_target; latest_target=$(remote_exec "readlink '$base/latest' 2>/dev/null" 2>/dev/null)
|
|
if [[ -n "$latest_target" ]]; then
|
|
log_info " latest -> $(basename "$latest_target")"
|
|
else
|
|
log_warn " latest symlink not set"
|
|
fi
|
|
fi
|
|
|
|
if (( errors > 0 )); then
|
|
log_error "Verification found $errors issue(s) for $user"
|
|
return 1
|
|
fi
|
|
|
|
log_info "Verification passed for $user"
|
|
return 0
|
|
}
|
|
|
|
verify_all_accounts() {
|
|
local accounts; accounts=$(list_remote_accounts)
|
|
local total=0 passed=0 failed=0
|
|
|
|
if [[ -z "$accounts" ]]; then
|
|
log_warn "No remote accounts found to verify"
|
|
return 0
|
|
fi
|
|
|
|
while IFS= read -r user; do
|
|
[[ -z "$user" ]] && continue
|
|
((total++)) || true
|
|
if verify_account_backup "$user"; then
|
|
((passed++)) || true
|
|
else
|
|
((failed++)) || true
|
|
fi
|
|
done <<< "$accounts"
|
|
|
|
echo ""
|
|
log_info "Verification complete: $passed/$total passed, $failed failed"
|
|
(( failed > 0 )) && return 1
|
|
return 0
|
|
}
|