This is an automated email from the ASF dual-hosted git repository.

alinsran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git


The following commit(s) were added to refs/heads/master by this push:
     new 0a7b0402 fix: residual data issue when updating ingressClassName 
(#2543)
0a7b0402 is described below

commit 0a7b0402528091e7435674a2ef42e2742e2a297e
Author: AlinsRan <[email protected]>
AuthorDate: Mon Sep 8 12:26:19 2025 +0800

    fix: residual data issue when updating ingressClassName (#2543)
---
 internal/controller/apisixconsumer_controller.go   | 13 +---
 internal/controller/apisixglobalrule_controller.go | 51 ++-------------
 .../controller/apisixpluginconfig_controller.go    |  2 +-
 internal/controller/apisixroute_controller.go      | 12 +++-
 internal/controller/apisixtls_controller.go        | 46 +-------------
 internal/controller/apisixupstream_controller.go   |  2 +-
 internal/controller/httproutepolicy.go             |  2 +-
 internal/controller/ingress_controller.go          | 31 +++------
 internal/controller/utils.go                       | 74 +++++++++++++---------
 internal/manager/controllers.go                    |  3 +-
 internal/types/k8s.go                              |  7 ++
 test/e2e/crds/v2/route.go                          | 55 ++++++++++++++++
 test/e2e/framework/ingress.go                      |  2 +-
 test/e2e/framework/manifests/ingress.yaml          |  9 +++
 test/e2e/ingress/ingress.go                        | 56 ++++++++++++++++
 test/e2e/scaffold/apisix_deployer.go               |  4 +-
 16 files changed, 207 insertions(+), 162 deletions(-)

diff --git a/internal/controller/apisixconsumer_controller.go 
b/internal/controller/apisixconsumer_controller.go
index 6f591ca5..2cb473ca 100644
--- a/internal/controller/apisixconsumer_controller.go
+++ b/internal/controller/apisixconsumer_controller.go
@@ -83,7 +83,7 @@ func (r *ApisixConsumerReconciler) Reconcile(ctx 
context.Context, req ctrl.Reque
                ingressClass *networkingv1.IngressClass
                err          error
        )
-       if ingressClass, err = GetIngressClass(tctx, r.Client, r.Log, 
ac.Spec.IngressClassName); err != nil {
+       if ingressClass, err = FindMatchingIngressClass(tctx, r.Client, r.Log, 
ac); err != nil {
                r.Log.V(1).Info("no matching IngressClass available",
                        "ingressClassName", ac.Spec.IngressClassName,
                        "error", err.Error())
@@ -113,7 +113,7 @@ func (r *ApisixConsumerReconciler) SetupWithManager(mgr 
ctrl.Manager) error {
        return ctrl.NewControllerManagedBy(mgr).
                For(&apiv2.ApisixConsumer{},
                        builder.WithPredicates(
-                               
predicate.NewPredicateFuncs(r.checkIngressClass),
+                               MatchesIngressClassPredicate(r.Client, r.Log),
                        )).
                WithEventFilter(
                        predicate.Or(
@@ -139,15 +139,6 @@ func (r *ApisixConsumerReconciler) SetupWithManager(mgr 
ctrl.Manager) error {
                Complete(r)
 }
 
-func (r *ApisixConsumerReconciler) checkIngressClass(obj client.Object) bool {
-       ac, ok := obj.(*apiv2.ApisixConsumer)
-       if !ok {
-               return false
-       }
-
-       return matchesIngressClass(r.Client, r.Log, ac.Spec.IngressClassName)
-}
-
 func (r *ApisixConsumerReconciler) listApisixConsumerForGatewayProxy(ctx 
context.Context, obj client.Object) []reconcile.Request {
        return listIngressClassRequestsForGatewayProxy(ctx, r.Client, obj, 
r.Log, r.listApisixConsumerForIngressClass)
 }
diff --git a/internal/controller/apisixglobalrule_controller.go 
b/internal/controller/apisixglobalrule_controller.go
index cd14ee30..f99eab68 100644
--- a/internal/controller/apisixglobalrule_controller.go
+++ b/internal/controller/apisixglobalrule_controller.go
@@ -35,8 +35,6 @@ import (
 
        "github.com/apache/apisix-ingress-controller/api/v1alpha1"
        apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
-       "github.com/apache/apisix-ingress-controller/internal/controller/config"
-       
"github.com/apache/apisix-ingress-controller/internal/controller/indexer"
        "github.com/apache/apisix-ingress-controller/internal/controller/status"
        "github.com/apache/apisix-ingress-controller/internal/manager/readiness"
        "github.com/apache/apisix-ingress-controller/internal/provider"
@@ -84,11 +82,15 @@ func (r *ApisixGlobalRuleReconciler) Reconcile(ctx 
context.Context, req ctrl.Req
        tctx := provider.NewDefaultTranslateContext(ctx)
 
        // get the ingress class
-       ingressClass, err := GetIngressClass(tctx, r.Client, r.Log, 
globalRule.Spec.IngressClassName)
+       ingressClass, err := FindMatchingIngressClass(tctx, r.Client, r.Log, 
&globalRule)
        if err != nil {
                r.Log.V(1).Info("no matching IngressClass available",
                        "ingressClassName", globalRule.Spec.IngressClassName,
                        "error", err.Error())
+               if err := r.Provider.Delete(ctx, &globalRule); err != nil {
+                       r.Log.Error(err, "failed to delete global rule from 
provider")
+                       return ctrl.Result{}, err
+               }
                return ctrl.Result{}, nil
        }
 
@@ -131,7 +133,7 @@ func (r *ApisixGlobalRuleReconciler) SetupWithManager(mgr 
ctrl.Manager) error {
        return ctrl.NewControllerManagedBy(mgr).
                For(&apiv2.ApisixGlobalRule{},
                        builder.WithPredicates(
-                               
predicate.NewPredicateFuncs(r.checkIngressClass),
+                               MatchesIngressClassPredicate(r.Client, r.Log),
                        ),
                ).
                WithEventFilter(
@@ -154,47 +156,6 @@ func (r *ApisixGlobalRuleReconciler) SetupWithManager(mgr 
ctrl.Manager) error {
                Complete(r)
 }
 
-// checkIngressClass checks if the ApisixGlobalRule uses the ingress class 
that we control
-func (r *ApisixGlobalRuleReconciler) checkIngressClass(obj client.Object) bool 
{
-       globalRule, ok := obj.(*apiv2.ApisixGlobalRule)
-       if !ok {
-               return false
-       }
-
-       return r.matchesIngressClass(globalRule.Spec.IngressClassName)
-}
-
-// matchesIngressClass checks if the given ingress class name matches our 
controlled classes
-func (r *ApisixGlobalRuleReconciler) matchesIngressClass(ingressClassName 
string) bool {
-       if ingressClassName == "" {
-               // Check for default ingress class
-               ingressClassList := &networkingv1.IngressClassList{}
-               if err := r.List(context.Background(), ingressClassList, 
client.MatchingFields{
-                       indexer.IngressClass: config.GetControllerName(),
-               }); err != nil {
-                       r.Log.Error(err, "failed to list ingress classes")
-                       return false
-               }
-
-               // Find the ingress class that is marked as default
-               for _, ic := range ingressClassList.Items {
-                       if IsDefaultIngressClass(&ic) && 
matchesController(ic.Spec.Controller) {
-                               return true
-                       }
-               }
-               return false
-       }
-
-       // Check if the specified ingress class is controlled by us
-       var ingressClass networkingv1.IngressClass
-       if err := r.Get(context.Background(), client.ObjectKey{Name: 
ingressClassName}, &ingressClass); err != nil {
-               r.Log.Error(err, "failed to get ingress class", "ingressClass", 
ingressClassName)
-               return false
-       }
-
-       return matchesController(ingressClass.Spec.Controller)
-}
-
 // listGlobalRulesForIngressClass list all global rules that use a specific 
ingress class
 func (r *ApisixGlobalRuleReconciler) listGlobalRulesForIngressClass(ctx 
context.Context, obj client.Object) []reconcile.Request {
        ingressClass, ok := obj.(*networkingv1.IngressClass)
diff --git a/internal/controller/apisixpluginconfig_controller.go 
b/internal/controller/apisixpluginconfig_controller.go
index 7ac25d1b..8751d107 100644
--- a/internal/controller/apisixpluginconfig_controller.go
+++ b/internal/controller/apisixpluginconfig_controller.go
@@ -58,7 +58,7 @@ func (r *ApisixPluginConfigReconciler) Reconcile(ctx 
context.Context, req ctrl.R
 
        tctx := provider.NewDefaultTranslateContext(ctx)
 
-       _, err := GetIngressClass(tctx, r.Client, r.Log, 
pc.Spec.IngressClassName)
+       _, err := FindMatchingIngressClass(tctx, r.Client, r.Log, &pc)
        if err != nil {
                r.Log.V(1).Info("no matching IngressClass available",
                        "ingressClassName", pc.Spec.IngressClassName,
diff --git a/internal/controller/apisixroute_controller.go 
b/internal/controller/apisixroute_controller.go
index 4e9ff5cd..2616e595 100644
--- a/internal/controller/apisixroute_controller.go
+++ b/internal/controller/apisixroute_controller.go
@@ -64,7 +64,11 @@ type ApisixRouteReconciler struct {
 // SetupWithManager sets up the controller with the Manager.
 func (r *ApisixRouteReconciler) SetupWithManager(mgr ctrl.Manager) error {
        return ctrl.NewControllerManagedBy(mgr).
-               For(&apiv2.ApisixRoute{}).
+               For(&apiv2.ApisixRoute{},
+                       builder.WithPredicates(
+                               MatchesIngressClassPredicate(r.Client, r.Log),
+                       ),
+               ).
                WithEventFilter(
                        predicate.Or(
                                predicate.GenerationChangedPredicate{},
@@ -125,10 +129,14 @@ func (r *ApisixRouteReconciler) Reconcile(ctx 
context.Context, req ctrl.Request)
                err  error
        )
 
-       if ic, err = GetIngressClass(tctx, r.Client, r.Log, 
ar.Spec.IngressClassName); err != nil {
+       if ic, err = FindMatchingIngressClass(tctx, r.Client, r.Log, &ar); err 
!= nil {
                r.Log.V(1).Info("no matching IngressClass available",
                        "ingressClassName", ar.Spec.IngressClassName,
                        "error", err.Error())
+               if err := r.Provider.Delete(ctx, &ar); err != nil {
+                       r.Log.Error(err, "failed to delete apisixroute", 
"apisixroute", ar)
+                       return ctrl.Result{}, err
+               }
                return ctrl.Result{}, nil
        }
        defer func() { r.updateStatus(&ar, err) }()
diff --git a/internal/controller/apisixtls_controller.go 
b/internal/controller/apisixtls_controller.go
index eb4b8a66..4758f728 100644
--- a/internal/controller/apisixtls_controller.go
+++ b/internal/controller/apisixtls_controller.go
@@ -36,7 +36,6 @@ import (
 
        "github.com/apache/apisix-ingress-controller/api/v1alpha1"
        apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
-       "github.com/apache/apisix-ingress-controller/internal/controller/config"
        
"github.com/apache/apisix-ingress-controller/internal/controller/indexer"
        "github.com/apache/apisix-ingress-controller/internal/controller/status"
        "github.com/apache/apisix-ingress-controller/internal/manager/readiness"
@@ -59,7 +58,7 @@ func (r *ApisixTlsReconciler) SetupWithManager(mgr 
ctrl.Manager) error {
        return ctrl.NewControllerManagedBy(mgr).
                For(&apiv2.ApisixTls{},
                        builder.WithPredicates(
-                               
predicate.NewPredicateFuncs(r.checkIngressClass),
+                               MatchesIngressClassPredicate(r.Client, r.Log),
                        ),
                ).
                WithEventFilter(
@@ -115,7 +114,7 @@ func (r *ApisixTlsReconciler) Reconcile(ctx 
context.Context, req ctrl.Request) (
        tctx := provider.NewDefaultTranslateContext(ctx)
 
        // get the ingress class
-       ingressClass, err := GetIngressClass(tctx, r.Client, r.Log, 
tls.Spec.IngressClassName)
+       ingressClass, err := FindMatchingIngressClass(tctx, r.Client, r.Log, 
&tls)
        if err != nil {
                r.Log.V(1).Info("no matching IngressClass available, skip 
processing",
                        "ingressClassName", tls.Spec.IngressClassName,
@@ -227,47 +226,6 @@ func (r *ApisixTlsReconciler) updateStatus(tls 
*apiv2.ApisixTls, condition metav
        })
 }
 
-// checkIngressClass checks if the ApisixTls uses the ingress class that we 
control
-func (r *ApisixTlsReconciler) checkIngressClass(obj client.Object) bool {
-       tls, ok := obj.(*apiv2.ApisixTls)
-       if !ok {
-               return false
-       }
-
-       return r.matchesIngressClass(tls.Spec.IngressClassName)
-}
-
-// matchesIngressClass checks if the given ingress class name matches our 
controlled classes
-func (r *ApisixTlsReconciler) matchesIngressClass(ingressClassName string) 
bool {
-       if ingressClassName == "" {
-               // Check for default ingress class
-               ingressClassList := &networkingv1.IngressClassList{}
-               if err := r.List(context.Background(), ingressClassList, 
client.MatchingFields{
-                       indexer.IngressClass: config.GetControllerName(),
-               }); err != nil {
-                       r.Log.Error(err, "failed to list ingress classes")
-                       return false
-               }
-
-               // Find the ingress class that is marked as default
-               for _, ic := range ingressClassList.Items {
-                       if IsDefaultIngressClass(&ic) && 
matchesController(ic.Spec.Controller) {
-                               return true
-                       }
-               }
-               return false
-       }
-
-       // Check if the specified ingress class is controlled by us
-       var ingressClass networkingv1.IngressClass
-       if err := r.Get(context.Background(), client.ObjectKey{Name: 
ingressClassName}, &ingressClass); err != nil {
-               r.Log.Error(err, "failed to get ingress class", "ingressClass", 
ingressClassName)
-               return false
-       }
-
-       return matchesController(ingressClass.Spec.Controller)
-}
-
 func (r *ApisixTlsReconciler) listApisixTlsForSecret(ctx context.Context, obj 
client.Object) []reconcile.Request {
        secret, ok := obj.(*corev1.Secret)
        if !ok {
diff --git a/internal/controller/apisixupstream_controller.go 
b/internal/controller/apisixupstream_controller.go
index dad9d968..14dba916 100644
--- a/internal/controller/apisixupstream_controller.go
+++ b/internal/controller/apisixupstream_controller.go
@@ -57,7 +57,7 @@ func (r *ApisixUpstreamReconciler) Reconcile(ctx 
context.Context, req ctrl.Reque
 
        tctx := provider.NewDefaultTranslateContext(ctx)
 
-       _, err := GetIngressClass(tctx, r.Client, r.Log, 
au.Spec.IngressClassName)
+       _, err := FindMatchingIngressClass(tctx, r.Client, r.Log, &au)
        if err != nil {
                r.Log.V(1).Info("no matching IngressClass available, skip 
processing",
                        "ingressClassName", au.Spec.IngressClassName,
diff --git a/internal/controller/httproutepolicy.go 
b/internal/controller/httproutepolicy.go
index f829cb6c..260b09e5 100644
--- a/internal/controller/httproutepolicy.go
+++ b/internal/controller/httproutepolicy.go
@@ -198,7 +198,7 @@ func (r *IngressReconciler) 
updateHTTPRoutePolicyStatusOnDeleting(ctx context.Co
                                if err := r.Get(ctx, namespacedName, &ingress); 
err != nil {
                                        continue
                                }
-                               ingressClass, err := r.getIngressClass(ctx, 
&ingress)
+                               ingressClass, err := 
FindMatchingIngressClass(ctx, r.Client, r.Log, &ingress)
                                if err != nil {
                                        continue
                                }
diff --git a/internal/controller/ingress_controller.go 
b/internal/controller/ingress_controller.go
index 25b52990..c86b40c2 100644
--- a/internal/controller/ingress_controller.go
+++ b/internal/controller/ingress_controller.go
@@ -70,7 +70,7 @@ func (r *IngressReconciler) SetupWithManager(mgr 
ctrl.Manager) error {
        return ctrl.NewControllerManagedBy(mgr).
                For(&networkingv1.Ingress{},
                        builder.WithPredicates(
-                               
predicate.NewPredicateFuncs(r.checkIngressClass),
+                               MatchesIngressClassPredicate(r.Client, r.Log),
                        ),
                ).
                WithEventFilter(
@@ -151,10 +151,13 @@ func (r *IngressReconciler) Reconcile(ctx 
context.Context, req ctrl.Request) (ct
        // create a translate context
        tctx := provider.NewDefaultTranslateContext(ctx)
 
-       ingressClass, err := r.getIngressClass(ctx, ingress)
+       ingressClass, err := FindMatchingIngressClass(tctx, r.Client, r.Log, 
ingress)
        if err != nil {
-               r.Log.Error(err, "failed to get IngressClass")
-               return ctrl.Result{}, err
+               if err := r.Provider.Delete(ctx, ingress); err != nil {
+                       r.Log.Error(err, "failed to delete ingress resources", 
"ingress", ingress.Name)
+                       return ctrl.Result{}, nil
+               }
+               return ctrl.Result{}, nil
        }
 
        tctx.RouteParentRefs = append(tctx.RouteParentRefs, 
gatewayv1.ParentReference{
@@ -207,22 +210,6 @@ func (r *IngressReconciler) Reconcile(ctx context.Context, 
req ctrl.Request) (ct
        return ctrl.Result{}, nil
 }
 
-// getIngressClass get the ingress class for the ingress
-func (r *IngressReconciler) getIngressClass(ctx context.Context, obj 
client.Object) (*networkingv1.IngressClass, error) {
-       ingress := obj.(*networkingv1.Ingress)
-       var ingressClassName string
-       if ingress.Spec.IngressClassName != nil {
-               ingressClassName = *ingress.Spec.IngressClassName
-       }
-       return GetIngressClass(ctx, r.Client, r.Log, ingressClassName)
-}
-
-// checkIngressClass check if the ingress uses the ingress class that we 
control
-func (r *IngressReconciler) checkIngressClass(obj client.Object) bool {
-       _, err := r.getIngressClass(context.Background(), obj)
-       return err == nil
-}
-
 // matchesIngressController check if the ingress class is controlled by us
 func (r *IngressReconciler) matchesIngressController(obj client.Object) bool {
        ingressClass, ok := obj.(*networkingv1.IngressClass)
@@ -307,7 +294,7 @@ func (r *IngressReconciler) listIngressesByService(ctx 
context.Context, obj clie
 
        requests := make([]reconcile.Request, 0, len(ingressList.Items))
        for _, ingress := range ingressList.Items {
-               if r.checkIngressClass(&ingress) {
+               if MatchesIngressClass(r.Client, r.Log, &ingress) {
                        requests = append(requests, reconcile.Request{
                                NamespacedName: client.ObjectKey{
                                        Namespace: ingress.Namespace,
@@ -340,7 +327,7 @@ func (r *IngressReconciler) listIngressesBySecret(ctx 
context.Context, obj clien
 
        requests := make([]reconcile.Request, 0, len(ingressList.Items))
        for _, ingress := range ingressList.Items {
-               if r.checkIngressClass(&ingress) {
+               if MatchesIngressClass(r.Client, r.Log, &ingress) {
                        requests = append(requests, reconcile.Request{
                                NamespacedName: client.ObjectKey{
                                        Namespace: ingress.Namespace,
diff --git a/internal/controller/utils.go b/internal/controller/utils.go
index bf47a1de..3d0c5018 100644
--- a/internal/controller/utils.go
+++ b/internal/controller/utils.go
@@ -40,6 +40,7 @@ import (
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/apimachinery/pkg/labels"
        k8stypes "k8s.io/apimachinery/pkg/types"
+       "k8s.io/utils/ptr"
        "sigs.k8s.io/controller-runtime/pkg/client"
        "sigs.k8s.io/controller-runtime/pkg/event"
        "sigs.k8s.io/controller-runtime/pkg/predicate"
@@ -1261,36 +1262,6 @@ func matchesIngressController(obj client.Object) bool {
        return matchesController(ingressClass.Spec.Controller)
 }
 
-func matchesIngressClass(c client.Client, log logr.Logger, ingressClassName 
string) bool {
-       if ingressClassName == "" {
-               // Check for default ingress class
-               ingressClassList := &networkingv1.IngressClassList{}
-               if err := c.List(context.Background(), ingressClassList, 
client.MatchingFields{
-                       indexer.IngressClass: config.GetControllerName(),
-               }); err != nil {
-                       log.Error(err, "failed to list ingress classes")
-                       return false
-               }
-
-               // Find the ingress class that is marked as default
-               for _, ic := range ingressClassList.Items {
-                       if IsDefaultIngressClass(&ic) && 
matchesController(ic.Spec.Controller) {
-                               return true
-                       }
-               }
-               return false
-       }
-
-       // Check if the specified ingress class is controlled by us
-       var ingressClass networkingv1.IngressClass
-       if err := c.Get(context.Background(), client.ObjectKey{Name: 
ingressClassName}, &ingressClass); err != nil {
-               log.Error(err, "failed to get ingress class", "ingressClass", 
ingressClassName)
-               return false
-       }
-
-       return matchesController(ingressClass.Spec.Controller)
-}
-
 func ProcessIngressClassParameters(tctx *provider.TranslateContext, c 
client.Client, log logr.Logger, object client.Object, ingressClass 
*networkingv1.IngressClass) error {
        if ingressClass == nil || ingressClass.Spec.Parameters == nil {
                return nil
@@ -1368,7 +1339,12 @@ func ProcessIngressClassParameters(tctx 
*provider.TranslateContext, c client.Cli
        return nil
 }
 
-func GetIngressClass(ctx context.Context, c client.Client, log logr.Logger, 
ingressClassName string) (*networkingv1.IngressClass, error) {
+func FindMatchingIngressClass(ctx context.Context, c client.Client, log 
logr.Logger, obj client.Object) (*networkingv1.IngressClass, error) {
+       ingressClassName := ExtractIngressClass(obj)
+       return FindMatchingIngressClassByName(ctx, c, log, ingressClassName)
+}
+
+func FindMatchingIngressClassByName(ctx context.Context, c client.Client, log 
logr.Logger, ingressClassName string) (*networkingv1.IngressClass, error) {
        if ingressClassName == "" {
                // Check for default ingress class
                ingressClassList := &networkingv1.IngressClassList{}
@@ -1533,3 +1509,39 @@ func GetGatewayProxyByGateway(ctx context.Context, r 
client.Client, gateway *gat
        }
        return gatewayProxy, nil
 }
+
+func MatchesIngressClassPredicate(c client.Client, log logr.Logger) 
predicate.Funcs {
+       predicateFuncs := predicate.NewPredicateFuncs(func(obj client.Object) 
bool {
+               return MatchesIngressClass(c, log, obj)
+       })
+       predicateFuncs.UpdateFunc = func(e event.UpdateEvent) bool {
+               return MatchesIngressClass(c, log, e.ObjectOld) || 
MatchesIngressClass(c, log, e.ObjectNew)
+       }
+       return predicateFuncs
+}
+
+func MatchesIngressClass(c client.Client, log logr.Logger, obj client.Object) 
bool {
+       _, err := FindMatchingIngressClass(context.Background(), c, log, obj)
+       return err == nil
+}
+
+func ExtractIngressClass(obj client.Object) string {
+       switch v := obj.(type) {
+       case *networkingv1.Ingress:
+               return ptr.Deref(v.Spec.IngressClassName, "")
+       case *apiv2.ApisixConsumer:
+               return v.Spec.IngressClassName
+       case *apiv2.ApisixRoute:
+               return v.Spec.IngressClassName
+       case *apiv2.ApisixTls:
+               return v.Spec.IngressClassName
+       case *apiv2.ApisixPluginConfig:
+               return v.Spec.IngressClassName
+       case *apiv2.ApisixUpstream:
+               return v.Spec.IngressClassName
+       case *apiv2.ApisixGlobalRule:
+               return v.Spec.IngressClassName
+       default:
+               panic(fmt.Errorf("unhandled object type %T for extracting 
ingress class", obj))
+       }
+}
diff --git a/internal/manager/controllers.go b/internal/manager/controllers.go
index 0688055d..6c878b21 100644
--- a/internal/manager/controllers.go
+++ b/internal/manager/controllers.go
@@ -210,10 +210,11 @@ func registerReadinessGVK(c client.Client, readier 
readiness.ReadinessManager) {
                                types.GvkOf(&apiv2.ApisixPluginConfig{}),
                                types.GvkOf(&apiv2.ApisixTls{}),
                                types.GvkOf(&apiv2.ApisixConsumer{}),
+                               types.GvkOf(&apiv2.ApisixUpstream{}),
                        },
                        Filter: readiness.GVKFilter(func(obj 
*unstructured.Unstructured) bool {
                                icName, _, _ := 
unstructured.NestedString(obj.Object, "spec", "ingressClassName")
-                               ingressClass, _ := 
controller.GetIngressClass(context.Background(), c, log, icName)
+                               ingressClass, _ := 
controller.FindMatchingIngressClassByName(context.Background(), c, log, icName)
                                return ingressClass != nil
                        }),
                },
diff --git a/internal/types/k8s.go b/internal/types/k8s.go
index d83158fe..3f50033a 100644
--- a/internal/types/k8s.go
+++ b/internal/types/k8s.go
@@ -48,6 +48,7 @@ const (
        KindBackendTrafficPolicy = "BackendTrafficPolicy"
        KindConsumer             = "Consumer"
        KindPluginConfig         = "PluginConfig"
+       KindApisixUpstream       = "ApisixUpstream"
 )
 
 func KindOf(obj any) string {
@@ -132,6 +133,12 @@ func GvkOf(obj any) schema.GroupVersionKind {
                        Version: "v2",
                        Kind:    KindApisixConsumer,
                }
+       case *v2.ApisixUpstream:
+               return schema.GroupVersionKind{
+                       Group:   "apisix.apache.org",
+                       Version: "v2",
+                       Kind:    KindApisixUpstream,
+               }
        case *v1alpha1.HTTPRoutePolicy:
                return schema.GroupVersionKind{
                        Group:   "apisix.apache.org",
diff --git a/test/e2e/crds/v2/route.go b/test/e2e/crds/v2/route.go
index c60d01b0..4e593ef6 100644
--- a/test/e2e/crds/v2/route.go
+++ b/test/e2e/crds/v2/route.go
@@ -526,6 +526,61 @@ spec:
                                Check:  
scaffold.WithExpectedStatus(http.StatusOK),
                        })
                })
+
+               It("IngressClassName Change", func() {
+                       const apisixRouteSpec = `
+apiVersion: apisix.apache.org/v2
+kind: ApisixRoute
+metadata:
+  name: default
+spec:
+  ingressClassName: %s
+  http:
+  - name: rule0
+    match:
+      hosts:
+      - httpbin
+      paths:
+      - /get
+    backends:
+    - serviceName: httpbin-service-e2e-test
+      servicePort: 80
+`
+
+                       By("apply ApisixRoute")
+                       var apisixRoute apiv2.ApisixRoute
+                       applier.MustApplyAPIv2(types.NamespacedName{Namespace: 
s.Namespace(), Name: "default"},
+                               &apisixRoute, fmt.Sprintf(apisixRouteSpec, 
s.Namespace()))
+
+                       s.RequestAssert(&scaffold.RequestAssert{
+                               Method: "GET",
+                               Path:   "/get",
+                               Host:   "httpbin",
+                               Check:  
scaffold.WithExpectedStatus(http.StatusOK),
+                       })
+
+                       By("change IngressClassName to invalid")
+                       err := 
s.CreateResourceFromString(fmt.Sprintf(apisixRouteSpec, "invalid"))
+                       Expect(err).NotTo(HaveOccurred(), "creating ApisixRoute 
with IngressClass")
+
+                       s.RequestAssert(&scaffold.RequestAssert{
+                               Method: "GET",
+                               Path:   "/get",
+                               Host:   "httpbin",
+                               Check:  
scaffold.WithExpectedStatus(http.StatusNotFound),
+                       })
+
+                       By("change IngressClassName to default")
+                       applier.MustApplyAPIv2(types.NamespacedName{Namespace: 
s.Namespace(), Name: "default"},
+                               &apisixRoute, fmt.Sprintf(apisixRouteSpec, 
s.Namespace()))
+
+                       s.RequestAssert(&scaffold.RequestAssert{
+                               Method: "GET",
+                               Path:   "/get",
+                               Host:   "httpbin",
+                               Check:  
scaffold.WithExpectedStatus(http.StatusOK),
+                       })
+               })
        })
 
        Context("Test ApisixRoute reference ApisixUpstream", func() {
diff --git a/test/e2e/framework/ingress.go b/test/e2e/framework/ingress.go
index 11de509c..e77db052 100644
--- a/test/e2e/framework/ingress.go
+++ b/test/e2e/framework/ingress.go
@@ -49,7 +49,7 @@ type IngressDeployOpts struct {
        ProviderSyncPeriod time.Duration
        Namespace          string
        StatusAddress      string
-       Replicas           int
+       Replicas           *int
        InitSyncDelay      time.Duration
 }
 
diff --git a/test/e2e/framework/manifests/ingress.yaml 
b/test/e2e/framework/manifests/ingress.yaml
index c411a93d..ae0f440b 100644
--- a/test/e2e/framework/manifests/ingress.yaml
+++ b/test/e2e/framework/manifests/ingress.yaml
@@ -326,6 +326,15 @@ data:
     log_level: "debug"
     controller_name: {{ .ControllerName | default 
"apisix.apache.org/apisix-ingress-controller" }}
     leader_election_id: "apisix-ingress-controller-leader"
+    leader_election:
+      lease_duration: 10s                   # lease_duration is the duration 
that non-leader candidates will wait
+                                            # after observing a leadership 
renewal until attempting to acquire leadership of a
+                                            # leader election.
+      renew_deadline: 5s                   # renew_deadline is the time in 
seconds that the acting controller
+                                            # will retry refreshing leadership 
before giving up.
+      retry_period: 2s                      # retry_period is the time in 
seconds that the acting controller
+                                            # will wait between tries of 
actions with the controller.
+      disable: false                        # Whether to disable leader 
election.
     exec_adc_timeout: 5s
     provider:
       type: {{ .ProviderType | default "apisix" }}
diff --git a/test/e2e/ingress/ingress.go b/test/e2e/ingress/ingress.go
index eb93db67..b61e3109 100644
--- a/test/e2e/ingress/ingress.go
+++ b/test/e2e/ingress/ingress.go
@@ -178,6 +178,26 @@ spec:
               number: 80
 `
 
+               var ingressSpec = `
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: %s
+spec:
+  ingressClassName: %s
+  rules:
+  - host: default.example.com
+    http:
+      paths:
+      - path: /
+        pathType: Prefix
+        backend:
+          service:
+            name: httpbin-service-e2e-test
+            port:
+              number: 80
+`
+
                var ingressWithExternalName = `
 apiVersion: v1
 kind: Service
@@ -322,6 +342,42 @@ spec:
                                Expect().
                                Status(404)
                })
+
+               It("IngressClassName Change", func() {
+                       By("create Ingress with IngressClass")
+                       err := 
s.CreateResourceFromString(fmt.Sprintf(ingressSpec, s.Namespace(), 
"apisix-default"))
+                       Expect(err).NotTo(HaveOccurred(), "creating Ingress 
with IngressClass")
+
+                       By("verify default ingress")
+                       s.RequestAssert(&scaffold.RequestAssert{
+                               Method: "GET",
+                               Path:   "/get",
+                               Host:   "default.example.com",
+                               Check:  
scaffold.WithExpectedStatus(http.StatusOK),
+                       })
+
+                       By("change IngressClassName to invalid")
+                       err = 
s.CreateResourceFromString(fmt.Sprintf(ingressSpec, s.Namespace(), "invalid"))
+                       Expect(err).NotTo(HaveOccurred(), "creating Ingress 
with IngressClass")
+
+                       s.RequestAssert(&scaffold.RequestAssert{
+                               Method: "GET",
+                               Path:   "/get",
+                               Host:   "default.example.com",
+                               Check:  
scaffold.WithExpectedStatus(http.StatusNotFound),
+                       })
+
+                       By("change IngressClassName to default")
+                       err = 
s.CreateResourceFromString(fmt.Sprintf(ingressSpec, s.Namespace(), 
"apisix-default"))
+                       Expect(err).NotTo(HaveOccurred(), "creating Ingress 
with IngressClass")
+
+                       s.RequestAssert(&scaffold.RequestAssert{
+                               Method: "GET",
+                               Path:   "/get",
+                               Host:   "default.example.com",
+                               Check:  
scaffold.WithExpectedStatus(http.StatusOK),
+                       })
+               })
        })
 
        // Tests concerning the default ingress class need to be run serially
diff --git a/test/e2e/scaffold/apisix_deployer.go 
b/test/e2e/scaffold/apisix_deployer.go
index cab432ff..57f15cb5 100644
--- a/test/e2e/scaffold/apisix_deployer.go
+++ b/test/e2e/scaffold/apisix_deployer.go
@@ -258,7 +258,7 @@ func (s *APISIXDeployer) DeployIngress() {
                ProviderType:       framework.ProviderType,
                ProviderSyncPeriod: 1 * time.Hour,
                Namespace:          s.namespace,
-               Replicas:           1,
+               Replicas:           ptr.To(1),
        })
 }
 
@@ -268,7 +268,7 @@ func (s *APISIXDeployer) ScaleIngress(replicas int) {
                ProviderType:       framework.ProviderType,
                ProviderSyncPeriod: 1 * time.Hour,
                Namespace:          s.namespace,
-               Replicas:           replicas,
+               Replicas:           ptr.To(replicas),
        })
 }
 

Reply via email to