Commit Graph
6 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 4.8 fbe50d10ed fix(svc-runner): make the runner role swarm-compatible
Workers failed 'docker build: no Dockerfile': the build context, compose file, .env and runner binary were staged on the stack host only while every node deploys its own node-local runner stack. Build and push the image once on the manager (RUNNER_IMAGE_REF via the swarm registry, 04_image.yml) and let workers pull it; render compose.yml (template with lstrip_blocks, matching the replaced stack_host_template action), .env and the extracted run.sh on every node. Add a node_local kwarg to the compose_networks/container_networks/compose_restart/compose_only lookups so this node-local compose stack renders a bridge default network (workers cannot create overlays), keeps restart: unless-stopped (ephemeral runners died after one job) and keeps container_name under swarm; default is unchanged for every other role. Treat build/install.stamp as stale when the venv is missing and exclude ./build from the nested-src copy, closing the nested-e2e ruamel failure class. Regression tests for the node_local render paths; the network include tests now accept lookup kwargs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 02:37:26 +02:00
kevinveenbirkenbachandClaude Opus 4.8 baae3c377e fix(openresty-swarm): out-of-band overlay creation + stop-first host-mode redeploy
- Load openresty via the sys-svc-compose network/routine.yml helper (same
  pattern as the db/ollama roles) so the shared `openresty` overlay is created
  attachable + swarm-scoped before the stack deploys; emit the top-level
  networks block via compose_networks.
- Add an opt-in `order:` to the swarm update_config and set it to `stop-first`
  for openresty: it publishes 80/443 in host mode, so a default rolling update
  deadlocks (the new task cannot bind ports the old task still holds).
- Relax the network-include lint to accept a single compose_networks lookup in
  a host-mode template (openresty is mode-conditional: host in compose, overlay
  in swarm).
- Whitelist openresty's path_join network/routine.yml include in
  .ansible-lint-ignore (same dynamic-include pattern as the db/ollama roles).

Runtime-confirmed (swarm, attempt 32): openresty created its overlay, attached
consumers, reached backends, and redeployed cleanly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 19:49:18 +02:00
kevinveenbirkenbachandClaude Opus 4.7 cb27ff3756 refactor(networks): replace Jinja includes with compose_networks/container_networks lookup plugins
Convert the two registry-driven networks templates into pure-Python
rendering functions plus thin Ansible lookup plugins:

  roles/sys-svc-compose/templates/networks.yml.j2  -> {{ lookup('compose_networks') }}
  roles/sys-svc-container/templates/networks.yml.j2 -> {{ lookup('container_networks') | indent(4) }}

The rendering logic lives in utils/networks/render.py as pure-Python
functions that take a registry + closure-style config/database lookups,
making the logic directly unit-testable without a Jinja stub harness.
The lookup plugins are thin wrappers that resolve application_id,
DEPLOYMENT_MODE, and swarm.network.encryption from the templar, build
the service_registry, and forward to the render functions.

Migrate 233 include lines across 85 production templates. Convert
web-app-matrix's hand-coded MDAD networks block (default + conditional
postgres + conditional openldap) to the generic lookup; this adds an
openresty attachment when services.sso.enabled (harmless extra
interface, pinned in test_matrix_mdad_consumer_attaches_postgres_ldap_sso).

Mark local-DB / redis sidecars (sys-svc-rdbms/templates/services/,
svc-db-redis/templates/service.yml.j2) with `# nocheck: networks-literal`
because they intentionally attach to default-only.

Extend the lint to scan ALL roles/*/templates/**/*.yml.j2 (not only
compose.yml.j2) and to forbid the legacy include form; the marker
above is the documented escape hatch.

Coverage:
  - tests/unit/utils/networks/test_render.py (30 cases incl. encrypted=false literal pin)
  - tests/unit/plugins/lookup/test_compose_networks.py (5 cases incl. lookup_loader arg-schema)
  - tests/unit/plugins/lookup/test_container_networks.py (5 cases incl. lookup_loader arg-schema)
  - tests/integration/infrastructure/compose/test_networks_render.py (10 snapshot scenarios)
  - tests/integration/infrastructure/compose/test_network_includes.py (3 lint rules)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-16 18:42:04 +02:00
kevinveenbirkenbachandClaude Opus 4.7 5adf3011fe refactor(swarm-nfs): generalize swarm+NFS chain across all roles
Migrate the mediawiki-specific swarm patterns into shared sys-svc-compose
helpers so every role inherits swarm + NFS portability:

- meta/volumes.yml: dict schema with mandatory name|path + optional nfs
  block (uid/gid/mode); 47 roles migrated, 48 lookup consumers updated to
  volumes.<key>.{name,path}
- sys-svc-compose helpers: finalize.yml (flush + post_deploy),
  post_deploy.yml (swarm-resolve + DB-healthy-wait), nfs_prep.yml
  (pre-create NFS subdirs), swarm/resolve_self.yml (canonical
  <ENTITY>_CONTAINER fact), render_replicated_templates.yml +
  _render_one_template.yml (template render + swarm-peer replication,
  per-entry notify, fileglob support)
- 15 roles migrated to render_replicated_templates.yml helper
  (mediawiki, prometheus, kix, friendica, dashboard, nextcloud,
  suitecrm, matrix, flowise, openldap)
- 5 new lint tests pin the architecture: volumes schema, compose chain,
  volume-constants-are-lookups, template-render-centralization,
  meta-no-role-var-refs
- ROLE_FILE_TEMPL_COMPOSE SPOT constant + 7 tests migrated to use it
- Handler test scanner extended to detect nested notify in
  vars: role_templates: lists

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 18:57:35 +02:00
kevinveenbirkenbachandClaude Opus 4.7 a5ba14d5b3 test(lint/cache-read): extend scope to all tests/ + convert callers
Widens the cache-read lint guard from ``tests/lint/`` to every ``.py``
under ``tests/``. Integration tests show the same compounding cost
pattern (one role's compose template / nginx conf / scrape fragment
read across many shape tests) that motivated the original lint for
lint/.

Converts 91 violations across 28 test files:

- **Cache (utils.cache.files.read_text)** for project-tracked reads
  and single-read tempdir fixtures, e.g. test_prometheus.py (32x),
  test_keycloak_import_flow.py (11x), test_dashboard_oidc.py (3x),
  test_changelog_md.py (8x), test_package_mirror.py (8x), plus
  test_logging.py / test_summarize.py / test_version_updater.py /
  test_get_url_retry.py / test_pull_specific_host.py.

- **Cache + UnicodeDecodeError handler** for project-walk scanners
  that previously used ``errors="replace"`` / ``errors="ignore"`` to
  defend against non-UTF-8 files (compose volumes, password quoting,
  template image, mailu dependency, URL reachability). Wraps each
  read in ``try/except (OSError, UnicodeDecodeError): continue``,
  which has the same observable effect (skip undecodable files).

- **Refactor away the binary heuristic** in test_no_raw_docker.py:
  ``read_bytes() + b"\x00" not in raw`` becomes
  ``read_text() / except UnicodeDecodeError``. Same files skipped,
  with cache benefit.

- **Variable extraction** in test_changelog_md.py / test_package_mirror.py
  for cases where ``self.assertEqual(path.read_text(...), expected)``
  exceeded ruff's 88-char limit. Ruff was wrapping the marker onto a
  line outside the AST span of the read_text call.

- **Compute-from-setup** for two test methods that previously read
  ``self.changelog`` twice (before/after) to verify a no-op:
  ``before`` is now derived from the known input, dropping the first
  read.

Five ``# nocheck: cache-read`` markers remain, each annotated inline
with the reason: idempotency tests where the second read must hit
disk to catch non-idempotent regressions, and tests with intermediate
``write_text`` whose subsequent read would return stale cache data.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:23:32 +02:00
kevinveenbirkenbachandClaude Opus 4.7 4ac7a95ec6 refactor(tests): split overflowing folders into thematic subdirs
Reorganises four folders that exceeded the 12-item readability limit:

- tests/lint/repository/ (27 -> 11): structure/, naming/, documentation/,
  python/, dependencies/, shell/, yaml/, network/, settings/
- tests/integration/ (25 -> 7): ansible/, infrastructure/, iam/, meta/
  (24 sibling dirs grouped under 4 super-categories)
- tests/integration/roles/ (13 -> 10): naming/, playwright/, dashboard/
- tests/unit/utils/ (15 -> 12): certs/ for 3 cert/TLS test files

Renames 7 test files whose name duplicated the new folder name
(e.g. test_no_direct_yaml_calls.py -> yaml/test_no_direct_calls.py,
test_dashboard_integration_scope.py -> dashboard/test_integration_scope.py).

Adjusts parents[N] in moved __init__.py files, fixes __file__-based
path resolution in 8 tests, updates self-path whitelists, and uses
absolute imports for PROJECT_ROOT re-exports (ruff TID252).

Adds README.md to each new subfolder following the existing scope
template. Updates all docs links (suppression.md, base.md, email.md,
playwright spec/parity docs, 005-/019- requirements) to new paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:23:32 +02:00