Refactor swap configuration

This commit is contained in:
buildplan 2025-11-26 21:33:25 +00:00
parent 37655c0736
commit dfae3a2fb9

View File

@ -4879,153 +4879,220 @@ test_backup() {
} }
configure_swap() { configure_swap() {
if [[ $IS_CONTAINER == true ]]; then if [[ "$IS_CONTAINER" == true ]]; then
print_info "Swap configuration skipped in container." print_info "Swap configuration skipped in container."
return 0 return 0
fi fi
print_section "Swap Configuration" print_section "Swap Configuration"
# Check for existing swap partition
# Check for existing swap partition entries in fstab for awareness
if lsblk -r | grep -q '\[SWAP\]'; then if lsblk -r | grep -q '\[SWAP\]'; then
print_warning "Existing swap partition found. Verify with 'lsblk -f'. Proceed with caution." print_warning "Existing swap partition found on disk."
fi fi
local existing_swap
existing_swap=$(swapon --show --noheadings | awk '{print $1}' || true) # Detect active swap
local existing_swap swap_type
# --show=NAME,TYPE,SIZE ensures consistent column order
existing_swap=$(swapon --show=NAME,TYPE,SIZE --noheadings --bytes 2>/dev/null | head -n 1 | awk '{print $1}' || true)
if [[ -n "$existing_swap" ]]; then if [[ -n "$existing_swap" ]]; then
local current_size swap_type=$(swapon --show=NAME,TYPE,SIZE --noheadings | head -n 1 | awk '{print $2}')
current_size=$(du -h "$existing_swap" | awk '{print $1}')
print_info "Existing swap file found: $existing_swap ($current_size)" # Get human readable size for display using du (disk usage)
if confirm "Modify existing swap file size?"; then local display_size
local SWAP_SIZE display_size=$(du -h "$existing_swap" 2>/dev/null | awk '{print $1}' || echo "Unknown")
while true; do
read -rp "$(printf '%s' "${CYAN}Enter new swap size (e.g., 2G, 512M) [current: $current_size]: ${NC}")" SWAP_SIZE print_info "Existing swap detected: $existing_swap (Type: $swap_type, Size: $display_size)"
SWAP_SIZE=${SWAP_SIZE:-$current_size}
if validate_swap_size "$SWAP_SIZE"; then # --- Case 1: Partition detected ---
break if [[ "$swap_type" == "partition" ]] || [[ "$existing_swap" =~ ^/dev/ ]]; then
else print_warning "The detected swap is a disk partition, which cannot be resized by this script."
print_error "Invalid size. Use format like '2G' or '512M'."
if confirm "Disable this swap partition and create a standard /swapfile instead?" "n"; then
print_info "Disabling swap partition $existing_swap..."
if ! swapoff "$existing_swap"; then
print_error "Failed to disable swap partition. Keeping it active."
return 0
fi fi
done
local REQUIRED_SPACE # Comment out the partition in fstab to prevent it mounting on reboot
REQUIRED_SPACE=$(convert_to_bytes "$SWAP_SIZE") sed -i "s|^$existing_swap|#$existing_swap|" /etc/fstab
local AVAILABLE_SPACE sed -i "s|^UUID=.*swap|#&|" /etc/fstab
AVAILABLE_SPACE=$(df -k / | tail -n 1 | awk '{print $4}') print_success "Swap partition disabled and removed from fstab."
if (( AVAILABLE_SPACE < REQUIRED_SPACE / 1024 )); then
print_error "Insufficient disk space for $SWAP_SIZE swap file. Available: $((AVAILABLE_SPACE / 1024))MB" # Clear variable to trigger new file creation below
exit 1 existing_swap=""
else
print_info "Keeping existing swap partition."
configure_swap_settings
return 0
fi fi
print_info "Disabling existing swap file..."
swapoff "$existing_swap" || { print_error "Failed to disable swap file."; exit 1; }
print_info "Resizing swap file to $SWAP_SIZE..."
if ! fallocate -l "$SWAP_SIZE" "$existing_swap" || ! chmod 600 "$existing_swap" || ! mkswap "$existing_swap" || ! swapon "$existing_swap"; then
print_error "Failed to resize or enable swap file."
exit 1
fi
print_success "Swap file resized to $SWAP_SIZE."
else else
print_info "Keeping existing swap file." # --- Case 2: Swap File detected ---
if confirm "Modify existing swap file size?"; then
local SWAP_SIZE
while true; do
read -rp "$(printf '%s' "${CYAN}Enter new swap size (e.g., 2G, 512M) [current: $display_size]: ${NC}")" SWAP_SIZE
SWAP_SIZE=${SWAP_SIZE:-$display_size}
if validate_swap_size "$SWAP_SIZE"; then break; else print_error "Invalid size. Use format like '2G' or '512M'."; fi
done
# Disk space check
local REQUIRED_SPACE AVAILABLE_SPACE
REQUIRED_SPACE=$(convert_to_bytes "$SWAP_SIZE")
AVAILABLE_SPACE=$(df -k / | tail -n 1 | awk '{print $4}')
# Convert available to bytes for comparison (df output is 1K blocks)
if (( (AVAILABLE_SPACE * 1024) < REQUIRED_SPACE )); then
print_error "Insufficient disk space. Required: $SWAP_SIZE, Available: $(numfmt --to=iec $((AVAILABLE_SPACE * 1024)))"
exit 1
fi
print_info "Disabling existing swap file..."
swapoff "$existing_swap" || { print_error "Failed to disable swap file."; exit 1; }
print_info "Resizing swap file to $SWAP_SIZE..."
# Try fallocate first (fast), fallback to dd (compatible)
if ! fallocate -l "$SWAP_SIZE" "$existing_swap" 2>/dev/null; then
print_warning "fallocate failed (filesystem might not support it). Using dd (slower)..."
rm -f "$existing_swap"
# Quoted command substitution for ShellCheck compliance
if ! dd if=/dev/zero of="$existing_swap" bs=1M count="$(convert_to_mb "$SWAP_SIZE")" status=progress; then
print_error "Failed to create swap file with dd."
exit 1
fi
fi
if ! chmod 600 "$existing_swap" || ! mkswap "$existing_swap" >/dev/null || ! swapon "$existing_swap"; then
print_error "Failed to configure swap file."
exit 1
fi
print_success "Swap file resized to $SWAP_SIZE."
else
print_info "Keeping existing swap file."
fi
configure_swap_settings
return 0 return 0
fi fi
else fi
# --- Case 3: Create New Swap (No swap exists, or partition was disabled above) ---
if [[ -z "$existing_swap" ]]; then
if ! confirm "Configure a swap file (recommended for < 4GB RAM)?"; then if ! confirm "Configure a swap file (recommended for < 4GB RAM)?"; then
print_info "Skipping swap configuration." print_info "Skipping swap configuration."
return 0 return 0
fi fi
local SWAP_SIZE local SWAP_SIZE
while true; do while true; do
read -rp "$(printf '%s' "${CYAN}Enter swap file size (e.g., 2G, 512M) [2G]: ${NC}")" SWAP_SIZE read -rp "$(printf '%s' "${CYAN}Enter swap file size (e.g., 2G, 512M) [2G]: ${NC}")" SWAP_SIZE
SWAP_SIZE=${SWAP_SIZE:-2G} SWAP_SIZE=${SWAP_SIZE:-2G}
if validate_swap_size "$SWAP_SIZE"; then if validate_swap_size "$SWAP_SIZE"; then break; else print_error "Invalid size. Use format like '2G' or '512M'."; fi
break
else
print_error "Invalid size. Use format like '2G' or '512M'."
fi
done done
local REQUIRED_SPACE
local REQUIRED_SPACE AVAILABLE_SPACE
REQUIRED_SPACE=$(convert_to_bytes "$SWAP_SIZE") REQUIRED_SPACE=$(convert_to_bytes "$SWAP_SIZE")
local AVAILABLE_SPACE
AVAILABLE_SPACE=$(df -k / | tail -n 1 | awk '{print $4}') AVAILABLE_SPACE=$(df -k / | tail -n 1 | awk '{print $4}')
if (( AVAILABLE_SPACE < REQUIRED_SPACE / 1024 )); then
print_error "Insufficient disk space for $SWAP_SIZE swap file. Available: $((AVAILABLE_SPACE / 1024))MB" if (( (AVAILABLE_SPACE * 1024) < REQUIRED_SPACE )); then
print_error "Insufficient disk space. Required: $SWAP_SIZE, Available: $(numfmt --to=iec $((AVAILABLE_SPACE * 1024)))"
exit 1 exit 1
fi fi
print_info "Creating $SWAP_SIZE swap file..."
if ! fallocate -l "$SWAP_SIZE" /swapfile || ! chmod 600 /swapfile || ! mkswap /swapfile || ! swapon /swapfile; then print_info "Creating $SWAP_SIZE swap file at /swapfile..."
print_error "Failed to create or enable swap file." if ! fallocate -l "$SWAP_SIZE" /swapfile 2>/dev/null; then
print_warning "fallocate failed. Using dd (slower)..."
# Quoted command substitution for ShellCheck compliance
if ! dd if=/dev/zero of=/swapfile bs=1M count="$(convert_to_mb "$SWAP_SIZE")" status=progress; then
print_error "Failed to create swap file."
rm -f /swapfile || true
exit 1
fi
fi
if ! chmod 600 /swapfile || ! mkswap /swapfile >/dev/null || ! swapon /swapfile; then
print_error "Failed to enable swap file."
rm -f /swapfile || true rm -f /swapfile || true
exit 1 exit 1
fi fi
# Check for existing swap entry in /etc/fstab to prevent duplicates
if grep -q '^/swapfile ' /etc/fstab; then # Add to fstab if missing
print_info "Swap entry already exists in /etc/fstab. Skipping." if ! grep -q '^/swapfile ' /etc/fstab; then
else
echo '/swapfile none swap sw 0 0' >> /etc/fstab echo '/swapfile none swap sw 0 0' >> /etc/fstab
print_success "Swap entry added to /etc/fstab." print_success "Swap entry added to /etc/fstab."
else
print_info "Swap entry already exists in /etc/fstab."
fi fi
print_success "Swap file created: $SWAP_SIZE" print_success "Swap file created: $SWAP_SIZE"
fi fi
configure_swap_settings
}
# Helper: Apply Sysctl Settings for Swap
configure_swap_settings() {
print_info "Configuring swap settings..." print_info "Configuring swap settings..."
local SWAPPINESS=10 local SWAPPINESS=10
local CACHE_PRESSURE=50 local CACHE_PRESSURE=50
if confirm "Customize swap settings (vm.swappiness and vm.vfs_cache_pressure)?"; then if confirm "Customize swap settings (vm.swappiness and vm.vfs_cache_pressure)?"; then
while true; do while true; do
read -rp "$(printf '%s' "${CYAN}Enter vm.swappiness (0-100) [default: $SWAPPINESS]: ${NC}")" INPUT_SWAPPINESS read -rp "$(printf '%s' "${CYAN}Enter vm.swappiness (0-100) [default: $SWAPPINESS]: ${NC}")" INPUT
INPUT_SWAPPINESS=${INPUT_SWAPPINESS:-$SWAPPINESS} INPUT=${INPUT:-$SWAPPINESS}
if [[ "$INPUT_SWAPPINESS" =~ ^[0-9]+$ && "$INPUT_SWAPPINESS" -ge 0 && "$INPUT_SWAPPINESS" -le 100 ]]; then if [[ "$INPUT" =~ ^[0-9]+$ && "$INPUT" -ge 0 && "$INPUT" -le 100 ]]; then SWAPPINESS=$INPUT; break; fi
SWAPPINESS=$INPUT_SWAPPINESS print_error "Invalid value (0-100)."
break
else
print_error "Invalid value for vm.swappiness. Must be between 0 and 100."
fi
done done
while true; do while true; do
read -rp "$(printf '%s' "${CYAN}Enter vm.vfs_cache_pressure (1-1000) [default: $CACHE_PRESSURE]: ${NC}")" INPUT_CACHE_PRESSURE read -rp "$(printf '%s' "${CYAN}Enter vm.vfs_cache_pressure (1-1000) [default: $CACHE_PRESSURE]: ${NC}")" INPUT
INPUT_CACHE_PRESSURE=${INPUT_CACHE_PRESSURE:-$CACHE_PRESSURE} INPUT=${INPUT:-$CACHE_PRESSURE}
if [[ "$INPUT_CACHE_PRESSURE" =~ ^[0-9]+$ && "$INPUT_CACHE_PRESSURE" -ge 1 && "$INPUT_CACHE_PRESSURE" -le 1000 ]]; then if [[ "$INPUT" =~ ^[0-9]+$ && "$INPUT" -ge 1 && "$INPUT" -le 1000 ]]; then CACHE_PRESSURE=$INPUT; break; fi
CACHE_PRESSURE=$INPUT_CACHE_PRESSURE print_error "Invalid value (1-1000)."
break
else
print_error "Invalid value for vm.vfs_cache_pressure. Must be between 1 and 1000."
fi
done done
else else
print_info "Using default swap settings (vm.swappiness=$SWAPPINESS, vm.vfs_cache_pressure=$CACHE_PRESSURE)." print_info "Using default swap settings (vm.swappiness=$SWAPPINESS, vm.vfs_cache_pressure=$CACHE_PRESSURE)."
fi fi
local NEW_SWAP_CONFIG local NEW_SWAP_CONFIG
NEW_SWAP_CONFIG=$(mktemp) NEW_SWAP_CONFIG=$(mktemp)
tee "$NEW_SWAP_CONFIG" > /dev/null <<EOF tee "$NEW_SWAP_CONFIG" > /dev/null <<EOF
vm.swappiness=$SWAPPINESS vm.swappiness=$SWAPPINESS
vm.vfs_cache_pressure=$CACHE_PRESSURE vm.vfs_cache_pressure=$CACHE_PRESSURE
EOF EOF
# Check if sysctl settings are already correct to prevent duplicates
if [[ -f /etc/sysctl.d/99-swap.conf ]] && cmp -s "$NEW_SWAP_CONFIG" /etc/sysctl.d/99-swap.conf; then if [[ -f /etc/sysctl.d/99-swap.conf ]] && cmp -s "$NEW_SWAP_CONFIG" /etc/sysctl.d/99-swap.conf; then
print_info "Swap settings already correct in /etc/sysctl.d/99-swap.conf. Skipping." print_info "Swap settings already correct. Skipping."
rm -f "$NEW_SWAP_CONFIG" rm -f "$NEW_SWAP_CONFIG"
else else
# Check for conflicting settings in /etc/sysctl.conf or other sysctl files # Scan for conflicts
local sysctl_conflicts=false
for file in /etc/sysctl.conf /etc/sysctl.d/*.conf; do for file in /etc/sysctl.conf /etc/sysctl.d/*.conf; do
if [[ -f "$file" && "$file" != "/etc/sysctl.d/99-swap.conf" ]]; then [[ -f "$file" && "$file" != "/etc/sysctl.d/99-swap.conf" ]] && \
if grep -E '^(vm\.swappiness|vm\.vfs_cache_pressure)=' "$file" >/dev/null; then grep -E '^(vm\.swappiness|vm\.vfs_cache_pressure)=' "$file" >/dev/null && \
print_warning "Existing swap settings found in $file. Manual review recommended." print_warning "Note: Duplicate swap settings found in $file."
sysctl_conflicts=true
fi
fi
done done
mv "$NEW_SWAP_CONFIG" /etc/sysctl.d/99-swap.conf mv "$NEW_SWAP_CONFIG" /etc/sysctl.d/99-swap.conf
chmod 644 /etc/sysctl.d/99-swap.conf chmod 644 /etc/sysctl.d/99-swap.conf
sysctl -p /etc/sysctl.d/99-swap.conf >/dev/null sysctl -p /etc/sysctl.d/99-swap.conf >/dev/null
if [[ $sysctl_conflicts == true ]]; then print_success "Swap settings applied to /etc/sysctl.d/99-swap.conf."
print_warning "Potential conflicting sysctl settings detected. Verify with 'sysctl -a | grep -E \"vm\.swappiness|vm\.vfs_cache_pressure\"'."
else
print_success "Swap settings applied to /etc/sysctl.d/99-swap.conf."
fi
fi fi
print_success "Swap configured successfully."
swapon --show | tee -a "$LOG_FILE" swapon --show | tee -a "$LOG_FILE"
free -h | tee -a "$LOG_FILE" free -h | tee -a "$LOG_FILE"
log "Swap configuration completed." log "Swap configuration completed."
} }
# Helper: Convert size (e.g., 2G) to MB for dd count
convert_to_mb() {
local size="$1"
local num="${size%[MGmg]}"
local unit="${size: -1}"
case "${unit^^}" in
G) echo "$((num * 1024))" ;;
M) echo "$num" ;;
*) echo "1024" ;; # Default to 1GB if parsing fails
esac
}
configure_time_sync() { configure_time_sync() {
print_section "Time Synchronization" print_section "Time Synchronization"
print_info "Ensuring chrony is active..." print_info "Ensuring chrony is active..."