plugin/kubernetes: Add support for topology-aware headless services via "az-pinned" subdomains (#8388)

This commit is contained in:
rpb-ant
2026-08-10 16:24:50 -04:00
committed by GitHub
parent b2ef1a13e8
commit c2ca1b2c23
10 changed files with 624 additions and 39 deletions

View File

@@ -2,6 +2,8 @@ package object
import (
"fmt"
"maps"
"strings"
discovery "k8s.io/api/discovery/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -17,6 +19,12 @@ type Endpoints struct {
Index string
IndexIP []string
Subsets []EndpointSubset
// Zones maps address IPs to their topology.kubernetes.io/zone,
// lowercased. Nil unless the kubernetes plugin's `zonal` option
// selected the zone-retaining transform, so default configurations
// carry one nil pointer per slice and their addresses stay exactly
// as slim as before.
Zones map[string]string
*Empty
}
@@ -48,6 +56,18 @@ func EndpointsKey(name, namespace string) string { return name + "." + namespace
// EndpointSliceToEndpoints converts a *discovery.EndpointSlice to a *Endpoints.
func EndpointSliceToEndpoints(obj meta.Object) (meta.Object, error) {
return endpointSliceToEndpoints(obj, false /* withZones */)
}
// EndpointSliceToEndpointsWithZones is EndpointSliceToEndpoints, but also
// retains each endpoint's topology zone. Used only when the kubernetes
// plugin's zonal option is enabled, so the default configuration's cache
// stays exactly as slim as before.
func EndpointSliceToEndpointsWithZones(obj meta.Object) (meta.Object, error) {
return endpointSliceToEndpoints(obj, true /* withZones */)
}
func endpointSliceToEndpoints(obj meta.Object, withZones bool) (meta.Object, error) {
ends, ok := obj.(*discovery.EndpointSlice)
if !ok {
return nil, fmt.Errorf("unexpected object %v", obj)
@@ -92,6 +112,14 @@ func EndpointSliceToEndpoints(obj meta.Object) (meta.Object, error) {
if end.Hostname != nil {
ea.Hostname = *end.Hostname
}
if withZones && end.Zone != nil {
if e.Zones == nil {
e.Zones = make(map[string]string)
}
// Lowercased once here: qnames arrive case-folded, so
// lookups compare without folding per query.
e.Zones[a] = strings.ToLower(*end.Zone)
}
// ignore pod names that are too long to be a valid label
if end.TargetRef != nil && len(end.TargetRef.Name) < 64 {
ea.TargetRefName = end.TargetRef.Name
@@ -144,6 +172,9 @@ func (e *Endpoints) DeepCopyObject() runtime.Object {
Subsets: make([]EndpointSubset, len(e.Subsets)),
}
copy(e1.IndexIP, e.IndexIP)
if e.Zones != nil {
e1.Zones = maps.Clone(e.Zones)
}
for i, eps := range e.Subsets {
sub := EndpointSubset{