who_need_help/scripts/install-production-external-monitor.sh

138 lines
5.1 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
umask 077
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
source_target=${PRODUCTION_SSH_TARGET:-whoneedhelp}
monitor_target=${MONITOR_SSH_TARGET:-buyvm-maya}
production_env=${PRODUCTION_ENV_PATH:-/srv/who_need_help-production/.env}
remote_root=${MONITOR_REMOTE_ROOT:-/home/simple/.local/lib/who-need-help}
remote_config=${MONITOR_REMOTE_CONFIG:-/home/simple/.config/who-need-help/monitor.json}
remote_state=${MONITOR_REMOTE_STATE:-/home/simple/.local/state/who-need-help/monitor.json}
monitor_url=${MONITOR_URL:-https://whoneedhelp.com/healthz/ready}
monitor_calendar=${MONITOR_ON_CALENDAR:-'*:0/1'}
health_timeout=${MONITOR_HEALTH_TIMEOUT_SECONDS:-3}
for command in mktemp scp ssh; do
command -v "$command" >/dev/null 2>&1 || {
echo "Required command is unavailable: $command" >&2
exit 2
}
done
source_host=$(ssh -G "$source_target" | awk '$1 == "hostname" {print $2; exit}')
monitor_host=$(ssh -G "$monitor_target" | awk '$1 == "hostname" {print $2; exit}')
if [[ -z "$source_host" || -z "$monitor_host" || "$source_host" == "$monitor_host" ]]; then
echo "The external monitor must resolve and run on a host other than production." >&2
exit 2
fi
case "$health_timeout" in
'' | *[!0-9]*) echo "MONITOR_HEALTH_TIMEOUT_SECONDS must be a positive integer." >&2; exit 2 ;;
0) echo "MONITOR_HEALTH_TIMEOUT_SECONDS must be a positive integer." >&2; exit 2 ;;
esac
work_dir=$(mktemp -d "$ROOT/tmp/production-operations/monitor-install.XXXXXX")
config="$work_dir/monitor.json"
service="$work_dir/who-need-help-production-monitor.service"
timer="$work_dir/who-need-help-production-monitor.timer"
cleanup() {
rm -rf "$work_dir"
}
trap cleanup EXIT HUP INT TERM
ssh -o BatchMode=yes "$source_target" \
"python3 - '$production_env' '$monitor_url' '$health_timeout'" >"$config" <<'PY'
import json
import shlex
import sys
path, health_url, timeout = sys.argv[1:]
wanted = {
"SMTP_RELAY",
"SMTP_PORT",
"SMTP_USERNAME",
"SMTP_PASSWORD",
"SMTP_TLS",
"SMTP_SSL",
"EMAIL_FROM_ADDRESS",
"EMAIL_FROM_NAME",
"SUPPORT_INBOX_ADDRESS",
}
values = {}
with open(path, encoding="utf-8") as handle:
for raw_line in handle:
line = raw_line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, value = line.split("=", 1)
if key not in wanted:
continue
parsed = shlex.split(value, comments=False, posix=True)
values[key] = parsed[0] if parsed else ""
missing = sorted(key for key in wanted if not values.get(key))
if missing:
raise SystemExit("Missing production mail settings: " + ", ".join(missing))
payload = {
"health_timeout_seconds": int(timeout),
"health_url": health_url,
"smtp": {
"from_address": values["EMAIL_FROM_ADDRESS"],
"from_name": values["EMAIL_FROM_NAME"],
"implicit_ssl": values["SMTP_SSL"].lower() == "true",
"password": values["SMTP_PASSWORD"],
"port": int(values["SMTP_PORT"]),
"recipient": values["SUPPORT_INBOX_ADDRESS"],
"relay": values["SMTP_RELAY"],
"starttls": values["SMTP_TLS"].lower() == "always",
"username": values["SMTP_USERNAME"],
},
}
json.dump(payload, sys.stdout, ensure_ascii=False, indent=2, sort_keys=True)
sys.stdout.write("\n")
PY
chmod 600 "$config"
cat >"$service" <<EOF
[Unit]
Description=Who Need Help independent production readiness monitor
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/python3 $remote_root/production-external-monitor.py --config $remote_config --state $remote_state check
EOF
cat >"$timer" <<EOF
[Unit]
Description=Run the Who Need Help independent production readiness monitor
[Timer]
OnCalendar=$monitor_calendar
Persistent=true
Unit=who-need-help-production-monitor.service
[Install]
WantedBy=timers.target
EOF
ssh -o BatchMode=yes "$monitor_target" \
"install -d -m 700 '$remote_root' /home/simple/.config/who-need-help /home/simple/.local/state/who-need-help /home/simple/.config/systemd/user"
scp -q "$ROOT/scripts/production-external-monitor.py" \
"$monitor_target:$remote_root/production-external-monitor.py"
scp -q "$config" "$monitor_target:$remote_config"
scp -q "$service" "$monitor_target:/home/simple/.config/systemd/user/who-need-help-production-monitor.service"
scp -q "$timer" "$monitor_target:/home/simple/.config/systemd/user/who-need-help-production-monitor.timer"
ssh -o BatchMode=yes "$monitor_target" \
"chmod 700 '$remote_root/production-external-monitor.py'; chmod 600 '$remote_config' /home/simple/.config/systemd/user/who-need-help-production-monitor.service /home/simple/.config/systemd/user/who-need-help-production-monitor.timer; systemctl --user daemon-reload; systemctl --user start who-need-help-production-monitor.service; systemctl --user enable --now who-need-help-production-monitor.timer"
printf 'External monitor installed on %s (%s).\n' "$monitor_target" "$monitor_host"
printf 'Health URL: %s\n' "$monitor_url"
printf 'Schedule: %s; request timeout: %ss.\n' "$monitor_calendar" "$health_timeout"
echo "The SMTP credential is stored only in a mode-0600 configuration on the external monitor host."