personal_infra/ansible/services/mempool/deploy_mempool_playbook.yml

34 lines
1.6 KiB
YAML
Raw Normal View History

mempool: convert to a role, de-Uptime-Kuma the health checks 745-line playbook becomes 37 lines (the role, plus the Caddy play for the edge host) and a 408-line role with docker/deploy/healthcheck phases and six templates. mempool_vars.yml is deleted; its content is the role's defaults. Three health checks are kept, not collapsed: Mempool is three moving parts and knowing which one is down is the point. Each has its own script, unit, timer and push_url, driven by a mempool_healthchecks list. The Uptime Kuma specifics are gone - the embedded Python creating monitors over the API, the /tmp credentials file, the push-URL file read back and parsed, three Environment= rewrites - and the three live push URLs are preserved from the vault, so reporting is unchanged. `Enable and start health check timers` and `Display deployment status` were both guarded by uptime_kuma_enabled despite being deployment tasks. Third service in a row with that pattern: the deprecation banner was applied to contiguous blocks, so anything sitting near the push plumbing was disabled with it. Ungated. TWO OWNERSHIP PROBLEMS, different in kind: - MINE: I wrote `owner: root` on docker-compose.yml where the original says `owner: "{{ ansible_user }}"`. A straight violation of extract-mechanically- change-nothing, caught only by reading the check-mode diff line by line. Reverted to match the original. - PRE-EXISTING, and dangerous: the playbook declared `owner: "{{ ansible_user }}"` (1000) on the MariaDB data directory, which the container owns as uid 999. Confirmed against `git show HEAD:` before concluding it was not mine. It had drifted since the containers were created and went unnoticed because the playbook had not been run since. This was not academic. The first real run pulled a newer mariadb:10.11 and recreated mempool-db; with the chown still in place MariaDB would have come back to a data directory it could not write. The role now ensures the directory exists and leaves ownership to the container. Verified after the run: /opt/mempool/mysql is still 999:999 and all three containers are healthy. This is a deliberate behaviour change, not part of the extraction. It is in this commit rather than a follow-up because the faithful version was never safe to run, so there was no intermediate state worth recording as verified. mempool_frontend_port moved to services_config.yml: two hosts need it (this role deploys the frontend, the Caddy play proxies to it from the edge host) and a role default is invisible to the second play. caddy_site's parameter assert caught this loudly - "'mempool_frontend_port' is undefined" - rather than silently. Verified: check-mode diff clean apart from unavoidable check-mode artifacts; first run ok=24 changed=5, zero failures; second run changed=2 - the two bare `command:` tasks (pull, compose up) that have no changed_when and always report changed. That is the idempotent floor. All three health checks report ExecMainStatus 0 with their push URLs intact. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-12 18:49:11 +02:00
---
2025-12-14 22:15:29 +01:00
- name: Deploy Mempool Block Explorer with Docker
hosts: mempool
2025-12-14 22:15:29 +01:00
become: yes
vars:
mempool: convert to a role, de-Uptime-Kuma the health checks 745-line playbook becomes 37 lines (the role, plus the Caddy play for the edge host) and a 408-line role with docker/deploy/healthcheck phases and six templates. mempool_vars.yml is deleted; its content is the role's defaults. Three health checks are kept, not collapsed: Mempool is three moving parts and knowing which one is down is the point. Each has its own script, unit, timer and push_url, driven by a mempool_healthchecks list. The Uptime Kuma specifics are gone - the embedded Python creating monitors over the API, the /tmp credentials file, the push-URL file read back and parsed, three Environment= rewrites - and the three live push URLs are preserved from the vault, so reporting is unchanged. `Enable and start health check timers` and `Display deployment status` were both guarded by uptime_kuma_enabled despite being deployment tasks. Third service in a row with that pattern: the deprecation banner was applied to contiguous blocks, so anything sitting near the push plumbing was disabled with it. Ungated. TWO OWNERSHIP PROBLEMS, different in kind: - MINE: I wrote `owner: root` on docker-compose.yml where the original says `owner: "{{ ansible_user }}"`. A straight violation of extract-mechanically- change-nothing, caught only by reading the check-mode diff line by line. Reverted to match the original. - PRE-EXISTING, and dangerous: the playbook declared `owner: "{{ ansible_user }}"` (1000) on the MariaDB data directory, which the container owns as uid 999. Confirmed against `git show HEAD:` before concluding it was not mine. It had drifted since the containers were created and went unnoticed because the playbook had not been run since. This was not academic. The first real run pulled a newer mariadb:10.11 and recreated mempool-db; with the chown still in place MariaDB would have come back to a data directory it could not write. The role now ensures the directory exists and leaves ownership to the container. Verified after the run: /opt/mempool/mysql is still 999:999 and all three containers are healthy. This is a deliberate behaviour change, not part of the extraction. It is in this commit rather than a follow-up because the faithful version was never safe to run, so there was no intermediate state worth recording as verified. mempool_frontend_port moved to services_config.yml: two hosts need it (this role deploys the frontend, the Caddy play proxies to it from the edge host) and a role default is invisible to the second play. caddy_site's parameter assert caught this loudly - "'mempool_frontend_port' is undefined" - rather than silently. Verified: check-mode diff clean apart from unavoidable check-mode artifacts; first run ok=24 changed=5, zero failures; second run changed=2 - the two bare `command:` tasks (pull, compose up) that have no changed_when and always report changed. That is the idempotent floor. All three health checks report ExecMainStatus 0 with their push URLs intact. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-12 18:49:11 +02:00
# Preserves the three push URLs these checks have been reporting to all
# along, so the move to a role changes no behaviour. The role knows nothing
# about Uptime Kuma — these are just "URLs that accept a ping", and whatever
# replaces it sets the same values.
mempool_healthchecks:
uptime kuma: remove every live reference, repoint the probes to Gatus Nothing in the repo pushes to, authenticates against, or is gated by Uptime Kuma any more. ── The sixth instance of the banner bug ──────────────────────────────────── memos had `Restart memos` guarded by `uptime_kuma_enabled`, because the deprecation banner was placed immediately above it and swept it in. It is a HANDLER, so every memos config change since 2026-09-11 applied to disk and silently never restarted the service. Ungated. That is the same failure found in forgejo-runner's self-assert, phoenixd's timer enable, mempool's three timer enables, fulcrum's restart handler and bitcoind's restart handler. Every guard was read and asked "monitoring or deployment?" before being deleted, which is the only reason this was caught. ── What was removed ──────────────────────────────────────────────────────── 30 uptime_kuma_enabled guards across 7 unconverted service playbooks, and the 29 Kuma monitor-creation tasks they gated (embedded Python that drove the Kuma API, temp credential files, cleanup) 7 dead uptime_kuma_api_url definitions 7 stale DEPRECATED banners uptime_kuma_enabled and subdomains.uptime_kuma from group_vars/all healthcheck_push_urls from the vault - 30 push tokens services/ntfy/setup_ntfy_uptime_kuma_notification.yml -> archive/ The explanatory comments in the six converted roles are KEPT on purpose. They record why a handler is ungated, and deleting the explanation invites someone to helpfully re-add the guard. ── The probes moved rather than died ─────────────────────────────────────── Eight per-service health checks were still pushing to Kuma. They are not superseded by infra/401: that answers "is the unit running", these answer "does the service actually respond" - an RPC call to bitcoind, a TCP connect to Fulcrum's Electrum port, an HTTP fetch from Mempool's backend. A process can be perfectly `active` and useless. So they were repointed, not deleted. Gatus external endpoints take a POST with a bearer token and success=true|false where Kuma took a GET with ?status=up, so report() now maps up/down to true/false internally and no call site changed. Registered by infra/403 as the `probe` group, one token per host. Two bugs fixed while in there: * forgejo-runner's check only ever reported SUCCESS - it exited before pushing when the runner was down, so a failure was invisible until the heartbeat window expired. Reporting the failure is the entire point of a check. * All six healthcheck .service units were mode 0644 and now carry a bearer token. They are 0600. Verified: 91 endpoints, 91 UP, 0 DOWN. Every probe triggered by hand and confirmed arriving. Zero Kuma URLs left in the vault, zero live references in any playbook or role. Still standing, deliberately: the Kuma container on watchtower, its Caddy vhost, and the uptime.contrapeso.xyz DNS record. Turning the service off is a separate decision from removing the code that talked to it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 10:30:28 +02:00
- {name: mariadb, label: MariaDB, push_url: "https://{{ subdomains.gatus }}.{{ root_domain }}/api/v1/endpoints/probe_mempool-mariadb/external"}
- {name: backend, label: Backend, push_url: "https://{{ subdomains.gatus }}.{{ root_domain }}/api/v1/endpoints/probe_mempool-backend/external"}
- {name: frontend, label: Frontend, push_url: "https://{{ subdomains.gatus }}.{{ root_domain }}/api/v1/endpoints/probe_mempool-frontend/external"}
# One token for all three components: they run on the same host, so the
# blast radius is already that host.
healthcheck_push_token: "{{ gatus_push_tokens[inventory_hostname] }}"
mempool: convert to a role, de-Uptime-Kuma the health checks 745-line playbook becomes 37 lines (the role, plus the Caddy play for the edge host) and a 408-line role with docker/deploy/healthcheck phases and six templates. mempool_vars.yml is deleted; its content is the role's defaults. Three health checks are kept, not collapsed: Mempool is three moving parts and knowing which one is down is the point. Each has its own script, unit, timer and push_url, driven by a mempool_healthchecks list. The Uptime Kuma specifics are gone - the embedded Python creating monitors over the API, the /tmp credentials file, the push-URL file read back and parsed, three Environment= rewrites - and the three live push URLs are preserved from the vault, so reporting is unchanged. `Enable and start health check timers` and `Display deployment status` were both guarded by uptime_kuma_enabled despite being deployment tasks. Third service in a row with that pattern: the deprecation banner was applied to contiguous blocks, so anything sitting near the push plumbing was disabled with it. Ungated. TWO OWNERSHIP PROBLEMS, different in kind: - MINE: I wrote `owner: root` on docker-compose.yml where the original says `owner: "{{ ansible_user }}"`. A straight violation of extract-mechanically- change-nothing, caught only by reading the check-mode diff line by line. Reverted to match the original. - PRE-EXISTING, and dangerous: the playbook declared `owner: "{{ ansible_user }}"` (1000) on the MariaDB data directory, which the container owns as uid 999. Confirmed against `git show HEAD:` before concluding it was not mine. It had drifted since the containers were created and went unnoticed because the playbook had not been run since. This was not academic. The first real run pulled a newer mariadb:10.11 and recreated mempool-db; with the chown still in place MariaDB would have come back to a data directory it could not write. The role now ensures the directory exists and leaves ownership to the container. Verified after the run: /opt/mempool/mysql is still 999:999 and all three containers are healthy. This is a deliberate behaviour change, not part of the extraction. It is in this commit rather than a follow-up because the faithful version was never safe to run, so there was no intermediate state worth recording as verified. mempool_frontend_port moved to services_config.yml: two hosts need it (this role deploys the frontend, the Caddy play proxies to it from the edge host) and a role default is invisible to the second play. caddy_site's parameter assert caught this loudly - "'mempool_frontend_port' is undefined" - rather than silently. Verified: check-mode diff clean apart from unavoidable check-mode artifacts; first run ok=24 changed=5, zero failures; second run changed=2 - the two bare `command:` tasks (pull, compose up) that have no changed_when and always report changed. That is the idempotent floor. All three health checks report ExecMainStatus 0 with their push URLs intact. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-12 18:49:11 +02:00
roles:
- mempool
2025-12-14 22:15:29 +01:00
- name: Configure Caddy reverse proxy for Mempool on the edge host
hosts: edge
2025-12-14 22:15:29 +01:00
become: yes
vars:
mempool: convert to a role, de-Uptime-Kuma the health checks 745-line playbook becomes 37 lines (the role, plus the Caddy play for the edge host) and a 408-line role with docker/deploy/healthcheck phases and six templates. mempool_vars.yml is deleted; its content is the role's defaults. Three health checks are kept, not collapsed: Mempool is three moving parts and knowing which one is down is the point. Each has its own script, unit, timer and push_url, driven by a mempool_healthchecks list. The Uptime Kuma specifics are gone - the embedded Python creating monitors over the API, the /tmp credentials file, the push-URL file read back and parsed, three Environment= rewrites - and the three live push URLs are preserved from the vault, so reporting is unchanged. `Enable and start health check timers` and `Display deployment status` were both guarded by uptime_kuma_enabled despite being deployment tasks. Third service in a row with that pattern: the deprecation banner was applied to contiguous blocks, so anything sitting near the push plumbing was disabled with it. Ungated. TWO OWNERSHIP PROBLEMS, different in kind: - MINE: I wrote `owner: root` on docker-compose.yml where the original says `owner: "{{ ansible_user }}"`. A straight violation of extract-mechanically- change-nothing, caught only by reading the check-mode diff line by line. Reverted to match the original. - PRE-EXISTING, and dangerous: the playbook declared `owner: "{{ ansible_user }}"` (1000) on the MariaDB data directory, which the container owns as uid 999. Confirmed against `git show HEAD:` before concluding it was not mine. It had drifted since the containers were created and went unnoticed because the playbook had not been run since. This was not academic. The first real run pulled a newer mariadb:10.11 and recreated mempool-db; with the chown still in place MariaDB would have come back to a data directory it could not write. The role now ensures the directory exists and leaves ownership to the container. Verified after the run: /opt/mempool/mysql is still 999:999 and all three containers are healthy. This is a deliberate behaviour change, not part of the extraction. It is in this commit rather than a follow-up because the faithful version was never safe to run, so there was no intermediate state worth recording as verified. mempool_frontend_port moved to services_config.yml: two hosts need it (this role deploys the frontend, the Caddy play proxies to it from the edge host) and a role default is invisible to the second play. caddy_site's parameter assert caught this loudly - "'mempool_frontend_port' is undefined" - rather than silently. Verified: check-mode diff clean apart from unavoidable check-mode artifacts; first run ok=24 changed=5, zero failures; second run changed=2 - the two bare `command:` tasks (pull, compose up) that have no changed_when and always report changed. That is the idempotent floor. All three health checks report ExecMainStatus 0 with their push URLs intact. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-12 18:49:11 +02:00
mempool_domain: "{{ subdomains.mempool }}.{{ root_domain }}"
2025-12-14 22:15:29 +01:00
tasks:
- name: Publish Mempool through Caddy (via Tailscale)
ansible.builtin.include_role:
name: caddy_site
vars:
caddy_site_name: mempool
caddy_site_domain: "{{ mempool_domain }}"
ansible: move the cross-host ports to host_vars, delete services_config.yml The four ports were the only entries in services_config.yml with a real justification: each is read twice, by the role that deploys the service on its own box AND by a socket-proxy or Caddy play that runs on the EDGE host and publishes it. A role default is invisible to that second play. But the shape was wrong in two ways. The file had to be named in vars_files: by 30 plays - opt-in configuration that someone will eventually forget - and five role defaults silently interpolated service_settings.*, so bitcoin_knots, fulcrum, datum_gateway and mempool were not self-contained: using any of them without that one vars_file entry broke it. Each port now lives in host_vars/<owning box>/main.yml: host_vars/knots_box_local/main.yml bitcoin_p2p_port, datum_gateway_api_port, datum_gateway_stratum_port host_vars/fulcrum_box_local/main.yml fulcrum_ssl_port host_vars/mempool_box_local/main.yml mempool_frontend_port host_vars auto-loads and outranks role defaults, so the owning role picks the value up with no vars_files at all, and the edge play reads the same single definition as hostvars['<host>'].<name>. The role defaults keep the protocol standard (8333, 50002, ...) so each role still works standalone, with the live deployment's value in host_vars winning. Also fixed a fourth copy of an inventory identity: the mempool Caddy play had "mempool-box:{{ ... }}" hardcoded in the upstream. It now derives the host from hostvars['mempool_box_local'].ansible_host, so inventory is the only place any box's name is written down. services_config.yml is deleted, with 25 more vars_files entries across 19 playbooks. Between this and the previous commit, 87 vars_files entries are gone and every variable in the repo now comes from group_vars/all, host_vars, inventory, a role default, or that service's own *_vars.yml. Verification: an edge-host probe resolves all eight ports and hostnames to byte-identical values to the ones services_config.yml used to supply. Each owning host resolves its own port through host_vars. All 37 playbooks' --list-tasks output is unchanged. The four edge plays that consume these values all check-diff changed=0 - the socket-proxy and Caddy units on vipy are byte-identical, which is the direct proof the rewiring landed on the same values. fulcrum and datum-gateway check-diff exactly as before (ok=28/changed=1 and ok=15/changed=1, both the known timer re-arm). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-13 21:02:57 +02:00
caddy_site_upstream: "{{ hostvars['mempool_box_local'].ansible_host }}:{{ hostvars['mempool_box_local'].mempool_frontend_port }}"
caddy_site_resolvers: "100.100.100.100"