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 2bab77aa fix: record attachedRoutes and supportedkinds for gateway 
status (#2670)
2bab77aa is described below

commit 2bab77aa9403993bb637ae48987194aadb47280d
Author: AlinsRan <[email protected]>
AuthorDate: Fri Dec 5 13:26:14 2025 +0800

    fix: record attachedRoutes and supportedkinds for gateway status (#2670)
---
 internal/controller/gateway_controller.go |  53 +++----
 internal/controller/utils.go              | 159 ++++++++++++++-------
 internal/types/route_adapter.go           | 147 ++++++++++++++++++++
 test/e2e/gatewayapi/gateway.go            | 224 ++++++++++++++++++++++++++++++
 test/e2e/scaffold/k8s.go                  |  19 +++
 test/e2e/scaffold/scaffold.go             |   3 +
 6 files changed, 530 insertions(+), 75 deletions(-)

diff --git a/internal/controller/gateway_controller.go 
b/internal/controller/gateway_controller.go
index 76648a4a..e2806304 100644
--- a/internal/controller/gateway_controller.go
+++ b/internal/controller/gateway_controller.go
@@ -21,7 +21,6 @@ import (
        "context"
        "errors"
        "fmt"
-       "reflect"
 
        "github.com/go-logr/logr"
        corev1 "k8s.io/api/core/v1"
@@ -35,6 +34,7 @@ import (
        "sigs.k8s.io/controller-runtime/pkg/predicate"
        "sigs.k8s.io/controller-runtime/pkg/reconcile"
        gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
+       gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
        "sigs.k8s.io/gateway-api/apis/v1beta1"
 
        "github.com/apache/apisix-ingress-controller/api/v1alpha1"
@@ -62,13 +62,10 @@ func (r *GatewayReconciler) SetupWithManager(mgr 
ctrl.Manager) error {
                For(
                        &gatewayv1.Gateway{},
                        builder.WithPredicates(
-                               
predicate.NewPredicateFuncs(r.checkGatewayClass),
-                       ),
-               ).
-               WithEventFilter(
-                       predicate.Or(
-                               predicate.GenerationChangedPredicate{},
-                               
predicate.NewPredicateFuncs(TypePredicate[*corev1.Secret]()),
+                               predicate.And(
+                                       
predicate.NewPredicateFuncs(r.checkGatewayClass),
+                                       predicate.GenerationChangedPredicate{},
+                               ),
                        ),
                ).
                Watches(
@@ -80,7 +77,23 @@ func (r *GatewayReconciler) SetupWithManager(mgr 
ctrl.Manager) error {
                ).
                Watches(
                        &gatewayv1.HTTPRoute{},
-                       
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForHTTPRoute),
+                       
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForStatusParentRefs),
+               ).
+               Watches(
+                       &gatewayv1.GRPCRoute{},
+                       
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForStatusParentRefs),
+               ).
+               Watches(
+                       &gatewayv1alpha2.TCPRoute{},
+                       
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForStatusParentRefs),
+               ).
+               Watches(
+                       &gatewayv1alpha2.TLSRoute{},
+                       
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForStatusParentRefs),
+               ).
+               Watches(
+                       &gatewayv1alpha2.UDPRoute{},
+                       
handler.EnqueueRequestsFromMapFunc(r.listGatewaysForStatusParentRefs),
                ).
                Watches(
                        &v1alpha1.GatewayProxy{},
@@ -300,19 +313,11 @@ func (r *GatewayReconciler) 
listGatewaysForGatewayProxy(ctx context.Context, obj
        return recs
 }
 
-func (r *GatewayReconciler) listGatewaysForHTTPRoute(ctx context.Context, obj 
client.Object) []reconcile.Request {
-       httpRoute, ok := obj.(*gatewayv1.HTTPRoute)
-       if !ok {
-               r.Log.Error(
-                       fmt.Errorf("unexpected object type"),
-                       "HTTPRoute watch predicate received unexpected object 
type",
-                       "expected", "*gatewayapi.HTTPRoute", "found", 
reflect.TypeOf(obj),
-               )
-               return nil
-       }
-       recs := []reconcile.Request{}
-       for _, routeParentStatus := range httpRoute.Status.Parents {
-               gatewayNamespace := httpRoute.GetNamespace()
+func (r *GatewayReconciler) listGatewaysForStatusParentRefs(ctx 
context.Context, obj client.Object) []reconcile.Request {
+       route := internaltypes.NewRouteAdapter(obj)
+       reqs := []reconcile.Request{}
+       for _, routeParentStatus := range route.GetParentStatuses() {
+               gatewayNamespace := route.GetNamespace()
                parentRef := routeParentStatus.ParentRef
                if parentRef.Group != nil && *parentRef.Group != 
gatewayv1.GroupName {
                        continue
@@ -336,14 +341,14 @@ func (r *GatewayReconciler) listGatewaysForHTTPRoute(ctx 
context.Context, obj cl
                        continue
                }
 
-               recs = append(recs, reconcile.Request{
+               reqs = append(reqs, reconcile.Request{
                        NamespacedName: client.ObjectKey{
                                Namespace: gatewayNamespace,
                                Name:      string(parentRef.Name),
                        },
                })
        }
-       return recs
+       return reqs
 }
 
 func (r *GatewayReconciler) listGatewaysForSecret(ctx context.Context, obj 
client.Object) (requests []reconcile.Request) {
diff --git a/internal/controller/utils.go b/internal/controller/utils.go
index 845d56df..869efefc 100644
--- a/internal/controller/utils.go
+++ b/internal/controller/utils.go
@@ -376,7 +376,7 @@ func ParseRouteParentRefs(
                                }
                        }
 
-                       if !routeMatchesListenerType(route, listener) {
+                       if ok, _ := routeMatchesListenerType(route, listener); 
!ok {
                                continue
                        }
 
@@ -475,8 +475,8 @@ func checkRouteAcceptedByListener(
                        return false, gatewayv1.RouteReasonNoMatchingParent, nil
                }
        }
-       if !routeMatchesListenerType(route, listener) {
-               return false, gatewayv1.RouteReasonNoMatchingParent, nil
+       if ok, err := routeMatchesListenerType(route, listener); !ok {
+               return false, gatewayv1.RouteReasonNoMatchingParent, err
        }
        if !routeHostnamesIntersectsWithListenerHostname(route, listener) {
                return false, gatewayv1.RouteReasonNoMatchingListenerHostname, 
nil
@@ -649,71 +649,95 @@ func isRouteNamespaceAllowed(
        }
 }
 
-func routeMatchesListenerType(route client.Object, listener 
gatewayv1.Listener) bool {
+func routeMatchesListenerType(route client.Object, listener 
gatewayv1.Listener) (bool, error) {
        switch route.(type) {
        case *gatewayv1.HTTPRoute, *gatewayv1.GRPCRoute:
                if listener.Protocol != gatewayv1.HTTPProtocolType && 
listener.Protocol != gatewayv1.HTTPSProtocolType {
-                       return false
+                       return false, nil
                }
 
                if listener.Protocol == gatewayv1.HTTPSProtocolType {
                        if listener.TLS == nil {
-                               return false
+                               return false, nil
                        }
 
                        if listener.TLS.Mode != nil && *listener.TLS.Mode != 
gatewayv1.TLSModeTerminate {
-                               return false
+                               return false, nil
                        }
                }
        case *gatewayv1alpha2.TCPRoute:
                if listener.Protocol != gatewayv1.TCPProtocolType {
-                       return false
+                       return false, nil
                }
        case *gatewayv1alpha2.UDPRoute:
                if listener.Protocol != gatewayv1.UDPProtocolType {
-                       return false
+                       return false, nil
                }
        case *gatewayv1alpha2.TLSRoute:
                if listener.Protocol != gatewayv1.TLSProtocolType {
-                       return false
+                       return false, nil
                }
        default:
-               return false
+               return false, fmt.Errorf("unsupported route type %T", route)
        }
-       return true
+       return true, nil
 }
 
 func getAttachedRoutesForListener(ctx context.Context, mgrc client.Client, 
gateway gatewayv1.Gateway, listener gatewayv1.Listener) (int32, error) {
-       httpRouteList := gatewayv1.HTTPRouteList{}
-       if err := mgrc.List(ctx, &httpRouteList); err != nil {
-               return 0, err
+       routes := []types.RouteAdapter{}
+       routeList := []client.ObjectList{}
+
+       listOption := client.MatchingFields{
+               indexer.ParentRefs: indexer.GenIndexKey(gateway.Namespace, 
gateway.Name),
        }
-       var attachedRoutes int32
-       for _, route := range httpRouteList.Items {
-               route := route
-               acceptedByGateway := lo.ContainsBy(route.Status.Parents, 
func(parentStatus gatewayv1.RouteParentStatus) bool {
-                       parentRef := parentStatus.ParentRef
-                       if parentRef.Group != nil && *parentRef.Group != 
gatewayv1.GroupName {
-                               return false
-                       }
-                       if parentRef.Kind != nil && *parentRef.Kind != 
KindGateway {
-                               return false
+       if listener.AllowedRoutes != nil && listener.AllowedRoutes.Kinds != nil 
{
+               for _, rgk := range listener.AllowedRoutes.Kinds {
+                       if rgk.Group != nil && *rgk.Group != 
gatewayv1.GroupName {
+                               continue
                        }
-                       gatewayNamespace := route.Namespace
-                       if parentRef.Namespace != nil {
-                               gatewayNamespace = string(*parentRef.Namespace)
+                       switch rgk.Kind {
+                       case types.KindHTTPRoute:
+                               routeList = append(routeList, 
&gatewayv1.HTTPRouteList{})
+                       case types.KindGRPCRoute:
+                               routeList = append(routeList, 
&gatewayv1.GRPCRouteList{})
+                       case types.KindTCPRoute:
+                               routeList = append(routeList, 
&gatewayv1alpha2.TCPRouteList{})
+                       case types.KindUDPRoute:
+                               routeList = append(routeList, 
&gatewayv1alpha2.UDPRouteList{})
+                       case types.KindTLSRoute:
+                               routeList = append(routeList, 
&gatewayv1alpha2.TLSRouteList{})
                        }
-                       return gateway.Namespace == gatewayNamespace && 
gateway.Name == string(parentRef.Name)
-               })
-               if !acceptedByGateway {
-                       continue
                }
+       } else {
+               switch listener.Protocol {
+               case gatewayv1.HTTPProtocolType, gatewayv1.HTTPSProtocolType:
+                       routeList = append(routeList, 
&gatewayv1.HTTPRouteList{}, &gatewayv1.GRPCRouteList{})
+               case gatewayv1.TCPProtocolType:
+                       routeList = append(routeList, 
&gatewayv1alpha2.TCPRouteList{})
+               case gatewayv1.UDPProtocolType:
+                       routeList = append(routeList, 
&gatewayv1alpha2.UDPRouteList{})
+               case gatewayv1.TLSProtocolType:
+                       routeList = append(routeList, 
&gatewayv1alpha2.TLSRouteList{})
+               }
+       }
+
+       for _, rl := range routeList {
+               if err := mgrc.List(ctx, rl, listOption); err != nil {
+                       return 0, fmt.Errorf("failed to list %T: %w", rl, err)
+               }
+               routes = append(routes, types.NewRouteListAdapter(rl)...)
+       }
 
-               for _, parentRef := range route.Spec.ParentRefs {
+       var attachedRoutes int32
+       for _, route := range routes {
+               if !checkStatusParent(route.GetParentStatuses(), 
route.GetNamespace(), gateway) {
+                       continue
+               }
+               for _, parentRef := range route.GetParentRefs() {
                        ok, _, err := checkRouteAcceptedByListener(
                                ctx,
                                mgrc,
-                               &route,
+                               route.GetObject(),
                                gateway,
                                listener,
                                parentRef,
@@ -729,13 +753,29 @@ func getAttachedRoutesForListener(ctx context.Context, 
mgrc client.Client, gatew
        return attachedRoutes, nil
 }
 
+func checkStatusParent(parents []gatewayv1.RouteParentStatus, routeNamespace 
string, gateway gatewayv1.Gateway) bool {
+       return lo.ContainsBy(parents, func(parentStatus 
gatewayv1.RouteParentStatus) bool {
+               parentRef := parentStatus.ParentRef
+               if parentRef.Group != nil && *parentRef.Group != 
gatewayv1.GroupName {
+                       return false
+               }
+               if parentRef.Kind != nil && *parentRef.Kind != KindGateway {
+                       return false
+               }
+               gatewayNamespace := routeNamespace
+               if parentRef.Namespace != nil {
+                       gatewayNamespace = string(*parentRef.Namespace)
+               }
+               return gateway.Namespace == gatewayNamespace && gateway.Name == 
string(parentRef.Name)
+       })
+}
+
 func getListenerStatus(
        ctx context.Context,
        mrgc client.Client,
        gateway *gatewayv1.Gateway,
 ) ([]gatewayv1.ListenerStatus, error) {
-       statuses := make(map[gatewayv1.SectionName]gatewayv1.ListenerStatus, 
len(gateway.Spec.Listeners))
-
+       statusArray := make([]gatewayv1.ListenerStatus, 0, 
len(gateway.Spec.Listeners))
        for i, listener := range gateway.Spec.Listeners {
                attachedRoutes, err := getAttachedRoutesForListener(ctx, mrgc, 
*gateway, listener)
                if err != nil {
@@ -776,10 +816,35 @@ func getListenerStatus(
                )
 
                if listener.AllowedRoutes == nil || 
listener.AllowedRoutes.Kinds == nil {
-                       supportedKinds = []gatewayv1.RouteGroupKind{
-                               {
-                                       Kind: KindHTTPRoute,
-                               },
+                       group := gatewayv1.Group(gatewayv1.GroupName)
+                       supportedKinds = []gatewayv1.RouteGroupKind{}
+                       switch listener.Protocol {
+                       case gatewayv1.TLSProtocolType:
+                               supportedKinds = append(supportedKinds, 
gatewayv1.RouteGroupKind{
+                                       Group: &group,
+                                       Kind:  types.KindTLSRoute,
+                               })
+                       case gatewayv1.TCPProtocolType:
+                               supportedKinds = append(supportedKinds, 
gatewayv1.RouteGroupKind{
+                                       Group: &group,
+                                       Kind:  types.KindTCPRoute,
+                               })
+                       case gatewayv1.UDPProtocolType:
+                               supportedKinds = append(supportedKinds, 
gatewayv1.RouteGroupKind{
+                                       Group: &group,
+                                       Kind:  types.KindUDPRoute,
+                               })
+                       case gatewayv1.HTTPProtocolType, 
gatewayv1.HTTPSProtocolType:
+                               supportedKinds = append(supportedKinds, 
[]gatewayv1.RouteGroupKind{
+                                       {
+                                               Group: &group,
+                                               Kind:  types.KindGRPCRoute,
+                                       },
+                                       {
+                                               Group: &group,
+                                               Kind:  types.KindHTTPRoute,
+                                       },
+                               }...)
                        }
                } else {
                        for _, kind := range listener.AllowedRoutes.Kinds {
@@ -789,7 +854,7 @@ func getListenerStatus(
                                        continue
                                }
                                switch kind.Kind {
-                               case KindHTTPRoute:
+                               case KindHTTPRoute, types.KindGRPCRoute, 
types.KindTLSRoute, types.KindTCPRoute, types.KindUDPRoute:
                                        supportedKinds = append(supportedKinds, 
kind)
                                default:
                                        conditionResolvedRefs.Status = 
metav1.ConditionFalse
@@ -892,17 +957,9 @@ func getListenerStatus(
                        changed = true
                }
 
-               if changed {
-                       statuses[listener.Name] = status
-               } else {
-                       statuses[listener.Name] = gateway.Status.Listeners[i]
+               if !changed {
+                       status = gateway.Status.Listeners[i]
                }
-       }
-
-       // check for conflicts
-
-       statusArray := []gatewayv1.ListenerStatus{}
-       for _, status := range statuses {
                statusArray = append(statusArray, status)
        }
 
diff --git a/internal/types/route_adapter.go b/internal/types/route_adapter.go
new file mode 100644
index 00000000..11da083d
--- /dev/null
+++ b/internal/types/route_adapter.go
@@ -0,0 +1,147 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package types
+
+import (
+       "github.com/samber/lo"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+       gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
+       gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
+)
+
+type HTTPRouteAdapter struct {
+       *gatewayv1.HTTPRoute
+}
+
+func (r HTTPRouteAdapter) GetParentStatuses() []gatewayv1.RouteParentStatus {
+       return r.Status.Parents
+}
+func (r HTTPRouteAdapter) GetParentRefs() []gatewayv1.ParentReference {
+       return r.Spec.ParentRefs
+}
+func (r HTTPRouteAdapter) GetObject() client.Object {
+       return r.HTTPRoute
+}
+
+type GRPCRouteAdapter struct {
+       *gatewayv1.GRPCRoute
+}
+
+func (r GRPCRouteAdapter) GetParentStatuses() []gatewayv1.RouteParentStatus {
+       return r.Status.Parents
+}
+func (r GRPCRouteAdapter) GetParentRefs() []gatewayv1.ParentReference {
+       return r.Spec.ParentRefs
+}
+func (r GRPCRouteAdapter) GetObject() client.Object {
+       return r.GRPCRoute
+}
+
+type TCPRouteAdapter struct {
+       *gatewayv1alpha2.TCPRoute
+}
+
+func (r TCPRouteAdapter) GetParentStatuses() []gatewayv1.RouteParentStatus {
+       return r.Status.Parents
+}
+
+func (r TCPRouteAdapter) GetParentRefs() []gatewayv1.ParentReference {
+       return r.Spec.ParentRefs
+}
+func (r TCPRouteAdapter) GetObject() client.Object {
+       return r.TCPRoute
+}
+
+type UDPRouteAdapter struct {
+       *gatewayv1alpha2.UDPRoute
+}
+
+func (r UDPRouteAdapter) GetParentStatuses() []gatewayv1.RouteParentStatus {
+       return r.Status.Parents
+}
+func (r UDPRouteAdapter) GetParentRefs() []gatewayv1.ParentReference {
+       return r.Spec.ParentRefs
+}
+func (r UDPRouteAdapter) GetObject() client.Object {
+       return r.UDPRoute
+}
+
+type TLSRouteAdapter struct {
+       *gatewayv1alpha2.TLSRoute
+}
+
+func (r TLSRouteAdapter) GetParentStatuses() []gatewayv1.RouteParentStatus {
+       return r.Status.Parents
+}
+func (r TLSRouteAdapter) GetParentRefs() []gatewayv1.ParentReference {
+       return r.Spec.ParentRefs
+}
+func (r TLSRouteAdapter) GetObject() client.Object {
+       return r.TLSRoute
+}
+
+type RouteAdapter interface {
+       client.Object
+       GetParentStatuses() []gatewayv1.RouteParentStatus
+       GetParentRefs() []gatewayv1.ParentReference
+       GetObject() client.Object
+}
+
+func NewRouteAdapter(obj client.Object) RouteAdapter {
+       switch r := obj.(type) {
+       case *gatewayv1.HTTPRoute:
+               return &HTTPRouteAdapter{HTTPRoute: r}
+       case *gatewayv1.GRPCRoute:
+               return &GRPCRouteAdapter{GRPCRoute: r}
+       case *gatewayv1alpha2.TLSRoute:
+               return &TLSRouteAdapter{TLSRoute: r}
+       case *gatewayv1alpha2.TCPRoute:
+               return &TCPRouteAdapter{TCPRoute: r}
+       case *gatewayv1alpha2.UDPRoute:
+               return &UDPRouteAdapter{UDPRoute: r}
+       default:
+               return nil
+       }
+}
+
+func NewRouteListAdapter(objList client.ObjectList) []RouteAdapter {
+       switch r := objList.(type) {
+       case *gatewayv1.HTTPRouteList:
+               return lo.Map(r.Items, func(item gatewayv1.HTTPRoute, _ int) 
RouteAdapter {
+                       return &HTTPRouteAdapter{HTTPRoute: &item}
+               })
+       case *gatewayv1.GRPCRouteList:
+               return lo.Map(r.Items, func(item gatewayv1.GRPCRoute, _ int) 
RouteAdapter {
+                       return &GRPCRouteAdapter{GRPCRoute: &item}
+               })
+       case *gatewayv1alpha2.TLSRouteList:
+               return lo.Map(r.Items, func(item gatewayv1alpha2.TLSRoute, _ 
int) RouteAdapter {
+                       return &TLSRouteAdapter{TLSRoute: &item}
+               })
+       case *gatewayv1alpha2.TCPRouteList:
+               return lo.Map(r.Items, func(item gatewayv1alpha2.TCPRoute, _ 
int) RouteAdapter {
+                       return &TCPRouteAdapter{TCPRoute: &item}
+               })
+       case *gatewayv1alpha2.UDPRouteList:
+               return lo.Map(r.Items, func(item gatewayv1alpha2.UDPRoute, _ 
int) RouteAdapter {
+                       return &UDPRouteAdapter{UDPRoute: &item}
+               })
+       default:
+               return nil
+       }
+}
diff --git a/test/e2e/gatewayapi/gateway.go b/test/e2e/gatewayapi/gateway.go
index f1e8ca3a..8c5557ef 100644
--- a/test/e2e/gatewayapi/gateway.go
+++ b/test/e2e/gatewayapi/gateway.go
@@ -26,6 +26,9 @@ import (
        . "github.com/onsi/ginkgo/v2"
        . "github.com/onsi/gomega"
        "github.com/stretchr/testify/assert"
+       k8stypes "k8s.io/apimachinery/pkg/types"
+       "k8s.io/utils/ptr"
+       gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
 
        "github.com/apache/apisix-ingress-controller/test/e2e/framework"
        "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
@@ -315,4 +318,225 @@ spec:
                        }).WithTimeout(20 * 
time.Second).ProbeEvery(time.Second).Should(Equal(framework.TestCert))
                })
        })
+
+       Context("Gateway Status", func() {
+               var gatewaySpec = `
+apiVersion: gateway.networking.k8s.io/v1
+kind: Gateway
+metadata:
+  name: %s
+spec:
+  gatewayClassName: %s
+  listeners:
+  - name: http
+    protocol: HTTP
+    port: 80
+  - name: tcp
+    protocol: TCP
+    port: 9000
+    allowedRoutes:
+      kinds:
+      - kind: TCPRoute
+  - name: udp
+    protocol: UDP
+    port: 80
+    allowedRoutes:
+      kinds:
+      - kind: UDPRoute
+  infrastructure:
+    parametersRef:
+      group: apisix.apache.org
+      kind: GatewayProxy
+      name: apisix-proxy-config
+`
+               var httprouteSpec = `
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: %s
+spec:
+  parentRefs:
+  - name: %s
+  hostnames:
+  - httpbin.org
+  rules:
+  - matches: 
+    - path:
+        type: Exact
+        value: /get
+    backendRefs:
+    - name: httpbin-service-e2e-test
+      port: 80
+`
+               var grpcrouteSpec = `
+apiVersion: gateway.networking.k8s.io/v1
+kind: GRPCRoute
+metadata:
+  name: %s
+spec:
+  parentRefs:
+  - name: %s
+  rules:
+  - backendRefs:
+    - name: grpc-infra-backend-v1
+      port: 8080
+`
+               var tcpRouteSpec = `
+apiVersion: gateway.networking.k8s.io/v1alpha2
+kind: TCPRoute
+metadata:
+  name: %s
+spec:
+  parentRefs:
+  - name: %s
+    sectionName: tcp
+  rules:
+  - backendRefs:
+    - name: httpbin-service-e2e-test
+      port: 80
+`
+               var udpRoute = `
+apiVersion: gateway.networking.k8s.io/v1alpha2
+kind: UDPRoute
+metadata:
+  name: %s
+spec:
+  parentRefs:
+  - name: %s
+    sectionName: udp
+  rules:
+  - backendRefs:
+    - name: %s
+      port: %d
+`
+               var (
+                       dnsName string
+                       dnsPort int32
+               )
+
+               BeforeEach(func() {
+                       dnsSvc := s.NewCoreDNSService()
+                       dnsName = dnsSvc.Name
+                       dnsPort = dnsSvc.Spec.Ports[0].Port
+
+                       By("deploy grpc backend")
+                       s.DeployGRPCBackend()
+
+                       By("create GatewayProxy")
+                       
Expect(s.CreateResourceFromString(s.GetGatewayProxySpec())).NotTo(HaveOccurred(),
 "creating GatewayProxy")
+
+                       By("create GatewayClass")
+                       
Expect(s.CreateResourceFromString(s.GetGatewayClassYaml())).NotTo(HaveOccurred(),
 "creating GatewayClass")
+
+                       s.RetryAssertion(func() string {
+                               gcyaml, _ := s.GetResourceYaml("GatewayClass", 
s.Namespace())
+                               return gcyaml
+                       }).Should(
+                               And(
+                                       ContainSubstring(`status: "True"`),
+                                       ContainSubstring("message: the 
gatewayclass has been accepted by the apisix-ingress-controller"),
+                               ),
+                               "check GatewayClass condition",
+                       )
+
+                       By("create Gateway")
+                       gateway := fmt.Sprintf(gatewaySpec, s.Namespace(), 
s.Namespace())
+                       
Expect(s.CreateResourceFromString(gateway)).NotTo(HaveOccurred(), "creating 
Gateway")
+
+                       s.RetryAssertion(func() string {
+                               gcyaml, _ := s.GetResourceYaml("Gateway", 
s.Namespace())
+                               return gcyaml
+                       }).Should(
+                               And(
+                                       ContainSubstring(`status: "True"`),
+                                       ContainSubstring("message: the gateway 
has been accepted by the apisix-ingress-controller"),
+                               ),
+                               "check Gateway condition status",
+                       )
+               })
+               getStatusLintener := func(listenerName string) 
(*gatewayv1.ListenerStatus, error) {
+                       var gateway gatewayv1.Gateway
+                       if err := s.GetKubeClient().Get(context.Background(), 
k8stypes.NamespacedName{
+                               Name:      s.Namespace(),
+                               Namespace: s.Namespace(),
+                       }, &gateway); err != nil {
+                               return nil, err
+                       }
+                       for _, listener := range gateway.Status.Listeners {
+                               if string(listener.Name) == listenerName {
+                                       return &listener, nil
+                               }
+                       }
+                       return nil, fmt.Errorf("listener %s not found", 
listenerName)
+               }
+               expectListenerAttachedRoutes := func(listenerName string, 
accectedRoutes int) {
+                       s.RetryAssertion(func() error {
+                               listener, err := getStatusLintener(listenerName)
+                               if err != nil {
+                                       return err
+                               }
+                               if listener.AttachedRoutes != 
int32(accectedRoutes) {
+                                       return fmt.Errorf("expected listener %s 
attached routes to be %d, got %d", listener.Name, accectedRoutes, 
listener.AttachedRoutes)
+                               }
+                               return nil
+                       }).ShouldNot(HaveOccurred(), "check listener attached 
routes")
+               }
+               It("check attachedRoutes and supportedkinds to gateway status", 
func() {
+                       By("check HTTPRoute/GRPCRoute attachedRoutes and 
supportedkinds to gateway status")
+                       s.ResourceApplied("HTTPRoute", "httpbin", 
fmt.Sprintf(httprouteSpec, "httpbin", s.Namespace()), 1)
+                       expectListenerAttachedRoutes("http", 1)
+                       for i := 0; i < 10; i++ {
+                               name := fmt.Sprintf("httpbin-%d", i)
+                               s.ResourceApplied("HTTPRoute", name, 
fmt.Sprintf(httprouteSpec, name, s.Namespace()), 1)
+                       }
+                       expectListenerAttachedRoutes("http", 11)
+                       for i := 0; i < 10; i++ {
+                               name := fmt.Sprintf("grcproute-%d", i)
+                               s.ResourceApplied("GRPCRoute", name, 
fmt.Sprintf(grpcrouteSpec, name, s.Namespace()), 1)
+                       }
+                       expectListenerAttachedRoutes("http", 21)
+
+                       listenner, err := getStatusLintener("http")
+                       Expect(err).NotTo(HaveOccurred(), "get http listener 
status")
+                       Expect(listenner.SupportedKinds).To(HaveLen(2), "http 
listener supported kinds length")
+                       Expect(listenner.SupportedKinds).To(ContainElements(
+                               gatewayv1.RouteGroupKind{
+                                       Group: 
ptr.To(gatewayv1.Group(gatewayv1.GroupName)),
+                                       Kind:  "HTTPRoute",
+                               },
+                               gatewayv1.RouteGroupKind{
+                                       Group: 
ptr.To(gatewayv1.Group(gatewayv1.GroupName)),
+                                       Kind:  "GRPCRoute",
+                               },
+                       ), "http listener supported kinds content")
+
+                       By("check TCPRoute attachedRoutes and supportedkinds to 
gateway status")
+                       name := "tcp-route"
+                       s.ResourceApplied("TCPRoute", name, 
fmt.Sprintf(tcpRouteSpec, name, s.Namespace()), 1)
+                       expectListenerAttachedRoutes("tcp", 1)
+                       for i := 0; i < 10; i++ {
+                               name := fmt.Sprintf("tcp-route-%d", i)
+                               s.ResourceApplied("TCPRoute", name, 
fmt.Sprintf(tcpRouteSpec, name, s.Namespace()), 1)
+                       }
+                       expectListenerAttachedRoutes("tcp", 11)
+                       getListener, err := getStatusLintener("tcp")
+                       Expect(err).NotTo(HaveOccurred(), "get tcp listener 
status")
+                       Expect(getListener.SupportedKinds).To(HaveLen(1), "tcp 
listener supported kinds length")
+                       
Expect(string(getListener.SupportedKinds[0].Kind)).To(Equal("TCPRoute"), "tcp 
listener supported kind content")
+
+                       By("check UDPRoute attachedRoutes and supportedkinds to 
gateway status")
+                       name = "udp-route"
+                       s.ResourceApplied("UDPRoute", name, 
fmt.Sprintf(udpRoute, name, s.Namespace(), dnsName, dnsPort), 1)
+                       expectListenerAttachedRoutes("udp", 1)
+                       for i := 0; i < 10; i++ {
+                               name := fmt.Sprintf("udp-route-%d", i)
+                               s.ResourceApplied("UDPRoute", name, 
fmt.Sprintf(udpRoute, name, s.Namespace(), dnsName, dnsPort), 1)
+                       }
+                       expectListenerAttachedRoutes("udp", 11)
+                       getListener, err = getStatusLintener("udp")
+                       Expect(err).NotTo(HaveOccurred(), "get udp listener 
status")
+                       Expect(getListener.SupportedKinds).To(HaveLen(1), "udp 
listener supported kinds length")
+                       
Expect(string(getListener.SupportedKinds[0].Kind)).To(Equal("UDPRoute"), "udp 
listener supported kind content")
+               })
+       })
 })
diff --git a/test/e2e/scaffold/k8s.go b/test/e2e/scaffold/k8s.go
index e99e4207..99fa57db 100644
--- a/test/e2e/scaffold/k8s.go
+++ b/test/e2e/scaffold/k8s.go
@@ -36,12 +36,16 @@ import (
        "github.com/stretchr/testify/require"
        corev1 "k8s.io/api/core/v1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/runtime"
        "k8s.io/apimachinery/pkg/types"
        "k8s.io/apimachinery/pkg/util/wait"
        "k8s.io/client-go/kubernetes"
+       "k8s.io/client-go/tools/clientcmd"
+       client "sigs.k8s.io/controller-runtime/pkg/client"
        gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
        "sigs.k8s.io/gateway-api/apis/v1alpha2"
 
+       apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
        "github.com/apache/apisix-ingress-controller/test/e2e/framework"
 )
 
@@ -366,3 +370,18 @@ func (s *Scaffold) SetupWebhookResources() error {
 
        return s.CreateResourceFromStringWithNamespace(buf.String(), "")
 }
+
+func (s *Scaffold) GetKubeClient() client.Client {
+       if s.client == nil {
+               scheme := runtime.NewScheme()
+               _ = apiv2.AddToScheme(scheme)
+               _ = corev1.AddToScheme(scheme)
+               _ = gatewayv1.Install(scheme)
+               _ = v1alpha2.Install(scheme)
+               cfg, err := clientcmd.BuildConfigFromFlags("", 
s.opts.Kubeconfig)
+               Expect(err).NotTo(HaveOccurred(), "building kubeconfig")
+               s.client, err = client.New(cfg, client.Options{Scheme: scheme})
+               Expect(err).NotTo(HaveOccurred(), "building controller-runtime 
client")
+       }
+       return s.client
+}
diff --git a/test/e2e/scaffold/scaffold.go b/test/e2e/scaffold/scaffold.go
index 432732ac..c23acd6a 100644
--- a/test/e2e/scaffold/scaffold.go
+++ b/test/e2e/scaffold/scaffold.go
@@ -34,6 +34,7 @@ import (
        . "github.com/onsi/gomega"    //nolint:staticcheck
        corev1 "k8s.io/api/core/v1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "sigs.k8s.io/controller-runtime/pkg/client"
 
        apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
        "github.com/apache/apisix-ingress-controller/test/e2e/framework"
@@ -74,6 +75,8 @@ type Scaffold struct {
 
        runtimeOpts Options
        Deployer    Deployer
+
+       client client.Client
 }
 
 type Tunnels struct {

Reply via email to