#!/bin/bash
# Navidrome health check — managed by Ansible (roles/navidrome)
#
# The exit code is the answer and systemd keeps it:
# systemctl is-failed {{ navidrome_healthcheck_service_name }}.service
# Reporting anywhere else is optional and generic.
#
# /app/ rather than /ping, established by testing against 0.64.0 on the box:
#
# /ping 200, Content-Type text/plain, body is a single "." - it
# proves something is listening and nothing more.
# /rest/ping.view identifies itself ("type":"navidrome") but logs TWO
# warning lines per call. At one call per 5 minutes that is
# ~576 spurious warnings a day, which is how you train
# yourself to ignore the warning level.
# /app/ 200, 2.8 KB,
Navidrome, and SILENT.
#
# So /app/ is the only one that proves it is really Navidrome serving its real
# UI without polluting the journal. Same reasoning as the xmrblocks check,
# which fetches a real page because a missing templates dir serves 200s of
# nothing.
URL="${NAVIDROME_URL:-http://127.0.0.1:{{ navidrome_port }}}"
PUSH_URL="${HEALTHCHECK_PUSH_URL:-}"
PUSH_TOKEN="${HEALTHCHECK_PUSH_TOKEN:-}"
report() {
local status=$1
local msg=$2
# No push URL is normal, not an error: the exit code below is still a
# complete answer for anything reading unit state.
[ -n "$PUSH_URL" ] || return 0
local encoded_msg="${msg// /%20}"
local _ok=false
[ "${status}" = "up" ] && _ok=true
curl -s --max-time 15 --retry 2 -o /dev/null -X POST \
-H "Authorization: Bearer ${PUSH_TOKEN}" \
"${PUSH_URL}?success=${_ok}&error=${encoded_msg}" || true
}
# 30s: Navidrome answers /ping in milliseconds normally, but this box has one
# core and a library scan will happily eat it. A tight timeout here would
# manufacture false DOWNs every time a scan runs.
body=$(curl -s --max-time 30 -w '\n%{http_code}' "${URL}/app/" 2>/dev/null)
code=$(printf '%s' "$body" | tail -1)
if [ -z "$code" ] || [ "$code" = "000" ]; then
report "down" "navidrome not responding"
exit 1
fi
if [ "$code" != "200" ]; then
report "down" "navidrome HTTP ${code}"
exit 1
fi
if ! printf '%s' "$body" | grep -qi "navidrome"; then
report "down" "navidrome served 200 but not its own UI (something else on the port?)"
exit 1
fi
report "up" "OK"
exit 0