The container_ports migration left make test red; reconcile it:
- Delete 10 port vars orphaned when their compose mappings moved to the
container_ports lookup (OPENLDAP_DOCKER_PORT_OPEN, RABBITMQ_INTERNAL_PORT,
REGISTRY_CACHE_PORT, ERPNEXT_FRONTEND_PORT, FLOWISE_PORT_PUBLIC,
JITSI_WEB_HTTP_PORT, KEYCLOAK_SERVER_HOST, MINIO_API_PORT_INTERNAL,
OPENCLOUD_HTTP_PORT, OPENWEBUI_PORT_PUBLIC).
- Add PORT_BANDS.public entries for the fixed protocol ports the migration
declared (smtp/smtps/submission/pop3/pop3s/imap/imaps/sieve, rtmp, c2s/s2s).
- Route the container_ports internal-declared lint through the SPOT constants
(ROLE_FILE_TEMPL_COMPOSE / ROLE_FILE_META_SERVICES), cached read_text, and
load_yaml_any, per repo conventions.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Take the host IP as an optional third element of each term
([service, protocol, host_ip]) instead of an ip= kwarg, and build the whole
ports: block from declared ports.local/public (host) + ports.internal
(container). Convert every compose template across 84 roles, folding the
remaining raw var/numeric/specific-ip mappings (including mailu's per-interface
mail ports bound to MAILU_IP4_PUBLIC). Multi-term calls render one term per line.
Add the compose-ports-must-use-container-ports lint: it forbids any raw
"<host>:<published>:<container>" publish item under a ports: block and requires
every term to declare ports.internal. Remove
tests/lint/roles/test_swarm_internal_ports.py, now subsumed.
Fix a container_depends_on rendering regression. The lookup self-indented
(default indent=4), so the added 4-space placement + | indent(4) triple-indented
the block. Flip the lookup default to column 0 (consistent with
container_networks), make every call use the 4-space + | indent(4) form, and add
a lint enforcing it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Surfaced by deep-inspecting the swarm matrix CI failures:
- sys-ctl-cln-faild-bkps: the systemd ExecStart resolved cleanback via the
command_path lookup, which runs on the Ansible controller; the binary is
pip-installed system-wide on the target node, so shutil.which returned None
("command not found in PATH: 'cleanback'"). The ExecStart already runs via
/bin/sh -c, so use the bare command and let the target shell resolve PATH.
- svc-db-rabbitmq: RABBITMQ_EXEC_SHELL used `sh -lc`; a login shell re-inits
PATH from /etc/profile and drops the image's /opt/rabbitmq/sbin, so
rabbitmq-diagnostics was not found (rc 127). Use `sh -c`.
- web-app-friendica: `{{ FRIENDICA_CONTAINER_ADDRESS | quote }}` single-quotes
the swarm $(resolve-container-id ...) subshell, killing the command
substitution ("No such container"). Drop the quote, matching 02_manager_ops.
- web-app-gitea: `gitea migrate` ran without `-c {{ GITEA_CONFIG }}` (admin-create
already has it), so MustInstalled() aborted against the custom app.ini. Add it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Shared single-host engine roles consumed via lookup('engine', ...), mirroring the central postgres/mariadb pattern: meta/services flags, overlay topology in meta/server, compose templates, per-consumer provisioning in 02_init. Lets apps drop their embedded sidecars and become unpinned/NFS-shareable in swarm.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>