diff --git a/internal/controller/apisixconsumer_controller.go b/internal/controller/apisixconsumer_controller.go index 35c580aa..66d005f4 100644 --- a/internal/controller/apisixconsumer_controller.go +++ b/internal/controller/apisixconsumer_controller.go @@ -58,6 +58,7 @@ type ApisixConsumerReconciler struct { Readier readiness.ReadinessManager ICGV schema.GroupVersion + SupportsEndpointSlice bool // cache capability } // Reconcile FIXME: implement the reconcile logic (For now, it dose nothing other than directly accepting) @@ -98,7 +99,7 @@ func (r *ApisixConsumerReconciler) Reconcile(ctx context.Context, req ctrl.Reque } defer func() { r.updateStatus(ac, err) }() - if err = ProcessIngressClassParameters(tctx, r.Client, r.Log, ac, ingressClass); err != nil { + if err = ProcessIngressClassParameters(tctx, r.Client, r.Log, ac, ingressClass, r.SupportsEndpointSlice); err != nil { r.Log.Error(err, "failed to process IngressClass parameters", "ingressClass", ingressClass.Name) return ctrl.Result{}, client.IgnoreNotFound(err) } diff --git a/internal/controller/apisixglobalrule_controller.go b/internal/controller/apisixglobalrule_controller.go index fabc60c2..e0ea4bd9 100644 --- a/internal/controller/apisixglobalrule_controller.go +++ b/internal/controller/apisixglobalrule_controller.go @@ -58,6 +58,8 @@ type ApisixGlobalRuleReconciler struct { Readier readiness.ReadinessManager ICGV schema.GroupVersion + + SupportsEndpointSlice bool // cache capability } // Reconcile implements the reconciliation logic for ApisixGlobalRule @@ -103,7 +105,7 @@ func (r *ApisixGlobalRuleReconciler) Reconcile(ctx context.Context, req ctrl.Req } // process IngressClass parameters if they reference GatewayProxy - if err := ProcessIngressClassParameters(tctx, r.Client, r.Log, &globalRule, ingressClass); err != nil { + if err := ProcessIngressClassParameters(tctx, r.Client, r.Log, &globalRule, ingressClass, r.SupportsEndpointSlice); err != nil { r.Log.Error(err, "failed to process IngressClass parameters", "ingressClass", ingressClass.Name) return ctrl.Result{}, client.IgnoreNotFound(err) } diff --git a/internal/controller/apisixroute_controller.go b/internal/controller/apisixroute_controller.go index dbb7c76a..250527ac 100644 --- a/internal/controller/apisixroute_controller.go +++ b/internal/controller/apisixroute_controller.go @@ -64,14 +64,14 @@ type ApisixRouteReconciler struct { Readier readiness.ReadinessManager ICGV schema.GroupVersion - // supportsEndpointSlice indicates whether the cluster supports EndpointSlice API - supportsEndpointSlice bool + // SupportsEndpointSlice indicates whether the cluster supports EndpointSlice API + SupportsEndpointSlice bool } // SetupWithManager sets up the controller with the Manager. func (r *ApisixRouteReconciler) SetupWithManager(mgr ctrl.Manager) error { // Check and store EndpointSlice API support - r.supportsEndpointSlice = pkgutils.HasAPIResource(mgr, &discoveryv1.EndpointSlice{}) + r.SupportsEndpointSlice = pkgutils.HasAPIResource(mgr, &discoveryv1.EndpointSlice{}) var icWatch client.Object switch r.ICGV.String() { case networkingv1beta1.SchemeGroupVersion.String(): @@ -86,7 +86,7 @@ func (r *ApisixRouteReconciler) SetupWithManager(mgr ctrl.Manager) error { predicate.NewPredicateFuncs(TypePredicate[*corev1.Secret]()), } - if !r.supportsEndpointSlice { + if !r.SupportsEndpointSlice { eventFilters = append(eventFilters, predicate.NewPredicateFuncs(TypePredicate[*corev1.Endpoints]())) } @@ -109,7 +109,7 @@ func (r *ApisixRouteReconciler) SetupWithManager(mgr ctrl.Manager) error { ) // Conditionally watch EndpointSlice or Endpoints based on cluster API support - bdr = watchEndpointSliceOrEndpoints(bdr, r.supportsEndpointSlice, + bdr = watchEndpointSliceOrEndpoints(bdr, r.SupportsEndpointSlice, r.listApisixRoutesForService, r.listApisixRoutesForEndpoints, r.Log) @@ -167,7 +167,7 @@ func (r *ApisixRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) } defer func() { r.updateStatus(&ar, err) }() - if err = ProcessIngressClassParameters(tctx, r.Client, r.Log, &ar, ic); err != nil { + if err = ProcessIngressClassParameters(tctx, r.Client, r.Log, &ar, ic, r.SupportsEndpointSlice); err != nil { r.Log.Error(err, "failed to process IngressClass parameters", "ingressClass", ic.Name) return ctrl.Result{}, client.IgnoreNotFound(err) } @@ -491,7 +491,7 @@ func (r *ApisixRouteReconciler) validateHTTPBackend(tctx *provider.TranslateCont // It specifies that the target pod's label should be a superset of the subset labels of the ApisixUpstream of the serviceName subsetLabels := r.getSubsetLabels(tctx, serviceNN, backend.Subset) - if err := resolveServiceEndpoints(tctx, r.Client, serviceNN, r.supportsEndpointSlice, subsetLabels); err != nil { + if err := resolveServiceEndpoints(tctx, r.Client, serviceNN, r.SupportsEndpointSlice, subsetLabels); err != nil { return types.ReasonError{ Reason: string(apiv2.ConditionReasonInvalidSpec), Message: err.Error(), diff --git a/internal/controller/apisixtls_controller.go b/internal/controller/apisixtls_controller.go index d854fdde..71f28c54 100644 --- a/internal/controller/apisixtls_controller.go +++ b/internal/controller/apisixtls_controller.go @@ -56,6 +56,7 @@ type ApisixTlsReconciler struct { Readier readiness.ReadinessManager ICGV schema.GroupVersion + SupportsEndpointSlice bool // cache capability } // SetupWithManager sets up the controller with the Manager. @@ -135,7 +136,7 @@ func (r *ApisixTlsReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( } // process IngressClass parameters if they reference GatewayProxy - if err := ProcessIngressClassParameters(tctx, r.Client, r.Log, &tls, ingressClass); err != nil { + if err := ProcessIngressClassParameters(tctx, r.Client, r.Log, &tls, ingressClass, r.SupportsEndpointSlice); err != nil { r.Log.Error(err, "failed to process IngressClass parameters", "ingressClass", ingressClass.Name) r.updateStatus(&tls, metav1.Condition{ Type: string(apiv2.ConditionTypeAccepted), diff --git a/internal/controller/consumer_controller.go b/internal/controller/consumer_controller.go index 6ebe8c96..692bee3d 100644 --- a/internal/controller/consumer_controller.go +++ b/internal/controller/consumer_controller.go @@ -56,6 +56,7 @@ type ConsumerReconciler struct { //nolint:revive Updater status.Updater Readier readiness.ReadinessManager + SupportsEndpointSlice bool // cache capability } // SetupWithManager sets up the controller with the Manager. @@ -219,7 +220,7 @@ func (r *ConsumerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c rk := utils.NamespacedNameKind(consumer) - if err := ProcessGatewayProxy(r.Client, r.Log, tctx, gateway, rk); err != nil { + if err := ProcessGatewayProxy(r.Client, r.Log, tctx, gateway, rk, r.SupportsEndpointSlice); err != nil { r.Log.Error(err, "failed to process gateway proxy", "gateway", gateway) statusErr = err } diff --git a/internal/controller/gateway_controller.go b/internal/controller/gateway_controller.go index 76648a4a..be890e45 100644 --- a/internal/controller/gateway_controller.go +++ b/internal/controller/gateway_controller.go @@ -54,6 +54,8 @@ type GatewayReconciler struct { //nolint:revive Provider provider.Provider Updater status.Updater + + SupportsEndpointSlice bool //cache capability } // SetupWithManager sets up the controller with the Manager. @@ -412,7 +414,7 @@ func (r *GatewayReconciler) listReferenceGrantsForGateway(ctx context.Context, o } func (r *GatewayReconciler) processInfrastructure(tctx *provider.TranslateContext, gateway *gatewayv1.Gateway) error { - return ProcessGatewayProxy(r.Client, r.Log, tctx, gateway, utils.NamespacedNameKind(gateway)) + return ProcessGatewayProxy(r.Client, r.Log, tctx, gateway, utils.NamespacedNameKind(gateway), r.SupportsEndpointSlice) } func (r *GatewayReconciler) processListenerConfig(tctx *provider.TranslateContext, gateway *gatewayv1.Gateway) { diff --git a/internal/controller/gatewayproxy_controller.go b/internal/controller/gatewayproxy_controller.go index 5ab1d877..5a7a925e 100644 --- a/internal/controller/gatewayproxy_controller.go +++ b/internal/controller/gatewayproxy_controller.go @@ -54,14 +54,14 @@ type GatewayProxyController struct { Provider provider.Provider ICGV schema.GroupVersion - // supportsEndpointSlice indicates whether the cluster supports EndpointSlice API - supportsEndpointSlice bool + // SupportsEndpointSlice indicates whether the cluster supports EndpointSlice API + SupportsEndpointSlice bool supportsGateway bool } func (r *GatewayProxyController) SetupWithManager(mrg ctrl.Manager) error { // Check and store EndpointSlice API support - r.supportsEndpointSlice = pkgutils.HasAPIResource(mrg, &discoveryv1.EndpointSlice{}) + r.SupportsEndpointSlice = pkgutils.HasAPIResource(mrg, &discoveryv1.EndpointSlice{}) r.supportsGateway = pkgutils.HasAPIResource(mrg, &gatewayv1.Gateway{}) && !config.ControllerConfig.DisableGatewayAPI var icWatch client.Object switch r.ICGV.String() { @@ -76,7 +76,7 @@ func (r *GatewayProxyController) SetupWithManager(mrg ctrl.Manager) error { predicate.NewPredicateFuncs(TypePredicate[*corev1.Secret]()), } - if !r.supportsEndpointSlice { + if !r.SupportsEndpointSlice { eventFilters = append(eventFilters, predicate.NewPredicateFuncs(TypePredicate[*corev1.Endpoints]())) } @@ -95,7 +95,7 @@ func (r *GatewayProxyController) SetupWithManager(mrg ctrl.Manager) error { ) // Conditionally watch EndpointSlice or Endpoints based on cluster API support - bdr = watchEndpointSliceOrEndpoints(bdr, r.supportsEndpointSlice, + bdr = watchEndpointSliceOrEndpoints(bdr, r.SupportsEndpointSlice, r.listGatewayProxiesForProviderEndpointSlice, r.listGatewayProxiesForProviderEndpoints, r.Log) @@ -145,7 +145,7 @@ func (r *GatewayProxyController) Reconcile(ctx context.Context, req ctrl.Request return reconcile.Result{}, err } tctx.Services[serviceNN] = service - if err := resolveServiceEndpoints(tctx, r.Client, serviceNN, r.supportsEndpointSlice, nil); err != nil { + if err := resolveServiceEndpoints(tctx, r.Client, serviceNN, r.SupportsEndpointSlice, nil); err != nil { return reconcile.Result{}, err } } diff --git a/internal/controller/grpcroute_controller.go b/internal/controller/grpcroute_controller.go index 3b423417..79e6c6d3 100644 --- a/internal/controller/grpcroute_controller.go +++ b/internal/controller/grpcroute_controller.go @@ -61,6 +61,8 @@ type GRPCRouteReconciler struct { //nolint:revive Updater status.Updater Readier readiness.ReadinessManager + + SupportsEndpointSlice bool // cache capability } // SetupWithManager sets up the controller with the Manager. @@ -196,7 +198,7 @@ func (r *GRPCRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( tctx.RouteParentRefs = gr.Spec.ParentRefs rk := utils.NamespacedNameKind(gr) for _, gateway := range gateways { - if err := ProcessGatewayProxy(r.Client, r.Log, tctx, gateway.Gateway, rk); err != nil { + if err := ProcessGatewayProxy(r.Client, r.Log, tctx, gateway.Gateway, rk, r.SupportsEndpointSlice); err != nil { acceptStatus.status = false acceptStatus.msg = err.Error() } diff --git a/internal/controller/httproute_controller.go b/internal/controller/httproute_controller.go index fdb5ec43..481d987f 100644 --- a/internal/controller/httproute_controller.go +++ b/internal/controller/httproute_controller.go @@ -67,8 +67,8 @@ type HTTPRouteReconciler struct { //nolint:revive Updater status.Updater Readier readiness.ReadinessManager - // supportsEndpointSlice indicates whether the cluster supports EndpointSlice API - supportsEndpointSlice bool + // SupportsEndpointSlice indicates whether the cluster supports EndpointSlice API + SupportsEndpointSlice bool } // SetupWithManager sets up the controller with the Manager. @@ -76,13 +76,13 @@ func (r *HTTPRouteReconciler) SetupWithManager(mgr ctrl.Manager) error { r.genericEvent = make(chan event.GenericEvent, 100) // Check and store EndpointSlice API support - r.supportsEndpointSlice = pkgutils.HasAPIResource(mgr, &discoveryv1.EndpointSlice{}) + r.SupportsEndpointSlice = pkgutils.HasAPIResource(mgr, &discoveryv1.EndpointSlice{}) eventFilters := []predicate.Predicate{ predicate.GenerationChangedPredicate{}, } - if !r.supportsEndpointSlice { + if !r.SupportsEndpointSlice { eventFilters = append(eventFilters, predicate.NewPredicateFuncs(TypePredicate[*corev1.Endpoints]())) } @@ -91,7 +91,7 @@ func (r *HTTPRouteReconciler) SetupWithManager(mgr ctrl.Manager) error { WithEventFilter(predicate.Or(eventFilters...)) // Conditionally watch EndpointSlice or Endpoints based on cluster API support - bdr = watchEndpointSliceOrEndpoints(bdr, r.supportsEndpointSlice, + bdr = watchEndpointSliceOrEndpoints(bdr, r.SupportsEndpointSlice, r.listHTTPRoutesByServiceRef, r.listHTTPRoutesByServiceForEndpoints, r.Log) @@ -199,7 +199,7 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( tctx.RouteParentRefs = hr.Spec.ParentRefs rk := utils.NamespacedNameKind(hr) for _, gateway := range gateways { - if err := ProcessGatewayProxy(r.Client, r.Log, tctx, gateway.Gateway, rk); err != nil { + if err := ProcessGatewayProxy(r.Client, r.Log, tctx, gateway.Gateway, rk, r.SupportsEndpointSlice); err != nil { acceptStatus.status = false acceptStatus.msg = err.Error() } @@ -576,7 +576,7 @@ func (r *HTTPRouteReconciler) processHTTPRouteBackendRefs(tctx *provider.Transla tctx.Services[targetNN] = &service // Collect endpoints with EndpointSlice support - if err := resolveServiceEndpoints(tctx, r.Client, targetNN, r.supportsEndpointSlice, nil); err != nil { + if err := resolveServiceEndpoints(tctx, r.Client, targetNN, r.SupportsEndpointSlice, nil); err != nil { r.Log.Error(err, "failed to collect endpoints", "Service", targetNN) terr = err continue diff --git a/internal/controller/ingress_controller.go b/internal/controller/ingress_controller.go index 8b1b8818..fdcdc82c 100644 --- a/internal/controller/ingress_controller.go +++ b/internal/controller/ingress_controller.go @@ -64,8 +64,8 @@ type IngressReconciler struct { //nolint:revive Updater status.Updater Readier readiness.ReadinessManager - // supportsEndpointSlice indicates whether the cluster supports EndpointSlice API - supportsEndpointSlice bool + // SupportsEndpointSlice indicates whether the cluster supports EndpointSlice API + SupportsEndpointSlice bool } // SetupWithManager sets up the controller with the Manager. @@ -73,7 +73,7 @@ func (r *IngressReconciler) SetupWithManager(mgr ctrl.Manager) error { r.genericEvent = make(chan event.GenericEvent, 100) // Check and store EndpointSlice API support - r.supportsEndpointSlice = pkgutils.HasAPIResource(mgr, &discoveryv1.EndpointSlice{}) + r.SupportsEndpointSlice = pkgutils.HasAPIResource(mgr, &discoveryv1.EndpointSlice{}) eventFilters := []predicate.Predicate{ predicate.GenerationChangedPredicate{}, @@ -81,7 +81,7 @@ func (r *IngressReconciler) SetupWithManager(mgr ctrl.Manager) error { predicate.NewPredicateFuncs(TypePredicate[*corev1.Secret]()), } - if !r.supportsEndpointSlice { + if !r.SupportsEndpointSlice { eventFilters = append(eventFilters, predicate.NewPredicateFuncs(TypePredicate[*corev1.Endpoints]())) } @@ -101,7 +101,7 @@ func (r *IngressReconciler) SetupWithManager(mgr ctrl.Manager) error { ) // Conditionally watch EndpointSlice or Endpoints based on cluster API support - bdr = watchEndpointSliceOrEndpoints(bdr, r.supportsEndpointSlice, + bdr = watchEndpointSliceOrEndpoints(bdr, r.SupportsEndpointSlice, r.listIngressesByService, r.listIngressesByEndpoints, r.Log) @@ -186,7 +186,7 @@ func (r *IngressReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct }) // process IngressClass parameters if they reference GatewayProxy - if err := ProcessIngressClassParameters(tctx, r.Client, r.Log, ingress, ingressClass); err != nil { + if err := ProcessIngressClassParameters(tctx, r.Client, r.Log, ingress, ingressClass, r.SupportsEndpointSlice); err != nil { r.Log.Error(err, "failed to process IngressClass parameters", "ingressClass", ingressClass.Name) return ctrl.Result{}, err } @@ -640,7 +640,7 @@ func (r *IngressReconciler) processBackendService(tctx *provider.TranslateContex } // Collect endpoints with EndpointSlice support - if err := resolveServiceEndpoints(tctx, r.Client, serviceNS, r.supportsEndpointSlice, nil); err != nil { + if err := resolveServiceEndpoints(tctx, r.Client, serviceNS, r.SupportsEndpointSlice, nil); err != nil { r.Log.Error(err, "failed to collect endpoints", "namespace", namespace, "name", backendService.Name) return err } diff --git a/internal/controller/ingressclass_controller.go b/internal/controller/ingressclass_controller.go index b0cea10e..45ac4267 100644 --- a/internal/controller/ingressclass_controller.go +++ b/internal/controller/ingressclass_controller.go @@ -45,6 +45,7 @@ type IngressClassReconciler struct { Log logr.Logger Provider provider.Provider + SupportsEndpointSlice bool // cache capability } // SetupWithManager sets up the controller with the Manager. @@ -96,7 +97,7 @@ func (r *IngressClassReconciler) Reconcile(ctx context.Context, req ctrl.Request // Create a translate context tctx := provider.NewDefaultTranslateContext(ctx) - if err := ProcessIngressClassParameters(tctx, r.Client, r.Log, ingressClass, ingressClass); err != nil { + if err := ProcessIngressClassParameters(tctx, r.Client, r.Log, ingressClass, ingressClass, r.SupportsEndpointSlice); err != nil { r.Log.Error(err, "failed to process infrastructure for ingressclass", "ingressclass", ingressClass.GetName()) return ctrl.Result{}, client.IgnoreNotFound(err) } diff --git a/internal/controller/ingressclass_v1beta1_controller.go b/internal/controller/ingressclass_v1beta1_controller.go index a55c1f9b..67a7e1fe 100644 --- a/internal/controller/ingressclass_v1beta1_controller.go +++ b/internal/controller/ingressclass_v1beta1_controller.go @@ -47,6 +47,7 @@ type IngressClassV1beta1Reconciler struct { Log logr.Logger Provider provider.Provider + SupportsEndpointSlice bool // cache capability } // SetupWithManager sets up the controller with the Manager. @@ -239,7 +240,7 @@ func (r *IngressClassV1beta1Reconciler) processInfrastructure(tctx *provider.Tra if err := addProviderEndpointsToTranslateContext(tctx, r.Client, r.Log, types.NamespacedName{ Namespace: gatewayProxy.GetNamespace(), Name: service.Name, - }); err != nil { + }, r.SupportsEndpointSlice); err != nil { return err } } diff --git a/internal/controller/tcproute_controller.go b/internal/controller/tcproute_controller.go index 125a14a9..914fd738 100644 --- a/internal/controller/tcproute_controller.go +++ b/internal/controller/tcproute_controller.go @@ -58,6 +58,8 @@ type TCPRouteReconciler struct { //nolint:revive Updater status.Updater Readier readiness.ReadinessManager + + SupportsEndpointSlice bool //cache capability } // SetupWithManager sets up the controller with the Manager. @@ -269,7 +271,7 @@ func (r *TCPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c tctx.RouteParentRefs = tr.Spec.ParentRefs rk := utils.NamespacedNameKind(tr) for _, gateway := range gateways { - if err := ProcessGatewayProxy(r.Client, r.Log, tctx, gateway.Gateway, rk); err != nil { + if err := ProcessGatewayProxy(r.Client, r.Log, tctx, gateway.Gateway, rk, r.SupportsEndpointSlice); err != nil { acceptStatus.status = false acceptStatus.msg = err.Error() } diff --git a/internal/controller/tlsroute_controller.go b/internal/controller/tlsroute_controller.go index f5f97721..7902acf8 100644 --- a/internal/controller/tlsroute_controller.go +++ b/internal/controller/tlsroute_controller.go @@ -58,6 +58,9 @@ type TLSRouteReconciler struct { //nolint:revive Updater status.Updater Readier readiness.ReadinessManager + + + SupportsEndpointSlice bool } // SetupWithManager sets up the controller with the Manager. @@ -269,7 +272,7 @@ func (r *TLSRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c tctx.RouteParentRefs = tr.Spec.ParentRefs rk := utils.NamespacedNameKind(tr) for _, gateway := range gateways { - if err := ProcessGatewayProxy(r.Client, r.Log, tctx, gateway.Gateway, rk); err != nil { + if err := ProcessGatewayProxy(r.Client, r.Log, tctx, gateway.Gateway, rk, r.SupportsEndpointSlice); err != nil { acceptStatus.status = false acceptStatus.msg = err.Error() } diff --git a/internal/controller/udproute_controller.go b/internal/controller/udproute_controller.go index 2a4a7a4a..048971f9 100644 --- a/internal/controller/udproute_controller.go +++ b/internal/controller/udproute_controller.go @@ -58,6 +58,8 @@ type UDPRouteReconciler struct { //nolint:revive Updater status.Updater Readier readiness.ReadinessManager + + SupportsEndpointSlice bool // cache capability } // SetupWithManager sets up the controller with the Manager. @@ -269,7 +271,7 @@ func (r *UDPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c tctx.RouteParentRefs = tr.Spec.ParentRefs rk := utils.NamespacedNameKind(tr) for _, gateway := range gateways { - if err := ProcessGatewayProxy(r.Client, r.Log, tctx, gateway.Gateway, rk); err != nil { + if err := ProcessGatewayProxy(r.Client, r.Log, tctx, gateway.Gateway, rk, r.SupportsEndpointSlice); err != nil { acceptStatus.status = false acceptStatus.msg = err.Error() } diff --git a/internal/controller/utils.go b/internal/controller/utils.go index 3803d531..9b7e8871 100644 --- a/internal/controller/utils.go +++ b/internal/controller/utils.go @@ -39,6 +39,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" k8stypes "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/discovery" + "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" @@ -935,7 +937,7 @@ func SplitMetaNamespaceKey(key string) (namespace, name string, err error) { return "", "", fmt.Errorf("unexpected key format: %q", key) } -func ProcessGatewayProxy(r client.Client, log logr.Logger, tctx *provider.TranslateContext, gateway *gatewayv1.Gateway, rk types.NamespacedNameKind) error { +func ProcessGatewayProxy(r client.Client, log logr.Logger, tctx *provider.TranslateContext, gateway *gatewayv1.Gateway, rk types.NamespacedNameKind, supportsEndpointSlice bool) error { if gateway == nil { return nil } @@ -993,7 +995,7 @@ func ProcessGatewayProxy(r client.Client, log logr.Logger, tctx *provider.Transl if err := addProviderEndpointsToTranslateContext(tctx, r, log, k8stypes.NamespacedName{ Namespace: gatewayProxy.GetNamespace(), Name: cp.Service.Name, - }); err != nil { + }, supportsEndpointSlice); err != nil { return err } } @@ -1327,7 +1329,7 @@ func matchesIngressController(obj client.Object) bool { return matchesController(ingressClass.Spec.Controller) } -func ProcessIngressClassParameters(tctx *provider.TranslateContext, c client.Client, log logr.Logger, object client.Object, ingressClass *networkingv1.IngressClass) error { +func ProcessIngressClassParameters(tctx *provider.TranslateContext, c client.Client, log logr.Logger, object client.Object, ingressClass *networkingv1.IngressClass, supportsEndpointSlice bool) error { if ingressClass == nil || ingressClass.Spec.Parameters == nil { return nil } @@ -1390,7 +1392,7 @@ func ProcessIngressClassParameters(tctx *provider.TranslateContext, c client.Cli if err := addProviderEndpointsToTranslateContext(tctx, c, log, client.ObjectKey{ Namespace: gatewayProxy.GetNamespace(), Name: cp.Service.Name, - }); err != nil { + }, supportsEndpointSlice); err != nil { return err } } @@ -1510,7 +1512,32 @@ func distinctRequests(requests []reconcile.Request) []reconcile.Request { return distinctRequests } -func addProviderEndpointsToTranslateContext(tctx *provider.TranslateContext, c client.Client, log logr.Logger, serviceNN k8stypes.NamespacedName) error { +// CheckEndpointSliceSupport checks if the cluster supports EndpointSlice API (K8s 1.19+) +func CheckEndpointSliceSupport(config *rest.Config) bool { + discoveryClient, err := discovery.NewDiscoveryClientForConfig(config) + if err != nil { + // Log warning and default to true (assume newer K8s) + return true + } + + // Check if discovery.k8s.io/v1 API group is available + resourceList, err := discoveryClient.ServerResourcesForGroupVersion("discovery.k8s.io/v1") + if err != nil { + // EndpointSlice API not available, fall back to Endpoints + return false + } + + // Check if endpointslices resource exists + for _, resource := range resourceList.APIResources { + if resource.Name == "endpointslices" { + return true + } + } + + return false +} + +func addProviderEndpointsToTranslateContext(tctx *provider.TranslateContext, c client.Client, log logr.Logger, serviceNN k8stypes.NamespacedName, supportsEndpointSlice bool,) error { log.V(1).Info("to process provider endpoints by provider.service", "service", serviceNN) var ( service corev1.Service @@ -1521,7 +1548,7 @@ func addProviderEndpointsToTranslateContext(tctx *provider.TranslateContext, c c } tctx.Services[serviceNN] = &service - return resolveServiceEndpoints(tctx, c, serviceNN, true, nil) + return resolveServiceEndpoints(tctx, c, serviceNN, supportsEndpointSlice, nil) } func TypePredicate[T client.Object]() func(obj client.Object) bool { diff --git a/internal/manager/controllers.go b/internal/manager/controllers.go index f8251e1d..ad1001af 100644 --- a/internal/manager/controllers.go +++ b/internal/manager/controllers.go @@ -113,6 +113,15 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro } setupLog := ctrl.LoggerFrom(ctx).WithName("setup") + + supportsEndpointSlice := controller.CheckEndpointSliceSupport(mgr.GetConfig()) + setupLog.Info("Kubernetes API detection", + "supportsEndpointSlice", supportsEndpointSlice, + "apiVersion", map[bool]string{ + true: "discovery.k8s.io/v1 (EndpointSlice)", + false: "v1/endpoints", + }[supportsEndpointSlice]) + var controllers []Controller icgv := netv1.SchemeGroupVersion @@ -124,6 +133,7 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Scheme: mgr.GetScheme(), Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindIngressClass), Provider: pro, + SupportsEndpointSlice: supportsEndpointSlice, }) } @@ -142,6 +152,7 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindGateway), Provider: pro, Updater: updater, + SupportsEndpointSlice: supportsEndpointSlice, }, &gatewayv1.HTTPRoute{}: &controller.HTTPRouteReconciler{ Client: mgr.GetClient(), @@ -150,6 +161,7 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Provider: pro, Updater: updater, Readier: readier, + SupportsEndpointSlice: supportsEndpointSlice, }, &gatewayv1alpha2.TCPRoute{}: &controller.TCPRouteReconciler{ Client: mgr.GetClient(), @@ -158,6 +170,7 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Provider: pro, Updater: updater, Readier: readier, + SupportsEndpointSlice: supportsEndpointSlice, }, &gatewayv1alpha2.UDPRoute{}: &controller.UDPRouteReconciler{ Client: mgr.GetClient(), @@ -166,6 +179,7 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Provider: pro, Updater: updater, Readier: readier, + SupportsEndpointSlice: supportsEndpointSlice, }, &gatewayv1.GRPCRoute{}: &controller.GRPCRouteReconciler{ Client: mgr.GetClient(), @@ -174,6 +188,7 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Provider: pro, Updater: updater, Readier: readier, + SupportsEndpointSlice: supportsEndpointSlice, }, &gatewayv1alpha2.TLSRoute{}: &controller.TLSRouteReconciler{ Client: mgr.GetClient(), @@ -182,6 +197,7 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Provider: pro, Updater: updater, Readier: readier, + SupportsEndpointSlice: supportsEndpointSlice, }, &v1alpha1.Consumer{}: &controller.ConsumerReconciler{ Client: mgr.GetClient(), @@ -190,6 +206,7 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Provider: pro, Updater: updater, Readier: readier, + SupportsEndpointSlice: supportsEndpointSlice, }, } { if utils.HasAPIResource(mgr, resource) { @@ -210,12 +227,14 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Provider: pro, Updater: updater, Readier: readier, + SupportsEndpointSlice: supportsEndpointSlice, }, &netv1.IngressClass{}: &controller.IngressClassReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindIngressClass), Provider: pro, + SupportsEndpointSlice: supportsEndpointSlice, }, } { if utils.HasAPIResource(mgr, resource) { @@ -233,6 +252,7 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName(types.KindGatewayProxy), Provider: pro, ICGV: icgv, + SupportsEndpointSlice: supportsEndpointSlice, }, &controller.ApisixRouteReconciler{ Client: mgr.GetClient(), @@ -242,6 +262,7 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Updater: updater, Readier: readier, ICGV: icgv, + SupportsEndpointSlice: supportsEndpointSlice, }, &controller.ApisixGlobalRuleReconciler{ Client: mgr.GetClient(), @@ -251,6 +272,7 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Updater: updater, Readier: readier, ICGV: icgv, + SupportsEndpointSlice: supportsEndpointSlice, }, &controller.ApisixConsumerReconciler{ Client: mgr.GetClient(), @@ -260,6 +282,7 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Updater: updater, Readier: readier, ICGV: icgv, + SupportsEndpointSlice: supportsEndpointSlice, }, &controller.ApisixPluginConfigReconciler{ Client: mgr.GetClient(), @@ -276,6 +299,7 @@ func setupControllers(ctx context.Context, mgr manager.Manager, pro provider.Pro Updater: updater, Readier: readier, ICGV: icgv, + SupportsEndpointSlice: supportsEndpointSlice, }, &controller.ApisixUpstreamReconciler{ Client: mgr.GetClient(),