From 9f0bc2025b6ce6e1d51e64e641e81c9e706e3f53 Mon Sep 17 00:00:00 2001 From: kai Date: Thu, 27 Nov 2025 20:01:16 +0800 Subject: [PATCH 1/3] Controllers are now K8s version aware. --- .../controller/apisixconsumer_controller.go | 3 +- .../controller/apisixglobalrule_controller.go | 4 +- internal/controller/apisixroute_controller.go | 14 +++--- internal/controller/apisixtls_controller.go | 3 +- internal/controller/consumer_controller.go | 3 +- internal/controller/gateway_controller.go | 4 +- .../controller/gatewayproxy_controller.go | 12 ++--- internal/controller/grpcroute_controller.go | 4 +- internal/controller/httproute_controller.go | 14 +++--- internal/controller/ingress_controller.go | 14 +++--- .../controller/ingressclass_controller.go | 3 +- .../ingressclass_v1beta1_controller.go | 7 ++- internal/controller/tcproute_controller.go | 4 +- internal/controller/tlsroute_controller.go | 5 +- internal/controller/udproute_controller.go | 4 +- internal/controller/utils.go | 48 ++++++++++++++++--- internal/manager/controllers.go | 24 ++++++++++ 17 files changed, 126 insertions(+), 44 deletions(-) diff --git a/internal/controller/apisixconsumer_controller.go b/internal/controller/apisixconsumer_controller.go index 35c580aaf..66d005f45 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 fabc60c23..e0ea4bd95 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 dbb7c76a2..250527acb 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 d854fddec..71f28c540 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 6ebe8c965..692bee3d7 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 76648a4a2..be890e452 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 5ab1d877e..5a7a925e8 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 3b4234171..79e6c6d35 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 fdb5ec432..481d987f4 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 8b1b88184..fdcdc82c3 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 b0cea10e9..45ac4267c 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 a55c1f9b9..ffa378eea 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. @@ -76,6 +77,7 @@ func (r *IngressClassV1beta1Reconciler) SetupWithManager(mgr ctrl.Manager) error Complete(r) } +// TODO: functions calls processInfrastructure func (r *IngressClassV1beta1Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { IngressClassV1beta1 := new(v1beta1.IngressClass) if err := r.Get(ctx, req.NamespacedName, IngressClassV1beta1); err != nil { @@ -176,6 +178,7 @@ func (r *IngressClassV1beta1Reconciler) listIngressClassV1beta1esForSecret(ctx c return distinctRequests(requests) } +// TODO : problem here func (r *IngressClassV1beta1Reconciler) processInfrastructure(tctx *provider.TranslateContext, IngressClassV1beta1 *v1beta1.IngressClass) error { if IngressClassV1beta1.Spec.Parameters == nil { return nil @@ -235,11 +238,13 @@ func (r *IngressClassV1beta1Reconciler) processInfrastructure(tctx *provider.Tra } } + // TODO : Problem starts here, rn error is just returned by + // addProviderEndpointsToTranslateContext(), which calls resolveServiceEndpoints, which defaults EndpointsSlice to true if service := gatewayProxy.Spec.Provider.ControlPlane.Service; service != nil { 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 125a14a90..914fd7384 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 f5f97721b..7902acf89 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 2a4a7a4a2..048971f98 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 3803d531e..0408ac32d 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,37 @@ 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 +} + +// TODO : Problem 1.2, here in the return call EndpointsSlice is set to true +// only called by ingressclass_v1beta1_controller.go so not coupled +// i am quite unsure about touching this since it in the util class, +// either add a paramerter EndpointSlice, which defaults to True, or just change it to +// purely support K8s +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 +1553,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 { @@ -1577,6 +1609,10 @@ func watchEndpointSliceOrEndpoints(bdr *ctrl.Builder, supportsEndpointSlice bool // resolveServiceEndpoints collects endpoints and adds them to the translate context // It handles both EndpointSlice (K8s 1.19+) and Endpoints (K8s 1.18) APIs with automatic fallback +// TODO : I think here is where there is relevance to EndpointSlice +// RN EndpointSlice is set as True by default but it is not supported by Endpoints (K8s, 1.18) +// the problem is that this function is called by multiple files (apisixroute, gateway_proxy, httproute_controller, ingress_controller) +// optimally we dont fix this and we assume this to be right func resolveServiceEndpoints( tctx *provider.TranslateContext, c client.Client, diff --git a/internal/manager/controllers.go b/internal/manager/controllers.go index f8251e1d6..ad1001af1 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(), From 5cb6bd50908890e1b15954e890d369ee1143eb2a Mon Sep 17 00:00:00 2001 From: kai Date: Sun, 30 Nov 2025 23:30:42 +0800 Subject: [PATCH 2/3] removed comments --- internal/controller/ingressclass_v1beta1_controller.go | 4 ---- internal/controller/utils.go | 5 ----- 2 files changed, 9 deletions(-) diff --git a/internal/controller/ingressclass_v1beta1_controller.go b/internal/controller/ingressclass_v1beta1_controller.go index ffa378eea..67a7e1fe4 100644 --- a/internal/controller/ingressclass_v1beta1_controller.go +++ b/internal/controller/ingressclass_v1beta1_controller.go @@ -77,7 +77,6 @@ func (r *IngressClassV1beta1Reconciler) SetupWithManager(mgr ctrl.Manager) error Complete(r) } -// TODO: functions calls processInfrastructure func (r *IngressClassV1beta1Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { IngressClassV1beta1 := new(v1beta1.IngressClass) if err := r.Get(ctx, req.NamespacedName, IngressClassV1beta1); err != nil { @@ -178,7 +177,6 @@ func (r *IngressClassV1beta1Reconciler) listIngressClassV1beta1esForSecret(ctx c return distinctRequests(requests) } -// TODO : problem here func (r *IngressClassV1beta1Reconciler) processInfrastructure(tctx *provider.TranslateContext, IngressClassV1beta1 *v1beta1.IngressClass) error { if IngressClassV1beta1.Spec.Parameters == nil { return nil @@ -238,8 +236,6 @@ func (r *IngressClassV1beta1Reconciler) processInfrastructure(tctx *provider.Tra } } - // TODO : Problem starts here, rn error is just returned by - // addProviderEndpointsToTranslateContext(), which calls resolveServiceEndpoints, which defaults EndpointsSlice to true if service := gatewayProxy.Spec.Provider.ControlPlane.Service; service != nil { if err := addProviderEndpointsToTranslateContext(tctx, r.Client, r.Log, types.NamespacedName{ Namespace: gatewayProxy.GetNamespace(), diff --git a/internal/controller/utils.go b/internal/controller/utils.go index 0408ac32d..562fcbbf1 100644 --- a/internal/controller/utils.go +++ b/internal/controller/utils.go @@ -1537,11 +1537,6 @@ func CheckEndpointSliceSupport(config *rest.Config) bool { return false } -// TODO : Problem 1.2, here in the return call EndpointsSlice is set to true -// only called by ingressclass_v1beta1_controller.go so not coupled -// i am quite unsure about touching this since it in the util class, -// either add a paramerter EndpointSlice, which defaults to True, or just change it to -// purely support K8s 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 ( From 6343c494fcfeb6ecbe8356f4979ecc3397b637ba Mon Sep 17 00:00:00 2001 From: kai Date: Sun, 30 Nov 2025 23:31:19 +0800 Subject: [PATCH 3/3] Removing more thought comments --- internal/controller/utils.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/internal/controller/utils.go b/internal/controller/utils.go index 562fcbbf1..9b7e88711 100644 --- a/internal/controller/utils.go +++ b/internal/controller/utils.go @@ -1604,10 +1604,6 @@ func watchEndpointSliceOrEndpoints(bdr *ctrl.Builder, supportsEndpointSlice bool // resolveServiceEndpoints collects endpoints and adds them to the translate context // It handles both EndpointSlice (K8s 1.19+) and Endpoints (K8s 1.18) APIs with automatic fallback -// TODO : I think here is where there is relevance to EndpointSlice -// RN EndpointSlice is set as True by default but it is not supported by Endpoints (K8s, 1.18) -// the problem is that this function is called by multiple files (apisixroute, gateway_proxy, httproute_controller, ingress_controller) -// optimally we dont fix this and we assume this to be right func resolveServiceEndpoints( tctx *provider.TranslateContext, c client.Client,