Zero-dependency local agent: collect one snapshot through the shared metrics.js, POST it once to /hosts/<id>, exit. Cron runs it every five minutes. Nothing is queued and nothing is replayed — a heartbeat from five minutes ago describes a machine that no longer exists, so a failed push is logged and dropped rather than spooled. run-push.sh sources ~/.config/maximus-host-agent.env (mode 600), refuses to start when HOSTS_API_URL, HOSTS_INGEST_TOKEN or HOST_ID is missing, and never enables shell tracing: the script is meant to be piped into `logger`, where `set -x` would echo the ingest token into /var/log/syslog and journald for good. Same reason the failure path reports only err.code and the HTTP status — never an error object, request options, headers, or a response body. The cost is accepted: a 400 says the payload was rejected, not why. 50 tests, including two that spawn the real process against a failing server and scan its actual stdout and stderr for any five-character fragment of the token. The payload is pinned against the server's own sanitizeSnapshot(), and one case pushes a real collectMetrics() snapshot through the real ingestion handler, so a drift between agent and server turns a test red instead of producing a 400 at 3 a.m. on the ThinkPad. agent/ stays out of the Docker image: the COPY line is untouched, and a test pins that it copies files one by one and never names the directory. Installing on a workstation — frozen copy, env file, crontab line, dry run, and why two machines must never share a HOST_ID — is documented in agent/README.md. The install itself belongs to the commissioning issue. Resolves #15
67 lines
2.2 KiB
Bash
Executable file
67 lines
2.2 KiB
Bash
Executable file
#!/bin/sh
|
|
#
|
|
# Cron wrapper for push-metrics.js: load the secrets, check the install, hand
|
|
# over to node. Every five minutes, forever, unattended.
|
|
#
|
|
# NEVER add `set -x`. This script is meant to be piped into `logger`, and the
|
|
# shell would echo the `. "$ENV_FILE"` expansion — the ingest token — straight
|
|
# into /var/log/syslog and journald, where it would stay. Same reason nothing
|
|
# below ever echoes a variable that holds a secret: the checks print the NAME of
|
|
# what is missing, never its value.
|
|
#
|
|
# Suggested crontab line (see README.md):
|
|
# */5 * * * * $HOME/.local/share/maximus-host-agent/agent/run-push.sh 2>&1 | logger -t host-agent
|
|
|
|
set -eu
|
|
|
|
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
|
AGENT="$SCRIPT_DIR/push-metrics.js"
|
|
|
|
# Overridable for testing only; cron uses the default.
|
|
ENV_FILE="${HOST_AGENT_ENV_FILE:-$HOME/.config/maximus-host-agent.env}"
|
|
|
|
if [ ! -f "$ENV_FILE" ]; then
|
|
echo "host-agent: env file not found: $ENV_FILE" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# A warning, not a refusal: a wrong mode bit is worth shouting about, but it is
|
|
# not worth silencing the heartbeat of the whole workstation over.
|
|
FILE_MODE=$(stat -c "%a" "$ENV_FILE" 2>/dev/null || echo "")
|
|
if [ -n "$FILE_MODE" ] && [ "$FILE_MODE" != "600" ]; then
|
|
echo "host-agent: warning: $ENV_FILE is mode $FILE_MODE, expected 600" >&2
|
|
fi
|
|
|
|
# shellcheck source=/dev/null
|
|
. "$ENV_FILE"
|
|
|
|
if [ -z "${HOSTS_API_URL:-}" ]; then
|
|
echo "host-agent: HOSTS_API_URL is not set in $ENV_FILE" >&2
|
|
exit 1
|
|
fi
|
|
if [ -z "${HOSTS_INGEST_TOKEN:-}" ]; then
|
|
echo "host-agent: HOSTS_INGEST_TOKEN is not set in $ENV_FILE" >&2
|
|
exit 1
|
|
fi
|
|
if [ -z "${HOST_ID:-}" ]; then
|
|
echo "host-agent: HOST_ID is not set in $ENV_FILE" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "$AGENT" ]; then
|
|
echo "host-agent: agent not found: $AGENT" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# cron's PATH is famously short (/usr/bin:/bin), and a node installed through
|
|
# nvm or /usr/local lives outside it. Set NODE_BIN in the env file when
|
|
# `command -v node` comes up empty under cron but works in a login shell.
|
|
NODE_BIN="${NODE_BIN:-node}"
|
|
if ! command -v "$NODE_BIN" >/dev/null 2>&1; then
|
|
echo "host-agent: node not found (NODE_BIN=$NODE_BIN); set NODE_BIN in $ENV_FILE" >&2
|
|
exit 1
|
|
fi
|
|
|
|
export HOSTS_API_URL HOSTS_INGEST_TOKEN HOST_ID
|
|
|
|
exec "$NODE_BIN" "$AGENT" "$@"
|