#!/bin/sh
# sc-agent-pprof.sh — enciende (o apaga) los perfiles de Go en un agente.
#
# Para qué: contestar en qué se va el CPU de un agente cargado. Hoy no lo
# sabemos — el descifrado AES quedó descartado midiendo (0,065% de un core), así
# que la saturación de las cajas con decenas de SRT cifrados sigue sin causa.
#
# El binario trae el flag apagado por default; esto solo lo agrega al unit. Toca
# el unit (a diferencia de sc-update-agent.sh, que nunca lo toca) porque es la
# única forma de pasar un flag nuevo — por eso respalda antes y revierte si el
# servicio no levanta.
#
# Se corre como root en el agente, en UNA sola sesión SSH (fail2ban corta el SSH
# si se abren varias conexiones seguidas):
#     ssh -t USUARIO@AGENTE 'curl -fsS http://10.20.1.229:7070/sc-agent-pprof.sh | sudo sh'
#     ssh -t USUARIO@AGENTE 'curl -fsS http://10.20.1.229:7070/sc-agent-pprof.sh | sudo sh -s -- --off'
#
# Los perfiles quedan en 127.0.0.1:6060 y NO se exponen a la red: los volcados
# llevan la URL cruda de cada stream, con su passphrase. Se llegan por túnel:
#     ssh -N -L 6060:127.0.0.1:6060 USUARIO@AGENTE
#     go tool pprof -http=: http://127.0.0.1:6060/debug/pprof/profile?seconds=60
set -eu

ADDR="${SC_PPROF_ADDR:-127.0.0.1:6060}"
FLAGS="-pprof $ADDR -pprof-contention"
STAMP="${SC_STAMP:-$(date +%Y%m%d)}"
OFF=0
[ "${1:-}" = "--off" ] && OFF=1

UNIT=$(systemctl list-units --type=service --all --no-legend 'streamchecker*' | awk '{print $1; exit}')
UNIT=${UNIT:-streamchecker.service}
FILE=$(systemctl show -p FragmentPath --value "$UNIT")
[ -n "$FILE" ] && [ -f "$FILE" ] || { echo "no encuentro el unit de $UNIT"; exit 1; }

echo "== agente $(hostname) — $UNIT ($FILE) =="
echo "   ExecStart actual: $(systemctl show -p ExecStart --value "$UNIT" | head -1)"

HAS=0
grep -q '^ExecStart=.* -pprof' "$FILE" && HAS=1

if [ "$OFF" = 1 ]; then
  [ "$HAS" = 1 ] || { echo "   los perfiles ya estaban apagados — nada que hacer"; exit 0; }
  cp -a "$FILE" "$FILE.bak-pprof-$STAMP"
  sed -i -E 's/ -pprof[= ][^ ]*//g; s/ -pprof-contention//g' "$FILE"
  echo "== apagando los perfiles =="
else
  # El binario tiene que entender el flag: uno viejo aborta con "flag provided
  # but not defined" y el servicio queda caído. Se verifica ANTES de tocar nada.
  BIN=$(command -v streamchecker 2>/dev/null || echo /usr/local/bin/streamchecker)
  "$BIN" -pprof 127.0.0.1:0 -version >/dev/null 2>&1 || {
    echo "   este binario no conoce -pprof ($("$BIN" -version 2>&1 | head -1))."
    echo "   Actualizalo primero con sc-update-agent.sh — abortado."; exit 1; }
  [ "$HAS" = 0 ] || { echo "   los perfiles ya estaban encendidos — nada que hacer"; exit 0; }
  cp -a "$FILE" "$FILE.bak-pprof-$STAMP"
  # Se insertan justo después del binario, que es el primer token del ExecStart.
  sed -i -E "s|^(ExecStart=[^ ]*)|\1 $FLAGS|" "$FILE"
  echo "== encendiendo los perfiles en $ADDR =="
fi

systemctl daemon-reload
systemctl restart "$UNIT"
sleep 5
if ! systemctl is-active --quiet "$UNIT"; then
  echo "   NO levantó — revirtiendo el unit"
  cp -a "$FILE.bak-pprof-$STAMP" "$FILE"
  systemctl daemon-reload; systemctl restart "$UNIT"
  exit 1
fi

echo "== verificación =="
echo "   ExecStart: $(systemctl show -p ExecStart --value "$UNIT" | head -1)"
if [ "$OFF" = 0 ]; then
  # Que el servicio esté activo no prueba que el endpoint escuche (si el puerto
  # está ocupado, el agente avisa y sigue monitoreando, que es lo correcto).
  CODE=$(curl -s -m 5 -o /dev/null -w '%{http_code}' "http://$ADDR/debug/pprof/" || echo 000)
  echo "   http://$ADDR/debug/pprof/ -> $CODE  (200 = listo; 000 = no escucha, mirar el journal)"
  echo "   túnel: ssh -N -L 6060:$ADDR $(logname 2>/dev/null || echo USUARIO)@$(hostname -I 2>/dev/null | awk '{print $1}')"
fi
echo "== listo en $(hostname) =="
