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 {