Some checks failed
CI / skip-ci-check (pull_request) Successful in 35s
CI / lint-and-test (pull_request) Failing after 31s
CI / secret-scanning (pull_request) Successful in 9s
CI / dependency-scan (pull_request) Successful in 17s
CI / sast-scan (pull_request) Successful in 30s
CI / ansible-validation (pull_request) Successful in 1m15s
CI / license-check (pull_request) Successful in 15s
CI / vault-check (pull_request) Successful in 13s
CI / container-scan (pull_request) Successful in 8s
CI / sonar-analysis (pull_request) Successful in 8s
CI / playbook-test (pull_request) Successful in 27s
CI / workflow-summary (pull_request) Successful in 5s
Deploy Kuma/Beszel monitoring docs and scripts, UniFi API key in vault, listmonk migration inventory, status.levkin.ca + stats on Caddy, and handoff doc for next agent. Co-authored-by: Cursor <cursoragent@cursor.com>
90 lines
3.5 KiB
Bash
Executable File
90 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Add or update Uptime Kuma HTTP monitors via API.
|
|
# Usage:
|
|
# export KUMA_PASSWORD='...' # not in vault yet — set manually once
|
|
# ./scripts/kuma-add-monitors.sh
|
|
#
|
|
# Monitors are idempotent: existing names are skipped.
|
|
# Links the default SMTP notification to any monitor that has none.
|
|
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
KUMA_URL="${KUMA_URL:-http://10.0.10.22:3001}"
|
|
KUMA_USER="${KUMA_USER:-admin}"
|
|
KUMA_PASSWORD="${KUMA_PASSWORD:-}"
|
|
|
|
if [[ -z "${KUMA_PASSWORD}" ]] && [[ -f "${REPO_ROOT}/.env" ]]; then
|
|
# shellcheck disable=SC1091
|
|
set -a
|
|
source "${REPO_ROOT}/.env"
|
|
set +a
|
|
KUMA_PASSWORD="${KUMA_PASSWORD:-}"
|
|
fi
|
|
|
|
if [[ -z "${KUMA_PASSWORD}" ]]; then
|
|
echo "Set KUMA_PASSWORD (admin UI password; not stored in vault yet)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
export KUMA_URL KUMA_USER KUMA_PASSWORD
|
|
|
|
"${REPO_ROOT}/.venv/bin/python3" <<'PY'
|
|
import os
|
|
import sys
|
|
|
|
try:
|
|
from uptime_kuma_api import UptimeKumaApi
|
|
except ImportError:
|
|
print("Run: .venv/bin/pip install uptime-kuma-api", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
# Public HTTPS endpoints worth watching (Beszel covers host metrics separately).
|
|
MONITORS = [
|
|
{"type": "http", "name": "levkin.ca", "url": "https://levkin.ca", "interval": 60, "retryInterval": 60, "maxretries": 3, "accepted_statuscodes": ["200-299"]},
|
|
{"type": "http", "name": "Portfolio", "url": "https://iliadobkin.com", "interval": 60, "retryInterval": 60, "maxretries": 3, "accepted_statuscodes": ["200-299"]},
|
|
{"type": "http", "name": "Search", "url": "https://search.levkin.ca", "interval": 120, "retryInterval": 60, "maxretries": 3, "accepted_statuscodes": ["200-299"]},
|
|
{"type": "http", "name": "PDF", "url": "https://pdf.levkin.ca", "interval": 120, "retryInterval": 60, "maxretries": 3, "accepted_statuscodes": ["200-299"]},
|
|
{"type": "http", "name": "Umami script", "url": "https://stats.levkin.ca/script.js", "interval": 300, "retryInterval": 120, "maxretries": 3, "accepted_statuscodes": ["200-299"]},
|
|
{"type": "http", "name": "Mattermost", "url": "https://slack.levkin.ca", "interval": 120, "retryInterval": 60, "maxretries": 3, "accepted_statuscodes": ["200-299"]},
|
|
]
|
|
|
|
url = os.environ["KUMA_URL"]
|
|
user = os.environ["KUMA_USER"]
|
|
password = os.environ["KUMA_PASSWORD"]
|
|
|
|
with UptimeKumaApi(url) as api:
|
|
api.login(user, password)
|
|
existing = {m.get("name"): m for m in api.get_monitors()}
|
|
notifs = [n for n in api.get_notifications() if n.get("isActive")]
|
|
smtp = next((n for n in notifs if n.get("isActive")), None)
|
|
if not smtp and notifs:
|
|
smtp = notifs[0]
|
|
if not smtp:
|
|
smtp = {"id": 1} # fallback: first notification in DB
|
|
|
|
for spec in MONITORS:
|
|
name = spec["name"]
|
|
if name in existing:
|
|
print(f"skip (exists): {name} id={existing[name].get('id')}")
|
|
continue
|
|
result = api.add_monitor(**spec)
|
|
print(f"added: {name} -> {result}")
|
|
existing[name] = result if isinstance(result, dict) else {"id": result}
|
|
|
|
if smtp:
|
|
nid = smtp["id"]
|
|
for m in api.get_monitors():
|
|
nlist = m.get("notificationIDList") or {}
|
|
if isinstance(nlist, dict) and nlist.get(str(nid)):
|
|
continue
|
|
if isinstance(nlist, dict):
|
|
nlist[str(nid)] = True
|
|
else:
|
|
nlist = {str(nid): True}
|
|
api.edit_monitor(m["id"], notificationIDList=nlist)
|
|
print(f"linked notification {nid} -> {m.get('name')}")
|
|
else:
|
|
print("warn: no SMTP notification found — create one in Kuma UI first", file=sys.stderr)
|
|
PY
|