`systemctl is-active` prints the state AND exits non-zero when a unit is not active, so `... || echo unknown` appended a second line: STATE became "inactive\nunknown" and the script emitted a raw newline inside a JSON string. The scheduler rejected all 14 process checks with "invalid character '\n' in string literal". Latent since the script was written — process checks never actually ran, because checkdefaults wrote an `args` config the ssh-script checker ignored. Passing args through finally executed them and exposed it. - head -1 keeps the state, and the fallback only fires on empty output. - Quotes are stripped from both the unit name and the state; either would break the hand-built JSON just as thoroughly. - signalKind is now the constant "process" rather than "$SERVICE". Emitting the service name minted a distinct signal kind per service (kind=paperless, kind=qbit, …) — nothing an approval_rule can match, and it makes "how many process checks are failing?" unanswerable. Co-Authored-By: Claude <noreply@anthropic.com>
37 lines
1.5 KiB
Bash
37 lines
1.5 KiB
Bash
#!/usr/bin/env bash
|
|
# process_check.sh — systemd service liveness.
|
|
set -euo pipefail
|
|
|
|
SERVICE="${1:-}"
|
|
if [ -z "$SERVICE" ]; then
|
|
echo '{"health":"unknown","signalKind":"process-check","evidence":"no service name provided"}'
|
|
exit 0
|
|
fi
|
|
|
|
if ! command -v systemctl >/dev/null 2>&1; then
|
|
echo '{"health":"unknown","signalKind":"process-check","evidence":"systemctl not found"}'
|
|
exit 0
|
|
fi
|
|
|
|
# `systemctl is-active` PRINTS the state and exits non-zero when the unit is
|
|
# not active, so `... || echo unknown` appended a second line and produced
|
|
# "paperless is inactive\nunknown" — a raw newline inside a JSON string, which
|
|
# the scheduler rejected as invalid output. head -1 keeps the first line and
|
|
# the fallback only fires when there was no output at all.
|
|
STATE=$(systemctl is-active "$SERVICE" 2>/dev/null | head -1 || true)
|
|
[ -z "$STATE" ] && STATE="unknown"
|
|
# Belt and braces: a unit name or state containing a quote would break the
|
|
# hand-built JSON below just as thoroughly.
|
|
STATE=${STATE//\"/}
|
|
SAFE_SERVICE=${SERVICE//\"/}
|
|
|
|
if [ "$STATE" = "active" ]; then
|
|
echo "{\"health\":\"healthy\"}"
|
|
else
|
|
# signalKind is a taxonomy, not a per-service label. Emitting "$SERVICE"
|
|
# here minted a distinct signal kind for every service (kind=paperless,
|
|
# kind=qbit, …), which no approval_rule can match and which makes
|
|
# "how many process checks are failing?" unanswerable.
|
|
echo "{\"health\":\"degraded\",\"signalKind\":\"process\",\"evidence\":\"$SAFE_SERVICE is $STATE\"}"
|
|
fi
|