Files
homelab/ansible/roles/uptime-kuma/tasks/main.yml
T
claude-botandClaude Opus 5.5 37c83ed6c2 feat(kuma-sync): declare the public status page as a KumaStatusPage
New namespaced CRD KumaStatusPage (uptime.renner.uno/v1alpha1) and a
reconciler that owns the Kuma status page completely: config, domain
names and the full group/monitor list. Sections select KumaMonitors in
any namespace by label; monitors are ordered by displayName, then
namespace/name, a monitor goes to the first matching section only, and
monitors without a Kuma ID are left out and counted in status.

The reconciler adopts an existing page with the slug, writes only when
the managed content differs (no write per resync), reuses Kuma group IDs
by position so saves do not churn them, reverts UI edits on resync,
deletes the page on resource deletion, and reports Ready=False/Conflict
for a younger resource claiming the same slug. Every KumaMonitor change
to labels, displayName, monitor ID or deletion enqueues all pages.

kumaclient gains a StatusPages interface (Breml + Fake). The socket API
returns no group list, so groups are read from Kuma's public
GET /api/status-page/<slug>, as the bootstrap did. Fields kuma-sync does
not manage (logo, custom CSS, analytics, RSS title, auto refresh
interval) are written back unchanged. autoRefreshInterval is not in the
spec: go-uptime-kuma-client v0.6.2 (latest) never sends it on save.

The Ansible bootstrap no longer creates or edits status pages; the
existing page is left in place for kuma-sync to adopt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 21:03:50 +02:00

220 lines
6.7 KiB
YAML

---
# Admin bootstrap runs with the Traefik route disabled so /setup is never
# reachable from outside; the route is enabled once the admin exists.
- name: Read admin credentials from OpenBao
community.hashi_vault.vault_kv2_get:
url: "{{ uptime_kuma_openbao_url }}"
engine_mount_point: "{{ uptime_kuma_openbao_mount }}"
path: "{{ uptime_kuma_openbao_path }}"
auth_method: token
delegate_to: localhost
become: false
run_once: true
register: _uptime_kuma_secret
no_log: true
- name: Read SMTP credentials from OpenBao
community.hashi_vault.vault_kv2_get:
url: "{{ uptime_kuma_openbao_url }}"
engine_mount_point: "{{ uptime_kuma_openbao_mount }}"
path: "{{ uptime_kuma_openbao_smtp_path }}"
auth_method: token
delegate_to: localhost
become: false
run_once: true
register: _uptime_kuma_smtp
no_log: true
- name: Read metrics API key from OpenBao
community.hashi_vault.vault_kv2_get:
url: "{{ uptime_kuma_openbao_url }}"
engine_mount_point: "{{ uptime_kuma_openbao_mount }}"
path: "{{ uptime_kuma_openbao_metrics_path }}"
auth_method: token
delegate_to: localhost
become: false
run_once: true
register: _uptime_kuma_metrics_secret
failed_when:
- _uptime_kuma_metrics_secret.failed | default(false)
- "'Invalid or missing path' not in (_uptime_kuma_metrics_secret.msg | default(''))"
no_log: true
- name: Ensure Uptime Kuma directories exist
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: "0755"
loop:
- "{{ uptime_kuma_dir }}"
- "{{ uptime_kuma_dir }}/data"
- "{{ uptime_kuma_dir }}/setup"
- name: Deploy kuma-setup.js
ansible.builtin.copy:
src: kuma-setup.js
dest: "{{ uptime_kuma_dir }}/setup/kuma-setup.js"
mode: "0644"
- name: Check for setup marker
ansible.builtin.stat:
path: "{{ uptime_kuma_dir }}/data/.setup-done"
register: _uptime_kuma_marker
- name: Deploy docker-compose.yml
ansible.builtin.template:
src: docker-compose.yml.j2
dest: "{{ uptime_kuma_dir }}/docker-compose.yml"
mode: "0644"
vars:
uptime_kuma_route_enabled: "{{ _uptime_kuma_marker.stat.exists }}"
- name: Pull Uptime Kuma image
ansible.builtin.command: docker compose pull
args:
chdir: "{{ uptime_kuma_dir }}"
changed_when: false
- name: Start Uptime Kuma
ansible.builtin.command: docker compose up -d
args:
chdir: "{{ uptime_kuma_dir }}"
changed_when: false
- name: Remove the script from its former single-file mount path
ansible.builtin.file:
path: "{{ uptime_kuma_dir }}/kuma-setup.js"
state: absent
- name: Wait for Uptime Kuma on loopback
ansible.builtin.uri:
url: http://127.0.0.1:3001
status_code: 200
register: _uptime_kuma_up
until: _uptime_kuma_up.status == 200
retries: 30
delay: 5
- name: Check the stored metrics API key against Uptime Kuma
ansible.builtin.uri:
url: http://127.0.0.1:3001/metrics
headers:
Authorization: "Basic {{ (':' ~ _uptime_kuma_metrics_key) | b64encode }}"
status_code: [200, 401]
vars:
_uptime_kuma_metrics_key: "{{ (_uptime_kuma_metrics_secret.secret | default({})).api_key | default('') }}"
when: _uptime_kuma_metrics_key | length > 0
register: _uptime_kuma_metrics_check
no_log: true
- name: Remove a leftover metrics API key handoff file
ansible.builtin.file:
path: "{{ uptime_kuma_dir }}/data/.metrics-api-key"
state: absent
- name: Bootstrap Uptime Kuma
ansible.builtin.command:
argv:
- docker
- compose
- exec
- -T
- -e
- KUMA_SETUP_USERNAME
- -e
- KUMA_SETUP_PASSWORD
- -e
- KUMA_BASE_URL
- -e
- KUMA_SMTP_HOST
- -e
- KUMA_SMTP_PORT
- -e
- KUMA_SMTP_USERNAME
- -e
- KUMA_SMTP_PASSWORD
- -e
- KUMA_SMTP_FROM
- -e
- KUMA_SMTP_TO
- -e
- KUMA_METRICS_ROTATE
- -e
- KUMA_METRICS_KEY_FILE
- uptime-kuma
- node
- /app/setup/kuma-setup.js
args:
chdir: "{{ uptime_kuma_dir }}"
environment:
KUMA_SETUP_USERNAME: "{{ _uptime_kuma_secret.secret.username }}"
KUMA_SETUP_PASSWORD: "{{ _uptime_kuma_secret.secret.password }}"
KUMA_BASE_URL: "{{ uptime_kuma_base_url }}"
KUMA_SMTP_HOST: "{{ _uptime_kuma_smtp.secret.server }}"
KUMA_SMTP_PORT: "{{ _uptime_kuma_smtp.secret.port }}"
KUMA_SMTP_USERNAME: "{{ _uptime_kuma_smtp.secret.username }}"
KUMA_SMTP_PASSWORD: "{{ _uptime_kuma_smtp.secret.token }}"
KUMA_SMTP_FROM: "{{ uptime_kuma_smtp_from }}"
KUMA_SMTP_TO: "{{ uptime_kuma_smtp_to }}"
KUMA_METRICS_ROTATE: "{{ 'false' if (_uptime_kuma_metrics_check.status | default(0)) == 200 else 'true' }}"
KUMA_METRICS_KEY_FILE: /app/data/.metrics-api-key
register: _uptime_kuma_setup
changed_when: "'admin user created' in _uptime_kuma_setup.stdout or 'changed:' in _uptime_kuma_setup.stdout"
failed_when: false
no_log: true
- name: Fail if Uptime Kuma setup failed
ansible.builtin.fail:
msg: "kuma-setup.js failed: rc={{ _uptime_kuma_setup.rc | default('undefined') }} stdout={{ _uptime_kuma_setup.stdout | default('') }} stderr={{ _uptime_kuma_setup.stderr | default('') }}"
when: (_uptime_kuma_setup.rc | default(1)) != 0
- name: Store the new metrics API key in OpenBao
when: "'changed: metrics api key' in _uptime_kuma_setup.stdout"
block:
- name: Read the new metrics API key
ansible.builtin.slurp:
src: "{{ uptime_kuma_dir }}/data/.metrics-api-key"
register: _uptime_kuma_new_metrics_key
no_log: true
- name: Write the metrics API key to OpenBao
community.hashi_vault.vault_kv2_write:
url: "{{ uptime_kuma_openbao_url }}"
engine_mount_point: "{{ uptime_kuma_openbao_mount }}"
path: "{{ uptime_kuma_openbao_metrics_path }}"
auth_method: token
data:
api_key: "{{ _uptime_kuma_new_metrics_key.content | b64decode }}"
delegate_to: localhost
become: false
run_once: true
no_log: true
always:
- name: Remove the metrics API key handoff file
ansible.builtin.file:
path: "{{ uptime_kuma_dir }}/data/.metrics-api-key"
state: absent
- name: Record setup completion
ansible.builtin.copy:
content: ""
dest: "{{ uptime_kuma_dir }}/data/.setup-done"
mode: "0644"
force: false
- name: Deploy docker-compose.yml with the route enabled
ansible.builtin.template:
src: docker-compose.yml.j2
dest: "{{ uptime_kuma_dir }}/docker-compose.yml"
mode: "0644"
vars:
uptime_kuma_route_enabled: true
- name: Start Uptime Kuma with the route enabled
ansible.builtin.command: docker compose up -d
args:
chdir: "{{ uptime_kuma_dir }}"
register: _uptime_kuma_route
changed_when: "'Recreate' in _uptime_kuma_route.stderr or 'Started' in _uptime_kuma_route.stderr"