mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 02:54:26 +00:00
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>
57 lines
2.0 KiB
Python
57 lines
2.0 KiB
Python
from __future__ import annotations
|
|
|
|
import contextlib
|
|
from typing import Any
|
|
|
|
from ansible.errors import AnsibleError
|
|
from ansible.plugins.loader import lookup_loader
|
|
from ansible.plugins.lookup import LookupBase
|
|
|
|
from plugins.lookup.tor_socks import resolve_socks_endpoint
|
|
|
|
_SWARM_HOST = "tor"
|
|
_COMPOSE_HOST = "host.docker.internal"
|
|
|
|
|
|
def resolve_proxy_url(applications: dict[str, Any], deployment_mode: str) -> str:
|
|
"""Return the ``socks5h://`` URL a sibling container uses to reach Tor:
|
|
the ``tor`` overlay alias in swarm, the host gateway in compose.
|
|
"""
|
|
host = _SWARM_HOST if str(deployment_mode).strip() == "swarm" else _COMPOSE_HOST
|
|
return f"socks5h://{resolve_socks_endpoint(applications, host)}"
|
|
|
|
|
|
class LookupModule(LookupBase):
|
|
"""
|
|
Usage:
|
|
{{ lookup('tor_socks_proxy') }} -> socks5h://tor:<port> (swarm)
|
|
-> socks5h://host.docker.internal:<port> (compose)
|
|
|
|
Single spot for the outbound Tor SOCKS proxy URL of a containerised client,
|
|
so the swarm/compose split is not restated per consuming role.
|
|
"""
|
|
|
|
def run(
|
|
self,
|
|
terms: list[Any] | None,
|
|
variables: dict[str, Any] | None = None,
|
|
**kwargs: Any,
|
|
) -> list[str]:
|
|
if terms:
|
|
raise AnsibleError("lookup('tor_socks_proxy') expects no terms.")
|
|
|
|
variables = variables or getattr(self._templar, "available_variables", {}) or {}
|
|
applications = lookup_loader.get(
|
|
"applications",
|
|
loader=getattr(self, "_loader", None),
|
|
templar=getattr(self, "_templar", None),
|
|
).run([], variables=variables, roles_dir=kwargs.get("roles_dir"))[0]
|
|
|
|
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())]
|