mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
fix(tor): resolve DEPLOYMENT_MODE before picking the SOCKS host
A lookup plugin receives group_vars through variables.get() untemplated, and group_vars/all/18_swarm.yml:2 defines DEPLOYMENT_MODE as a Jinja expression. The comparison against 'swarm' could therefore never match, so every swarm deploy fell through to _COMPOSE_HOST and baked socks5h://host.docker.internal:9050 into Nextcloud's proxy system value. svc-net-tor publishes SOCKS with mode: host, so that listener exists on the manager alone. With three Nextcloud replicas against one Tor node the failure is node-determined, not intermittent: the 104 'cURL error 7 ... over proxy host.docker.internal' lines in run 31340965955 split 56 on wrk-02, 48 on wrk-01 and 0 on mgr-01, which is what made the OIDC callback 500 on 2 of 3 replicas and read as a 39% flake. Templating first yields socks5h://tor:9050 in swarm, which every replica reaches over the overlay it already joins through the onion_sso consumer rule. Compose is unchanged: a single-node inventory renders the expression to 'compose', and a suppressed template error falls through to the same branch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
05f425ea51
commit
1bb31fba41
2 files changed
+53
-3
No files matched your search
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
from typing import Any
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
@@ -46,6 +47,10 @@ class LookupModule(LookupBase):
|
||||
templar=getattr(self, "_templar", None),
|
||||
).run([], variables=variables, roles_dir=kwargs.get("roles_dir"))[0]
|
||||
|
||||
return [
|
||||
resolve_proxy_url(applications, variables.get("DEPLOYMENT_MODE", "compose"))
|
||||
]
|
||||
raw_mode = variables.get("DEPLOYMENT_MODE", "compose")
|
||||
templar = getattr(self, "_templar", None)
|
||||
if templar is not None:
|
||||
with contextlib.suppress(Exception):
|
||||
raw_mode = templar.template(raw_mode)
|
||||
|
||||
return [resolve_proxy_url(applications, str(raw_mode).strip())]
|
||||
@@ -1,8 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.loader import lookup_loader
|
||||
|
||||
from plugins.lookup.tor_socks_proxy import LookupModule, resolve_proxy_url
|
||||
|
||||
@@ -38,6 +40,27 @@ class TestResolveProxyUrl(unittest.TestCase):
|
||||
resolve_proxy_url({"svc-net-tor": {"services": {"tor": {}}}}, "swarm")
|
||||
|
||||
|
||||
DEPLOYMENT_MODE_EXPR = (
|
||||
"{{ 'swarm' if (groups['svc-swarm-node'] | default([]) | length) > 1"
|
||||
" else 'compose' }}"
|
||||
)
|
||||
|
||||
|
||||
class _StubTemplar:
|
||||
"""Templar stub resolving the DEPLOYMENT_MODE expression to a fixed mode.
|
||||
|
||||
Args:
|
||||
resolved: the mode string the expression evaluates to.
|
||||
"""
|
||||
|
||||
def __init__(self, resolved: str) -> None:
|
||||
self.resolved = resolved
|
||||
self.available_variables: dict[str, object] = {}
|
||||
|
||||
def template(self, value):
|
||||
return self.resolved if value == DEPLOYMENT_MODE_EXPR else value
|
||||
|
||||
|
||||
class TestTorSocksProxyLookup(unittest.TestCase):
|
||||
def test_terms_raise(self):
|
||||
lookup = LookupModule()
|
||||
@@ -45,6 +68,28 @@ class TestTorSocksProxyLookup(unittest.TestCase):
|
||||
with self.assertRaises(AnsibleError):
|
||||
lookup.run(["x"], variables={})
|
||||
|
||||
def _run(self, resolved: str) -> str:
|
||||
lookup = LookupModule()
|
||||
lookup._templar = _StubTemplar(resolved)
|
||||
lookup._loader = None
|
||||
variables = {
|
||||
"DEPLOYMENT_MODE": DEPLOYMENT_MODE_EXPR,
|
||||
"applications": APPS,
|
||||
}
|
||||
with mock.patch.object(lookup_loader, "get", return_value=_StubApplications()):
|
||||
return lookup.run([], variables=variables)[0]
|
||||
|
||||
def test_a_swarm_deployment_reaches_tor_over_the_overlay(self):
|
||||
self.assertEqual(self._run("swarm"), "socks5h://tor:9050")
|
||||
|
||||
def test_a_compose_deployment_reaches_tor_over_the_host_gateway(self):
|
||||
self.assertEqual(self._run("compose"), "socks5h://host.docker.internal:9050")
|
||||
|
||||
|
||||
class _StubApplications:
|
||||
def run(self, terms, variables=None, roles_dir=None):
|
||||
return [APPS]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user