diff --git a/decnet/services/base.py b/decnet/services/base.py index 65030b4b..1e771ce6 100644 --- a/decnet/services/base.py +++ b/decnet/services/base.py @@ -88,6 +88,15 @@ class BaseService(ABC): """ return None + def udp_ports(self, cfg: dict | None = None) -> list[int]: + """UDP ports this service needs published, given its resolved config. + + Only meaningful for gateway deckies in topology deployments where the + base container publishes ports on the host. Fleet deckies use MACVLAN + and need no port publishing at all. Default: no UDP ports. + """ + return [] + def validate_cfg(self, cfg: dict | None) -> dict: """ Coerce a user-submitted dict against this service's config_schema. diff --git a/decnet/services/https.py b/decnet/services/https.py index 729e2ea6..6f5fbf7e 100644 --- a/decnet/services/https.py +++ b/decnet/services/https.py @@ -116,5 +116,9 @@ class HTTPSService(BaseService): return fragment + def udp_ports(self, cfg: dict | None = None) -> list[int]: + versions = (cfg or {}).get("http_versions", []) + return [443] if "http/3" in versions else [] + def dockerfile_context(self) -> Path | None: return TEMPLATES_DIR diff --git a/decnet/topology/compose.py b/decnet/topology/compose.py index df8e6128..e4e0f147 100644 --- a/decnet/topology/compose.py +++ b/decnet/topology/compose.py @@ -108,8 +108,11 @@ def generate_topology_compose(hydrated: dict[str, Any]) -> dict: svc = get_service(svc_name) if svc is None or svc.fleet_singleton: continue + svc_cfg = service_config.get(svc_name, {}) for port in svc.ports: published.append(f"{port}:{port}") + for port in svc.udp_ports(svc_cfg): + published.append(f"{port}:{port}/udp") if published: base["ports"] = published