@@ -964,10 +964,11 @@ func ProcessGatewayProxy(r client.Client, log logr.Logger, tctx *provider.Transl
964964 }
965965
966966 if cp .Service != nil {
967- if err := addProviderEndpointsToTranslateContext ( tctx , r , k8stypes.NamespacedName {
967+ serviceNN := k8stypes.NamespacedName {
968968 Namespace : gatewayProxy .GetNamespace (),
969969 Name : cp .Service .Name ,
970- }); err != nil {
970+ }
971+ if err := addProviderEndpointsToTranslateContext (tctx , r , serviceNN ); err != nil {
971972 return err
972973 }
973974 }
@@ -1377,10 +1378,11 @@ func ProcessIngressClassParameters(tctx *provider.TranslateContext, c client.Cli
13771378
13781379 // process control plane provider service
13791380 if cp .Service != nil {
1380- if err := addProviderEndpointsToTranslateContext ( tctx , c , client. ObjectKey {
1381+ serviceNN := k8stypes. NamespacedName {
13811382 Namespace : gatewayProxy .GetNamespace (),
13821383 Name : cp .Service .Name ,
1383- }); err != nil {
1384+ }
1385+ if err := addProviderEndpointsToTranslateContext (tctx , c , serviceNN ); err != nil {
13841386 return err
13851387 }
13861388 }
@@ -1486,10 +1488,6 @@ func distinctRequests(requests []reconcile.Request) []reconcile.Request {
14861488}
14871489
14881490func addProviderEndpointsToTranslateContext (tctx * provider.TranslateContext , c client.Client , serviceNN k8stypes.NamespacedName ) error {
1489- return addProviderEndpointsToTranslateContextWithEndpointSliceSupport (tctx , c , serviceNN , true )
1490- }
1491-
1492- func addProviderEndpointsToTranslateContextWithEndpointSliceSupport (tctx * provider.TranslateContext , c client.Client , serviceNN k8stypes.NamespacedName , supportsEndpointSlice bool ) error {
14931491 log .Debugw ("to process provider endpoints by provider.service" , zap .Any ("service" , serviceNN ))
14941492 var (
14951493 service corev1.Service
@@ -1500,39 +1498,7 @@ func addProviderEndpointsToTranslateContextWithEndpointSliceSupport(tctx *provid
15001498 }
15011499 tctx .Services [serviceNN ] = & service
15021500
1503- // Conditionally get EndpointSlice or Endpoints based on cluster API support
1504- if supportsEndpointSlice {
1505- // get es
1506- var (
1507- esList discoveryv1.EndpointSliceList
1508- )
1509- if err := c .List (tctx , & esList ,
1510- client .InNamespace (serviceNN .Namespace ),
1511- client.MatchingLabels {
1512- discoveryv1 .LabelServiceName : serviceNN .Name ,
1513- }); err != nil {
1514- log .Errorw ("failed to get endpoints for GatewayProxy provider" , zap .Error (err ), zap .Any ("endpoints" , serviceNN ))
1515- return err
1516- }
1517- tctx .EndpointSlices [serviceNN ] = esList .Items
1518- } else {
1519- // Fallback to Endpoints API for Kubernetes 1.18 compatibility
1520- var endpoints corev1.Endpoints
1521- if err := c .Get (tctx , serviceNN , & endpoints ); err != nil {
1522- if client .IgnoreNotFound (err ) != nil {
1523- log .Errorw ("failed to get endpoints for GatewayProxy provider" , zap .Error (err ), zap .Any ("endpoints" , serviceNN ))
1524- return err
1525- }
1526- // If endpoints not found, create empty EndpointSlice list
1527- tctx .EndpointSlices [serviceNN ] = []discoveryv1.EndpointSlice {}
1528- } else {
1529- // Convert Endpoints to EndpointSlice format for internal consistency
1530- convertedEndpointSlices := pkgutils .ConvertEndpointsToEndpointSlice (& endpoints )
1531- tctx .EndpointSlices [serviceNN ] = convertedEndpointSlices
1532- }
1533- }
1534-
1535- return nil
1501+ return resolveServiceEndpoints (tctx , c , tctx , serviceNN , true , nil )
15361502}
15371503
15381504func TypePredicate [T client.Object ]() func (obj client.Object ) bool {
@@ -1585,3 +1551,94 @@ func watchEndpointSliceOrEndpoints(bdr *ctrl.Builder, supportsEndpointSlice bool
15851551 return bdr .Watches (& corev1.Endpoints {}, handler .EnqueueRequestsFromMapFunc (endpointsMapFunc ))
15861552 }
15871553}
1554+
1555+ // resolveServiceEndpoints collects endpoints and adds them to the translate context
1556+ // It handles both EndpointSlice (K8s 1.19+) and Endpoints (K8s 1.18) APIs with automatic fallback
1557+ func resolveServiceEndpoints (
1558+ ctx context.Context ,
1559+ c client.Client ,
1560+ tctx * provider.TranslateContext ,
1561+ serviceNN k8stypes.NamespacedName ,
1562+ supportsEndpointSlice bool ,
1563+ subsetLabels map [string ]string ,
1564+ ) error {
1565+ if supportsEndpointSlice {
1566+ var endpoints discoveryv1.EndpointSliceList
1567+ if err := c .List (ctx , & endpoints ,
1568+ client .InNamespace (serviceNN .Namespace ),
1569+ client.MatchingLabels {
1570+ discoveryv1 .LabelServiceName : serviceNN .Name ,
1571+ },
1572+ ); err != nil {
1573+ return fmt .Errorf ("failed to list endpoint slices: %v" , err )
1574+ }
1575+
1576+ if len (subsetLabels ) == 0 {
1577+ tctx .EndpointSlices [serviceNN ] = endpoints .Items
1578+ } else {
1579+ // Apply subset filtering
1580+ tctx .EndpointSlices [serviceNN ] = filterEndpointSlicesBySubsetLabels (ctx , c , endpoints .Items , subsetLabels )
1581+ }
1582+ } else {
1583+ // Fallback to Endpoints API for Kubernetes 1.18 compatibility
1584+ var ep corev1.Endpoints
1585+ if err := c .Get (ctx , serviceNN , & ep ); err != nil {
1586+ if client .IgnoreNotFound (err ) != nil {
1587+ return fmt .Errorf ("failed to get endpoints: %v" , err )
1588+ }
1589+ // If endpoints not found, create empty EndpointSlice list
1590+ tctx .EndpointSlices [serviceNN ] = []discoveryv1.EndpointSlice {}
1591+ } else {
1592+ // Convert Endpoints to EndpointSlice format for internal consistency
1593+ convertedEndpointSlices := pkgutils .ConvertEndpointsToEndpointSlice (& ep )
1594+
1595+ if len (subsetLabels ) == 0 {
1596+ tctx .EndpointSlices [serviceNN ] = convertedEndpointSlices
1597+ } else {
1598+ // Apply subset filtering to converted EndpointSlices
1599+ tctx .EndpointSlices [serviceNN ] = filterEndpointSlicesBySubsetLabels (ctx , c , convertedEndpointSlices , subsetLabels )
1600+ }
1601+ }
1602+ }
1603+
1604+ return nil
1605+ }
1606+
1607+ // filterEndpointSlicesBySubsetLabels filters EndpointSlices by subset labels
1608+ func filterEndpointSlicesBySubsetLabels (ctx context.Context , c client.Client , endpointSlices []discoveryv1.EndpointSlice , labels map [string ]string ) []discoveryv1.EndpointSlice {
1609+ if len (labels ) == 0 {
1610+ return endpointSlices
1611+ }
1612+
1613+ for i := range endpointSlices {
1614+ endpointSlices [i ] = filterEndpointSliceByTargetPod (ctx , c , endpointSlices [i ], labels )
1615+ }
1616+
1617+ return utils .Filter (endpointSlices , func (v discoveryv1.EndpointSlice ) bool {
1618+ return len (v .Endpoints ) > 0
1619+ })
1620+ }
1621+
1622+ // filterEndpointSliceByTargetPod filters item.Endpoints which is not a subset of labels
1623+ func filterEndpointSliceByTargetPod (ctx context.Context , c client.Client , item discoveryv1.EndpointSlice , labels map [string ]string ) discoveryv1.EndpointSlice {
1624+ item .Endpoints = utils .Filter (item .Endpoints , func (v discoveryv1.Endpoint ) bool {
1625+ if v .TargetRef == nil || v .TargetRef .Kind != KindPod {
1626+ return true
1627+ }
1628+
1629+ var (
1630+ pod corev1.Pod
1631+ podNN = k8stypes.NamespacedName {
1632+ Namespace : v .TargetRef .Namespace ,
1633+ Name : v .TargetRef .Name ,
1634+ }
1635+ )
1636+ if err := c .Get (ctx , podNN , & pod ); err != nil {
1637+ return false
1638+ }
1639+
1640+ return utils .IsSubsetOf (labels , pod .GetLabels ())
1641+ })
1642+
1643+ return item
1644+ }
0 commit comments