diff --git a/TODO.md b/TODO.md index 9f401239e6..48cc42d59f 100644 --- a/TODO.md +++ b/TODO.md @@ -83,7 +83,8 @@ against those runs say so inline. `container_extra_hosts` lookup yet (fix is the same one-line lookup, apply on CI evidence): wordpress (daggerhart plugin) and mediawiki (PluggableAuth) are structurally identical PHP in-app plugins (high - likelihood); discourse, jenkins, jira, confluence, odoo, openwebui, + likelihood); discourse is now confirmed and pinned (run 33445831564, job + Nextcloud#7); jenkins, jira, confluence, odoo, openwebui, pretix, zammad, semaphore, jellyfin, listmonk, xwiki, mastodon consume the issuer server-side too (unverified network path). oauth2-proxy-based apps are NOT affected (proven green: prometheus admin SSO). Two names have left diff --git a/plugins/lookup/container_extra_hosts.py b/plugins/lookup/container_extra_hosts.py index fd96e823ef..4ba17a12fd 100644 --- a/plugins/lookup/container_extra_hosts.py +++ b/plugins/lookup/container_extra_hosts.py @@ -24,6 +24,12 @@ through here, from two sources that are both optional: Entries are ``"name:address"`` strings and are deduplicated in first-seen order. With nothing to emit the lookup returns an empty string. +``entries_only=true`` returns those strings as a list instead of the rendered +block, for a container that is not described by a compose file at all: +``web-app-discourse`` is built by discourse_docker's ``launcher``, whose only +argument surface is ``docker_args:`` in its ``app.yml``, so it needs +``--add-host=`` lines. + The automatic pin follows the effective deploy mode, and in swarm it must NOT be ``host-gateway``: that alias resolves per node, while openresty publishes :80 with ``mode: host`` under ``node.role == manager``, so every replica on a worker @@ -48,6 +54,13 @@ Usage in any service template: {{ lookup('container_extra_hosts', extra_hosts=['host.docker.internal:host-gateway']) | indent(4) }} {{ lookup('container_extra_hosts', application_id='web-app-nextcloud') | indent(4) }} + +Usage from a non-compose call site: + + {% for entry in lookup('container_extra_hosts', + entries_only=True, wantlist=True) %} + - --add-host={{ entry }} + {% endfor %} """ from __future__ import annotations @@ -98,6 +111,8 @@ class LookupModule(LookupBase): ) entries += self._caller_entries(kwargs.get("extra_hosts")) merged = list(dict.fromkeys(entries)) + if _to_bool(self._render(kwargs.get("entries_only", False)), strict=False): + return merged if not merged: return [""] diff --git a/roles/web-app-discourse/templates/config.yml.j2 b/roles/web-app-discourse/templates/config.yml.j2 index f09f995673..c493f5bae1 100644 --- a/roles/web-app-discourse/templates/config.yml.j2 +++ b/roles/web-app-discourse/templates/config.yml.j2 @@ -234,4 +234,7 @@ docker_args: {% if DISCOURSE_LITELLM_ENABLED | bool %} - --network={{ DISCOURSE_LITELLM_NETWORK }} {% endif %} +{% for extra_host in lookup('container_extra_hosts', entries_only=True, wantlist=True) %} + - --add-host={{ extra_host }} +{% endfor %} - --name={{ DISCOURSE_CONTAINER }} diff --git a/tests/unit/python/plugins/lookup/test_container_extra_hosts.py b/tests/unit/python/plugins/lookup/test_container_extra_hosts.py index f914fa7c72..955349fc08 100644 --- a/tests/unit/python/plugins/lookup/test_container_extra_hosts.py +++ b/tests/unit/python/plugins/lookup/test_container_extra_hosts.py @@ -176,6 +176,34 @@ class TestContainerExtraHostsLookup(unittest.TestCase): def test_no_sources_at_all_emit_nothing(self): self.assertEqual(self._run(_sso_enabled=False, extra_hosts=[]), "") + def _run_entries(self, **overrides): + variables = { + "application_id": "web-app-discourse", + "_sso_enabled": True, + "_provider_domain": ONION, + "DEPLOYMENT_MODE": "compose", + } + variables.update(overrides) + return self.lookup.run(None, variables=variables, entries_only=True) + + def test_entries_only_returns_the_raw_mappings(self): + self.assertEqual( + self._run_entries(), + ["host.docker.internal:host-gateway", f"{ONION}:host-gateway"], + ) + + def test_entries_only_follows_the_swarm_address(self): + self.assertEqual( + self._run_entries( + DEPLOYMENT_MODE="swarm", + ansible_facts={"default_ipv4": {"address": "10.0.0.7"}}, + ), + ["host.docker.internal:host-gateway", f"{ONION}:10.0.0.7"], + ) + + def test_entries_only_is_empty_without_sso(self): + self.assertEqual(self._run_entries(_sso_enabled=False), []) + if __name__ == "__main__": unittest.main()