#!/usr/bin/env bash
# =============================================================================
#  start-apache.sh - install (offline) and start the Apache httpd daemon
#                    on RHEL 9.6, ready for performance testing
# =============================================================================
#
#  USAGE (as root)
#      ./start-apache.sh            install if needed, configure, start
#      ./start-apache.sh start      same as above
#      ./start-apache.sh stop       stop the httpd daemon
#      ./start-apache.sh restart    stop, then start again
#      ./start-apache.sh status     show whether Apache is running
#      ./start-apache.sh cleanup    remove test pages and test config
#
#  WHAT "start" DOES, STEP BY STEP
#      1. Checks the operating system (RHEL 9 expected).
#      2. Installs httpd + httpd-tools if missing, WITHOUT internet:
#           a) from RPM files in ./rpms/  (see download-rpms.sh), or
#           b) from a local dnf repository already set up on the host
#              (for example the mounted RHEL 9.6 DVD / ISO).
#      3. Creates small test web pages in /var/www/html/perf-test/.
#      4. Writes one extra config file, /etc/httpd/conf.d/zz-perf-test.conf
#         (status page + worker settings from settings.conf).
#      5. Checks the configuration with "httpd -t".
#      6. Starts the daemon with systemd (systemctl), then waits until the
#         first page is served.
#
#  Nothing else in /etc/httpd is changed. "cleanup" undoes steps 3 and 4.
# =============================================================================

set -euo pipefail
source "$(dirname -- "${BASH_SOURCE[0]}")/lib/common.sh"


# ----------------------------------------------------------------------------
#  Step 1 - operating system check
# ----------------------------------------------------------------------------
check_operating_system() {
    # /etc/os-release defines NAME, VERSION_ID, ...
    source /etc/os-release

    if [[ ${VERSION_ID%%.*} != 9 ]]; then
        die "This kit is made for RHEL 9. Found: $PRETTY_NAME"
    fi
    if [[ $ID != rhel || $VERSION_ID != 9.6 ]]; then
        warn "Target is RHEL 9.6; this host is '$PRETTY_NAME'. Continuing."
    fi
    log "Operating system: $PRETTY_NAME"
}


# ----------------------------------------------------------------------------
#  Step 2 - install Apache without internet access
# ----------------------------------------------------------------------------
install_apache_offline() {
    if rpm -q httpd httpd-tools >/dev/null 2>&1; then
        log "Apache is already installed: $(rpm -q httpd)"
        return
    fi

    local rpm_dir="$KIT_DIR/rpms"

    if compgen -G "$rpm_dir/*.rpm" >/dev/null; then
        # a) RPM files shipped next to this script. All other repositories
        #    are disabled so dnf never tries to reach the internet.
        log "Installing Apache from RPM files in $rpm_dir"
        dnf install -y --disablerepo='*' "$rpm_dir"/*.rpm
    else
        # b) A local repository already configured on this host (RHEL DVD).
        log "Installing Apache from the local dnf repositories"
        if ! dnf install -y httpd httpd-tools; then
            die "Could not install Apache offline.
       Either copy RPMs into $rpm_dir (see download-rpms.sh),
       or mount the RHEL 9.6 DVD and configure it as a local repository."
        fi
    fi
    ok "Installed $(rpm -q httpd) and $(rpm -q httpd-tools)"
}


# ----------------------------------------------------------------------------
#  Step 3 - test web pages
# ----------------------------------------------------------------------------
create_test_content() {
    log "Creating test pages in $TEST_CONTENT_DIR"
    mkdir -p "$TEST_CONTENT_DIR"

    # Health page: start/test scripts read it to know Apache is really serving.
    echo "apache-perf-test-ok" > "$TEST_CONTENT_DIR/health.txt"

    # 1 KB HTML page - a typical small request (throughput / latency tests).
    {
        echo "<html><head><title>perf test</title></head><body><pre>"
        head -c 700 /dev/zero | tr '\0' 'x' | fold -w 70
        echo "</pre></body></html>"
    } > "$TEST_CONTENT_DIR/small.html"

    # 1 MB binary file - a download (transfer-rate test).
    head -c 1048576 /dev/urandom > "$TEST_CONTENT_DIR/large.bin"

    chmod 755 "$TEST_CONTENT_DIR"
    chmod 644 "$TEST_CONTENT_DIR"/*

    # Give the files the SELinux label Apache is allowed to read.
    if command -v restorecon >/dev/null; then
        restorecon -R "$TEST_CONTENT_DIR"
    fi
}


# ----------------------------------------------------------------------------
#  Step 4 - Apache configuration for the test
# ----------------------------------------------------------------------------
write_test_config() {
    if (( MAX_REQUEST_WORKERS > SERVER_LIMIT * THREADS_PER_CHILD )); then
        die "settings.conf: MAX_REQUEST_WORKERS ($MAX_REQUEST_WORKERS) must be <= SERVER_LIMIT x THREADS_PER_CHILD ($(( SERVER_LIMIT * THREADS_PER_CHILD )))"
    fi

    log "Writing $DROPIN_CONF"
    cat > "$DROPIN_CONF" <<EOF
# =============================================================================
#  Created by $KIT_DIR/start-apache.sh
#  Values come from settings.conf. Delete this file to undo the changes.
# =============================================================================

# --- Status page, used by the test to count busy / idle workers -------------
ExtendedStatus On
<Location "/server-status">
    SetHandler server-status
    Require local
</Location>

# --- Test pages are only reachable from this machine -------------------------
<Directory "$TEST_CONTENT_DIR">
    Require local
</Directory>

# --- Keep-alive: reuse one TCP connection for many requests -------------------
KeepAlive            On
KeepAliveTimeout     $KEEPALIVE_TIMEOUT
MaxKeepAliveRequests $MAX_KEEPALIVE_REQUESTS

# --- Worker pool (event MPM, the RHEL 9 default) ------------------------------
<IfModule mpm_event_module>
    ServerLimit         $SERVER_LIMIT
    ThreadsPerChild     $THREADS_PER_CHILD
    MaxRequestWorkers   $MAX_REQUEST_WORKERS
    StartServers        $START_SERVERS
    MinSpareThreads     $MIN_SPARE_THREADS
    MaxSpareThreads     $MAX_SPARE_THREADS
</IfModule>
EOF

    if command -v restorecon >/dev/null; then
        restorecon "$DROPIN_CONF"
    fi
}


# ----------------------------------------------------------------------------
#  Step 5 - configuration check
# ----------------------------------------------------------------------------
check_config() {
    log "Checking Apache configuration (httpd -t)"
    if ! /usr/sbin/httpd -t; then
        die "Apache configuration has errors (see messages above)."
    fi
}


# ----------------------------------------------------------------------------
#  Step 6 - start the daemon
# ----------------------------------------------------------------------------
start_daemon() {
    # A full restart is needed so new worker settings take effect.
    if httpd_is_running; then
        log "Apache is running - restarting it to apply the configuration"
        apache_restart
    else
        log "Starting the Apache daemon"
        apache_start
    fi

    if ! wait_until_serving 30; then
        die "Apache did not answer $HEALTH_URL within 30 s.
       Look at:  journalctl -u httpd   and   /var/log/httpd/error_log"
    fi
}

print_summary() {
    local mpm selinux
    mpm="$(/usr/sbin/httpd -V 2>/dev/null | awk -F': *' '/Server MPM/ {print $2}')"
    selinux="$(getenforce 2>/dev/null || echo 'not available')"

    echo
    ok "Apache is running and serving pages."
    echo "    Version      : $(/usr/sbin/httpd -v | awk -F': ' '/version/ {print $2}')"
    echo "    MPM          : $mpm"
    echo "    Main PID     : $(apache_main_pid)"
    echo "    Test page    : $HEALTH_URL"
    echo "    Status page  : $BASE_URL/server-status"
    echo "    SELinux      : $selinux"
    if has_systemd; then
        echo "    Managed by   : systemd  (systemctl status httpd)"
        echo "    Boot start   : $(systemctl is-enabled httpd 2>/dev/null || true)" \
             "  (to start at every boot: systemctl enable httpd)"
    else
        echo "    Managed by   : httpd -k (no systemd found, e.g. inside a container)"
    fi
    echo
    echo "    Next step    : ./test-apache.sh"
}


# ----------------------------------------------------------------------------
#  Other actions
# ----------------------------------------------------------------------------
show_status() {
    if apache_is_serving; then
        ok "Apache is running (main PID $(apache_main_pid)) and serving $HEALTH_URL"
        curl --noproxy '*' -s "$STATUS_URL" \
            | grep -E '^(ServerVersion|ServerMPM|Uptime|Total Accesses|ReqPerSec|BusyWorkers|IdleWorkers):' \
            | sed 's/^/    /' || true      # the live numbers are extra; never fail on them
    elif httpd_is_running; then
        warn "httpd processes exist, but $HEALTH_URL does not answer. Run: ./start-apache.sh"
        exit 1
    else
        warn "Apache is not running."
        exit 1
    fi
}

cleanup_test_setup() {
    log "Removing $DROPIN_CONF and $TEST_CONTENT_DIR"
    rm -f "$DROPIN_CONF"
    rm -rf "$TEST_CONTENT_DIR"
    if httpd_is_running; then
        apache_restart
        ok "Apache restarted with its original configuration."
    fi
    ok "Cleanup finished."
}


# ----------------------------------------------------------------------------
#  Main
# ----------------------------------------------------------------------------
main() {
    local action="${1:-start}"
    require_root "$@"

    case "$action" in
        start)
            check_operating_system
            install_apache_offline
            create_test_content
            write_test_config
            check_config
            start_daemon
            print_summary
            ;;
        stop)
            apache_stop
            ok "Apache stopped."
            ;;
        restart)
            apache_restart
            wait_until_serving 30 || die "Apache did not come back. See /var/log/httpd/error_log"
            ok "Apache restarted."
            ;;
        status)
            show_status
            ;;
        cleanup)
            cleanup_test_setup
            ;;
        *)
            echo "Usage: $0 [start|stop|restart|status|cleanup]"
            exit 2
            ;;
    esac
}

main "$@"
