Files
computer-playbook/utils/networks/proxy.py
T
kevinveenbirkenbachandClaude Fable 5 40e553069d refactor(structure): nest prefix-grouped sibling files into subfolders
Move files that share a delimiter-bounded name prefix within a folder (threshold 2) into a subfolder named after the prefix, dropping the prefix from the filename. Covers plugins/filter (docker, generate, has, merge, get/all), env handler subpackages, utils/roles/entity, utils/tests/swarm/write, role SQL/scripts/templates, keycloak/mailu task-includes, shared tasks/utils/load, and CI scripts. Update every import, query_file/script/include_tasks/src/lookup target, compose bind mount, and python -m path to the new locations.

Extend the prefix-grouped-files lint to threshold 2 with dir-level .nocheck and file-head nocheck opt-outs, and skip groups whose shortest member's stem equals the shared prefix. Keep flat only where a loader forbids nesting: WordPress mu-plugins and the docs/requirements namespace. Ansible filter discovery is recursive, so nested filters stay Jinja-resolvable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 20:00:03 +02:00

123 lines
3.8 KiB
Python

"""Mode-aware nginx ``proxy_pass`` directive renderer (compose/swarm), SPOT.
Trip-wire: the swarm oauth2 endpoint must forward ``$uri$is_args$args``, not
``$request_uri`` — during ``error_page 401 = /oauth2/start`` the original
``$request_uri`` stays ``/`` and oauth2-proxy 403s instead of redirecting.
"""
from __future__ import annotations
import re
from typing import Any
from utils.roles.applications.config import get
from utils.roles.entity.name import get_entity_name
_REGEX_OR_NAMED_LOCATION = re.compile(r"^[@~]")
_LOCATION_MODIFIER = re.compile(r"^(?:=|\^~)\s*")
_UPSTREAM_VAR = "proxy_pass_upstream"
def _as_str(value: Any) -> str:
return "" if value is None else str(value).strip()
def resolve_upstream(
applications: dict[str, Any],
application_id: str,
service_key: str,
port_kind: str,
deployment_mode: str,
local_port: str = "",
internal_port: str = "",
) -> str:
"""Upstream ``host:port``: compose ``127.0.0.1:<local>``; swarm
``<entity>:<internal>`` (shared-overlay alias) for the app frontend, or
``<entity>_<service_key>:<internal>`` for named sidecars (sso-proxy).
Missing swarm internal port hard-fails."""
entity = get_entity_name(application_id)
if not entity:
raise ValueError(
f"resolve_upstream: cannot derive entity from {application_id!r}"
)
service_key = _as_str(service_key) or entity
def _config_port(scope: str) -> str:
return _as_str(
get(
applications=applications,
application_id=application_id,
config_path=f"services.{entity}.ports.{scope}.{port_kind}",
strict=False,
default="",
)
)
if deployment_mode != "swarm":
port = _as_str(local_port) or _config_port("local")
if not port:
raise ValueError(
f"resolve_upstream: no local port for {application_id!r} "
f"(services.{entity}.ports.local.{port_kind})"
)
host = (
_as_str(
get(
applications=applications,
application_id=application_id,
config_path=f"services.{entity}.upstream_host",
strict=False,
default="",
)
)
or "127.0.0.1"
)
return f"{host}:{port}"
port = _as_str(internal_port) or _config_port("internal")
if not port:
raise ValueError(
f"resolve_upstream: swarm upstream for {application_id!r} needs "
f"services.{entity}.ports.internal.{port_kind} (or internal_port=)"
)
if service_key == entity:
return f"{entity}:{port}"
return f"{entity}_{service_key}:{port}"
def _compose_suffix(tail: str, location: str) -> str:
if tail == "request":
loc = location.strip()
if _REGEX_OR_NAMED_LOCATION.match(loc):
return ""
return _LOCATION_MODIFIER.sub("", loc)
if tail.startswith("/"):
return tail
return ""
def _swarm_tail(tail: str) -> str:
if tail == "oauth2":
return "$uri$is_args$args"
if tail.startswith("/"):
return tail
return "$request_uri"
def render_proxy_pass(
authority: str,
deployment_mode: str,
tail: str = "request",
location: str = "/",
) -> str:
"""``proxy_pass`` directive; swarm prepends a ``set`` line (request-time DNS)."""
if not authority:
raise ValueError("render_proxy_pass: authority must be non-empty")
if deployment_mode == "swarm":
return (
f'set ${_UPSTREAM_VAR} "{authority}";\n'
f" proxy_pass http://${_UPSTREAM_VAR}{_swarm_tail(tail)};"
)
return f"proxy_pass http://{authority}{_compose_suffix(tail, location)};"