#!/bin/bash
# ansipa-checkmk-setup.sh — CheckMK CE integration for the IPA container.
#
# Phase 1 (one-time, guarded by /data/ansipa-checkmk.done):
#   Creates /ansipa folder, IPA monitoring groups, stores CMK credentials.
#
# Phase 2 (runs every invocation after phase 1):
#   Writes push-mode requests for all hosts in dev_mon_base to /cmk-creds/.
#   The CheckMK container polls /cmk-creds/push-mode-*.req and updates hosts.mk.
#   This lets clients in NAT environments push agent data without pull reachability.
#
# Credential format in IPA dev_mon_base description:
#   cmk://<host>:<port>/<site>:automation:<secret>

set -euo pipefail

LOG_TAG="ansipa-checkmk-setup"
DONE_FLAG="/data/ansipa-checkmk.done"
CMK_CREDS_FILE="/cmk-creds/automation.secret"

log()  { echo "[$LOG_TAG] $*"; }
warn() { echo "[$LOG_TAG][WARN] $*" >&2; }

# ── Phase 2: write push-mode requests for enrolled monitoring hosts ───────────
# Runs on EVERY invocation (not guarded by done flag). The CheckMK container
# polls /cmk-creds/push-mode-*.req and adds explicit_host_conf push-agent entries.
_write_push_requests() {
    [[ -d /cmk-creds ]] || return 0
    local _hosts _h
    # `ipa hostgroup-show` prints members on the SAME line as the label
    # ("  Member hosts: a.example, b.example") and wraps long lists onto
    # indented continuation lines. Capture the label line's own value AND any
    # continuation lines, stopping at the next "  Key:" field. (The previous
    # awk did `next` on the label line, discarding the very line that holds the
    # hostnames, so no host was ever extracted and no push request written.)
    _hosts=$(ipa hostgroup-show dev_mon_base --all 2>/dev/null \
        | awk '
            /^  [A-Za-z][A-Za-z0-9 _-]*:/ {
                if ($0 ~ /Member hosts:/) { sub(/.*Member hosts:[[:space:]]*/, ""); p=1; print; next }
                else { p=0 }
            }
            p { print }
        ' \
        | grep -oE '[a-zA-Z0-9._-]+\.[a-zA-Z]{2,}' | sort -u || true)
    [[ -z "$_hosts" ]] && return 0
    while IFS= read -r _h; do
        [[ -z "$_h" ]] && continue
        _req="/cmk-creds/push-mode-${_h}.req"
        [[ -f "$_req" ]] && continue
        echo "$_h" > "$_req" && log "Push-mode request created for ${_h}"
    done <<< "$_hosts"
}

# ── Resolve configuration ──────────────────────────────────────────────────────
# Must run BEFORE the DONE_FLAG early-exit: that path calls _write_push_requests,
# which needs IPA_REALM + IPA_ADMIN_PASS to kinit. Previously these were resolved
# only after the early exit, so every rerun kinit'd with an empty password, failed
# silently, and never wrote push-mode requests — leaving NAT'd clients stuck in
# pull mode (unreachable) forever.
# docker-env.service writes container env to /etc/container.env; source it.
[[ -f /etc/container.env ]] && source /etc/container.env || true

CMK_URL="${CMK_URL:-http://172.30.0.12:5000}"
CMK_SITE="${CMK_SITE_ID:-cmk}"
CMK_API="${CMK_URL}/${CMK_SITE}/check_mk/api/1.0"
IPA_REALM="${IPA_REALM:-}"
IPA_ADMIN_PASS="${IPA_ADMIN_PASSWORD:-}"

# Skip re-initialization but still run push-mode requests if already set up
if [[ -f "$DONE_FLAG" ]]; then
    if [[ -f /etc/ipa/default.conf && -n "$IPA_ADMIN_PASS" && -n "$IPA_REALM" ]]; then
        echo "$IPA_ADMIN_PASS" | kinit "admin@${IPA_REALM}" &>/dev/null \
            && _write_push_requests 2>/dev/null
        kdestroy &>/dev/null || true
    fi
    log "Already configured (delete $DONE_FLAG to force re-initialization)"
    exit 0
fi

if [[ -z "$IPA_REALM" || -z "$IPA_ADMIN_PASS" ]]; then
    warn "IPA_REALM or IPA_ADMIN_PASSWORD not set — cannot configure IPA side"
    exit 1
fi

# ── Wait for IPA to be fully configured ──────────────────────────────────────
if [[ ! -f /etc/ipa/default.conf ]]; then
    warn "IPA not yet configured — waiting for ipa-first-boot to complete"
    exit 1
fi

# ── Wait for CheckMK automation secret (written by checkmk container) ─────────
if [[ ! -f "$CMK_CREDS_FILE" ]]; then
    warn "CheckMK automation secret not yet available at $CMK_CREDS_FILE"
    warn "  (CheckMK container writes it after site init — will retry)"
    exit 1
fi
CMK_SECRET=$(tr -d '[:space:]' < "$CMK_CREDS_FILE")
if [[ -z "$CMK_SECRET" ]]; then
    warn "CheckMK automation secret is empty — CheckMK not ready yet"
    exit 1
fi

# ── Wait for CheckMK web API (use automation secret — no admin password needed) ──
log "Waiting for CheckMK API at ${CMK_API}..."
_wait=0
until curl -sf \
        -H "Authorization: Bearer automation ${CMK_SECRET}" \
        "${CMK_API}/version" >/dev/null 2>&1; do
    _wait=$(( _wait + 15 ))
    if [[ $_wait -ge 300 ]]; then
        warn "CheckMK API not reachable after 5 minutes — will retry on next start"
        exit 1
    fi
    sleep 15
done
log "CheckMK API is up"

# ── Create /ansipa folder in CheckMK ─────────────────────────────────────────
_folder_result=$(curl -sf -o /dev/null -w '%{http_code}' \
    -X POST "${CMK_API}/domain-types/folder_config/collections/all" \
    -H "Authorization: Bearer automation ${CMK_SECRET}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"ansipa","title":"Ansipa Managed Hosts","parent":"/"}' \
    2>/dev/null || echo "000")
if [[ "$_folder_result" =~ ^2 ]]; then
    log "Created /ansipa folder in CheckMK"
elif [[ "$_folder_result" == "422" ]]; then
    log "/ansipa folder already exists"
else
    warn "Unexpected response creating /ansipa folder: HTTP $_folder_result"
fi

# ── Activate changes in CheckMK ───────────────────────────────────────────────
curl -sf \
    -X POST "${CMK_API}/domain-types/activation_run/actions/activate-changes/invoke" \
    -H "Authorization: Bearer automation ${CMK_SECRET}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"redirect":false,"sites":[],"force_foreign_changes":false}' \
    >/dev/null 2>&1 && log "Changes activated" || warn "Activation failed (non-fatal)"

# ── Store CheckMK credentials in IPA host-group descriptions ─────────────────
# Format: cmk://<host>:<port>/<site>:automation:<secret>
# CMK_ADVERTISED_URL is what CLIENTS use to reach CheckMK. It must be a
# host-routable address (e.g. http://<docker-host>:8090), NOT the container's
# internal 172.30.0.x address — clients outside the docker network cannot
# reach that, and every dev_mon_* policy would silently fail to register.
# Falls back to CMK_URL for docker-network-internal test setups.
CMK_CLIENT_URL="${CMK_ADVERTISED_URL:-$CMK_URL}"
CMK_HOST=$(echo "$CMK_CLIENT_URL" | sed 's|http://||')
CMK_DESC="cmk://${CMK_HOST}/${CMK_SITE}:automation:${CMK_SECRET}"

echo "$IPA_ADMIN_PASS" | kinit "admin@${IPA_REALM}" &>/dev/null || {
    warn "kinit admin failed"
    exit 1
}

# dev_mon_base stores the credentials; clients parse them to register.
if ipa hostgroup-show dev_mon_base &>/dev/null 2>&1; then
    ipa hostgroup-mod dev_mon_base --desc="$CMK_DESC" &>/dev/null \
        && log "Updated dev_mon_base description with CMK credentials"
else
    ipa hostgroup-add dev_mon_base --desc="$CMK_DESC" &>/dev/null \
        && log "Created IPA hostgroup dev_mon_base with CMK credentials"
fi

# Create supplementary monitoring host-groups (no credentials needed in description).
for _hgrp in dev_mon_clamscan dev_mon_timeshift dev_mon_power; do
    ipa hostgroup-show "$_hgrp" &>/dev/null 2>&1 || \
        ipa hostgroup-add "$_hgrp" &>/dev/null || true
done

# usr_mon_logins is a USER group (monitoring follows the user, not the device).
ipa group-show usr_mon_logins &>/dev/null 2>&1 || \
    ipa group-add usr_mon_logins \
        --desc="Members: SSH login monitoring enabled on enrolled devices" &>/dev/null || true

kdestroy &>/dev/null || true

touch "$DONE_FLAG"
log "CheckMK setup complete."
log "  Phase 2 (push-mode requests) will run on next invocation."
log "  Web UI:  ${CMK_URL}/${CMK_SITE}/"
log "  Login:   cmkadmin / (CMK_ADMIN_PASSWORD from .env)"
log "  Clients: add to dev_mon_base hostgroup — agent self-registers via ansipa"
