mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-08 11:46:35 +00:00
fix(lookup): keep the clearnet apex redirect on a multi-network node
current_play_redirect_domains gated both apex entries on web-opt-rdr-domains being in lookup('deployment').deployed whenever the host serves Tor. On a multi node that also dropped the clearnet DOMAIN_PRIMARY -> DOMAIN_HOMEPAGE entry for every isolated variant without that role, so the apex had no vhost and answered with a TLS handshake reject; the Matrix federation delegation on the apex depends on that vhost in swarm. A clearnet node, and main, always schedules it.
The clearnet entry is now scheduled whenever the node's resolved NETWORK_MODE serves clearnet, and the deployment gate keeps guarding only the onion-apex entry. A tor-only node keeps the old behaviour, and the operator's production inventory runs no Tor host, so production is unaffected. Tests cover multi without the role (clearnet apex only) and tor-only (no apex).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6de71db3d0
commit
e4fd4552f0
2 files changed
+65
-19
No files matched your search
@@ -10,7 +10,14 @@ from ansible.plugins.lookup import LookupBase
|
||||
|
||||
from plugins.filter.merge.mapping import merge_mapping
|
||||
from utils.domains.list import render_domain_value
|
||||
from utils.networks.reachability import TOR, network_of, tor_serves_host
|
||||
from utils.networks.reachability import (
|
||||
CLEARNET,
|
||||
NODE_MODES,
|
||||
TOR,
|
||||
network_of,
|
||||
resolve_node_mode,
|
||||
tor_serves_host,
|
||||
)
|
||||
from utils.roles.entity.name import entity_name
|
||||
|
||||
|
||||
@@ -133,9 +140,11 @@ class LookupModule(LookupBase):
|
||||
is an onion host or has an onion sibling this node serves, which
|
||||
the redirect template sends the apex to; a homepage without one
|
||||
gets no onion apex entry, so an onion vhost never redirects to
|
||||
clearnet. Both entries require ``web-opt-rdr-domains`` in
|
||||
``lookup('deployment').deployed`` so isolated CI variants do not
|
||||
schedule a redirect whose target is not served.
|
||||
clearnet. On an onion node the onion-apex entry requires
|
||||
``web-opt-rdr-domains`` in ``lookup('deployment').deployed`` so
|
||||
isolated CI variants do not schedule a redirect whose target is not
|
||||
served; the clearnet entry needs it only when the node's
|
||||
``NETWORK_MODE`` does not serve clearnet.
|
||||
3. per-app alias-to-canonical mappings from
|
||||
``lookup('applications_current_play')``, gated by ``AUTO_BUILD_ALIASES``.
|
||||
|
||||
@@ -168,6 +177,22 @@ class LookupModule(LookupBase):
|
||||
node = tor.get("node") if isinstance(tor, Mapping) else None
|
||||
return self._resolve_str(node).strip()
|
||||
|
||||
def _serves_clearnet(self, vars_: Mapping[str, Any]) -> bool:
|
||||
"""Whether the node's resolved ``NETWORK_MODE`` includes clearnet.
|
||||
|
||||
Args:
|
||||
vars_: host variables carrying ``NETWORK_MODE``, ``group_names``
|
||||
and ``groups``.
|
||||
"""
|
||||
try:
|
||||
mode = resolve_node_mode(
|
||||
self._resolve_str(vars_.get("NETWORK_MODE")),
|
||||
tor_provided=tor_serves_host(vars_),
|
||||
)
|
||||
except ValueError as exc:
|
||||
raise AnsibleError(f"current_play_redirect_domains: {exc}") from exc
|
||||
return CLEARNET in NODE_MODES[mode]
|
||||
|
||||
def _reachable_on_onion(self, domain: str, vars_: Mapping[str, Any]) -> bool:
|
||||
"""Whether ``domain`` is an onion host or has an onion sibling this
|
||||
node serves.
|
||||
@@ -239,21 +264,23 @@ class LookupModule(LookupBase):
|
||||
else []
|
||||
)
|
||||
allowed = "web-opt-rdr-domains" in deployed
|
||||
if allowed:
|
||||
primary_redirects = []
|
||||
if domain_primary != domain_homepage:
|
||||
primary_redirects.append(
|
||||
{"source": domain_primary, "target": domain_homepage}
|
||||
)
|
||||
if (
|
||||
node_onion
|
||||
and node_onion != domain_homepage
|
||||
and self._reachable_on_onion(domain_homepage, vars_)
|
||||
):
|
||||
primary_redirects.append(
|
||||
{"source": node_onion, "target": domain_homepage}
|
||||
)
|
||||
merged = merge_mapping(merged, primary_redirects, "source")
|
||||
primary_redirects = []
|
||||
if domain_primary != domain_homepage and (
|
||||
allowed or self._serves_clearnet(vars_)
|
||||
):
|
||||
primary_redirects.append(
|
||||
{"source": domain_primary, "target": domain_homepage}
|
||||
)
|
||||
if (
|
||||
allowed
|
||||
and node_onion
|
||||
and node_onion != domain_homepage
|
||||
and self._reachable_on_onion(domain_homepage, vars_)
|
||||
):
|
||||
primary_redirects.append(
|
||||
{"source": node_onion, "target": domain_homepage}
|
||||
)
|
||||
merged = merge_mapping(merged, primary_redirects, "source")
|
||||
|
||||
current_play_apps = self._run_lookup("applications_current_play", vars_)
|
||||
if isinstance(current_play_apps, Mapping):
|
||||
|
||||
@@ -403,6 +403,25 @@ class CurrentPlayRedirectDomainsLookupTests(unittest.TestCase):
|
||||
def test_onion_apex_absent_when_rdr_domains_not_deployed(self):
|
||||
lm = self._make_lookup()
|
||||
variables = self._onion_variables()
|
||||
with self._patch_lookups(deployed=["web-opt-rdr-www"], current_play_apps={}):
|
||||
result = lm.run(terms=[], variables=variables)[0]
|
||||
self.assertEqual(
|
||||
result,
|
||||
[{"source": DOMAIN, "target": "dashboard.abcdefonion.onion"}],
|
||||
)
|
||||
|
||||
def test_multi_node_keeps_the_clearnet_apex_without_rdr_domains_deployed(self):
|
||||
lm = self._make_lookup()
|
||||
variables = self._onion_variables(
|
||||
NETWORK_MODE="multi", DOMAIN_HOMEPAGE="infinito.nexus"
|
||||
)
|
||||
with self._patch_lookups(deployed=["web-opt-rdr-www"], current_play_apps={}):
|
||||
result = lm.run(terms=[], variables=variables)[0]
|
||||
self.assertEqual(result, [{"source": DOMAIN, "target": "infinito.nexus"}])
|
||||
|
||||
def test_tor_only_node_drops_both_apex_entries_without_rdr_domains_deployed(self):
|
||||
lm = self._make_lookup()
|
||||
variables = self._onion_variables(NETWORK_MODE="tor")
|
||||
with self._patch_lookups(deployed=["web-opt-rdr-www"], current_play_apps={}):
|
||||
result = lm.run(terms=[], variables=variables)[0]
|
||||
self.assertEqual(result, [])
|
||||
|
||||
Reference in new issue
Block a user