fix(ansible): --check survives a not-yet-converged Guest (Closes #50) #51

Merged
pit merged 1 commit from hermes/50-fix-make-prod-check into main 2026-10-07 14:15:47 +00:00
Owner

What this fixes

make prod and make pre died at the service step on any Guest that had not been converged. The service Target rehearses with ansible-playbook --check --diff (Makefile:266-271), and the rehearsal itself failed, so the real run never happened.

Check mode skips the steps that create the inputs, and several modules do not tolerate a missing input even under --check:

  • get_url — dest's parent directory absent
  • unarchive / copy with remote_src — source absent
  • systemd: state=started|restarted — unit file never rendered
  • become_user: postgres — the user the skipped apt install would have created (Unprivileged become user would be unable to read the file)

uri and wait_for are unaffected (auto-skipped without check-mode support).

Approach

Guard only what --check genuinely cannot produce, with one read per fact — and keep it declarative:

  • forgejo_tree (/srv/forgejo/bin) around the get_urls, the two systemd starts and the two handlers in the forgejo role
  • forgejo_pg (/usr/bin/psql) around the five postgres tasks
  • forgejo_mcp_tree (/srv/forgejo-mcp/releases) around the install block, the start block and the handler in forgejo_mcp

The check writes nothing; a converged Guest previews exactly as before.

Also folds the forgejo_mcp install: unarchive straight into bin/ with --strip-components=1, dropping the separate copy task and the intermediate releases/<stem>/ tree.

get_url stays: unarchive has no checksum parameter, so fetching inside it would drop the pinned-sha256 verification, and get_url is also the cache — it revalidates with a HEAD rather than re-downloading the ~5.7 MB on every run and check.

Verification (live on PRE 142; PROD not touched)

Check Result
--check, fresh PRE, before failed=1 (Destination /srv/forgejo/bin does not exist)
--check, fresh PRE, after failed=0, nothing written
Stage 1 — forgejo role only changed=22
Stage 2 — full site.yml (+ forgejo_mcp) changed=7, MCP 401 probe ok
Re-run site.yml changed=0
--check, converged PRE failed=0
curl -X POST http://10.12.0.142:8089/mcp 401
Unlisted Host 403
systemctl is-active forgejo / runner / mcp active / active / active

Closes #50

## What this fixes `make prod` and `make pre` died at the service step on any Guest that had not been converged. The `service` Target rehearses with `ansible-playbook --check --diff` (Makefile:266-271), and the rehearsal itself failed, so the real run never happened. Check mode skips the steps that create the inputs, and several modules do not tolerate a missing input even under `--check`: - `get_url` — `dest`'s parent directory absent - `unarchive` / `copy` with `remote_src` — source absent - `systemd: state=started|restarted` — unit file never rendered - `become_user: postgres` — the user the skipped apt install would have created (`Unprivileged become user would be unable to read the file`) `uri` and `wait_for` are unaffected (auto-skipped without check-mode support). ## Approach Guard only what `--check` genuinely cannot produce, with one read per fact — and keep it declarative: - `forgejo_tree` (`/srv/forgejo/bin`) around the `get_url`s, the two `systemd` starts and the two handlers in the `forgejo` role - `forgejo_pg` (`/usr/bin/psql`) around the five `postgres` tasks - `forgejo_mcp_tree` (`/srv/forgejo-mcp/releases`) around the install block, the start block and the handler in `forgejo_mcp` The check writes nothing; a converged Guest previews exactly as before. Also folds the `forgejo_mcp` install: `unarchive` straight into `bin/` with `--strip-components=1`, dropping the separate copy task and the intermediate `releases/<stem>/` tree. `get_url` stays: `unarchive` has no `checksum` parameter, so fetching inside it would drop the pinned-sha256 verification, and `get_url` is also the cache — it revalidates with a HEAD rather than re-downloading the ~5.7 MB on every run and check. ## Verification (live on PRE 142; PROD not touched) | Check | Result | | --- | --- | | `--check`, fresh PRE, before | `failed=1` (`Destination /srv/forgejo/bin does not exist`) | | `--check`, fresh PRE, after | `failed=0`, nothing written | | Stage 1 — `forgejo` role only | `changed=22` | | Stage 2 — full `site.yml` (+ `forgejo_mcp`) | `changed=7`, MCP 401 probe ok | | Re-run `site.yml` | `changed=0` | | `--check`, converged PRE | `failed=0` | | `curl -X POST http://10.12.0.142:8089/mcp` | `401` | | Unlisted `Host` | `403` | | `systemctl is-active` forgejo / runner / mcp | active / active / active | Closes #50
The service step's rehearsal (`ansible-playbook --check --diff`) failed on
any Guest that had never been converged, so `make prod` / `make pre` died
before the real run. Check mode skips the steps that create the inputs and
several modules do not tolerate a missing input: `get_url` (dest parent
absent), `unarchive`/`copy remote_src` (source absent), `systemd` start on an
unrendered unit, and `become_user: postgres` on a user the skipped apt install
would have created.

Guard only what --check genuinely cannot produce, with one read per fact:

- `forgejo_tree` (/srv/forgejo/bin) around the `get_url`s, the `systemd`
  starts and the handlers in the `forgejo` role;
- `forgejo_pg` (/usr/bin/psql) around the five `postgres` tasks;
- `forgejo_mcp_tree` around the install block, the start block and the handler
  in `forgejo_mcp`.

Also fold the `forgejo_mcp` install: `unarchive` straight into `bin/` with
`--strip-components=1`, dropping the separate copy task and the intermediate
`releases/<stem>/` tree. `get_url` stays — `unarchive` has no `checksum`, and
it is the cache that revalidates with a HEAD instead of re-downloading.

Closes #50
pit force-pushed hermes/50-fix-make-prod-check from b63f56777e to 588573e066 2026-10-07 12:07:40 +00:00 Compare
pit merged commit adf6ce2681 into main 2026-10-07 14:15:47 +00:00
pit deleted branch hermes/50-fix-make-prod-check 2026-10-07 14:15:47 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
olympus/infra-forge!51
No description provided.