#!/sbin/openrc-run # rds-agent — Spinifex RDS in-guest agent. Reaches the control plane over # TLS+SigV4 (never NATS), signing with IMDS instance-role credentials. Static # config comes from /etc/spinifex-rds/agent.env, which carries no secrets. description="Spinifex RDS instance agent" command="/usr/local/bin/rds-agent" command_background="yes" pidfile="/run/rds-agent.pid" output_log="/var/log/rds-agent.log" error_log="/var/log/rds-agent.log" start_stop_daemon_args="--wait 2000" AGENT_ENV="/etc/spinifex-rds/agent.env" # The agent retries indefinitely, so this only bounds how long the boot waits # before letting rds-init fail visibly rather than hanging forever. handoff_timeout="${RDS_HANDOFF_TIMEOUT:-120}" # How much of the agent log to mirror to the console when the handoff times out. # Enough to carry a few backed-off retries with their errors, not the whole boot. handoff_tail="${RDS_HANDOFF_TAIL:-20}" depend() { need net after localmount before rds-datadir rds-init postgresql } start_pre() { # An absent file is tolerated, so the agent still starts and logs why it # cannot reach the gateway. if [ -f "${AGENT_ENV}" ]; then # shellcheck disable=SC1090 . "${AGENT_ENV}" export RDS_GATEWAY_URL RDS_GATEWAY_CA RDS_REGION RDS_DB_INSTANCE_IDENTIFIER \ RDS_ENGINE RDS_ENGINE_VERSION RDS_HANDOFF_DIR RDS_ENGINE_HOST RDS_ENGINE_PORT \ RDS_POLL_WAIT RDS_DATA_MOUNT fi } start_post() { # Resolve this after start_pre loads agent.env so custom handoff directories # are shared by the agent, this wait, and rds-init. HANDOFF_ENV="${RDS_HANDOFF_DIR:-/run/spinifex-rds}/bootstrap.env" # `before rds-init` only orders the starts; rds-init needs the fetched config # itself. The agent writes bootstrap.env last and renames it into place, so # its appearance means the whole handoff is there. ebegin "Waiting for the RDS bootstrap handoff" _waited=0 while [ ! -f "${HANDOFF_ENV}" ]; do if [ "${_waited}" -ge "${handoff_timeout}" ]; then eend 1 "no bootstrap handoff after ${handoff_timeout}s" # Mirror the agent's own tail onto the console. The log lives inside a # guest nothing can reach when this fails — an unreachable gateway is # the usual cause — so the host-side console capture is the only way # the dial error survives, and without it the failure reads as silence. if [ -s "${output_log}" ]; then einfo "last ${handoff_tail} lines of ${output_log}:" tail -n "${handoff_tail}" "${output_log}" 2>/dev/null | while IFS= read -r _line; do einfo " [rds-agent] ${_line}" done else einfo "${output_log} is empty — the agent produced no output at all" fi # The agent keeps retrying, so it is left running: rds-init fails on # the missing handoff and the engine stays down, which is what the # control plane observes. return 0 fi sleep 1 _waited=$((_waited + 1)) done eend 0 }