personal_infra/ansible/roles/datum_gateway/README.md
counterweight a0c23ae766
datum-gateway: convert to a role, de-Uptime-Kuma the health check
802-line playbook becomes 68 lines (three plays: the role, the Caddy dashboard,
the Stratum socket proxy) plus a 345-line role. datum_gateway_vars.yml is
deleted; its content is the role's defaults.

Verified after a real run with zero miners connected: datum-gateway restarted
cleanly onto the reformatted config, deployed config.json semantically identical
to what was there (pool_address bc1qvrj3g84..., pool_pass_* false, ports
unchanged), health check timer firing, and the Knots side untouched - bitcoind
still up since 2026-08-19 with blocknotify intact.

TWO PIECES OF DRIFT WHERE THE NODE WAS RIGHT, both confirmed with the operator:

- datum_mining_address: the vault held bc1qdse9dsg... while the node had been
  mining to bc1qvrj3g... since 2026-08-08. This is WHERE BLOCK REWARDS ARE PAID.
  And unlike fulcrum and bitcoin-knots, the `Restart datum-gateway` handler here
  was never gated, so the stale value would have applied immediately rather than
  sitting inert on disk.
- pool_pass_workers / pool_pass_full_users: false on the node, true in the vars
  file.

Both corrected in the vault and role defaults with notes recording why.

Comparing this config needs semantics, not text: the live file is single-line
JSON and the template renders pretty-printed, so a textual diff is pure noise.
Rendering it and comparing parsed JSON is what surfaced both differences.

config.json carries bitcoind.rpcpassword and api.admin_password, and --diff
prints rendered content - so `--check --diff` put them on the terminal. The task
now sets diff: false by default (-e datum_reveal_config=true to opt in). Those
two should be rotated.

I also mis-reported pool_pass_workers/pool_pass_full_users as exposed credentials
because my masking matched "pass" in the key name. They are BOOLEANS, and
mining.pool_address is a Bitcoin address, public by nature. Only the two real
passwords above were exposed.

`Configure cmake build` and `Compile datum_gateway` are bare command: tasks with
no changed_when, so they recompile on every run. The build is reproducible -
Install datum_gateway binary sees identical content and leaves the installed
binary's timestamp alone - but it is wasted work each time. Documented as the
idempotent floor.

Ownership parity checked mechanically against `git show HEAD:` keyed by task
name: 7/7 match, 9 Kuma tasks dropped.

This completes Plan 6 Stage 2: all six services in the list are roles.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-13 18:25:41 +02:00

3.1 KiB

datum_gateway

Builds and runs DATUM Gateway, the solo/pooled mining gateway, on knots-box. The calling playbook adds two more plays on the edge host: the dashboard via caddy_site, and the public Stratum port via socket_proxy.

Converted from deploy_datum_gateway_playbook.yml (802 lines) under Plan 6. The playbook is now 68 lines and keeps all three plays.

⚠ This is half of a system

The Bitcoin Knots node on the same host feeds this gateway through blocknotify=killall -USR1 datum_gateway in bitcoin.conf — see roles/bitcoin_knots/README.md, where that line was found to be missing from the template entirely. Changing either config means thinking about both.

Interrupting Stratum costs mining shares. Check before any run that restarts it:

ss -tn state established '( sport = :23334 )'

Two pieces of drift where the node was right

The repo and the node had diverged on values that matter, and the deployment would have applied the repo's:

node (correct) repo said
datum_mining_address bc1qvrj3g84… bc1qdse9dsg…
pool_pass_workers / _full_users false true

The address is the one that would have hurt: it is where block rewards are paid, and unlike fulcrum and bitcoin-knots the Restart datum-gateway handler here was never gated, so the change would have applied immediately rather than sitting inert. Both corrected in the vault and defaults, with notes.

Verify semantics rather than text when touching config.json — render it and compare parsed JSON, because the live file is single-line and the template is pretty-printed, so a textual diff is all noise:

json.load(open('live.json')) == json.load(open('rendered.json'))

config.json holds real secrets — diff is suppressed

The file carries bitcoind.rpcpassword and api.admin_password. --diff prints rendered content, so the task sets diff: false by default; pass -e datum_reveal_config=true to opt in.

Note pool_pass_workers / pool_pass_full_users are booleans, not passwords, despite the names — they control DATUM's pool-password passthrough. mining.pool_address is a Bitcoin address and public by nature.

Expect changed on the compile every run

Configure cmake build and Compile datum_gateway are bare command: tasks with no changed_when, so they always report changed and always re-run. The build is reproducible — Install datum_gateway binary sees identical content and does not replace it, so the installed binary keeps its original timestamp — but the compile itself is wasted work on every run. That is the idempotent floor, not drift.

Monitoring: one variable, no product knowledge

The check tests the gateway API and records the answer in its exit code, which systemd keeps: systemctl is-failed datum-gateway-healthcheck.service. Set healthcheck_push_url to report anywhere accepting an HTTP ping.

Unlike the other services here, only the health-check timer handler was gated by uptime_kuma_enabled; the main deployment restart worked throughout.