From 03221476cde7f4b83245d81b2c7c02fc90000a1d Mon Sep 17 00:00:00 2001 From: cschantz Date: Tue, 17 Feb 2026 23:06:08 -0500 Subject: [PATCH] Implement batch operations to select and optimize multiple domains at once - Add batch operation option to Option 4 - Allow user to select single domain or multiple domains - Display optimization status [NEEDS OPTIMIZATION] or [OK] for each domain - Support 'all' selection or individual number selection - Optimizes selected domains in sequence - Shows progress and summary of batch operation - Includes simplified per-domain optimization for batch mode - Provides fallback if recommendations can't be calculated Co-Authored-By: Claude Haiku 4.5 --- modules/performance/php-optimizer.sh | 232 +++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) diff --git a/modules/performance/php-optimizer.sh b/modules/performance/php-optimizer.sh index ee4a948..525bd55 100755 --- a/modules/performance/php-optimizer.sh +++ b/modules/performance/php-optimizer.sh @@ -309,6 +309,37 @@ quick_health_check() { optimize_domain() { show_banner + cecho "${WHITE}${BOLD}DOMAIN OPTIMIZATION${NC}" + echo "" + cecho " ${GREEN}s${NC}) Optimize single domain" + cecho " ${GREEN}m${NC}) Optimize multiple domains (batch)" + cecho " ${RED}q${NC}) Cancel" + echo "" + cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}" + + read -p "Select option: " batch_choice + + case "${batch_choice,,}" in + s) + optimize_single_domain_wrapper + ;; + m) + optimize_multiple_domains_wrapper + ;; + q) + return + ;; + *) + cecho "${RED}Invalid selection${NC}" + read -p "Press Enter to continue..." + return + ;; + esac +} + +optimize_single_domain_wrapper() { + show_banner + local selection selection=$(select_domain "optimize") @@ -770,6 +801,207 @@ optimize_domain() { read -p "Press Enter to continue..." } +optimize_multiple_domains_wrapper() { + show_banner + cecho "${WHITE}${BOLD}SELECT DOMAINS TO OPTIMIZE${NC}" + echo "" + cecho "${YELLOW}Batch operation: Optimize multiple domains in sequence${NC}" + echo "" + + # Get all users with domains + local users + users=$(list_all_users) + + if [ -z "$users" ]; then + cecho "${RED}ERROR: No users found on system${NC}" + read -p "Press Enter to continue..." + return + fi + + # Build domain list with optimization status + declare -a domains + declare -A domain_to_user + + while IFS= read -r username; do + local user_domains + user_domains=$(get_user_domains "$username") + + while IFS= read -r domain; do + [ -z "$domain" ] && continue + domains+=("$domain") + domain_to_user["$domain"]="$username" + done <<< "$user_domains" + done <<< "$users" + + if [ ${#domains[@]} -eq 0 ]; then + cecho "${RED}ERROR: No domains found on system${NC}" + read -p "Press Enter to continue..." + return + fi + + # Display numbered list with optimization status + cecho "${CYAN}Available domains (select ones to optimize):${NC}" + echo "" + + local index=1 + for domain in "${domains[@]}"; do + local username="${domain_to_user[$domain]}" + local issues + issues=$(detect_php_config_issues "$username" "$domain" 2>/dev/null || echo "NONE|NONE|None") + local has_high_issues + has_high_issues=$(echo "$issues" | grep -cE "^[^|]*\|(CRITICAL|HIGH)\|" 2>/dev/null || echo "0") + + local status_indicator="" + if [ "$has_high_issues" -gt 0 ]; then + status_indicator="${YELLOW}[NEEDS OPTIMIZATION]${NC}" + else + status_indicator="${GREEN}[OK]${NC}" + fi + + printf " ${GREEN}%-3d${NC}) %-40s ${CYAN}[${username}]${NC} %s\n" "$index" "$domain" "$(echo -e "$status_indicator")" + index=$((index + 1)) + done + + echo "" + cecho "${CYAN}Enter numbers separated by spaces (e.g., '1 3 5') or 'all' for all domains, 'none' to cancel${NC}" + cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}" + read -p "Selection: " user_selection + + # Parse selection + user_selection=$(echo "$user_selection" | tr '[:upper:]' '[:lower:]') + + declare -a selected_domains + + if [[ "$user_selection" == "all" ]]; then + selected_domains=("${domains[@]}") + elif [[ "$user_selection" =~ ^(none|n)$ ]]; then + return + else + # Parse individual numbers + for num in $user_selection; do + if [[ "$num" =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le ${#domains[@]} ]; then + selected_domains+=("${domains[$((num - 1))]}") + fi + done + fi + + if [ ${#selected_domains[@]} -eq 0 ]; then + cecho "${YELLOW}No domains selected${NC}" + read -p "Press Enter to continue..." + return + fi + + # Confirm + echo "" + cecho "${CYAN}Selected ${#selected_domains[@]} domain(s) for optimization${NC}" + if ! confirm "Continue?"; then + return + fi + + # Optimize each selected domain + show_banner + cecho "${WHITE}${BOLD}BATCH OPTIMIZATION IN PROGRESS${NC}" + echo "" + + local optimized=0 + local failed=0 + + for domain in "${selected_domains[@]}"; do + local username="${domain_to_user[$domain]}" + + cecho "${CYAN}Optimizing: ${WHITE}$domain${NC} ${CYAN}[$username]${NC}" + + # Run single domain optimization (simplified) + optimize_domain_direct "$domain" "$username" + local result=$? + + if [ $result -eq 0 ]; then + optimized=$((optimized + 1)) + else + failed=$((failed + 1)) + fi + + echo "" + done + + # Display summary + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + cecho "${WHITE}${BOLD}BATCH OPTIMIZATION COMPLETE${NC}" + cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}" + cecho " Successfully optimized: ${GREEN}$optimized${NC}" + if [ "$failed" -gt 0 ]; then + cecho " Failed: ${RED}$failed${NC}" + fi + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + echo "" + read -p "Press Enter to continue..." +} + +optimize_domain_direct() { + local domain="$1" + local username="$2" + + # Detect issues + local issues + issues=$(detect_php_config_issues "$username" "$domain" 2>/dev/null || echo "") + + # Check if there are issues + local critical_high_count + critical_high_count=$(echo "$issues" | grep -cE "^[^|]*\|(CRITICAL|HIGH)\|" 2>/dev/null || echo "0") + + if [ "$critical_high_count" -eq 0 ]; then + cecho " ${GREEN}✓ No optimization needed${NC}" + return 0 + fi + + # Get pool config + local pool_config + pool_config=$(find_fpm_pool_config "$username" "$domain" 2>/dev/null) + + if [ -z "$pool_config" ] || [ ! -f "$pool_config" ]; then + cecho " ${YELLOW}⊘ No pool config found - skipping${NC}" + return 1 + fi + + # Get recommendations + local total_ram_mb + total_ram_mb=$(free -m | awk '/^Mem:/ {print $2}') + + local improved_result + improved_result=$(calculate_optimal_php_settings "$username" "$total_ram_mb" 2>/dev/null || echo "") + + if [ -z "$improved_result" ]; then + cecho " ${YELLOW}⊘ Could not calculate recommendations - skipping${NC}" + return 1 + fi + + local improved_max=$(get_field "$improved_result" 1) + local current_max=$(grep "^pm.max_children" "$pool_config" 2>/dev/null | awk -F'=' '{print $2}' | tr -d ' ') + + if [ -z "$current_max" ] || [ -z "$improved_max" ] || [ "$current_max" = "$improved_max" ]; then + cecho " ${GREEN}✓ Already optimized${NC}" + return 0 + fi + + # Create backup + local backup_dir + backup_dir=$(backup_user_php_configs "$username" "$domain" 2>&1) + + if [ $? -ne 0 ]; then + cecho " ${RED}✗ Backup failed - skipping${NC}" + return 1 + fi + + # Apply optimization + if modify_fpm_pool_setting "$pool_config" "pm.max_children" "$improved_max" >/dev/null 2>&1; then + cecho " ${GREEN}✓ Updated max_children: $current_max → $improved_max${NC}" + return 0 + else + cecho " ${RED}✗ Optimization failed${NC}" + return 1 + fi +} + # ============================================================================ # OPTIMIZE ALL DOMAINS (SERVER-WIDE) # ============================================================================