Cut the comment bloat from the Podman playbooks

Comment blocks now stay within three lines and explain only the non-obvious. Long histories, include examples, and commented-out code are gone. No task, key, or value changed; the only data change is comment text inside the generated unit files.
This commit is contained in:
tanshu committed 2026-10-18 22:10:57 +05:30
1 parent 2aab1aec1e
commit 476a6d7cd0
85 files changed
+372 -2433

No files matched your search

+4 -17
View File
@@ -1,27 +1,14 @@
---
# Caddy is its own playbook (caddy/playbook.yml) and a rootless Quadlet unit
# there. These handlers run as the connection user, so `systemctl --user` and
# `podman exec` work without any XDG_RUNTIME_DIR juggling.
# Notified by this role when the Caddyfile changes. A reload keeps existing
# connections; a restart would briefly drop every hosted site.
#
# Note the config path: /etc/caddy/Caddyfile is the mount inside the container,
# not {{ caddyfile_path }}, which is the host side of it.
# A reload keeps existing connections. A restart would briefly drop every hosted site.
# The config path is inside the container, not caddyfile_path on the host.
- name: Reload Caddy configuration
ansible.builtin.command: >-
podman exec {{ caddy_name }} caddy reload --config /etc/caddy/Caddyfile
changed_when: true
listen: "Reload Caddy"
# Notified by caddy/roles/register when this service's network unit, or the
# drop-in that attaches Caddy to it, is written. Quadlet has no live equivalent
# of `docker network connect`, so the container has to be recreated — a brief
# restart of every hosted site, not just this one. See caddy/readme.md,
# "Trade-off worth knowing".
#
# Defined after the reload above so that when both are notified the cheap
# config reload happens first.
# Quadlet has no live equivalent of network connect, so Caddy is recreated and every hosted site restarts.
# Defined after the reload so the cheap reload runs first.
- name: Restart Caddy
ansible.builtin.systemd_service:
name: "{{ caddy_name }}.service"
-11
View File
@@ -1,15 +1,4 @@
---
# Append this site's block to the shared Caddyfile.
#
# The Caddyfile is a bind mount into the Caddy container, so Caddy sees the
# change as soon as the file is written; the handler only asks Caddy to re-read
# it. That is a reload, not a restart, so the other hosted sites are untouched.
#
# blockinfile is idempotent on its own via the marker, so there is no need to
# slurp the file and compare first — which also matters because slurp *fails*
# when the Caddyfile does not exist yet, on a host where the Caddy playbook has
# not run.
- name: "Add the {{ host }} site block to the Caddyfile"
ansible.builtin.blockinfile:
path: "{{ caddyfile_path }}"
+12 -63
View File
@@ -1,13 +1,5 @@
---
# TriliumNext Notes as a rootless Podman Quadlet unit.
#
# Everything here runs as {{ podman_user }} — the connection user. No become, no
# XDG_RUNTIME_DIR: the SSH connection gave us a real PAM session, so systemd's
# user manager is reachable through the standard environment.
# The image's data directory is one tree: document.db with its WAL sidecars,
# config.ini, session_secret.txt, and the three subdirectories below. It is
# created here as the copy target as much as for a fresh install.
# The image keeps document.db, config.ini, session_secret.txt and the subdirectories below in this one tree.
- name: Ensure the Trilium data directory exists
ansible.builtin.file:
path: "{{ data_dir }}"
@@ -16,12 +8,8 @@
group: "{{ podman_user }}"
mode: '0755'
# Trilium creates these itself on first start, at 0700 — which is exactly how
# they are on monoco. Creating them here means a fresh host and a migrated one
# look the same, and that the destinations named in readme.md exist before the
# copy. log/ is where the app writes its daily log — which the play reads back
# later as evidence that the container is writing to the host — and backup/ is
# where its own zipped document.db backups land.
# Trilium creates these at 0700 on first start. Creating them here makes a fresh host and a migrated one look the same.
# log/ holds the daily log the play reads back as evidence, and backup/ holds the app's own zipped backups.
- name: Ensure the app-managed subdirectories exist
ansible.builtin.file:
path: "{{ item }}"
@@ -34,11 +22,7 @@
- "{{ tmp_dir }}"
- "{{ backup_dir }}"
# Checked before the unit starts, because this is the one thing the play cannot
# tell after the fact: with no document.db the app serves a brand new, empty
# document, which is right for a fresh install and wrong for a migration whose
# copy has not run yet. Once the app has started it creates the file itself and
# the evidence is gone.
# Check before the unit starts, because an empty document it creates hides whether the copy ever landed.
- name: Check whether a document has been copied in
ansible.builtin.stat:
path: "{{ data_dir }}/document.db"
@@ -64,15 +48,7 @@
- Reload systemd user units
- Restart Trilium
# Quadlet honours [Install] WantedBy= when it generates the unit, so
# `systemctl --user enable` is neither needed nor possible on a generated unit.
#
# All three steps are in one block because they fail the same way and want the
# same evidence. `systemctl start` reports success as soon as it has handed the
# unit to systemd, so a container that dies a second later — `User=0` missing, a
# network that was never attached, an unwritable data directory — surfaces here
# as `activating`, or as a health check that never passes, with the real reason
# only in the journal. Restart=always makes that a crash loop, not an error.
# Quadlet honours [Install] WantedBy=, so the generated unit is never enabled.
- name: Start and verify Trilium
block:
- name: Start Trilium
@@ -82,9 +58,7 @@
state: started
daemon_reload: true
# Retried rather than checked once: the container is coming up, and podman
# reports `activating` for the interval between systemd starting it and the
# container's own readiness notification.
# Retried because podman reports `activating` until the container signals readiness.
- name: Verify Trilium is running
ansible.builtin.command: "systemctl --user is-active {{ unit_name }}"
register: trilium_active
@@ -93,11 +67,7 @@
delay: 5
changed_when: false
# `is-active` says the container is running; it does not say the app can
# serve. The unit defines the probe (HealthCmd=, see the template) because
# the image ships none, so this runs exactly that command once,
# synchronously, and fails while the app is still migrating or not yet
# listening.
# The image ships no health check, so the unit defines one and this runs it synchronously.
- name: Wait for Trilium to pass its health check
ansible.builtin.command: "podman healthcheck run {{ container_name }}"
register: trilium_health
@@ -106,10 +76,7 @@
delay: 5
changed_when: false
rescue:
# systemd reports "control process exited with error code" and nothing
# else, which is useless for the usual failures. The journal is where the
# entrypoint's own output is — that is where "su: Authentication failure"
# or a failed bind mount shows up.
# systemd only reports "control process exited with error code", so read the journal for the real reason.
- name: Collect Trilium diagnostics
ansible.builtin.command: "{{ item }}"
loop:
@@ -128,19 +95,8 @@
ansible.builtin.fail:
msg: "Trilium did not start — see the diagnostics above."
# The check that catches a missing or mistyped Volume= line, which is the one
# failure here that is silent: the app would run perfectly well with document.db
# in the container's writable layer — or in an anonymous volume, if the image
# declares one — and lose it on the next recreate.
#
# It has to be a mount check and not a file check. Audiobookshelf can assert that
# its database appeared on the host, because the app creates it; here the
# migration puts document.db on the host *before* the app ever runs, so its
# presence proves nothing about whether the container can see it.
#
# Both halves matter: the destination alone would still be satisfied by an
# anonymous volume mounted where the bind mount should be, which is exactly the
# silent case. `Source` is the path Quadlet passed to podman, verbatim.
# A missing or mistyped Volume= line would run fine and lose document.db on the next recreate, so check the mount.
# Both Source and Destination must match, since a destination-only check would pass an anonymous volume.
- name: Read the running container's configuration back
ansible.builtin.command: "podman inspect {{ container_name }}"
register: trilium_inspect
@@ -162,12 +118,7 @@
check the Volume= line in the generated unit
({{ quadlet_dir }}/{{ container_name }}.container).
# Evidence rather than a gate: with keep-id:uid=1000 mapped onto
# {{ podman_user }}, what the app writes lands in {{ data_dir }} owned by
# {{ podman_user }} — and the app writes a daily log the moment it starts. A log
# touched in the last few minutes is that, visible from the host. It is reported
# rather than asserted because a slow start can legitimately leave nothing here
# yet; the mount assertion above is the hard check.
# Evidence, not a gate: a log touched in the last five minutes shows the app writing into the host data directory, while a slow start may leave none.
- name: Look for a log written since the unit started
ansible.builtin.find:
paths: "{{ log_dir }}"
@@ -190,9 +141,7 @@
path: "{{ data_dir }}/document.db"
register: trilium_document_db_after
# A migrated document.db is a few megabytes; the empty one the app creates on a
# fresh install is kilobytes. Worth printing, because it is the difference
# between "the notes came across" and "the copy never ran".
# A migrated document.db is megabytes; the empty one from a fresh install is kilobytes.
- name: Report the document on the host
ansible.builtin.debug:
msg: >-