#!/usr/bin/env bash
# =============================================================================
# onx-cgroup-fpm-verify — Verify FPM workers are attached to customer slice
#
# Purpose (v86.2):
#   Diagnostic / smoke-test companion to `onx-fpm-slice-rebind`. Reports the
#   FPM worker PIDs for a given user, the cgroup each PID is currently a member
#   of, and a boolean flag whether ALL workers are in the expected slice.
#
#   Admin UI (v86.6) and operators can call this to spot-check rebind health.
#   No mutations — read-only.
#
# Input (stdin JSON):
#   { "username": "onx_xxxx" }
#
# Output (stdout JSON):
#   {
#     "ok": true,
#     "username": "onx_leafport",
#     "expected_cgroup": "/customer.slice/customer-onx_leafport.slice",
#     "fpm_pids": [12345, 12346, 12347],
#     "pid_cgroups": [
#       { "pid": 12345, "cgroup": "/customer.slice/customer-onx_leafport.slice", "in_slice": true,  "exe_pool": "onx_leafport" },
#       { "pid": 12346, "cgroup": "/system.slice/php82-php-fpm.service",         "in_slice": false, "exe_pool": "onx_leafport" },
#       { "pid": 12347, "cgroup": "/customer.slice/customer-onx_leafport.slice", "in_slice": true,  "exe_pool": "onx_leafport" }
#     ],
#     "total_workers": 3,
#     "in_slice_count": 2,
#     "out_of_slice_count": 1,
#     "all_in_customer_slice": false,
#     "slice_present": true,
#     "slice_path": "/sys/fs/cgroup/onoxsoft.slice/customer-onx_leafport.slice"
#   }
#
# Exit codes:
#   0 — read ok (even if all_in_customer_slice=false; verify is informational)
#   1 — invalid input
#   2 — preflight fail (cgroup v2 missing)
#
# Deployed to: /usr/local/onoxsoft/bin/onx-cgroup-fpm-verify
# =============================================================================

set -euo pipefail

SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
# shellcheck source=_lib/common.sh
source "${SCRIPT_DIR}/_lib/common.sh"

command -v jq >/dev/null 2>&1 || { printf '{"error":"jq required"}\n' >&2; exit 2; }
command -v ps >/dev/null 2>&1 || { printf '{"error":"ps required"}\n' >&2; exit 2; }
require_root

# ── Constants ────────────────────────────────────────────────────────────────
readonly ONOXSOFT_SLICE_ROOT="/sys/fs/cgroup/customer.slice"

# ── Read stdin ───────────────────────────────────────────────────────────────
INPUT=$(cat)
onx_require_json "${INPUT}"

USERNAME=$(onx_json_get "${INPUT}" "username")
onx_validate_username "${USERNAME}"

# ── Preflight ────────────────────────────────────────────────────────────────
if [[ ! -d /sys/fs/cgroup || ! -f /sys/fs/cgroup/cgroup.controllers ]]; then
    onx_die 2 "cgroup v2 unified hierarchy not mounted at /sys/fs/cgroup"
fi

SLICE_PATH="${ONOXSOFT_SLICE_ROOT}/customer-${USERNAME}.slice"
EXPECTED_CGROUP="/customer.slice/customer-${USERNAME}.slice"
SLICE_PRESENT="false"
[[ -d "${SLICE_PATH}" ]] && SLICE_PRESENT="true"

# ── Collect FPM worker PIDs ──────────────────────────────────────────────────
# Same matching logic as onx-fpm-slice-rebind for consistency.
PIDS=()
while IFS= read -r line; do
    [[ -z "${line}" ]] && continue
    PIDS+=("${line}")
done < <(ps -eo pid=,user:32=,args= 2>/dev/null | awk -v user="${USERNAME}" \
    '$2 == user && index($0, "php-fpm:") > 0 && index($0, "pool "user) > 0 {print $1}')

# ── Inspect each PID's cgroup membership ─────────────────────────────────────
PID_CGROUPS_JSON='[]'
PIDS_JSON='[]'
IN_SLICE=0
OUT_SLICE=0

for PID in "${PIDS[@]}"; do
    [[ "${PID}" =~ ^[0-9]+$ ]] || continue
    [[ -d "/proc/${PID}" ]] || continue

    CUR_CGROUP=""
    if [[ -r "/proc/${PID}/cgroup" ]]; then
        CUR_CGROUP=$(awk -F: 'NR==1 {print $3}' "/proc/${PID}/cgroup" 2>/dev/null || true)
    fi

    IN_SLICE_FLAG="false"
    if [[ "${CUR_CGROUP}" == "${EXPECTED_CGROUP}" ]]; then
        IN_SLICE_FLAG="true"
        IN_SLICE=$(( IN_SLICE + 1 ))
    else
        OUT_SLICE=$(( OUT_SLICE + 1 ))
    fi

    PID_CGROUPS_JSON=$(echo "${PID_CGROUPS_JSON}" | jq \
        --argjson pid "${PID}" \
        --arg cg "${CUR_CGROUP}" \
        --argjson in "${IN_SLICE_FLAG}" \
        --arg pool "${USERNAME}" \
        '. + [{"pid": $pid, "cgroup": $cg, "in_slice": $in, "exe_pool": $pool}]')

    PIDS_JSON=$(echo "${PIDS_JSON}" | jq --argjson p "${PID}" '. + [$p]')
done

TOTAL=${#PIDS[@]}
ALL_IN_SLICE="false"
if (( TOTAL > 0 && OUT_SLICE == 0 )); then
    ALL_IN_SLICE="true"
fi

onx_log "cgroup-fpm-verify: ${USERNAME} workers=${TOTAL} in_slice=${IN_SLICE} out=${OUT_SLICE} all_ok=${ALL_IN_SLICE}"

# ── Output ───────────────────────────────────────────────────────────────────
jq -n \
    --arg user "${USERNAME}" \
    --arg expected "${EXPECTED_CGROUP}" \
    --argjson pids "${PIDS_JSON}" \
    --argjson pid_cgroups "${PID_CGROUPS_JSON}" \
    --argjson total "${TOTAL}" \
    --argjson in_slice "${IN_SLICE}" \
    --argjson out_slice "${OUT_SLICE}" \
    --argjson all_ok "${ALL_IN_SLICE}" \
    --argjson slice_present "${SLICE_PRESENT}" \
    --arg slice_path "${SLICE_PATH}" \
    '{
        ok: true,
        username: $user,
        expected_cgroup: $expected,
        fpm_pids: $pids,
        pid_cgroups: $pid_cgroups,
        total_workers: $total,
        in_slice_count: $in_slice,
        out_of_slice_count: $out_slice,
        all_in_customer_slice: $all_ok,
        slice_present: $slice_present,
        slice_path: $slice_path
    }'
