@@ -957,10 +957,11 @@ func ProcessGatewayProxy(r client.Client, log logr.Logger, tctx *provider.Transl
957957 }
958958
959959 if cp .Service != nil {
960- if err := addProviderEndpointsToTranslateContext ( tctx , r , k8stypes.NamespacedName {
960+ serviceNN := k8stypes.NamespacedName {
961961 Namespace : gatewayProxy .GetNamespace (),
962962 Name : cp .Service .Name ,
963- }); err != nil {
963+ }
964+ if err := addProviderEndpointsToTranslateContext (tctx , r , serviceNN ); err != nil {
964965 return err
965966 }
966967 }
@@ -1357,10 +1358,11 @@ func ProcessIngressClassParameters(tctx *provider.TranslateContext, c client.Cli
13571358
13581359 // process control plane provider service
13591360 if cp .Service != nil {
1360- if err := addProviderEndpointsToTranslateContext ( tctx , c , client. ObjectKey {
1361+ serviceNN := k8stypes. NamespacedName {
13611362 Namespace : gatewayProxy .GetNamespace (),
13621363 Name : cp .Service .Name ,
1363- }); err != nil {
1364+ }
1365+ if err := addProviderEndpointsToTranslateContext (tctx , c , serviceNN ); err != nil {
13641366 return err
13651367 }
13661368 }
@@ -1419,10 +1421,6 @@ func distinctRequests(requests []reconcile.Request) []reconcile.Request {
14191421}
14201422
14211423func addProviderEndpointsToTranslateContext (tctx * provider.TranslateContext , c client.Client , serviceNN k8stypes.NamespacedName ) error {
1422- return addProviderEndpointsToTranslateContextWithEndpointSliceSupport (tctx , c , serviceNN , true )
1423- }
1424-
1425- func addProviderEndpointsToTranslateContextWithEndpointSliceSupport (tctx * provider.TranslateContext , c client.Client , serviceNN k8stypes.NamespacedName , supportsEndpointSlice bool ) error {
14261424 log .Debugw ("to process provider endpoints by provider.service" , zap .Any ("service" , serviceNN ))
14271425 var (
14281426 service corev1.Service
@@ -1433,39 +1431,7 @@ func addProviderEndpointsToTranslateContextWithEndpointSliceSupport(tctx *provid
14331431 }
14341432 tctx .Services [serviceNN ] = & service
14351433
1436- // Conditionally get EndpointSlice or Endpoints based on cluster API support
1437- if supportsEndpointSlice {
1438- // get es
1439- var (
1440- esList discoveryv1.EndpointSliceList
1441- )
1442- if err := c .List (tctx , & esList ,
1443- client .InNamespace (serviceNN .Namespace ),
1444- client.MatchingLabels {
1445- discoveryv1 .LabelServiceName : serviceNN .Name ,
1446- }); err != nil {
1447- log .Errorw ("failed to get endpoints for GatewayProxy provider" , zap .Error (err ), zap .Any ("endpoints" , serviceNN ))
1448- return err
1449- }
1450- tctx .EndpointSlices [serviceNN ] = esList .Items
1451- } else {
1452- // Fallback to Endpoints API for Kubernetes 1.18 compatibility
1453- var endpoints corev1.Endpoints
1454- if err := c .Get (tctx , serviceNN , & endpoints ); err != nil {
1455- if client .IgnoreNotFound (err ) != nil {
1456- log .Errorw ("failed to get endpoints for GatewayProxy provider" , zap .Error (err ), zap .Any ("endpoints" , serviceNN ))
1457- return err
1458- }
1459- // If endpoints not found, create empty EndpointSlice list
1460- tctx .EndpointSlices [serviceNN ] = []discoveryv1.EndpointSlice {}
1461- } else {
1462- // Convert Endpoints to EndpointSlice format for internal consistency
1463- convertedEndpointSlices := pkgutils .ConvertEndpointsToEndpointSlice (& endpoints )
1464- tctx .EndpointSlices [serviceNN ] = convertedEndpointSlices
1465- }
1466- }
1467-
1468- return nil
1434+ return collectEndpointsWithEndpointSliceSupport (tctx , c , tctx , serviceNN , true , nil )
14691435}
14701436
14711437func TypePredicate [T client.Object ]() func (obj client.Object ) bool {
@@ -1518,3 +1484,94 @@ func watchEndpointSliceOrEndpoints(bdr *ctrl.Builder, supportsEndpointSlice bool
15181484 return bdr .Watches (& corev1.Endpoints {}, handler .EnqueueRequestsFromMapFunc (endpointsMapFunc ))
15191485 }
15201486}
1487+
1488+ // collectEndpointsWithEndpointSliceSupport collects endpoints and adds them to the translate context
1489+ // It handles both EndpointSlice (K8s 1.19+) and Endpoints (K8s 1.18) APIs with automatic fallback
1490+ func collectEndpointsWithEndpointSliceSupport (
1491+ ctx context.Context ,
1492+ c client.Client ,
1493+ tctx * provider.TranslateContext ,
1494+ serviceNN k8stypes.NamespacedName ,
1495+ supportsEndpointSlice bool ,
1496+ subsetLabels map [string ]string ,
1497+ ) error {
1498+ if supportsEndpointSlice {
1499+ var endpoints discoveryv1.EndpointSliceList
1500+ if err := c .List (ctx , & endpoints ,
1501+ client .InNamespace (serviceNN .Namespace ),
1502+ client.MatchingLabels {
1503+ discoveryv1 .LabelServiceName : serviceNN .Name ,
1504+ },
1505+ ); err != nil {
1506+ return fmt .Errorf ("failed to list endpoint slices: %v" , err )
1507+ }
1508+
1509+ if len (subsetLabels ) == 0 {
1510+ tctx .EndpointSlices [serviceNN ] = endpoints .Items
1511+ } else {
1512+ // Apply subset filtering
1513+ tctx .EndpointSlices [serviceNN ] = filterEndpointSlicesBySubsetLabels (ctx , c , endpoints .Items , subsetLabels )
1514+ }
1515+ } else {
1516+ // Fallback to Endpoints API for Kubernetes 1.18 compatibility
1517+ var ep corev1.Endpoints
1518+ if err := c .Get (ctx , serviceNN , & ep ); err != nil {
1519+ if client .IgnoreNotFound (err ) != nil {
1520+ return fmt .Errorf ("failed to get endpoints: %v" , err )
1521+ }
1522+ // If endpoints not found, create empty EndpointSlice list
1523+ tctx .EndpointSlices [serviceNN ] = []discoveryv1.EndpointSlice {}
1524+ } else {
1525+ // Convert Endpoints to EndpointSlice format for internal consistency
1526+ convertedEndpointSlices := pkgutils .ConvertEndpointsToEndpointSlice (& ep )
1527+
1528+ if len (subsetLabels ) == 0 {
1529+ tctx .EndpointSlices [serviceNN ] = convertedEndpointSlices
1530+ } else {
1531+ // Apply subset filtering to converted EndpointSlices
1532+ tctx .EndpointSlices [serviceNN ] = filterEndpointSlicesBySubsetLabels (ctx , c , convertedEndpointSlices , subsetLabels )
1533+ }
1534+ }
1535+ }
1536+
1537+ return nil
1538+ }
1539+
1540+ // filterEndpointSlicesBySubsetLabels filters EndpointSlices by subset labels
1541+ func filterEndpointSlicesBySubsetLabels (ctx context.Context , c client.Client , endpointSlices []discoveryv1.EndpointSlice , labels map [string ]string ) []discoveryv1.EndpointSlice {
1542+ if len (labels ) == 0 {
1543+ return endpointSlices
1544+ }
1545+
1546+ for i := range endpointSlices {
1547+ endpointSlices [i ] = filterEndpointSliceByTargetPod (ctx , c , endpointSlices [i ], labels )
1548+ }
1549+
1550+ return utils .Filter (endpointSlices , func (v discoveryv1.EndpointSlice ) bool {
1551+ return len (v .Endpoints ) > 0
1552+ })
1553+ }
1554+
1555+ // filterEndpointSliceByTargetPod filters item.Endpoints which is not a subset of labels
1556+ func filterEndpointSliceByTargetPod (ctx context.Context , c client.Client , item discoveryv1.EndpointSlice , labels map [string ]string ) discoveryv1.EndpointSlice {
1557+ item .Endpoints = utils .Filter (item .Endpoints , func (v discoveryv1.Endpoint ) bool {
1558+ if v .TargetRef == nil || v .TargetRef .Kind != KindPod {
1559+ return true
1560+ }
1561+
1562+ var (
1563+ pod corev1.Pod
1564+ podNN = k8stypes.NamespacedName {
1565+ Namespace : v .TargetRef .Namespace ,
1566+ Name : v .TargetRef .Name ,
1567+ }
1568+ )
1569+ if err := c .Get (ctx , podNN , & pod ); err != nil {
1570+ return false
1571+ }
1572+
1573+ return utils .IsSubsetOf (labels , pod .GetLabels ())
1574+ })
1575+
1576+ return item
1577+ }
0 commit comments