@@ -2071,79 +2071,95 @@ def _k8s_parse_host_aliases() -> list[dict[str, Any]]:
20712071
20722072
20732073async def _k8s_ensure_coredns_host_aliases () -> None :
2074- """Patch CoreDNS to resolve HP_K8S_HOST_ALIASES cluster-wide."""
2074+ """Publish HP_K8S_HOST_ALIASES into the 'coredns-custom' ConfigMap so they resolve cluster-wide.
2075+
2076+ Uses k3s's /etc/coredns/custom/*.server import convention (also honoured by any CoreDNS
2077+ Deployment that mounts a 'coredns-custom' ConfigMap with optional=true). The main
2078+ 'coredns' ConfigMap managed by the distribution operator is never touched; the 'reload'
2079+ plugin present in the stock Corefile picks up the new file within seconds, so no
2080+ Deployment restart is needed either. The ConfigMap key is prefixed 'harp-' so other
2081+ operators writing unrelated keys into 'coredns-custom' are not disturbed.
2082+ """
20752083 if not K8S_ENABLED or not K8S_HOST_ALIASES_RAW .strip ():
20762084 return
20772085
20782086 host_aliases = _k8s_parse_host_aliases ()
20792087 if not host_aliases :
20802088 return
20812089
2082- LOGGER .info ("Ensuring CoreDNS resolves host aliases: %s" , K8S_HOST_ALIASES_RAW )
2090+ # Build one standalone Corefile server block per zone. Entries share a single block
2091+ # to keep the file compact and to avoid plugin-instance conflicts between zones.
2092+ hosts_entries : list [str ] = []
2093+ zone_names : list [str ] = []
2094+ for alias in host_aliases :
2095+ for hostname in alias ["hostnames" ]:
2096+ hosts_entries .append (f" { alias ['ip' ]} { hostname } " )
2097+ zone_names .append (f"{ hostname } :53" )
2098+
2099+ server_file = (
2100+ f"{ ' ' .join (zone_names )} {{\n "
2101+ " hosts {\n "
2102+ f"{ chr (10 ).join (hosts_entries )} \n "
2103+ " fallthrough\n "
2104+ " }\n "
2105+ " forward . /etc/resolv.conf\n "
2106+ "}\n "
2107+ )
20832108
2084- try :
2085- status , data , _text = await _k8s_request (
2086- "GET" , "/api/v1/namespaces/kube-system/configmaps/coredns" ,
2087- )
2088- if status != 200 or not data :
2089- LOGGER .warning ("Could not read CoreDNS ConfigMap (HTTP %d), skipping." , status )
2090- return
2109+ cm_path = "/api/v1/namespaces/kube-system/configmaps/coredns-custom"
2110+ key = "harp-host-aliases.server"
20912111
2092- corefile = data .get ("data" , {}).get ("Corefile" , "" )
2093- if not corefile :
2094- LOGGER .warning ("CoreDNS ConfigMap has no Corefile entry, skipping." )
2095- return
2112+ LOGGER .info ("Publishing %d host alias zone(s) into coredns-custom: %s" , len (zone_names ), K8S_HOST_ALIASES_RAW )
20962113
2097- hosts_lines : list [str ] = []
2098- for alias in host_aliases :
2099- for hostname in alias ["hostnames" ]:
2100- hosts_lines .append (f" { alias ['ip' ]} { hostname } " )
2101- hosts_block = "hosts {\n " + "\n " .join (hosts_lines ) + "\n fallthrough\n }"
2102-
2103- hosts_re = re .compile (r"hosts\s*\{[^}]*\}" )
2104- if hosts_re .search (corefile ):
2105- new_corefile = hosts_re .sub (hosts_block , corefile , count = 1 )
2106- elif "forward ." in corefile :
2107- new_corefile = corefile .replace ("forward ." , f"{ hosts_block } \n forward ." , 1 )
2108- else :
2109- LOGGER .warning (
2110- "CoreDNS Corefile has no 'hosts' block and no 'forward' directive, cannot patch."
2114+ try :
2115+ status , existing , _text = await _k8s_request ("GET" , cm_path )
2116+
2117+ if status == 404 :
2118+ configmap = {
2119+ "apiVersion" : "v1" ,
2120+ "kind" : "ConfigMap" ,
2121+ "metadata" : {
2122+ "name" : "coredns-custom" ,
2123+ "namespace" : "kube-system" ,
2124+ "labels" : {"app.kubernetes.io/managed-by" : "harp" },
2125+ },
2126+ "data" : {key : server_file },
2127+ }
2128+ status , _ , _text = await _k8s_request (
2129+ "POST" ,
2130+ "/api/v1/namespaces/kube-system/configmaps" ,
2131+ json_body = configmap ,
21112132 )
2133+ if status in (200 , 201 ):
2134+ LOGGER .info ("Created coredns-custom ConfigMap with HaRP host aliases." )
2135+ else :
2136+ LOGGER .warning ("Failed to create coredns-custom (HTTP %d): %s" , status , _text [:200 ])
21122137 return
21132138
2114- if new_corefile == corefile :
2115- LOGGER .info ( "CoreDNS already has correct host aliases, no patch needed." )
2139+ if status != 200 or not isinstance ( existing , dict ) :
2140+ LOGGER .warning ( "Could not read coredns-custom (HTTP %d), skipping." , status )
21162141 return
21172142
2118- status , _ , _text = await _k8s_request (
2119- "PATCH" ,
2120- "/api/v1/namespaces/kube-system/configmaps/coredns" ,
2121- json_body = {"data" : {"Corefile" : new_corefile }},
2122- content_type = "application/strategic-merge-patch+json" ,
2123- )
2124- if status != 200 :
2125- LOGGER .warning ("Failed to patch CoreDNS ConfigMap (HTTP %d): %s" , status , _text [:200 ])
2143+ current = (existing .get ("data" ) or {}).get (key )
2144+ if current == server_file :
2145+ LOGGER .info ("coredns-custom already carries the expected HaRP host aliases, no patch needed." )
21262146 return
21272147
2128- restart_annotation = time .strftime ("%Y-%m-%dT%H:%M:%SZ" , time .gmtime ())
2148+ # Strategic merge patch on ConfigMap.data merges keys individually — unrelated keys
2149+ # written by other operators stay intact.
21292150 status , _ , _text = await _k8s_request (
21302151 "PATCH" ,
2131- "/apis/apps/v1/namespaces/kube-system/deployments/coredns" ,
2132- json_body = {
2133- "spec" : {"template" : {"metadata" : {"annotations" : {
2134- "harp.nextcloud.com/restartedAt" : restart_annotation ,
2135- }}}}
2136- },
2152+ cm_path ,
2153+ json_body = {"data" : {key : server_file }},
21372154 content_type = "application/strategic-merge-patch+json" ,
21382155 )
2139- if status != 200 :
2140- LOGGER .warning ("Failed to restart CoreDNS Deployment (HTTP %d): %s" , status , _text [:200 ])
2141- return
2142-
2143- LOGGER .info ("CoreDNS patched and restarted with host aliases: %s" , K8S_HOST_ALIASES_RAW )
2156+ if status == 200 :
2157+ LOGGER .info ("Updated coredns-custom with HaRP host aliases." )
2158+ else :
2159+ LOGGER .warning ("Failed to patch coredns-custom (HTTP %d): %s" , status , _text [:200 ])
21442160
21452161 except Exception as exc :
2146- LOGGER .warning ("Failed to configure CoreDNS host aliases (non-fatal): %s" , exc )
2162+ LOGGER .warning ("Failed to configure coredns-custom host aliases (non-fatal): %s" , exc )
21472163
21482164
21492165def _k8s_build_deployment_manifest (payload : CreateExAppPayload , replicas : int ) -> dict [str , Any ]:
0 commit comments