#!/usr/bin/env bash # ansipa-infra-checkmk-install.sh — wire a Proxmox VE hypervisor or a Proxmox # Backup Server into the ansipa CheckMK instance. # # Unlike regular ansipa clients (enrolled in FreeIPA, driven by the # dev_mon_base host-group via ansipa-enforce-policies.sh), PVE/PBS hosts are # infrastructure appliances that are not FreeIPA members — so this script # does the same job (install agent, drop the local check, register with # CheckMK) standalone, taking the CheckMK automation credentials directly # instead of reading them from an IPA hostgroup description. # # Usage: # ansipa-infra-checkmk-install.sh [HOST_FQDN] [CMK_USER] # # CMK_URL e.g. http://mon.corp.example.com:8090 (client-routable — see # CMK_ADVERTISED_URL in image/.env.example) # CMK_SITE OMD site name, e.g. "cmk" # CMK_SECRET automation user's secret (CheckMK → Users → automation → API secret) # HOST_FQDN defaults to `hostname -f` # CMK_USER defaults to "automation" # # Run as root on the PVE or PBS host itself. Re-run any time to pick up a new # secret or to re-register after a host rename — it is idempotent. set -euo pipefail LOG_TAG="ansipa-infra-checkmk" log() { echo "[$LOG_TAG] $*"; } warn() { echo "[$LOG_TAG][WARN] $*" >&2; } die() { echo "[$LOG_TAG][ERROR] $*" >&2; exit 1; } [[ $EUID -eq 0 ]] || die "Run as root." [[ $# -ge 3 ]] || die "Usage: $0 [HOST_FQDN] [CMK_USER]" CMK_URL="${1%/}" CMK_SITE="$2" CMK_SECRET="$3" HOST_FQDN="${4:-$(hostname -f 2>/dev/null || hostname)}" CMK_USER="${5:-automation}" CMK_API="${CMK_URL}/${CMK_SITE}/check_mk/api/1.0" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LOCAL_DIR="/usr/lib/check_mk_agent/local" # ── Detect role ──────────────────────────────────────────────────────────── ROLE="" if command -v pveversion &>/dev/null; then ROLE="pve" elif command -v proxmox-backup-manager &>/dev/null; then ROLE="pbs" else die "Neither pveversion nor proxmox-backup-manager found — is this a PVE/PBS host?" fi MONITOR_SRC="$SCRIPT_DIR/ansipa-${ROLE}-monitor.sh" [[ -f "$MONITOR_SRC" ]] || die "Companion script not found: $MONITOR_SRC" log "Detected role: $ROLE (${HOST_FQDN})" # ── Install CheckMK agent (Debian .deb — PVE/PBS are Debian-based) ────────── _AGENT_INSTALLED=false if dpkg -s check-mk-agent &>/dev/null || command -v check_mk_agent &>/dev/null; then _AGENT_INSTALLED=true log "CheckMK agent already installed" else log "Downloading CheckMK agent from ${CMK_URL}" _DEB=$(curl -sf -u "${CMK_USER}:${CMK_SECRET}" \ "${CMK_URL}/${CMK_SITE}/check_mk/agents/" 2>/dev/null \ | grep -oE 'check-mk-agent_[^"]*_all\.deb' | head -1 || true) if [[ -n "$_DEB" ]]; then curl -sf -u "${CMK_USER}:${CMK_SECRET}" \ "${CMK_URL}/${CMK_SITE}/check_mk/agents/${_DEB}" \ -o /tmp/cmk-agent.deb 2>/dev/null \ && (dpkg -i /tmp/cmk-agent.deb 2>/dev/null || apt-get install -y -f 2>/dev/null) \ && dpkg -s check-mk-agent &>/dev/null \ && _AGENT_INSTALLED=true \ || warn "CheckMK .deb install failed" rm -f /tmp/cmk-agent.deb fi if [[ "$_AGENT_INSTALLED" == false ]]; then log "Falling back to the shell agent" curl -sf -u "${CMK_USER}:${CMK_SECRET}" \ "${CMK_URL}/${CMK_SITE}/check_mk/agents/check_mk_agent.linux" \ -o /usr/local/bin/check_mk_agent 2>/dev/null \ && chmod 755 /usr/local/bin/check_mk_agent \ && _AGENT_INSTALLED=true \ || die "Shell agent download failed — check CMK_URL/CMK_SITE/CMK_SECRET" fi fi # ── Serve the agent: enable the package's own socket, or roll our own ─────── if systemctl list-unit-files 2>/dev/null | grep -q '^check-mk-agent\.socket'; then systemctl enable --now check-mk-agent.socket 2>/dev/null \ && log "check-mk-agent.socket enabled" \ || warn "could not enable check-mk-agent.socket" elif [[ ! -f /etc/systemd/system/check_mk.socket ]]; then cat > /etc/systemd/system/check_mk.socket <<'UNIT' [Unit] Description=Check_MK agent socket (ansipa-managed) [Socket] ListenStream=6556 Accept=yes [Install] WantedBy=sockets.target UNIT cat > /etc/systemd/system/check_mk@.service <<'UNIT' [Unit] Description=Check_MK per-connection agent (ansipa-managed) [Service] ExecStart=/usr/local/bin/check_mk_agent StandardInput=socket StandardOutput=socket StandardError=null UNIT systemctl daemon-reload systemctl enable --now check_mk.socket 2>/dev/null \ && log "check_mk.socket enabled (port 6556)" \ || warn "could not enable check_mk.socket" fi # ── Drop in the local check ────────────────────────────────────────────────── mkdir -p "$LOCAL_DIR" install -m 755 "$MONITOR_SRC" "$LOCAL_DIR/ansipa_${ROLE}" log "Installed local check: $LOCAL_DIR/ansipa_${ROLE}" # ── cmk-agent-ctl: register for TLS/push transport (useful behind NAT) ────── if command -v cmk-agent-ctl &>/dev/null; then _RECV_HOST=$(echo "$CMK_URL" | sed 's|https\?://||;s|:.*||') _ALREADY_CTL=$(cmk-agent-ctl status 2>/dev/null | grep -c "${_RECV_HOST}/${CMK_SITE}" || true) if [[ "${_ALREADY_CTL:-0}" -eq 0 ]]; then cmk-agent-ctl register \ --server "${_RECV_HOST}:8000" \ --site "${CMK_SITE}" \ --user "${CMK_USER}" \ --password "${CMK_SECRET}" \ --hostname "${HOST_FQDN}" \ --trust-cert &>/dev/null \ && log "cmk-agent-ctl registered with ${_RECV_HOST}:8000" \ || warn "cmk-agent-ctl registration failed (non-fatal — pull mode still works if reachable)" fi _CTL_MODE=$(cmk-agent-ctl status 2>/dev/null | awk '/Connection mode:/{print $NF; exit}') if [[ "$_CTL_MODE" == "push-agent" ]]; then cmk-agent-ctl push 2>/dev/null || true if [[ ! -f /etc/systemd/system/cmk-agent-push.timer ]]; then cat > /etc/systemd/system/cmk-agent-push.service <<'UNIT' [Unit] Description=CheckMK agent push (ansipa-managed) [Service] Type=oneshot ExecStart=/usr/bin/cmk-agent-ctl push UNIT cat > /etc/systemd/system/cmk-agent-push.timer <<'UNIT' [Unit] Description=CheckMK agent push timer (ansipa-managed) [Timer] OnBootSec=30s OnUnitActiveSec=60s [Install] WantedBy=timers.target UNIT systemctl daemon-reload systemctl enable --now cmk-agent-push.timer 2>/dev/null \ && log "cmk-agent-push.timer enabled (push every 60s)" \ || warn "could not enable push timer" fi fi fi # ── Register the host in CheckMK (folder /ansipa/infra) ───────────────────── _folder_result=$(curl -sf -o /dev/null -w '%{http_code}' \ -X POST "${CMK_API}/domain-types/folder_config/collections/all" \ -H "Authorization: Bearer ${CMK_USER} ${CMK_SECRET}" \ -H "Content-Type: application/json" -H "Accept: application/json" \ -d '{"name":"infra","title":"Ansipa Infra (PVE/PBS)","parent":"/ansipa"}' \ 2>/dev/null || echo "000") [[ "$_folder_result" =~ ^2 || "$_folder_result" == "422" ]] \ || warn "Unexpected response creating /ansipa/infra folder: HTTP $_folder_result" _HOST_IP=$(hostname -I 2>/dev/null | awk '{print $1}' || echo "") _ALREADY_REG=false curl -sf -o /dev/null \ -H "Authorization: Bearer ${CMK_USER} ${CMK_SECRET}" \ "${CMK_API}/objects/host_config/${HOST_FQDN}" 2>/dev/null && _ALREADY_REG=true || true if [[ "$_ALREADY_REG" == false ]]; then _reg_body="{\"host_name\":\"${HOST_FQDN}\",\"folder\":\"/ansipa/infra\"" [[ -n "$_HOST_IP" ]] && _reg_body+=",\"attributes\":{\"ipaddress\":\"${_HOST_IP}\",\"tag_role\":\"${ROLE}\"}" _reg_body+="}" _reg_http=$(curl -sf -o /dev/null -w '%{http_code}' \ -X POST "${CMK_API}/domain-types/host_config/collections/all" \ -H "Authorization: Bearer ${CMK_USER} ${CMK_SECRET}" \ -H "Content-Type: application/json" -H "Accept: application/json" \ -d "$_reg_body" 2>/dev/null || echo "000") if [[ "$_reg_http" =~ ^2 ]]; then log "Registered ${HOST_FQDN} in CheckMK (/ansipa/infra)" else warn "Host registration failed (HTTP ${_reg_http}) — add it manually in the CheckMK UI" fi else log "${HOST_FQDN} already registered in CheckMK" fi curl -sf -X POST "${CMK_API}/domain-types/service_discovery_run/actions/start/invoke" \ -H "Authorization: Bearer ${CMK_USER} ${CMK_SECRET}" \ -H "Content-Type: application/json" -H "Accept: application/json" \ -d "{\"host_name\":\"${HOST_FQDN}\",\"mode\":\"refresh\"}" >/dev/null 2>&1 || true curl -sf -X POST "${CMK_API}/domain-types/activation_run/actions/activate-changes/invoke" \ -H "Authorization: Bearer ${CMK_USER} ${CMK_SECRET}" \ -H "Content-Type: application/json" -H "Accept: application/json" \ -d '{"redirect":false,"sites":[],"force_foreign_changes":true}' >/dev/null 2>&1 || true log "Done. ${HOST_FQDN} (${ROLE}) should appear under CheckMK folder /ansipa/infra within a minute."