mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-08 03:38:23 +00:00
Renames the local action plugin from `conf_template` to
`stack_host_template` so the name carries the actual semantics
(IS_STACK_HOST gate, not nginx config), broadens the lint guard to
every bare `template:` task, and migrates every consumer found in the
audit.
Plugin / tests / lint:
* plugins/action/conf_template.py -> plugins/action/stack_host_template.py
(drop nginx-specific docstring; trust_as_template gate unchanged)
* test_conf_template.py -> test_stack_host_template.py
* test_conf_template_migration.py -> test_stack_host_template_migration.py
Scope expanded from `.conf.j2` to every `template:` task; marker
renamed to `nocheck: stack-host-template`.
Migrations (~50 tasks now using stack_host_template:):
* sys-svc-compose/04_files.yml: compose.yml, .env, Dockerfile,
compose.override (every per-app compose-tree file)
* web-app-keycloak: sso_proxy upstream-config (fixes the friendica
CI failure that prompted this refactor) + realm-import
* web-app-taiga, web-app-matrix, web-app-opentalk, web-app-pgadmin,
web-app-moodle, web-app-listmonk, web-app-littlejs, web-app-fediwall,
web-app-wordpress, web-app-discourse, web-app-bigbluebutton,
web-app-jenkins, web-app-jitsi, web-app-mobilizon, web-app-suitecrm,
web-app-decidim, web-app-dashboard, web-app-nextcloud, web-app-xwiki,
web-app-mailu, web-app-magento, web-app-odoo, web-app-prometheus,
web-app-matrix, web-app-peertube, web-app-mailu (+ existing `conf_template:`
callers updated to the new name)
* sys-front-tls, svc-db-openldap, sys-svc-webserver-core,
sys-svc-rdbms (dedicated DB env + initdb), sys-front-inj-css,
sys-front-inj-dashboard, sys-front-inj-all, sys-stk-front-proxy,
web-svc-cdn-css, web-svc-xmpp, web-svc-legal, web-svc-simpleicons,
web-opt-rdr-domains
Nochecks (per-host or already-structurally-stack-host):
* sys-svc-mail-smtp/postfix, sys-svc-sshd, sys-svc-container/daemon.json
* sys-timer, sys-service, sys-svc-mail-msmtp, sys-svc-journalctl,
sys-daemon, sys-svc-compose/utils/_render_one_template (delegate_to
stack host with peer slurp dance)
* dev-locales, dev-nix, desk-*, user, user-backup, user-workstation
* svc-storage-nfs-server/exports, test-e2e-playwright stage dirs
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
111 lines
3.7 KiB
Python
111 lines
3.7 KiB
Python
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from plugins.action.stack_host_template import ActionModule
|
|
|
|
|
|
class _FakeTask:
|
|
def __init__(self, *, args=None):
|
|
self.args = {} if args is None else dict(args)
|
|
|
|
|
|
class _FakeTemplar:
|
|
def __init__(self, *, is_stack_host=True):
|
|
self._is_stack_host = is_stack_host
|
|
self.available_variables: dict[str, object] = {}
|
|
|
|
def template(self, raw):
|
|
return self._is_stack_host
|
|
|
|
|
|
def _make_action(task, templar):
|
|
action = object.__new__(ActionModule)
|
|
action._task = task
|
|
action._templar = templar
|
|
return action
|
|
|
|
|
|
class TestStackHostTemplate(unittest.TestCase):
|
|
def test_skips_silently_on_non_stack_host(self):
|
|
task = _FakeTask(args={"src": "x.j2", "dest": "/etc/x.conf"})
|
|
action = _make_action(task, _FakeTemplar(is_stack_host=False))
|
|
|
|
result = action.run(task_vars={})
|
|
|
|
self.assertTrue(result["skipped"])
|
|
self.assertFalse(result["changed"])
|
|
self.assertIn("IS_STACK_HOST", result["skip_reason"])
|
|
|
|
def test_skips_when_templar_returns_string_false(self):
|
|
task = _FakeTask(args={"src": "x.j2", "dest": "/etc/x.conf"})
|
|
action = _make_action(task, _FakeTemplar(is_stack_host="False"))
|
|
|
|
result = action.run(task_vars={})
|
|
|
|
self.assertTrue(result["skipped"])
|
|
|
|
def test_delegates_to_template_on_stack_host(self):
|
|
task = _FakeTask(args={"src": "x.j2", "dest": "/etc/x.conf"})
|
|
action = _make_action(task, _FakeTemplar(is_stack_host=True))
|
|
|
|
with patch(
|
|
"plugins.action.stack_host_template.TemplateActionModule.run",
|
|
return_value={"changed": True},
|
|
) as super_run:
|
|
action.run(task_vars={})
|
|
|
|
super_run.assert_called_once()
|
|
|
|
def test_seeds_templar_with_task_vars_before_rendering(self):
|
|
task = _FakeTask(args={"src": "x.j2", "dest": "/etc/x.conf"})
|
|
templar = _FakeTemplar(is_stack_host=True)
|
|
action = _make_action(task, templar)
|
|
|
|
with patch(
|
|
"plugins.action.stack_host_template.TemplateActionModule.run",
|
|
return_value={"changed": True},
|
|
):
|
|
action.run(task_vars={"IS_STACK_HOST": True, "ANSIBLE_VERSION": "9.0"})
|
|
|
|
self.assertEqual(templar.available_variables.get("IS_STACK_HOST"), True)
|
|
self.assertEqual(templar.available_variables.get("ANSIBLE_VERSION"), "9.0")
|
|
|
|
def test_defaults_mode_to_0644_when_unset(self):
|
|
task = _FakeTask(args={"src": "x.j2", "dest": "/etc/x.conf"})
|
|
action = _make_action(task, _FakeTemplar(is_stack_host=True))
|
|
|
|
with patch(
|
|
"plugins.action.stack_host_template.TemplateActionModule.run",
|
|
return_value={"changed": True},
|
|
):
|
|
action.run(task_vars={})
|
|
|
|
self.assertEqual(task.args["mode"], "0644")
|
|
|
|
def test_keeps_caller_supplied_mode(self):
|
|
task = _FakeTask(args={"src": "x.j2", "dest": "/etc/x.conf", "mode": "0600"})
|
|
action = _make_action(task, _FakeTemplar(is_stack_host=True))
|
|
|
|
with patch(
|
|
"plugins.action.stack_host_template.TemplateActionModule.run",
|
|
return_value={"changed": True},
|
|
):
|
|
action.run(task_vars={})
|
|
|
|
self.assertEqual(task.args["mode"], "0600")
|
|
|
|
def test_is_stack_host_expr_carries_trust_tag(self):
|
|
from ansible.template import is_trusted_as_template
|
|
|
|
from plugins.action.stack_host_template import _IS_STACK_HOST_EXPR
|
|
|
|
self.assertTrue(
|
|
is_trusted_as_template(_IS_STACK_HOST_EXPR),
|
|
"The IS_STACK_HOST template expression must carry the TrustedAsTemplate "
|
|
"tag; otherwise Ansible 2.19+ returns the literal string unchanged.",
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|