The wait filtered on the swarm-only com.docker.swarm.service.name label, which does not exist in compose, so the check timed out. Use that label in swarm and an anchored name filter in compose.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The container update mem-limit tasks used the raw compose name, which does not exist as a container in swarm. Use PEERTUBE_CONTAINER_ADDRESS like the other container ops in the file.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
network connect failed_when only matched one idempotent stderr phrasing; also accept 'already attached to network'. Fix the platform-logo truthiness gate (a URL string is never a bool) and drop a now-unused error var.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Over-indented continuation lines in the folded scalar made YAML insert a literal newline, so the shell ran 'docker exec <container>' with no command (rc 127). De-indent to fold to a single command.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
APP_NAME/MAIL_FROM_NAME/PF_OIDC_SCOPES rendered unquoted values containing spaces; phpdotenv rejects the whole file so artisan could not boot (compose migration failed, swarm worker never became healthy). Quote them (needed in both modes; the file is parsed literally).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
VAPID keys render empty (plain algorithm, allow-empty-plain); recent Mastodon hard-fails boot on empty VAPID env, crashing during Zeitwerk eager-load. Only emit the VAPID vars when both keys are set.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The frontend connected to the shared Redis without a password (and with REDIS_CACHE_PORT undefined), so Redis rejected it with NOAUTH and the container crash-looped. Pass REDIS_CACHE_PORT/PASSWORD from the engine lookup.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The one-shot install service wrote .env (with the DB name) into an unmounted throwaway container, so replicas read an .env without DB_DATABASE and fell back to Laravel's default db 'forge', 500ing every request. Mount the shared data volume into the install job.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The taiga-manager entrypoint 'python manage.py' exited immediately (no subcommand), crash-looping so migration exec hit 'No such container'. Give it a durable entrypoint and invoke django via 'python manage.py <cmd>'. Also render the frontend conf.json unconditionally since compose mounts it always.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
services.ldap.enabled/shared used host-scoped 'in group_names', which the process-wide applications cache poisons across hosts (a worker seeds false, the keycloak play reads it, LDAP federation is deleted and biber can no longer log in). Key on inventory-wide groups[] instead, which is identical on every host.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The manager-local ldap.yaml host bind was rejected on swarm workers. Declare it as a swarm type: config (mounted only when LDAP is enabled) and render it unconditionally so the config source always exists.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The manager-local /mnt/custom-addons host bind was rejected on swarm workers. Bake files/addons into the odoo image so every node has it, and relax the config mount mode for the non-root odoo user.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Swarm mounts type: config files as root:root; a non-root container process (or su'd user) then cannot read a 0440 file. Widen to 0444 (single-tenant containers).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The frontend service never joined the openresty overlay in swarm, so the reverse proxy could not resolve it and returned 502. Add the missing container_networks lookup.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Act does not propagate workflow-level env: to the discover job that
swarm-zombie pulls in as a needs dependency, so apps.sh aborted with
INFINITO_DEPLOY_MODE must be set. Re-pass it through ACT_ENV, matching
the existing INFINITO_APP_DISCOVERY_RUNNER=host workaround.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Shorten the two 11.3.0 bullets to about a third of their length while
keeping the substantive fix list, recurrence guards, retries/until
steps, stale-branches thresholds, and both doc links.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Embedded per-app DBs (shared:false) resolve to mariadb-on-NFS with no placement pin in swarm, which InnoDB does not support (locking, split-brain); embedded DBs are a compose-only pattern. After provisioning each swarm-test round's inventory, force shared:true on every svc-db-* provider service so consumers route to the central provider.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
autoformat reformats (settings sort, complexity/model.py, test_database_query.py, keycloak vars wrap); shorten akaunting swarm task name to <=80 chars; delete narration comments from keycloak vars; remove 'invariant' from the comment linter's valid marker set. make autoformat + make test verified green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add forum.keycloak.org, docs.redhat.com, git.coopcloud.tech and synacktiv.com to the WebFetch allowlist used during swarm/collabora/keycloak research.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
container network connect is not idempotent; on re-run the engine may report 'already attached to network' in addition to the already-handled 'already exists in network'. Widen the failed_when of both stack_host network-connect handlers (shared-DB connect + overlay connect) to tolerate it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Grant cap_add SYS_ADMIN so the default docker seccomp profile (which swarm enforces, since it ignores security_opt) allows the jail's mount/unshare/clone/setns syscalls (they are CAP_SYS_ADMIN-gated in moby default.json). With the capability present the full bind-mount jail works in both modes, so remove the swarm-only --o:mount_jail_tree=false workaround, which forced the slow link/copy path and risked kit segfaults (online#5247). Matches Nextcloud AIO (default seccomp + SYS_ADMIN, no mount overrides).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
In swarm the bootstrap service now deploys at replicas: 0 (created but unscheduled); the poll script scales it 0->1 with --force --replicas 1 so exactly one fresh installer run prints the token while the poll is already scraping its logs, removing the deploy-time-vs-poll-time race. Compose is unaffected (bootstrap stays profile-gated, run via run --rm).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add settle-waits after first-time OIDC registration (wait for redirect back to the DECIDIM_BASE_URL host + load) and after navigating to /account, to cut flakiness. The redirect host is derived from baseUrl, not hardcoded.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PENPOT_BACKEND_CONTAINER_ADDRESS resolves to a bare container id/name; | quote is redundant and inconsistent with the rest of the swarm container-exec pattern. Also remove a cosmetic comment.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace lookup('command_path', ...) (a controller-side lookup that searches a hardcoded PATH excluding the controller's pkgmgr venv, so it raised or embedded a controller path nonexistent on the remote target) with bare command names + a 'command -v' presence check. global_install installs baudolo system-wide to /usr/local/bin (or /usr/bin), which is on both systemd's default PATH and sudo secure_path on every supported distro; the role body runs when IS_STACK_HOST so install + systemd unit + baudolo-seed all execute on the same host. Verified empirically on the live Debian target.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Split the web-ready waits by mode: compose keeps container inspect (gated when compose), swarm uses wait_converged on the web service. Previously the container-inspect wait ran in swarm too, where the fixed container name does not exist, so it never converged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wrap the 04_users / 05_update includes in apply: { run_once, delegate_to: STACK_HOST }. They previously ran per-host, so multiple hosts gathered users and added missing objectClasses concurrently, racing into community.general.ldap_attrs 'value already exists' (result 20). Serialising to one host removes the race; compose is unaffected (single host).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a handler that blocks on swarm_stack_ready.sh (replica running == desired) on every swarm deploy, not only when compose_handlers_flush is set, so the app stack has converged before the health/e2e gates probe the proxy upstream. Without it sys-ctl-hlth-webserver probed the vhost while tasks were still starting, got 502, and sys-service-terminator aborted the play. Swarm-only (import-gated); stack name matches the deploy handler; no job/global services exist so replica-count parity is a valid convergence signal.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
database_query is a module: it opens query_file on the host it runs on. In swarm the task is delegated to the stack host, which has no repo checkout at role_path, so query_file is not found. A new action plugin (same name auto-wraps the module) reads query_file on the controller and passes the SQL as 'query', so every role's query_file: works in both compose and swarm with no call-site changes. Reverts the per-call-site fider workaround in favour of this root fix, which also covers mattermost, odoo, openproject and pixelfed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Switch database_query from query_file to query + lookup('file', ...) so the SQL is read on the Ansible controller and embedded, instead of opened on the (remote, delegated) swarm DB host which has no repo checkout. Works in both compose and swarm.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docker-entrypoint.sh is invoked directly as the container entrypoint; mode 0440 is not executable so the container failed to start with permission denied. 0555 makes it runnable.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Floor-to-1 now applies only to the topology default (no override term). An explicit service_replicas=0 emits 'replicas: 0' (service created but unscheduled, to be scaled up by a later task) instead of being bumped to 1. Empty/missing inventory group on the default path still floors to 1.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Swarm: KC_CACHE=ispn + KC_CACHE_STACK=jdbc-ping so replicas share an Infinispan session/realm cache via JDBC_PING2 over the existing Postgres (no multicast, built-in + auto-table in 26.6.3). Compose: KC_CACHE=local (single node). Realm-import scale-back uses KEYCLOAK_REPLICAS/_WANT constants; DB network attached only when the DB is shared (KEYCLOAK_DB_NETWORK_ARG). Does NOT by itself fix the admin-console static-chunk 404 (that needs a shared gzip cache / sticky routing).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Swarm: deploy N replicas without AKAUNTING_SETUP, run install exactly once in a one-shot swarm job (scale 0 -> install -> scale N), marker-gated. The one-shot runs akaunting.sh with AKAUNTING_SETUP=true and --no-start so it installs then exits 0. Compose: single container self-installs via AKAUNTING_SETUP. SESSION_DRIVER=database keeps sessions consistent across replicas. Repeated lookups extracted to vars; run_once core guard split (main -> 01_core -> 02_swarm).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On swarm, friendica's manager-node replica failed its curl healthcheck under
warmup contention: with no start_period the first DB/migration warmup probes
counted, 3 misses in 3 minutes made swarm kill the task on a fixed cadence
(2/3 converge), while the worker replicas stayed healthy. Add start_period:
120s + retries: 5 + a 30s interval so the warmup window is not counted and a
loaded node tolerates a slow first probe.
This lets friendica (and the other curl-healthchecked PHP apps) converge
multi-replica without pinning to a single replica. start_period is a standard
healthcheck field honored identically by compose and swarm.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drive the test-deploy matrix discovery through the complexity report instead of the type CLI: apps.sh selects the mode's tested roles via the 'compose'/'swarm' column (which already bakes in invokable + tested-lifecycle + per-mode skip), orders them coverage-first, and hard-caps the cumulative per-mode runner budget.
- complexity gains --deploy-mode {compose,swarm} (makes 'bundles'/'jobs' the runner count for that mode: compose packs variants into size/storage bundles, swarm runs one per deployable variant) and --max-jobs N (keep only the leading rows whose cumulative jobs stay below N).
- apps.sh emits whole role names; variant_bundles/output_apps.sh expand them into the matrix unchanged. Manual INFINITO_WHITELIST becomes a 'name %% {…}' filter clause applied before the cut, so a manual run only counts the apps it actually invokes.
- INFINITO_DEPLOY_MODE is now required; INFINITO_MAX_JOBS, INFINITO_DISCOVERY_SORT and INFINITO_REQUIRED_STORAGE move to default.env (the SPOT) + the passthrough handler, so no shell-side defaults remain.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
In swarm an app task can be scheduled on a worker, but the role exec'd
`container exec $(resolve-container-id ...)` on the manager -> "No such
container". Resolve the hosting node + node-local container id and delegate
each exec to that node.
- database.py: add a `service_name` want; resolve_host_cid/wait_converged
gain `*_service_name` for cross-stack services (mailu's shared mariadb)
- mailu wait-for-mariadb (DB probe + admin), mastodon db:migrate,
gitea migrate/admin-create, friendica manager-ops/patch/addons/bootstrap
(~13 exec sites) switch to resolve_host_cid + delegate_to
Compose-safe: resolve_host_cid degrades to HOST_NODE=inventory_hostname
(delegate is a no-op) + LOCAL_CID=bare compose container name, matching the
8 roles already using this pattern.
Note: friendica also needs service_replicas=1 (next bundle) so its resolved
container id does not churn across replicas.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Swarm deploy-test harness fixes (run 28439744622); swarm-test-harness only,
compose path untouched:
- NFS_STATE_PATH (<export>/infinito-state/<vol>): per-volume dirs are nested
under the fsid=0 state subdir (STORAGE_NFS_STATE_SUBDIR), but the seed,
assert and diagnostics used the bare export base -> "Directory nonexistent".
00_topology derives it, the workflow exports it, 09/11/12 consume it.
- pull-retry: pre-pull jrei/systemd-ubuntu with bounded retries before
docker run, so a Docker Hub registry blip no longer fails the job (exit 125).
- jitsi: derive the converge/drain SERVICE_NAME from proxy.service_key so
multi-service stacks (jitsi_jitsi-web/-jvb/...) resolve; single-service apps
fall back to the entity name (unchanged).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The test-deploy-compose "Fail on deprecation warnings" gate failed ~10 apps
while the deploys themselves succeeded. Sources cleared:
- svc-db-postgres: community.postgresql `db` -> `login_db` (the `db` param
alias is deprecated, removed in collection 5.0.0)
- assert_no_deprecation_warnings.sh: ignore ansible-core's legacy filter/test
PluginLoader-aliases deprecation (needs a collection migration with
meta/runtime.yml, not fixable in role YAML)
- joomla/wordpress: drop the `{{ }}` delimiters from task conditionals
(when/until/changed_when), per ansible-core 2.23
Also drop `upstream`/`compat`/`security`/`bug` from the comment-policy markers
and delete those comments from the joomla install tasks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>