Fix critical bugs and add domain-by-domain batch analyzer
- Fix line 63 in php-analyzer.sh: Add default value for count variable (integer comparison error) - Fix line 655 in php-analyzer.sh: Add default value for memory_error_count (integer comparison error) - Fix line 396 in php-scanner.sh: Replace unsafe eval with safe getent passwd lookup - Add php-ui.sh: User interface and menu system (18KB, 25+ functions) - Add php-scanner.sh: Server enumeration system (17KB, 18 functions) - Add php-action-executor.sh: Optimization execution system (17KB, 20 functions) - Add php-server-manager.sh: Orchestration framework (21KB, 7 functions) - Add php-fpm-batch-analyzer.sh: One-shot diagnostic script showing current vs recommended max_children, memory impact, and optimization potential - Add comprehensive test suite (24 tests) These fixes resolve "integer expression expected" errors during domain analysis. Batch analyzer enables users to see domain-by-domain optimization opportunities before applying changes. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Executable
+541
@@ -0,0 +1,541 @@
|
||||
#!/bin/bash
|
||||
# PHP-FPM Server Manager Module
|
||||
# Orchestrates large-scale server operations: scanning, planning, executing, reporting
|
||||
# Part of PHP Optimizer - Phase 3 Refactoring
|
||||
|
||||
# ============================================================================
|
||||
# SERVER SCANNING & INVENTORY
|
||||
# ============================================================================
|
||||
|
||||
# Scan entire server and collect comprehensive information
|
||||
scan_entire_server() {
|
||||
local filter_mode="${1:-all}" # all, user, pattern, traffic, needs_optimization
|
||||
local filter_arg="${2:-}"
|
||||
|
||||
init_change_tracking
|
||||
|
||||
local -a domains_to_analyze
|
||||
|
||||
case "$filter_mode" in
|
||||
all)
|
||||
mapfile -t domains_to_analyze < <(enumerate_all_domains)
|
||||
;;
|
||||
user)
|
||||
[ -z "$filter_arg" ] && return 1
|
||||
mapfile -t domains_to_analyze < <(enumerate_user_domains "$filter_arg")
|
||||
;;
|
||||
pattern)
|
||||
[ -z "$filter_arg" ] && return 1
|
||||
mapfile -t domains_to_analyze < <(filter_domains_by_name "$filter_arg")
|
||||
;;
|
||||
traffic)
|
||||
[ -z "$filter_arg" ] && filter_arg="100"
|
||||
mapfile -t domains_to_analyze < <(filter_domains_by_traffic "$filter_arg" "above")
|
||||
;;
|
||||
needs_optimization)
|
||||
mapfile -t domains_to_analyze < <(filter_domains_by_optimization_status "needs_optimization")
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
local total_domains=${#domains_to_analyze[@]}
|
||||
local current=0
|
||||
local -A scan_results
|
||||
|
||||
if [ "$total_domains" -eq 0 ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
for domain in "${domains_to_analyze[@]}"; do
|
||||
[ -z "$domain" ] && continue
|
||||
|
||||
current=$((current + 1))
|
||||
show_enumeration_progress "$current" "$total_domains"
|
||||
|
||||
# Collect domain info
|
||||
local owner
|
||||
owner=$(find_domain_owner "$domain")
|
||||
|
||||
local issues
|
||||
issues=$(detect_php_config_issues "$owner" "$domain" 2>/dev/null || echo "")
|
||||
|
||||
local issue_count
|
||||
issue_count=$(echo "$issues" | grep -c "^" || echo "0")
|
||||
|
||||
scan_results["$domain"]="$owner|$issue_count|$issues"
|
||||
done
|
||||
|
||||
echo ""
|
||||
|
||||
# Output results in scannable format
|
||||
for domain in "${!scan_results[@]}"; do
|
||||
echo "DOMAIN|$domain|${scan_results[$domain]}"
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Analyze entire server for optimization opportunities
|
||||
analyze_entire_server() {
|
||||
local -a all_domains
|
||||
|
||||
mapfile -t all_domains < <(enumerate_all_domains)
|
||||
|
||||
local total_domains=${#all_domains[@]}
|
||||
local domains_with_issues=0
|
||||
local critical_count=0
|
||||
local high_count=0
|
||||
local medium_count=0
|
||||
local low_count=0
|
||||
|
||||
local current=0
|
||||
|
||||
for domain in "${all_domains[@]}"; do
|
||||
[ -z "$domain" ] && continue
|
||||
|
||||
current=$((current + 1))
|
||||
display_progress "$current" "$total_domains" "Analyzing"
|
||||
|
||||
local owner
|
||||
owner=$(find_domain_owner "$domain")
|
||||
|
||||
if [ -z "$owner" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Detect issues
|
||||
local issues
|
||||
issues=$(detect_php_config_issues "$owner" "$domain" 2>/dev/null)
|
||||
|
||||
# Count issues by severity
|
||||
local c_count h_count m_count l_count
|
||||
c_count=$(echo "$issues" | grep -c "^[^|]*|CRITICAL|" || echo "0")
|
||||
h_count=$(echo "$issues" | grep -c "^[^|]*|HIGH|" || echo "0")
|
||||
m_count=$(echo "$issues" | grep -c "^[^|]*|MEDIUM|" || echo "0")
|
||||
l_count=$(echo "$issues" | grep -c "^[^|]*|LOW|" || echo "0")
|
||||
|
||||
if [ $((c_count + h_count + m_count + l_count)) -gt 0 ]; then
|
||||
domains_with_issues=$((domains_with_issues + 1))
|
||||
critical_count=$((critical_count + c_count))
|
||||
high_count=$((high_count + h_count))
|
||||
medium_count=$((medium_count + m_count))
|
||||
low_count=$((low_count + l_count))
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "$total_domains|$domains_with_issues|$critical_count|$high_count|$medium_count|$low_count"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# OPTIMIZATION PLANNING
|
||||
# ============================================================================
|
||||
|
||||
# Plan optimizations for entire server
|
||||
plan_server_optimizations() {
|
||||
local filter_mode="${1:-needs_optimization}"
|
||||
local filter_arg="${2:-}"
|
||||
local dry_run="${3:-true}"
|
||||
|
||||
local -a domains_to_optimize
|
||||
mapfile -t domains_to_optimize < <(scan_entire_server "$filter_mode" "$filter_arg")
|
||||
|
||||
local total_domains=0
|
||||
local optimization_count=0
|
||||
|
||||
# Parse scan results and identify optimization opportunities
|
||||
declare -A optimization_plan
|
||||
|
||||
while IFS='|' read -r type domain owner issue_count rest; do
|
||||
[ "$type" != "DOMAIN" ] && continue
|
||||
[ -z "$domain" ] && continue
|
||||
|
||||
total_domains=$((total_domains + 1))
|
||||
|
||||
if [ "$issue_count" -gt 0 ]; then
|
||||
optimization_count=$((optimization_count + 1))
|
||||
optimization_plan["$domain"]="$owner|$issue_count"
|
||||
fi
|
||||
done <<< "$(echo "${domains_to_optimize[@]}" | tr ' ' '\n')"
|
||||
|
||||
# Generate plan summary
|
||||
echo "OPTIMIZATION_PLAN"
|
||||
echo "Total domains: $total_domains"
|
||||
echo "Domains needing optimization: $optimization_count"
|
||||
echo ""
|
||||
|
||||
# List domains to be optimized
|
||||
for domain in "${!optimization_plan[@]}"; do
|
||||
local owner issue_count
|
||||
owner=$(echo "${optimization_plan[$domain]}" | cut -d'|' -f1)
|
||||
issue_count=$(echo "${optimization_plan[$domain]}" | cut -d'|' -f2)
|
||||
echo " - $domain (owner: $owner, $issue_count issues)"
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# OPTIMIZATION EXECUTION
|
||||
# ============================================================================
|
||||
|
||||
# Execute planned optimizations across server
|
||||
execute_server_optimization_plan() {
|
||||
local -a domains=("$@")
|
||||
local dry_run="${DRY_RUN:-false}"
|
||||
local require_confirmation="${REQUIRE_CONFIRMATION:-true}"
|
||||
|
||||
if [ ${#domains[@]} -eq 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Show summary before executing
|
||||
local total=${#domains[@]}
|
||||
echo ""
|
||||
echo "Server Optimization Summary:"
|
||||
echo " Total domains to optimize: $total"
|
||||
echo " Dry-run mode: $dry_run"
|
||||
echo ""
|
||||
|
||||
if [ "$require_confirmation" = "true" ]; then
|
||||
if ! confirm "Execute optimizations for $total domain(s)?"; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
init_change_tracking
|
||||
|
||||
local successful=0
|
||||
local failed=0
|
||||
local current=0
|
||||
|
||||
for domain in "${domains[@]}"; do
|
||||
[ -z "$domain" ] && continue
|
||||
|
||||
current=$((current + 1))
|
||||
display_progress "$current" "$total" "Optimizing"
|
||||
|
||||
local owner
|
||||
owner=$(find_domain_owner "$domain")
|
||||
|
||||
if [ -z "$owner" ]; then
|
||||
failed=$((failed + 1))
|
||||
log_change "$domain" "server_optimization" "unknown_owner" "skipped" "failed"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Apply optimizations
|
||||
if apply_optimization "$domain" "$owner" "all" "$dry_run"; then
|
||||
successful=$((successful + 1))
|
||||
else
|
||||
failed=$((failed + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Optimization Results:"
|
||||
echo " Successful: $successful"
|
||||
echo " Failed: $failed"
|
||||
echo " Total: $((successful + failed))"
|
||||
|
||||
# Reload PHP-FPM once for all changes
|
||||
if [ "$dry_run" != "true" ] && [ "$successful" -gt 0 ]; then
|
||||
echo "Reloading PHP-FPM to apply changes..."
|
||||
reload_php_fpm
|
||||
fi
|
||||
|
||||
return $((failed > 0 ? 1 : 0))
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# REPORTING
|
||||
# ============================================================================
|
||||
|
||||
# Generate comprehensive server analysis report
|
||||
generate_server_report() {
|
||||
local report_file="${1:-/tmp/php-optimizer-server-report-$(date +%Y%m%d-%H%M%S).txt}"
|
||||
local filter_mode="${2:-all}"
|
||||
local filter_arg="${3:-}"
|
||||
|
||||
{
|
||||
echo "╔════════════════════════════════════════════════════════════════════════╗"
|
||||
echo "║ PHP-FPM SERVER ANALYSIS REPORT ║"
|
||||
echo "╚════════════════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo "Generated: $(date)"
|
||||
echo ""
|
||||
|
||||
# Server Information
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo "SERVER INFORMATION"
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
echo "Total RAM: $(free -h | awk '/^Mem:/ {print $2}')"
|
||||
echo "CPU Cores: $(nproc)"
|
||||
echo "Total Accounts: $(get_total_account_count)"
|
||||
echo "Total Domains: $(get_total_domain_count)"
|
||||
echo ""
|
||||
|
||||
# Analysis Results
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo "ANALYSIS RESULTS"
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
local analysis_result
|
||||
analysis_result=$(analyze_entire_server)
|
||||
|
||||
local total_domains domains_with_issues critical high medium low
|
||||
total_domains=$(echo "$analysis_result" | cut -d'|' -f1)
|
||||
domains_with_issues=$(echo "$analysis_result" | cut -d'|' -f2)
|
||||
critical=$(echo "$analysis_result" | cut -d'|' -f3)
|
||||
high=$(echo "$analysis_result" | cut -d'|' -f4)
|
||||
medium=$(echo "$analysis_result" | cut -d'|' -f5)
|
||||
low=$(echo "$analysis_result" | cut -d'|' -f6)
|
||||
|
||||
echo "Total Domains Analyzed: $total_domains"
|
||||
echo "Domains with Issues: $domains_with_issues"
|
||||
echo ""
|
||||
echo "Issue Summary:"
|
||||
echo " CRITICAL: $critical"
|
||||
echo " HIGH: $high"
|
||||
echo " MEDIUM: $medium"
|
||||
echo " LOW: $low"
|
||||
echo ""
|
||||
|
||||
# Health Status
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo "SERVER HEALTH STATUS"
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
local capacity_result
|
||||
capacity_result=$(calculate_server_memory_capacity 2>/dev/null)
|
||||
|
||||
local total_required_mb total_ram_mb percentage status
|
||||
total_required_mb=$(echo "$capacity_result" | head -1 | cut -d'|' -f1)
|
||||
total_ram_mb=$(echo "$capacity_result" | head -1 | cut -d'|' -f2)
|
||||
percentage=$(echo "$capacity_result" | head -1 | cut -d'|' -f3)
|
||||
status=$(echo "$capacity_result" | head -1 | cut -d'|' -f4)
|
||||
|
||||
echo "Total Server RAM: ${total_ram_mb}MB"
|
||||
echo "Current FPM Capacity: ${total_required_mb}MB (${percentage}% of RAM)"
|
||||
echo "Server Status: $status"
|
||||
echo ""
|
||||
|
||||
# Recommendations
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo "RECOMMENDATIONS"
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
if [ "$domains_with_issues" -gt 0 ]; then
|
||||
echo "1. Apply recommended optimizations to $domains_with_issues domain(s)"
|
||||
if [ "$critical" -gt 0 ]; then
|
||||
echo " - URGENT: Address $critical CRITICAL issue(s)"
|
||||
fi
|
||||
if [ "$high" -gt 0 ]; then
|
||||
echo " - HIGH PRIORITY: Address $high HIGH severity issue(s)"
|
||||
fi
|
||||
else
|
||||
echo "No issues detected - server configuration is optimal"
|
||||
fi
|
||||
|
||||
case "$status" in
|
||||
CRITICAL)
|
||||
echo "2. URGENT: Review memory allocation - server at OOM risk!"
|
||||
;;
|
||||
WARNING)
|
||||
echo "2. Review memory allocation - consider reducing max_children"
|
||||
;;
|
||||
CAUTION)
|
||||
echo "2. Monitor memory usage - consider minor adjustments"
|
||||
;;
|
||||
HEALTHY)
|
||||
echo "2. Continue monitoring - no immediate action needed"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
|
||||
# Change History (if available)
|
||||
if [ -n "$EXECUTOR_CHANGE_LOG" ] && [ -f "$EXECUTOR_CHANGE_LOG" ]; then
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo "RECENT CHANGES"
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
tail -20 "$EXECUTOR_CHANGE_LOG"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Footer
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo "Report generated by PHP-FPM Optimizer - Phase 3"
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
|
||||
} | tee "$report_file"
|
||||
|
||||
echo ""
|
||||
echo "Report saved to: $report_file"
|
||||
}
|
||||
|
||||
# Generate domain-specific report
|
||||
generate_domain_report() {
|
||||
local domain="$1"
|
||||
local report_file="${2:-/tmp/php-optimizer-${domain}-report-$(date +%Y%m%d-%H%M%S).txt}"
|
||||
|
||||
local owner
|
||||
owner=$(find_domain_owner "$domain")
|
||||
|
||||
if [ -z "$owner" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
{
|
||||
echo "╔════════════════════════════════════════════════════════════════════════╗"
|
||||
echo "║ PHP-FPM DOMAIN ANALYSIS REPORT ║"
|
||||
echo "╚════════════════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo "Domain: $domain"
|
||||
echo "Owner: $owner"
|
||||
echo "Generated: $(date)"
|
||||
echo ""
|
||||
|
||||
# Domain Information
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo "DOMAIN INFORMATION"
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
local pool_config
|
||||
pool_config=$(find_fpm_pool_config "$owner" "$domain" 2>/dev/null)
|
||||
|
||||
if [ -n "$pool_config" ]; then
|
||||
echo "Pool Config: $pool_config"
|
||||
echo ""
|
||||
echo "Current Settings:"
|
||||
grep "^pm" "$pool_config" | sed 's/^/ /'
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Analysis
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo "ANALYSIS"
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
local issues
|
||||
issues=$(detect_php_config_issues "$owner" "$domain" 2>/dev/null)
|
||||
|
||||
if [ -z "$issues" ] || [ "$(echo "$issues" | wc -l)" -eq 0 ]; then
|
||||
echo "No issues detected - configuration is optimal"
|
||||
else
|
||||
echo "Issues Found:"
|
||||
echo ""
|
||||
while IFS='|' read -r issue_type severity message recommendation; do
|
||||
[ -z "$issue_type" ] && continue
|
||||
echo "[$severity] $message"
|
||||
echo " → $recommendation"
|
||||
echo ""
|
||||
done <<< "$issues"
|
||||
fi
|
||||
|
||||
# Recommendations
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo "RECOMMENDATIONS"
|
||||
echo "═══════════════════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
local total_ram_mb
|
||||
total_ram_mb=$(free -m | awk '/^Mem:/ {print $2}')
|
||||
|
||||
local improved_result
|
||||
improved_result=$(calculate_optimal_php_settings "$owner" "$total_ram_mb" 2>/dev/null)
|
||||
|
||||
if [ -n "$improved_result" ]; then
|
||||
local improved_max_children improved_pm_mode improved_reason
|
||||
improved_max_children=$(echo "$improved_result" | cut -d'|' -f1)
|
||||
improved_pm_mode=$(echo "$improved_result" | cut -d'|' -f2)
|
||||
improved_reason=$(echo "$improved_result" | cut -d'|' -f5)
|
||||
|
||||
echo "Recommended pm.max_children: $improved_max_children"
|
||||
echo "Recommended pm mode: $improved_pm_mode"
|
||||
echo "Reason: $improved_reason"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
} | tee "$report_file"
|
||||
|
||||
echo "Report saved to: $report_file"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# BATCH OPERATIONS
|
||||
# ============================================================================
|
||||
|
||||
# Perform batch operation on multiple domains
|
||||
batch_operation() {
|
||||
local operation="$1" # optimize, analyze, health_check
|
||||
local filter_mode="${2:-needs_optimization}"
|
||||
local filter_arg="${3:-}"
|
||||
local require_confirmation="${4:-true}"
|
||||
|
||||
local -a target_domains
|
||||
mapfile -t target_domains < <(scan_entire_server "$filter_mode" "$filter_arg")
|
||||
|
||||
case "$operation" in
|
||||
optimize)
|
||||
echo "Planning server-wide optimization..."
|
||||
plan_server_optimizations "$filter_mode" "$filter_arg"
|
||||
|
||||
if [ "$require_confirmation" = "true" ]; then
|
||||
if ! confirm "Execute optimizations?"; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
execute_server_optimization_plan "${target_domains[@]}"
|
||||
;;
|
||||
analyze)
|
||||
echo "Analyzing entire server..."
|
||||
analyze_entire_server
|
||||
;;
|
||||
health_check)
|
||||
echo "Performing health check on all domains..."
|
||||
init_change_tracking
|
||||
|
||||
local total=${#target_domains[@]}
|
||||
local current=0
|
||||
|
||||
for domain in "${target_domains[@]}"; do
|
||||
[ -z "$domain" ] && continue
|
||||
|
||||
current=$((current + 1))
|
||||
display_progress "$current" "$total"
|
||||
|
||||
local owner
|
||||
owner=$(find_domain_owner "$domain")
|
||||
[ -n "$owner" ] && perform_health_check "$owner" "$domain" >/dev/null 2>&1
|
||||
done
|
||||
|
||||
echo ""
|
||||
;;
|
||||
esac
|
||||
|
||||
return $?
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# EXPORT ALL FUNCTIONS
|
||||
# ============================================================================
|
||||
|
||||
export -f scan_entire_server
|
||||
export -f analyze_entire_server
|
||||
export -f plan_server_optimizations
|
||||
export -f execute_server_optimization_plan
|
||||
export -f generate_server_report
|
||||
export -f generate_domain_report
|
||||
export -f batch_operation
|
||||
Reference in New Issue
Block a user