#!/usr/bin/env bash
# Configure Zabbix agent to allow system.run and passwordless sudo for user zabbix
# - Detect OS and package manager
# - Verify zabbix agent presence (agentd or agent2), abort if missing
# - Ensure sudo installed
# - Ensure user 'zabbix' exists (system user, nologin)
# - Grant NOPASSWD: ALL to zabbix via /etc/sudoers.d/
# - Ensure AllowKey=system.run[*] and UnsafeUserParameters=1 in agent config
# - Restart zabbix-agent service

set -euo pipefail

#----- Helpers
die(){ echo "ERROR: $*" >&2; exit 1; }
msg(){ echo "[*] $*"; }
ok(){  echo "[✓] $*"; }

require_root(){
  if [[ ${EUID:-$(id -u)} -ne 0 ]]; then
    die "Run as root (sudo $0)"
  fi
}

detect_pm(){
  if   command -v apt-get >/dev/null 2>&1; then PM="apt"
  elif command -v dnf      >/dev/null 2>&1; then PM="dnf"
  elif command -v yum      >/dev/null 2>&1; then PM="yum"
  elif command -v zypper   >/dev/null 2>&1; then PM="zypper"
  elif command -v apk      >/dev/null 2>&1; then PM="apk"
  else die "Unsupported OS (no apt/dnf/yum/zypper/apk found)"; fi
  ok "Package manager: $PM"
}

pm_install(){
  case "$PM" in
    apt)    apt-get update -y || apt-get update; DEBIAN_FRONTEND=noninteractive apt-get install -y "$@" ;;
    dnf)    dnf install -y "$@" ;;
    yum)    yum install -y "$@" ;;
    zypper) zypper --non-interactive refresh; zypper --non-interactive install -y "$@" ;;
    apk)    apk add --no-cache "$@" ;;
  esac
}

service_try(){
  local unit="$1"
  if systemctl list-unit-files | grep -q "^${unit}\.service"; then
    systemctl restart "$unit"
    systemctl enable --now "$unit" >/dev/null 2>&1 || true
    ok "Service restarted: $unit"
    return 0
  fi
  return 1
}

ensure_line(){
  # ensure_line <file> <key> <value_line>
  local file="$1" key="$2" line="$3"
  touch "$file"
  chmod 0644 "$file"
  if grep -Eq "^${key}=" "$file"; then
    # Replace existing line (any value)
    sed -i "s|^${key}=.*|${line}|g" "$file"
  else
    echo "$line" >> "$file"
  fi
}

#----- Start
require_root
detect_pm

# 1) Vérifier présence de l'agent Zabbix
AGENT_BIN=""
CONF_FILE=""
SERVICE_UNIT=""

if command -v zabbix_agentd >/dev/null 2>&1; then
  AGENT_BIN="$(command -v zabbix_agentd)"
  SERVICE_UNIT="zabbix-agent"
  CONF_FILE="/etc/zabbix/zabbix_agentd.conf"
elif command -v zabbix_agent2 >/dev/null 2>&1; then
  AGENT_BIN="$(command -v zabbix_agent2)"
  SERVICE_UNIT="zabbix-agent2"
  # Debian/RHEL: zabbix_agent2.conf
  if [[ -f /etc/zabbix/zabbix_agent2.conf ]]; then
    CONF_FILE="/etc/zabbix/zabbix_agent2.conf"
  else
    CONF_FILE="/etc/zabbix/zabbix_agentd.conf" # fallback
  fi
fi

if [[ -z "${AGENT_BIN}" || ! -x "${AGENT_BIN}" ]]; then
  die "Zabbix agent not found. Please install zabbix-agent/agent2 first, then re-run."
fi
ok "Found Zabbix agent binary: ${AGENT_BIN}"
[[ -n "$CONF_FILE" ]] || die "Unable to determine agent config file path"
msg "Agent config file: ${CONF_FILE}"

# 2) Installer sudo si absent
if ! command -v sudo >/dev/null 2>&1; then
  msg "Installing sudo..."
  pm_install sudo
  ok "sudo installed"
else
  ok "sudo already present"
fi

# 3) Créer l'utilisateur zabbix (si manquant)
if ! id zabbix >/dev/null 2>&1; then
  msg "Creating system user 'zabbix'..."
  # -r system user, -M no home creation, -s nologin, -d /var/lib/zabbix
  useradd -r -M -s /usr/sbin/nologin -d /var/lib/zabbix zabbix
  ok "User 'zabbix' created"
else
  ok "User 'zabbix' already exists"
fi

# 4) Donner droits root sans mot de passe (NOPASSWD: ALL) pour zabbix
#    (via drop-in /etc/sudoers.d/, c'est la méthode recommandée et traçable)
SUDOERS_DROP="/etc/sudoers.d/99-zabbix-nopasswd-all"
if [[ ! -f "$SUDOERS_DROP" ]]; then
  msg "Writing sudoers drop-in: $SUDOERS_DROP"
  umask 077
  printf "Defaults:zabbix !requiretty\nzabbix ALL=(ALL) NOPASSWD: ALL\n" > "$SUDOERS_DROP"
  chmod 0440 "$SUDOERS_DROP"
  # Valider la conf sudoers
  if command -v visudo >/dev/null 2>&1; then
    visudo -cf /etc/sudoers >/dev/null || { rm -f "$SUDOERS_DROP"; die "Invalid sudoers, change reverted."; }
  fi
  ok "NOPASSWD: ALL granted to 'zabbix' via $SUDOERS_DROP"
else
  ok "Sudoers drop-in already present: $SUDOERS_DROP"
fi

# 5) Préparer /run/zabbix (verrouillage pour scripts)
install -d -m 0755 -o zabbix -g zabbix /run/zabbix
# le rendre persistant à chaque boot
if [[ ! -f /etc/tmpfiles.d/zabbix.conf ]]; then
  echo 'd /run/zabbix 0755 zabbix zabbix -' > /etc/tmpfiles.d/zabbix.conf
  systemd-tmpfiles --create || true
fi

# 6) Modifier la configuration agent : AllowKey & UnsafeUserParameters
if [[ -f "$CONF_FILE" ]]; then
  cp -a "$CONF_FILE" "${CONF_FILE}.bak.$(date +%Y%m%d-%H%M%S)"
  ensure_line "$CONF_FILE" "AllowKey" "AllowKey=system.run[*]"
  ensure_line "$CONF_FILE" "UnsafeUserParameters" "UnsafeUserParameters=1"
  ok "Updated agent config: AllowKey=system.run[*], UnsafeUserParameters=1"
else
  die "Agent config file not found: $CONF_FILE"
fi

# 7) Redémarrer l’agent
if ! service_try "$SERVICE_UNIT"; then
  msg "Trying legacy service name fallback..."
  service_try zabbix-agent || service_try zabbix-agent2 || die "Unable to restart zabbix agent service"
fi

ok "All done."
