@@ -2038,6 +2038,98 @@ def _k8s_parse_host_aliases() -> list[dict[str, Any]]:
20382038 return [{"ip" : ip , "hostnames" : hosts } for ip , hosts in ip_to_hosts .items ()]
20392039
20402040
2041+ async def _k8s_ensure_coredns_host_aliases () -> None :
2042+ """Patch CoreDNS to resolve hostnames from HP_K8S_HOST_ALIASES cluster-wide.
2043+
2044+ In local/development setups, ``nextcloud.local`` only exists in the host's
2045+ ``/etc/hosts``. Pod-level ``hostAliases`` fix this for ExApp pods, but
2046+ other K8s-native components (KEDA, monitoring, etc.) still rely on
2047+ cluster DNS. This function patches the CoreDNS ``hosts`` plugin so that
2048+ **every** pod in the cluster can resolve those names.
2049+
2050+ Only runs when ``HP_K8S_HOST_ALIASES`` is set and ``HP_K8S_ENABLED`` is
2051+ true. Errors are logged but never fatal — pod hostAliases remain as
2052+ fallback.
2053+ """
2054+ if not K8S_ENABLED or not K8S_HOST_ALIASES_RAW .strip ():
2055+ return
2056+
2057+ host_aliases = _k8s_parse_host_aliases ()
2058+ if not host_aliases :
2059+ return
2060+
2061+ LOGGER .info ("Ensuring CoreDNS resolves host aliases: %s" , K8S_HOST_ALIASES_RAW )
2062+
2063+ try :
2064+ # 1. Read current CoreDNS ConfigMap.
2065+ status , data , _text = await _k8s_request (
2066+ "GET" , "/api/v1/namespaces/kube-system/configmaps/coredns" ,
2067+ )
2068+ if status != 200 or not data :
2069+ LOGGER .warning ("Could not read CoreDNS ConfigMap (HTTP %d), skipping." , status )
2070+ return
2071+
2072+ corefile = data .get ("data" , {}).get ("Corefile" , "" )
2073+ if not corefile :
2074+ LOGGER .warning ("CoreDNS ConfigMap has no Corefile entry, skipping." )
2075+ return
2076+
2077+ # 2. Build the ``hosts { … }`` block from our aliases.
2078+ hosts_lines : list [str ] = []
2079+ for alias in host_aliases :
2080+ for hostname in alias ["hostnames" ]:
2081+ hosts_lines .append (f" { alias ['ip' ]} { hostname } " )
2082+ hosts_block = "hosts {\n " + "\n " .join (hosts_lines ) + "\n fallthrough\n }"
2083+
2084+ # 3. Replace existing hosts block or insert before ``forward``.
2085+ hosts_re = re .compile (r"hosts\s*\{[^}]*\}" )
2086+ if hosts_re .search (corefile ):
2087+ new_corefile = hosts_re .sub (hosts_block , corefile , count = 1 )
2088+ elif "forward ." in corefile :
2089+ new_corefile = corefile .replace ("forward ." , f"{ hosts_block } \n forward ." , 1 )
2090+ else :
2091+ LOGGER .warning (
2092+ "CoreDNS Corefile has no 'hosts' block and no 'forward' directive, cannot patch."
2093+ )
2094+ return
2095+
2096+ if new_corefile == corefile :
2097+ LOGGER .info ("CoreDNS already has correct host aliases, no patch needed." )
2098+ return
2099+
2100+ # 4. Patch the ConfigMap.
2101+ status , _ , _text = await _k8s_request (
2102+ "PATCH" ,
2103+ "/api/v1/namespaces/kube-system/configmaps/coredns" ,
2104+ json_body = {"data" : {"Corefile" : new_corefile }},
2105+ content_type = "application/strategic-merge-patch+json" ,
2106+ )
2107+ if status != 200 :
2108+ LOGGER .warning ("Failed to patch CoreDNS ConfigMap (HTTP %d): %s" , status , _text [:200 ])
2109+ return
2110+
2111+ # 5. Trigger a CoreDNS rollout restart (annotation change).
2112+ restart_annotation = time .strftime ("%Y-%m-%dT%H:%M:%SZ" , time .gmtime ())
2113+ status , _ , _text = await _k8s_request (
2114+ "PATCH" ,
2115+ "/apis/apps/v1/namespaces/kube-system/deployments/coredns" ,
2116+ json_body = {
2117+ "spec" : {"template" : {"metadata" : {"annotations" : {
2118+ "harp.nextcloud.com/restartedAt" : restart_annotation ,
2119+ }}}}
2120+ },
2121+ content_type = "application/strategic-merge-patch+json" ,
2122+ )
2123+ if status != 200 :
2124+ LOGGER .warning ("Failed to restart CoreDNS Deployment (HTTP %d): %s" , status , _text [:200 ])
2125+ return
2126+
2127+ LOGGER .info ("CoreDNS patched and restarted with host aliases: %s" , K8S_HOST_ALIASES_RAW )
2128+
2129+ except Exception as exc :
2130+ LOGGER .warning ("Failed to configure CoreDNS host aliases (non-fatal): %s" , exc )
2131+
2132+
20412133def _k8s_build_deployment_manifest (payload : CreateExAppPayload , replicas : int ) -> dict [str , Any ]:
20422134 """Build a Deployment manifest from CreateExAppPayload."""
20432135 deployment_name = payload .exapp_k8s_name
@@ -3003,6 +3095,9 @@ async def run_http_server(host="127.0.0.1", port=8200):
30033095
30043096
30053097async def main ():
3098+ # Ensure cluster-wide DNS for host aliases before starting servers.
3099+ await _k8s_ensure_coredns_host_aliases ()
3100+
30063101 spoa_task = asyncio .create_task (SPOA_AGENT ._run (host = SPOA_HOST , port = SPOA_PORT )) # noqa
30073102 http_task = asyncio .create_task (run_http_server (host = "127.0.0.1" , port = 8200 ))
30083103
0 commit comments