Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 29 additions & 24 deletions internal/controller/gateway_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"context"
"errors"
"fmt"
"reflect"

"github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1"
Expand All @@ -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"
Expand Down Expand Up @@ -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(
Expand All @@ -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{},
Expand Down Expand Up @@ -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
Expand All @@ -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) {
Expand Down
159 changes: 108 additions & 51 deletions internal/controller/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ func ParseRouteParentRefs(
}
}

if !routeMatchesListenerType(route, listener) {
if ok, _ := routeMatchesListenerType(route, listener); !ok {
continue
}

Expand Down Expand Up @@ -485,8 +485,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
Expand Down Expand Up @@ -659,71 +659,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,
Expand All @@ -739,13 +763,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 {
Expand Down Expand Up @@ -786,10 +826,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 {
Expand All @@ -799,7 +864,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
Expand Down Expand Up @@ -902,17 +967,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)
}

Expand Down
Loading