perf(web-opt-rdr-domains): render redirect vhosts without deep-copying the variables

ansible-core 2.20's template lookup deep-copies all task variables on
every call. The redirect loop renders two templates per source domain,
so on galaxyserver this copy dominated the resolve and render step.

A role-local lookup, template_shallow, hands the builtin template lookup
a top-level copy of the variables whose values stay shared with the
caller; nothing on the reachable template and lookup paths mutates them
in place. Rendered output is identical across 12 variants (TLS, Tor,
logout, self-signed, wildcard keep_path), per-item failures and
undefined-variable messages included. A real playbook with 65 items
went from 10.5 s to 5.8 s.

🎯 Fix: 92 %
💥 Break: 3 %
🌱 Efficiency: –
⚡ Speed: –
🛡️ Security: ~100 %
🏆 Score: 89
🚦 Gate: ✅ 90/5, efficiency and speed <= 100, security 100 %

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 5.5 committed 2026-11-05 11:11:56 +00:00
1 parent 025ebe9754
commit 4a6bec9cf0
5 files changed
+142 -2

No files matched your search

@@ -0,0 +1,32 @@
from __future__ import annotations
from typing import Any
from ansible.plugins.loader import lookup_loader
from ansible.plugins.lookup import LookupBase
class _SharedVariables(dict):
def __deepcopy__(self, memo: dict[int, Any]) -> dict[str, Any]:
return dict(self)
class LookupModule(LookupBase):
def run(
self, terms: list[Any], variables: dict[str, Any], **kwargs: Any
) -> list[Any]:
"""
Args:
terms: the template paths, resolved like ``ansible.builtin.template``.
variables: the caller's variables; every term renders over a fresh
top-level copy whose values are shared with the caller.
kwargs: the ``ansible.builtin.template`` options, such as
``template_vars``.
Returns:
One rendered string per term.
"""
template = lookup_loader.get(
"template", loader=self._loader, templar=self._templar
)
return template.run(terms, variables=_SharedVariables(variables), **kwargs)
+2 -2
View File
@@ -26,11 +26,11 @@
- "{{ lookup('cert', item.source, 'files.key') }}"
files: >-
{{ [{'path': lookup('nginx', 'files.domain', item.source),
'content': lookup('template', 'redirect-domain.conf.j2',
'content': lookup('template_shallow', 'redirect-domain.conf.j2',
template_vars={'domain': item.source, 'target': item.target,
'keep_path': item.get('keep_path', true)})}]
+ ([{'path': lookup('nginx', 'files.domain', item.source, protocol='http'),
'content': lookup('template', lookup('path_absolute', 'roles/sys-front-tls/templates/http.conf.j2'),
'content': lookup('template_shallow', lookup('path_absolute', 'roles/sys-front-tls/templates/http.conf.j2'),
template_vars={'domain': item.source})}]
if redirect_source_tls else []) }}
Whitespace-only changes.
@@ -0,0 +1,5 @@
from pathlib import Path
PROJECT_ROOT: Path = Path(__file__).resolve().parents[6]
__all__ = ["PROJECT_ROOT"]
@@ -0,0 +1,103 @@
from __future__ import annotations
import json
import tempfile
import unittest
from pathlib import Path
from ansible.errors import AnsibleError
from ansible.parsing.dataloader import DataLoader
from ansible.plugins.loader import lookup_loader
from ansible.template import Templar, trust_as_template
from utils.cache.yaml import load_yaml_any
from utils.roles.mapping import ROLE_FILE_TASKS_MAIN
from . import PROJECT_ROOT
ROLE = PROJECT_ROOT / "roles" / "web-opt-rdr-domains"
PROBE_PLUGIN = """
from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables, **kwargs):
return [variables["domain"]]
"""
TEMPLATE = "{{ domain }} {{ lookup('rdr_probe_variables_domain') }}\n"
class _NoDeepCopy:
def __deepcopy__(self, memo):
raise AssertionError("the variables were deep-copied")
class TestTemplateShallow(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls._tmp = tempfile.TemporaryDirectory()
tmp = Path(cls._tmp.name)
(tmp / "plugins").mkdir()
(tmp / "plugins" / "rdr_probe_variables_domain.py").write_text(PROBE_PLUGIN)
(tmp / "templates").mkdir()
(tmp / "templates" / "vhost.j2").write_text(TEMPLATE)
lookup_loader.add_directory(str(ROLE / "lookup_plugins"))
lookup_loader.add_directory(str(tmp / "plugins"))
cls.search_path = [str(tmp)]
@classmethod
def tearDownClass(cls) -> None:
cls._tmp.cleanup()
def _variables(self) -> dict:
return {"domain": "play.example", "ansible_search_path": self.search_path}
def _render(self, plugin: str, variables: dict) -> str:
return Templar(loader=DataLoader(), variables=variables).template(
trust_as_template(
"{{ lookup('" + plugin + "', 'vhost.j2', "
"template_vars={'domain': 'source.example'}) }}"
)
)
def test_a_lookup_inside_the_template_reads_the_per_call_domain(self) -> None:
rendered = self._render("template_shallow", self._variables())
self.assertEqual(rendered, "source.example source.example\n")
self.assertEqual(rendered, self._render("template", self._variables()))
def test_the_caller_variables_keep_their_values(self) -> None:
variables = self._variables()
self._render("template_shallow", variables)
self.assertEqual(variables, self._variables())
def test_no_value_of_the_caller_is_deep_copied(self) -> None:
variables = {**self._variables(), "untouchable": _NoDeepCopy()}
self.assertEqual(
self._render("template_shallow", variables),
"source.example source.example\n",
)
with self.assertRaises(AnsibleError) as raised:
self._render("template", variables)
causes = []
error: BaseException | None = raised.exception
while error is not None:
causes.append(str(error))
error = error.__cause__
self.assertTrue(any("deep-copied" in cause for cause in causes), causes)
class TestRedirectLoopRendersShallow(unittest.TestCase):
def test_both_files_of_every_source_render_through_template_shallow(
self,
) -> None:
tasks = load_yaml_any(str(ROLE / ROLE_FILE_TASKS_MAIN))
[loop_task] = [
task for task in tasks if "redirect_source" in task.get("vars", {})
]
files = loop_task["vars"]["redirect_source"]["files"]
self.assertEqual(files.count("lookup('template_shallow', "), 2)
self.assertNotIn("lookup('template', ", json.dumps(loop_task))
if __name__ == "__main__":
unittest.main()