Commit Graph
23 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 5.5 1c35cdef91 style: apply the autoformat output main drifted from
`make quality-high` on main (fea6f31d9f) rewrote two files in its
autoformat step:

- roles/sys-service/handlers/refresh_systemctl_service.yml: the
  handler's `when` was wrapped by hand; the formatter wraps it at line
  width. Both forms parse to the same YAML.
- tests/unit/python/roles/web-app-nextcloud/test_onlyoffice_check_deadline.py:
  two over-long assertIn calls that ruff format splits.

A second autoformat run leaves the tree unchanged, so main is stable
under the formatter again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 01:35:21 +02:00
kevinveenbirkenbachandClaude Opus 5.5 62f31fe675 fix(sys-service): judge a unit's result only after a deploy started it
The handlers after "Set systemctl service state" read Result and
ExecMainStatus and fail the deploy with "Unable to start service ..."
when either reports a failure. Most roles leave system_service_state
omitted (SYS_SERVICE_DEFAULT_STATE is omit outside MODE_DEBUG, and the
backup roles start their unit only in MODE_BACKUP), so the state task
changes nothing, and the two properties describe the unit's last run,
whenever it was.

Measured on a local stack: the volume backup unit had failed on
2026-10-12 in the CLI test of another deploy, when a container it had
stopped was recreated before it could start it again. The next day a
deploy of web-app-seaweedfs and web-app-prometheus, which did not run
the unit, read Result=exit-code and failed in the backup role.

The diagnostics now fire on a stale result only when the deploy set a
state itself. A failed state change still fails as before.

Verified in the stack container against a oneshot unit whose ExecStart
is /bin/false, left failed before each run, with the real handler file:
with the state omitted, main's handler fails with "Unable to start
service" and the new one passes; with state=started, which reruns the
unit, both fail. ansible lints and test_comments_valid pass.

Closes #914

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 21:32:33 +02:00
kevinveenbirkenbachandClaude Opus 5 99f7e03845 feat(sys-service): carry unit ordering, an Install section and a user scope
The generic unit template could express neither an ordering dependency nor an Install section, so a role needing either shipped its own templates/systemctl.service.j2 and re-answered the daemon reload, the enable and the flush behaviour by hand.

Add After, Before, Wants, RemainAfterExit and a WantedBy driven Install section, all inert at their defaults, and route the unit path, its owner, become and the systemctl probes through a system_service_scope so a per-login unit lands under the user's own systemd directory.

00_core is gated on the system scope rather than only its prune and lockdown steps: it sets run_once_sys_service, so a user-scope caller running first would otherwise skip the lockdown for every system-scope role behind it in the same play.

Rendering the previous template against the same inputs drops no directive and adds none; the only difference is the blank line an empty directive used to leave behind.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 18:09:43 +02:00
kevinveenbirkenbachandClaude Opus 5 a46348b6cf refactor(handlers): bind notify to a listen topic, not to a name
A handler name was doing two jobs at once: the line an operator reads in the
play output, and the identifier a `notify:` binds to. The two pull in opposite
directions -- the log wants "restart the SSH service, with diagnostics", the
binding wants a token that survives quoting, YAML flow style and a shell
round-trip -- and a name that changes for readability silently changes which
handler runs.

Every handler that a notify reached by name now carries a `listen:` with that
exact wording, so the binding is explicit before anything is renamed. The
topics themselves become identifiers: `compose up` reads `compose-up`,
`Restart NFS ganesha` reads `restart-nfs-ganesha`, 22 of them across both
sides of every notify. Where the topic is assembled at runtime, both branches
moved together: the conditional in sys-service carries two literals, and the
LDAP renderer interpolates `import-{{ folder }}-ldif-files`, which is what
makes those handlers reachable at all.

Freed from the binding, the names take the emoji prefix every other task line
already has.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 03:38:42 +02:00
kevinveenbirkenbachandClaude Opus 5 2a7f34113d docs(sys-service): record why the unit handlers stay async
The async on these two handlers is not an oversight to be swept with the
rest: system_service_async resolves to omit whenever a caller sets
system_service_force_linear_sync, so it is an opt-out the calling role
decides. The backup and repair roles ask for linear execution, the cleanup
and alarm roles deliberately do not.

That also settles the Result gate below them, which reads systemctl show
and looked pointless under fire and forget. It is not: it runs meaningfully
for exactly the callers that asked to wait.

Comments only, no behaviour change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 04:05:38 +02:00
kevinveenbirkenbachandClaude Opus 4.7 43fe446bef style(sys-service): reflow when: condition onto fewer lines
Pure cosmetic YAML reflow of the `or`-chain in the refresh handler.
Same operands, same precedence — no behavioural change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 02:53:05 +02:00
kevinveenbirkenbach 44e198c430 fix(sys-service): correct unit-name query swallowing service failures
The `Set systemctl service state` handler called the systemd module with
the resolved `{{ system_service_name }}` (e.g.
`mtn-cert-deploy.7.0.0.infinito.nexus.service`), but the subsequent
`systemctl show -p Result/ExecMainStatus` queries used
`{{ system_service_id }}.infinito.nexus.service` (e.g.
`sys-ctl-mtn-cert-deploy.infinito.nexus.service`) — a different,
non-existent unit. systemctl returned the default `success`/`0` for the
non-existent unit, so the diagnostic-on-failure task was skipped and
real oneshot failures (Mailu cert-deploy in the test-deploy-server CI
runs) were silently swallowed by the playbook.

Use `{{ system_service_name }}` for both queries so the actual unit's
result is inspected, and add `systemd_set_state.failed` to the
diagnostic trigger as a belt-and-suspenders against any future
systemctl-show false positives.
2026-05-21 23:46:48 +02:00
kevinveenbirkenbachandClaude Opus 4.7 2a023ca6a1 chore(lint): autoformat strict-failure semantics + claude.sh rename
* scripts/lint/autoformat.sh:
  - rename run_sort_claude_settings worker to run_claude (matches the
    renamed scripts/lint/claude.sh).
  - drop the EXIT trap that wiped status_dir; cleanup happens explicitly
    after `wait` returns, so a parallel worker that interrupts the
    parent never races a vanished status dir.
  - each worker now captures its tool's exit code and writes one of
    OK / SKIP / FAIL. Tolerated `expected violations remain`-style exits
    (markdownlint-cli2 rc≤1, ansible-lint rc≤2) still count as OK; only
    real failures count as FAIL.
  - all workers run to completion regardless of individual tool failures
    (so the user always sees the full picture); after the summary, the
    script exits 1 if any worker reported FAIL.
* scripts/lint/sort_claude_settings.sh -> scripts/lint/claude.sh
  (history preserved via git mv); update test_claude_settings_sorted.py
  fix-hint accordingly.

Plus working-tree drift across roles/, group_vars/, inventories/,
requirements/, and .pre-commit-config.yaml accumulated from the
make-test setup phase regenerating generated artefacts during recent
test runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 01:30:49 +02:00
Environment TestandClaude Sonnet 4.6 7b2ff3b698 refactor(service): centralize systemd diagnostics into shared debug script
- Extract repeated systemctl/journalctl diagnostic blocks from
  sys-service, sys-service-terminator, sys-svc-container, and
  sys-svc-sshd handlers into a reusable files/debug.sh SPOT
- Add tasks/utils/debug.yml as the canonical Ansible wrapper
- Wrap sys-svc-sshd restart handler in block/rescue to emit
  diagnostics and sshd -t config validation on failure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 07:30:42 +02:00
kevinveenbirkenbach 32891be285 fix(sys-service): avoid false failure by trimming systemctl status output
https://chatgpt.com/share/6973ddfd-68dc-800f-bbae-74170b45de92
2026-01-23 21:45:42 +01:00
kevinveenbirkenbach 5686a5ba29 fix(sys-pip-install,sys-service): avoid venv pip installs and handle oneshot services correctly
- Force sys-pip-install to use system python (/usr/bin/python3) instead of active venv
- Add explicit PATH for system-wide pip installs
- Add diagnostics task to verify installation context with system python
- Replace systemctl is-active check with Result/ExecMainStatus to correctly handle oneshot units
- Prevent false failures when oneshot services exit successfully

https://chatgpt.com/share/695123ba-8da4-800f-ae0d-2f09a5efb1e7
2025-12-28 13:33:53 +01:00
kevinveenbirkenbach 27b50d4a3c refactor(sys-service): move systemctl handler logic to include and add rc-based diagnostics
- Refactor sys-service handler to use include_tasks for better structure
- Add robust systemctl restart diagnostics based on exit code (is-active)
- Ensure systemctl status and journalctl output are shown before failing
- Prevent premature handler failure by making systemd restart non-fatal
- Minor style cleanup in filter plugin (PEP8 / quoting)

https://chatgpt.com/share/6950f59e-d6cc-800f-9981-f9af4cbb5590
2025-12-28 10:17:14 +01:00
kevinveenbirkenbach b207134472 feat(ci): enable systemd-in-docker and use explicit container detection
- Install systemd and dbus in Docker image for CI service tests
- Run systemd as PID 1 with proper container conventions
- Mark container environment explicitly via ENV container=docker
- Simplify container detection to rely on explicit env flag
- Skip host-only tasks (timezone, systemctl handlers) inside containers
- Adjust docker-compose runner for privileged systemd execution
- Reduce CI parallelism to avoid OOM kills

This makes systemd-based Ansible roles reliable in Docker/CI
and avoids fragile virtualization heuristics.

https://chatgpt.com/share/6950110b-111c-800f-bbcd-83a551d5a3b8
2025-12-27 18:14:28 +01:00
kevinveenbirkenbach 2b5ff60a6f infra(docker): drop host networking and normalize port binding logic
This change removes --network=host usage, introduces DOCKER_IN_CONTAINER
for reliable environment detection, and replaces hardcoded localhost
bindings with an explicit DOCKER_BIND_HOST abstraction to avoid nftables
issues in CI/DiD environments.

https://chatgpt.com/share/69497616-7b00-800f-8fa3-ddc6eb9c5e98
2025-12-22 17:46:08 +01:00
kevinveenbirkenbach 5ee48dfb63 fix(sys-service): run container service scripts synchronously to avoid async rc errors
- Remove async/poll from container handler
- Ensure rc/stderr are available for changed/failed conditions
- Keep systemctl-related errors non-fatal in containers

https://chatgpt.com/share/6949249b-62b0-800f-99c3-62b50a49a63b
2025-12-22 11:59:26 +01:00
kevinveenbirkenbach afc209633b feat(sys-service): ignore systemctl-related failures when running in containers
- Execute service scripts in containers with async/poll support
- Treat missing systemd/systemctl as non-fatal in container context
- Preserve failure handling for genuine script execution errors

https://chatgpt.com/share/69491f89-468c-800f-998f-1eb5424a2cf9
2025-12-22 11:48:24 +01:00
kevinveenbirkenbach 8b21b864f1 feat(sys-service): support async execution of service scripts in containers
- Enable async/poll for container-based service script execution
- Align container handler behavior with systemd handlers
- Preserve linear sync and suppression logic via existing variables

https://chatgpt.com/share/69491f89-468c-800f-998f-1eb5424a2cf9
2025-12-22 11:41:55 +01:00
kevinveenbirkenbach 2f51d88f21 feat(sys-service): execute service script on refresh when running in container
- Add container-specific handler listening on refresh systemctl service
- Execute service script directly when IS_CONTAINER is true
- Trigger only for restarted state and non-suppressed flushes
- Keep native systemd handling unchanged for non-container environments

https://chatgpt.com/share/69491f89-468c-800f-998f-1eb5424a2cf9
2025-12-22 11:37:53 +01:00
kevinveenbirkenbach 91d5ba35d1 Add container-aware execution logic and CI stability fixes
- Introduce global IS_CONTAINER flag based on ansible_virtualization facts
- Skip systemd-based handlers and tasks when running inside containers
- Extend EXCLUDED_ROLES list in GitHub Actions test-deploy workflow
- Ensure docker.sock is mounted for all CI deploy stages
- Improve sys-svc-docker by suppressing service restarts inside containers
- Add meta: flush_handlers to properly trigger delayed docker restarts
- Update sys-service handlers with container guards
- Update sys-timer tasks to avoid systemctl inside CI containers
- Enhance drv-non-free role with Manjaro detection and mhwd fallback warning
- Skip swapfile generation in containers
- Minor service template fixes and cleanup in proxy.conf.j2

Details and discussion: https://chatgpt.com/share/6930a4ca-56f4-800f-9b3d-4791f040a03b
2025-12-03 22:00:18 +01:00
kevinveenbirkenbach 23353ac878 infra(sys-service): centralize async control + pre-deploy backup safeguard
- Added MODE_BACKUP to trigger backup before the rest of the deployment

- sys-ctl-bkp-docker-2-loc: force linear sync and force flush when MODE_BACKUP is true

- Unified name resolution via system_service_name across handlers and tasks

- Introduced system_service_force_linear_sync and system_service_force_flush (rename from system_force_flush)

- Drive async/poll via system_service_async/system_service_poll using omit when disabled

- Propagated per-role overrides (cleanup, repair, cert tasks) for clarity and safety

- Minor formatting and consistency cleanups

Why: Ensure the backup runs before the deployment routine to safeguard data integrity.

Refs: Conversation https://chatgpt.com/share/68de4c41-b6e4-800f-85cd-ce6949097b5e
Signed-off-by: Kevin Veen-Birkenbach <kevin@veen.world>
2025-10-02 11:58:23 +02:00
kevinveenbirkenbach 3224e24d76 Refactor systemd handling
- sys-ctl-rpr-btrfs-balancer: suppress service flush for btrfs balancer (too expensive to run each play)
- sys-daemon: replace raw systemctl calls with ansible.builtin.systemd (daemon_reload, daemon_reexec)
- sys-service: split handler into 'Enable systemctl service' and 'Set systemctl service state', add become, async/poll, suppress flush guard

Conversation: https://chatgpt.com/share/68c2f7a6-6fe4-800f-9d79-3e3b0ab4a563
2025-09-11 18:24:21 +02:00
kevinveenbirkenbach 6c2d5c52c8 Attached 'not (system_service_suppress_flush | bool)' directly to handler 2025-08-28 21:16:04 +02:00
kevinveenbirkenbach 26b392ea76 refactor!: replace sys-systemctl with sys-service, add sys-daemon, and rename systemctl_* → system_service_* across repo
- Swap role includes: sys-systemctl → sys-service in all roles
- Rename variables everywhere: systemctl_* → system_service_* (incl. systemctl_id → system_service_id)
- Templates: ExecStart now uses {{ system_service_script_exec }}; add optional RuntimeMaxSec via SYS_SERVICE_DEFAULT_RUNTIME
- Move SYS_SERVICE defaults into roles/sys-service/defaults (remove SYS_SERVICE_ALL_ENABLED & SYS_SERVICE_DEFAULT_STATE from group_vars/07_services.yml)
- Tidy group_vars/all/08_timer.yml formatting
- Introduce roles/sys-daemon:
  - default manager timeouts (timeouts.conf)
  - optional purge of /etc/systemd/system.conf.d
  - validation via systemd-analyze verify
  - handlers for daemon-reload & daemon-reexec
- Refactor sys-timer to system_service_* variables (docs and templates updated)
- Move filter_plugins/filetype.py under sys-service
- Update meta/README to point to official systemd docs
- Touch many roles (backup/cleanup/health/repair/certs/nginx/csp/wireguard/ssd-hdd/keyboard/update-docker/alarm compose/email/telegram/etc.) to new naming

BREAKING CHANGE:
- Role path/name change: use `sys-service` instead of `sys-systemctl`
- All `systemctl_*` vars are now `system_service_*` (e.g., on_calendar, state, timer_enabled, script_exec, id)
- If you have custom templates, adopt RuntimeMaxSec and new variable names

Chat context: https://chatgpt.com/share/68a47568-312c-800f-af3f-e98575446327
2025-08-19 15:00:44 +02:00