#!/usr/bin/env bash # koopa-amanita-probe — external ICMP+SSH last-alive for amanita freezes. # Runs as hernani on koopa (~15s user timer). Log is hernani-readable on koopa. # SSH uses dedicated ed25519 → vx only (forced command: cat heartbeat.last). # # Usage: # koopa-amanita-probe # one probe cycle (default; timer path) # koopa-amanita-probe once # same # koopa-amanita-probe show # tail last lines # koopa-amanita-probe status # last line + timer hint # # Env: # AMANITA_PROBE_HOST default 192.168.100.6 # AMANITA_PROBE_USER default vx # AMANITA_PROBE_KEY default ~/.ssh/id_ed25519_amanita_probe # AMANITA_PROBE_STATE default ~/.local/state/amanita-probe # AMANITA_PROBE_REF second ICMP target (default 192.168.100.3, rabbithole) set +e set +u CMD="${1:-once}" HOST="${AMANITA_PROBE_HOST:-192.168.100.6}" USER_R="${AMANITA_PROBE_USER:-vx}" KEY="${AMANITA_PROBE_KEY:-${HOME}/.ssh/id_ed25519_amanita_probe}" STATE="${AMANITA_PROBE_STATE:-${XDG_STATE_HOME:-${HOME}/.local/state}/amanita-probe}" LOG="${STATE}/amanita-probe.log" LAST="${STATE}/amanita-probe.last" META="${STATE}/amanita-probe.meta" SSH_TO="${AMANITA_PROBE_SSH_TIMEOUT:-5}" PING_TO="${AMANITA_PROBE_PING_TIMEOUT:-2}" REF="${AMANITA_PROBE_REF:-192.168.100.3}" mkdir -p "${STATE}" 2>/dev/null || true do_show() { if [ ! -f "${LOG}" ]; then echo "amanita-probe: no log yet (${LOG})" echo " start: systemctl --user start koopa-amanita-probe.service" return 0 fi tail -n "${1:-20}" "${LOG}" } do_status() { if [ -f "${LAST}" ]; then echo "last: $(cat "${LAST}")" else echo "last: (none)" fi if [ -f "${META}" ]; then cat "${META}" fi systemctl --user is-active koopa-amanita-probe.timer 2>/dev/null \ | awk '{print "timer=" $0}' } do_once() { local ts icmp ssh hb gap prev_ts prev_epoch now_epoch local old_icmp old_ssh old_pair new_pair edge ref ts="$(date -Iseconds)" now_epoch="$(date +%s)" icmp=fail ssh=fail hb="-" old_icmp="" old_ssh="" old_pair="" if [ -f "${LAST}" ]; then old_icmp="$(awk '{for(i=1;i<=NF;i++) if($i ~ /^icmp=/){sub(/^icmp=/,"",$i); print $i; exit}}' "${LAST}" 2>/dev/null)" old_ssh="$(awk '{for(i=1;i<=NF;i++) if($i ~ /^ssh=/){sub(/^ssh=/,"",$i); print $i; exit}}' "${LAST}" 2>/dev/null)" if [ -n "${old_icmp}" ] && [ -n "${old_ssh}" ]; then old_pair="${old_icmp}/${old_ssh}" fi fi if ping -c1 -W "${PING_TO}" "${HOST}" >/dev/null 2>&1; then icmp=ok fi if [ ! -f "${KEY}" ]; then ssh=nokey else # Forced command on amanita returns heartbeat.last; ignore remote argv. hb="$( ssh -i "${KEY}" -o IdentitiesOnly=yes -o BatchMode=yes \ -o StrictHostKeyChecking=accept-new \ -o ConnectTimeout="${SSH_TO}" -o ConnectionAttempts=1 \ -o PreferredAuthentications=publickey \ "${USER_R}@${HOST}" true 2>/dev/null \ | tr '\n' ' ' | tr -s ' ' | head -c 800 )" if [ -n "${hb}" ]; then ssh=ok else # Distinguish timeout/refuse when ICMP ok if [ "${icmp}" = "ok" ]; then ssh=fail else ssh=down fi hb="-" fi fi gap="?" if [ -f "${LAST}" ]; then prev_ts="$(awk '{print $1}' "${LAST}" 2>/dev/null)" if prev_epoch="$(date -d "${prev_ts}" +%s 2>/dev/null)"; then gap=$((now_epoch - prev_epoch)) fi fi ref=fail if ping -c1 -W "${PING_TO}" "${REF}" >/dev/null 2>&1; then ref=ok fi new_pair="${icmp}/${ssh}" edge="" if [ -n "${old_pair}" ] && [ "${old_pair}" != "${new_pair}" ]; then edge=" edge=${old_pair}>${new_pair}" fi local line line="$(printf '%s icmp=%s ssh=%s gap_s=%s host=%s user=%s ref=%s%s hb=%s' \ "${ts}" "${icmp}" "${ssh}" "${gap}" "${HOST}" "${USER_R}" "${ref}" "${edge}" "${hb}")" printf '%s\n' "${line}" >>"${LOG}" printf '%s\n' "${line}" >"${LAST}" { echo "updated=${ts}" echo "log=${LOG}" echo "icmp=${icmp}" echo "ssh=${ssh}" echo "gap_s=${gap}" echo "ref=${ref}" } >"${META}" # Keep log bounded (~14d at 15s ≈ 80k lines; rotate soft at 200k lines) if [ -f "${LOG}" ]; then local lines lines="$(wc -l <"${LOG}" 2>/dev/null | tr -d ' ')" if [ "${lines:-0}" -gt 200000 ] 2>/dev/null; then tail -n 100000 "${LOG}" >"${LOG}.tmp" && mv "${LOG}.tmp" "${LOG}" fi fi # Exit 0 always for timer; FAIL is data, not unit failure return 0 } case "${CMD}" in once|probe|"") do_once ;; show) do_show "${2:-20}" ;; status) do_status ;; -h|--help) sed -n '2,20p' "$0" | sed 's/^# \?//' ;; *) echo "unknown: ${CMD} (once|show|status)" >&2 exit 2 ;; esac