- If already have 4GB+ swap, skip creation - Only add additional swap if needed - Target: 8GB total swap - Shows current vs new swap size
295 lines
9.5 KiB
Bash
Executable File
295 lines
9.5 KiB
Bash
Executable File
#!/bin/bash
|
||
#
|
||
# SYSTEM PREPARATION FOR LARGE DATABASE RESTORES
|
||
# ===============================================
|
||
# Run as: root
|
||
#
|
||
# This script handles system-level preparation:
|
||
# - Swap creation
|
||
# - OOM killer protection
|
||
# - Kernel tuning
|
||
#
|
||
# Usage:
|
||
# sudo ./prepare_system.sh # Run diagnostics
|
||
# sudo ./prepare_system.sh --fix # Apply all fixes
|
||
# sudo ./prepare_system.sh --swap # Create swap only
|
||
#
|
||
|
||
set -euo pipefail
|
||
|
||
VERSION="1.0.0"
|
||
|
||
# Colors
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
CYAN='\033[0;36m'
|
||
NC='\033[0m'
|
||
|
||
log_info() { echo -e "${BLUE}ℹ${NC} $1"; }
|
||
log_ok() { echo -e "${GREEN}✓${NC} $1"; }
|
||
log_warn() { echo -e "${YELLOW}⚠${NC} $1"; }
|
||
log_error() { echo -e "${RED}✗${NC} $1"; }
|
||
|
||
#==============================================================================
|
||
# CHECK ROOT
|
||
#==============================================================================
|
||
check_root() {
|
||
if [ "$EUID" -ne 0 ]; then
|
||
log_error "This script must be run as root"
|
||
echo " Run: sudo $0"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
#==============================================================================
|
||
# DIAGNOSE
|
||
#==============================================================================
|
||
diagnose() {
|
||
echo
|
||
echo "╔══════════════════════════════════════════════════════════════════╗"
|
||
echo "║ SYSTEM DIAGNOSIS FOR LARGE RESTORES ║"
|
||
echo "╚══════════════════════════════════════════════════════════════════╝"
|
||
echo
|
||
|
||
# Memory
|
||
echo -e "${CYAN}━━━ MEMORY ━━━${NC}"
|
||
free -h
|
||
echo
|
||
|
||
# Swap
|
||
echo -e "${CYAN}━━━ SWAP ━━━${NC}"
|
||
swapon --show 2>/dev/null || echo " No swap configured!"
|
||
echo
|
||
|
||
# Disk
|
||
echo -e "${CYAN}━━━ DISK SPACE ━━━${NC}"
|
||
df -h / /var/lib/pgsql 2>/dev/null || df -h /
|
||
echo
|
||
|
||
# OOM
|
||
echo -e "${CYAN}━━━ RECENT OOM KILLS ━━━${NC}"
|
||
dmesg 2>/dev/null | grep -i "out of memory\|oom\|killed process" | tail -5 || echo " None found"
|
||
echo
|
||
|
||
# PostgreSQL OOM protection
|
||
echo -e "${CYAN}━━━ POSTGRESQL OOM PROTECTION ━━━${NC}"
|
||
local pg_pid
|
||
pg_pid=$(pgrep -x postgres 2>/dev/null | head -1 || echo "")
|
||
if [ -n "$pg_pid" ] && [ -f "/proc/$pg_pid/oom_score_adj" ]; then
|
||
local score=$(cat "/proc/$pg_pid/oom_score_adj")
|
||
if [ "$score" = "-1000" ]; then
|
||
log_ok "PostgreSQL protected (oom_score_adj = -1000)"
|
||
else
|
||
log_warn "PostgreSQL NOT protected (oom_score_adj = $score)"
|
||
fi
|
||
else
|
||
log_warn "Cannot check PostgreSQL OOM status"
|
||
fi
|
||
echo
|
||
|
||
# Summary
|
||
echo -e "${CYAN}━━━ RECOMMENDATIONS ━━━${NC}"
|
||
local swap_gb=$(free -g | awk '/^Swap:/ {print $2}')
|
||
local avail_gb=$(df -BG / | tail -1 | awk '{print $4}' | tr -d 'G')
|
||
|
||
if [ "${swap_gb:-0}" -lt 4 ]; then
|
||
log_warn "Create swap: sudo $0 --swap"
|
||
fi
|
||
|
||
if [ -n "$pg_pid" ]; then
|
||
local score=$(cat "/proc/$pg_pid/oom_score_adj" 2>/dev/null || echo "0")
|
||
if [ "$score" != "-1000" ]; then
|
||
log_warn "Enable OOM protection: sudo $0 --oom-protect"
|
||
fi
|
||
fi
|
||
|
||
echo
|
||
echo "To apply all fixes: sudo $0 --fix"
|
||
echo
|
||
}
|
||
|
||
#==============================================================================
|
||
# CREATE SWAP
|
||
#==============================================================================
|
||
create_swap() {
|
||
local SWAP_FILE="/swapfile_dbbackup"
|
||
|
||
echo -e "${CYAN}━━━ SWAP CHECK ━━━${NC}"
|
||
|
||
# Check existing swap
|
||
local current_swap_gb=$(free -g | awk '/^Swap:/ {print $2}')
|
||
current_swap_gb=${current_swap_gb:-0}
|
||
|
||
echo " Current swap: ${current_swap_gb}GB"
|
||
swapon --show 2>/dev/null || true
|
||
echo
|
||
|
||
# If already have 4GB+ swap, we're good
|
||
if [ "$current_swap_gb" -ge 4 ]; then
|
||
log_ok "Sufficient swap already configured (${current_swap_gb}GB)"
|
||
return 0
|
||
fi
|
||
|
||
# Check if our swap file already exists
|
||
if [ -f "$SWAP_FILE" ]; then
|
||
if swapon --show | grep -q "$SWAP_FILE"; then
|
||
log_ok "Our swap file already active: $SWAP_FILE"
|
||
return 0
|
||
else
|
||
# File exists but not active - activate it
|
||
log_info "Activating existing swap file..."
|
||
swapon "$SWAP_FILE" 2>/dev/null && log_ok "Swap activated" && return 0
|
||
fi
|
||
fi
|
||
|
||
# Need to create swap
|
||
local avail_gb=$(df -BG / | tail -1 | awk '{print $4}' | tr -d 'G')
|
||
|
||
# Calculate how much MORE swap we need (target: 8GB total)
|
||
local target_swap=8
|
||
local need_swap=$((target_swap - current_swap_gb))
|
||
|
||
if [ "$need_swap" -le 0 ]; then
|
||
log_ok "Swap is sufficient"
|
||
return 0
|
||
fi
|
||
|
||
# Auto-detect size based on available disk AND what we need
|
||
local size
|
||
if [ "$avail_gb" -ge 40 ] && [ "$need_swap" -ge 16 ]; then
|
||
size="32G"
|
||
elif [ "$avail_gb" -ge 20 ] && [ "$need_swap" -ge 8 ]; then
|
||
size="16G"
|
||
elif [ "$avail_gb" -ge 12 ] && [ "$need_swap" -ge 4 ]; then
|
||
size="8G"
|
||
elif [ "$avail_gb" -ge 6 ]; then
|
||
size="4G"
|
||
elif [ "$avail_gb" -ge 4 ]; then
|
||
size="3G"
|
||
elif [ "$avail_gb" -ge 3 ]; then
|
||
size="2G"
|
||
elif [ "$avail_gb" -ge 2 ]; then
|
||
size="1G"
|
||
else
|
||
log_error "Not enough disk space (only ${avail_gb}GB available)"
|
||
return 1
|
||
fi
|
||
|
||
log_info "Creating additional swap: $size (current: ${current_swap_gb}GB, disk: ${avail_gb}GB)"
|
||
|
||
echo " Creating ${size} swap file..."
|
||
|
||
if command -v fallocate &>/dev/null; then
|
||
fallocate -l "$size" "$SWAP_FILE"
|
||
else
|
||
local size_mb=$((${size//[!0-9]/} * 1024))
|
||
dd if=/dev/zero of="$SWAP_FILE" bs=1M count="$size_mb" status=progress
|
||
fi
|
||
|
||
chmod 600 "$SWAP_FILE"
|
||
mkswap "$SWAP_FILE"
|
||
swapon "$SWAP_FILE"
|
||
|
||
# Persist
|
||
if ! grep -q "$SWAP_FILE" /etc/fstab 2>/dev/null; then
|
||
echo "$SWAP_FILE none swap sw 0 0" >> /etc/fstab
|
||
log_ok "Added to /etc/fstab"
|
||
fi
|
||
|
||
# Show result
|
||
local new_swap_gb=$(free -g | awk '/^Swap:/ {print $2}')
|
||
log_ok "Swap now: ${new_swap_gb}GB (was ${current_swap_gb}GB)"
|
||
swapon --show
|
||
}
|
||
|
||
#==============================================================================
|
||
# OOM PROTECTION
|
||
#==============================================================================
|
||
enable_oom_protection() {
|
||
echo -e "${CYAN}━━━ ENABLING OOM PROTECTION ━━━${NC}"
|
||
|
||
# Protect PostgreSQL
|
||
local pg_pids=$(pgrep -x postgres 2>/dev/null || echo "")
|
||
|
||
if [ -z "$pg_pids" ]; then
|
||
log_warn "PostgreSQL not running"
|
||
else
|
||
for pid in $pg_pids; do
|
||
if [ -f "/proc/$pid/oom_score_adj" ]; then
|
||
echo -1000 > "/proc/$pid/oom_score_adj" 2>/dev/null || true
|
||
fi
|
||
done
|
||
log_ok "PostgreSQL processes protected"
|
||
fi
|
||
|
||
# Kernel tuning
|
||
sysctl -w vm.overcommit_memory=2 2>/dev/null && log_ok "vm.overcommit_memory = 2"
|
||
sysctl -w vm.overcommit_ratio=90 2>/dev/null && log_ok "vm.overcommit_ratio = 90"
|
||
|
||
# Persist
|
||
if ! grep -q "vm.overcommit_memory" /etc/sysctl.conf 2>/dev/null; then
|
||
echo "vm.overcommit_memory = 2" >> /etc/sysctl.conf
|
||
echo "vm.overcommit_ratio = 90" >> /etc/sysctl.conf
|
||
log_ok "Settings persisted to /etc/sysctl.conf"
|
||
fi
|
||
}
|
||
|
||
#==============================================================================
|
||
# APPLY ALL FIXES
|
||
#==============================================================================
|
||
apply_all() {
|
||
echo
|
||
echo "╔══════════════════════════════════════════════════════════════════╗"
|
||
echo "║ APPLYING SYSTEM FIXES ║"
|
||
echo "╚══════════════════════════════════════════════════════════════════╝"
|
||
echo
|
||
|
||
create_swap
|
||
echo
|
||
enable_oom_protection
|
||
|
||
echo
|
||
log_ok "System preparation complete!"
|
||
echo
|
||
echo " Next: Run PostgreSQL tuning as postgres user:"
|
||
echo " su - postgres -c './prepare_postgres.sh --fix'"
|
||
echo
|
||
}
|
||
|
||
#==============================================================================
|
||
# HELP
|
||
#==============================================================================
|
||
show_help() {
|
||
echo "SYSTEM PREPARATION v$VERSION"
|
||
echo
|
||
echo "Usage: sudo $0 [OPTION]"
|
||
echo
|
||
echo "Options:"
|
||
echo " (none) Run diagnostics"
|
||
echo " --fix Apply all fixes"
|
||
echo " --swap Create swap file only"
|
||
echo " --oom-protect Enable OOM protection only"
|
||
echo " --help Show this help"
|
||
echo
|
||
}
|
||
|
||
#==============================================================================
|
||
# MAIN
|
||
#==============================================================================
|
||
main() {
|
||
check_root
|
||
|
||
case "${1:-}" in
|
||
--help|-h) show_help ;;
|
||
--fix) apply_all ;;
|
||
--swap) create_swap ;;
|
||
--oom-protect) enable_oom_protection ;;
|
||
"") diagnose ;;
|
||
*) log_error "Unknown option: $1"; show_help; exit 1 ;;
|
||
esac
|
||
}
|
||
|
||
main "$@"
|