Skip to content

Commit 31a6c4b

Browse files
committed
fix status route status overwrite
1 parent edfaa62 commit 31a6c4b

12 files changed

+196
-84
lines changed

config/crd/bases/elbv2.k8s.aws_ingressclassparams.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ spec:
1111
kind: IngressClassParams
1212
listKind: IngressClassParamsList
1313
plural: ingressclassparams
14-
singular: ingressclassparam
14+
singular: ingressclassparams
1515
scope: Cluster
1616
versions:
1717
- additionalPrinterColumns:

pkg/gateway/routeutils/listener_attachment_helper.go

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
// listenerAttachmentHelper is an internal utility interface that can be used to determine if a listener will allow
1515
// a route to attach to it.
1616
type listenerAttachmentHelper interface {
17-
listenerAllowsAttachment(ctx context.Context, gw gwv1.Gateway, listener gwv1.Listener, route preLoadRouteDescriptor, deferredRouteReconciler RouteReconcilerSubmitter, hostnamesFromHttpRoutes map[types.NamespacedName][]gwv1.Hostname, hostnamesFromGrpcRoutes map[types.NamespacedName][]gwv1.Hostname) (bool, error)
17+
listenerAllowsAttachment(ctx context.Context, gw gwv1.Gateway, listener gwv1.Listener, route preLoadRouteDescriptor, hostnamesFromHttpRoutes map[types.NamespacedName][]gwv1.Hostname, hostnamesFromGrpcRoutes map[types.NamespacedName][]gwv1.Hostname) (bool, *RouteData, error)
1818
}
1919

2020
var _ listenerAttachmentHelper = &listenerAttachmentHelperImpl{}
@@ -34,40 +34,33 @@ func newListenerAttachmentHelper(k8sClient client.Client, logger logr.Logger) li
3434

3535
// listenerAllowsAttachment utility method to determine if a listener will allow a route to connect using
3636
// Gateway API rules to determine compatibility between lister and route.
37-
func (attachmentHelper *listenerAttachmentHelperImpl) listenerAllowsAttachment(ctx context.Context, gw gwv1.Gateway, listener gwv1.Listener, route preLoadRouteDescriptor, deferredRouteReconciler RouteReconcilerSubmitter, hostnamesFromHttpRoutes map[types.NamespacedName][]gwv1.Hostname, hostnamesFromGrpcRoutes map[types.NamespacedName][]gwv1.Hostname) (bool, error) {
37+
func (attachmentHelper *listenerAttachmentHelperImpl) listenerAllowsAttachment(ctx context.Context, gw gwv1.Gateway, listener gwv1.Listener, route preLoadRouteDescriptor, hostnamesFromHttpRoutes map[types.NamespacedName][]gwv1.Hostname, hostnamesFromGrpcRoutes map[types.NamespacedName][]gwv1.Hostname) (bool, *RouteData, error) {
3838
// check namespace
3939
namespaceOK, err := attachmentHelper.namespaceCheck(ctx, gw, listener, route)
4040
if err != nil {
41-
return false, err
41+
return false, nil, err
4242
}
4343
if !namespaceOK {
44-
deferredRouteReconciler.Enqueue(
45-
GenerateRouteData(false, true, string(gwv1.RouteReasonNotAllowedByListeners), RouteStatusInfoRejectedMessageNamespaceNotMatch, route.GetRouteNamespacedName(), route.GetRouteKind(), route.GetRouteGeneration(), gw),
46-
)
47-
48-
return false, nil
44+
rd := GenerateRouteData(false, true, string(gwv1.RouteReasonNotAllowedByListeners), RouteStatusInfoRejectedMessageNamespaceNotMatch, route.GetRouteNamespacedName(), route.GetRouteKind(), route.GetRouteGeneration(), gw)
45+
return false, &rd, nil
4946
}
5047

5148
// check kind
5249
kindOK := attachmentHelper.kindCheck(listener, route)
5350
if !kindOK {
54-
deferredRouteReconciler.Enqueue(
55-
GenerateRouteData(false, true, string(gwv1.RouteReasonNotAllowedByListeners), RouteStatusInfoRejectedMessageKindNotMatch, route.GetRouteNamespacedName(), route.GetRouteKind(), route.GetRouteGeneration(), gw),
56-
)
57-
return false, nil
51+
rd := GenerateRouteData(false, true, string(gwv1.RouteReasonNotAllowedByListeners), RouteStatusInfoRejectedMessageKindNotMatch, route.GetRouteNamespacedName(), route.GetRouteKind(), route.GetRouteGeneration(), gw)
52+
return false, &rd, nil
5853
}
5954

6055
// check hostname
6156
if (route.GetRouteKind() == HTTPRouteKind || route.GetRouteKind() == GRPCRouteKind || route.GetRouteKind() == TLSRouteKind) && route.GetHostnames() != nil {
6257
hostnameOK, err := attachmentHelper.hostnameCheck(listener, route)
6358
if err != nil {
64-
return false, err
59+
return false, nil, err
6560
}
6661
if !hostnameOK {
67-
deferredRouteReconciler.Enqueue(
68-
GenerateRouteData(false, true, string(gwv1.RouteReasonNoMatchingListenerHostname), RouteStatusInfoRejectedMessageNoMatchingHostname, route.GetRouteNamespacedName(), route.GetRouteKind(), route.GetRouteGeneration(), gw),
69-
)
70-
return false, nil
62+
rd := GenerateRouteData(false, true, string(gwv1.RouteReasonNoMatchingListenerHostname), RouteStatusInfoRejectedMessageNoMatchingHostname, route.GetRouteNamespacedName(), route.GetRouteKind(), route.GetRouteGeneration(), gw)
63+
return false, &rd, nil
7164
}
7265
}
7366

@@ -76,14 +69,12 @@ func (attachmentHelper *listenerAttachmentHelperImpl) listenerAllowsAttachment(c
7669
hostnameUniquenessOK, conflictRoute := attachmentHelper.crossServingHostnameUniquenessCheck(route, hostnamesFromHttpRoutes, hostnamesFromGrpcRoutes)
7770
if !hostnameUniquenessOK {
7871
message := fmt.Sprintf("HTTPRoute and GRPCRoute have overlap hostname, attachment is rejected. Conflict route: %s", conflictRoute)
79-
deferredRouteReconciler.Enqueue(
80-
GenerateRouteData(false, true, string(gwv1.RouteReasonNotAllowedByListeners), message, route.GetRouteNamespacedName(), route.GetRouteKind(), route.GetRouteGeneration(), gw),
81-
)
82-
return false, nil
72+
rd := GenerateRouteData(false, true, string(gwv1.RouteReasonNotAllowedByListeners), message, route.GetRouteNamespacedName(), route.GetRouteKind(), route.GetRouteGeneration(), gw)
73+
return false, &rd, nil
8374
}
8475
}
8576

86-
return true, nil
77+
return true, nil, nil
8778
}
8879

8980
// namespaceCheck namespace check implements the Gateway API spec for namespace matching between listener

pkg/gateway/routeutils/listener_attachment_helper_test.go

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,19 @@ func (mnss *mockNamespaceSelector) getNamespacesFromSelector(_ context.Context,
2222
}
2323

2424
func Test_listenerAllowsAttachment(t *testing.T) {
25+
26+
type expectedRouteStatus struct {
27+
reason string
28+
message string
29+
}
30+
2531
testCases := []struct {
26-
name string
27-
gwNamespace string
28-
routeNamespace string
29-
listenerProtocol gwv1.ProtocolType
30-
expected bool
32+
name string
33+
gwNamespace string
34+
routeNamespace string
35+
listenerProtocol gwv1.ProtocolType
36+
expectedStatusUpdate *expectedRouteStatus
37+
expected bool
3138
}{
3239
{
3340
name: "namespace and kind are ok",
@@ -41,12 +48,20 @@ func Test_listenerAllowsAttachment(t *testing.T) {
4148
gwNamespace: "ns1",
4249
routeNamespace: "ns2",
4350
listenerProtocol: gwv1.HTTPProtocolType,
51+
expectedStatusUpdate: &expectedRouteStatus{
52+
reason: string(gwv1.RouteReasonNotAllowedByListeners),
53+
message: RouteStatusInfoRejectedMessageNamespaceNotMatch,
54+
},
4455
},
4556
{
4657
name: "kind is not ok",
4758
gwNamespace: "ns1",
4859
routeNamespace: "ns1",
4960
listenerProtocol: gwv1.TLSProtocolType,
61+
expectedStatusUpdate: &expectedRouteStatus{
62+
reason: string(gwv1.RouteReasonNotAllowedByListeners),
63+
message: RouteStatusInfoRejectedMessageKindNotMatch,
64+
},
5065
},
5166
}
5267

@@ -72,12 +87,22 @@ func Test_listenerAllowsAttachment(t *testing.T) {
7287
}
7388
hostnameFromHttpRoute := map[types.NamespacedName][]gwv1.Hostname{}
7489
hostnameFromGrpcRoute := map[types.NamespacedName][]gwv1.Hostname{}
75-
mockReconciler := NewMockRouteReconciler()
76-
result, err := attachmentHelper.listenerAllowsAttachment(context.Background(), gw, gwv1.Listener{
90+
result, statusUpdate, err := attachmentHelper.listenerAllowsAttachment(context.Background(), gw, gwv1.Listener{
7791
Protocol: tc.listenerProtocol,
78-
}, route, mockReconciler, hostnameFromHttpRoute, hostnameFromGrpcRoute)
92+
}, route, hostnameFromHttpRoute, hostnameFromGrpcRoute)
7993
assert.NoError(t, err)
8094
assert.Equal(t, tc.expected, result)
95+
if tc.expectedStatusUpdate == nil {
96+
assert.Nil(t, statusUpdate)
97+
} else {
98+
assert.NotNil(t, statusUpdate)
99+
assert.Equal(t, gw.Name, statusUpdate.ParentRefGateway.Name)
100+
assert.Equal(t, gw.Namespace, statusUpdate.ParentRefGateway.Namespace)
101+
assert.Equal(t, route.GetRouteNamespacedName().Name, statusUpdate.RouteMetadata.RouteName)
102+
assert.Equal(t, route.GetRouteNamespacedName().Namespace, statusUpdate.RouteMetadata.RouteNamespace)
103+
assert.Equal(t, tc.expectedStatusUpdate.message, statusUpdate.RouteStatusInfo.Message)
104+
assert.Equal(t, tc.expectedStatusUpdate.reason, statusUpdate.RouteStatusInfo.Reason)
105+
}
81106
})
82107
}
83108
}

pkg/gateway/routeutils/loader.go

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,23 @@ func (l *loaderImpl) LoadRoutesForGateway(ctx context.Context, gw gwv1.Gateway,
7676
// 1. Load all relevant routes according to the filter
7777

7878
loadedRoutes := make([]preLoadRouteDescriptor, 0)
79+
80+
routeStatusUpdates := make([]RouteData, 0)
81+
82+
defer func() {
83+
seenCache := sets.NewString()
84+
// As we process the failures first, we ensure that we don't flip flop the route status from
85+
// failed -> ok.
86+
for _, v := range routeStatusUpdates {
87+
k := generateRouteDataCacheKey(v)
88+
if seenCache.Has(k) {
89+
continue
90+
}
91+
seenCache.Insert(k)
92+
l.routeSubmitter.Enqueue(v)
93+
}
94+
}()
95+
7996
for route, loader := range l.allRouteLoaders {
8097
applicable := filter.IsApplicable(route)
8198
l.logger.V(1).Info("Processing route", "route", route, "is applicable", applicable)
@@ -90,35 +107,37 @@ func (l *loaderImpl) LoadRoutesForGateway(ctx context.Context, gw gwv1.Gateway,
90107

91108
// 2. Remove routes that aren't granted attachment by the listener.
92109
// Map any routes that are granted attachment to the listener port that allows the attachment.
93-
mappedRoutes, err := l.mapper.mapGatewayAndRoutes(ctx, gw, loadedRoutes, l.routeSubmitter)
110+
mappedRoutes, statusUpdates, err := l.mapper.mapGatewayAndRoutes(ctx, gw, loadedRoutes)
111+
112+
routeStatusUpdates = append(routeStatusUpdates, statusUpdates...)
113+
94114
if err != nil {
95115
return nil, err
96116
}
97117

98118
// 3. Load the underlying resource(s) for each route that is configured.
99-
loadedRoute, err := l.loadChildResources(ctx, mappedRoutes, gw)
119+
loadedRoute, childRouteLoadUpdates, err := l.loadChildResources(ctx, mappedRoutes, gw)
120+
routeStatusUpdates = append(routeStatusUpdates, childRouteLoadUpdates...)
100121
if err != nil {
101122
return nil, err
102123
}
103124

104125
// update status for accepted routes
105126
for _, routeList := range loadedRoute {
106127
for _, route := range routeList {
107-
l.routeSubmitter.Enqueue(
108-
GenerateRouteData(true, true, string(gwv1.RouteConditionAccepted), RouteStatusInfoAcceptedMessage, route.GetRouteNamespacedName(), route.GetRouteKind(), route.GetRouteGeneration(), gw),
109-
)
128+
routeStatusUpdates = append(routeStatusUpdates, GenerateRouteData(true, true, string(gwv1.RouteConditionAccepted), RouteStatusInfoAcceptedMessage, route.GetRouteNamespacedName(), route.GetRouteKind(), route.GetRouteGeneration(), gw))
110129
}
111130
}
112131
return loadedRoute, nil
113132
}
114133

115134
// loadChildResources responsible for loading all resources that a route descriptor references.
116-
func (l *loaderImpl) loadChildResources(ctx context.Context, preloadedRoutes map[int][]preLoadRouteDescriptor, gw gwv1.Gateway) (map[int32][]RouteDescriptor, error) {
135+
func (l *loaderImpl) loadChildResources(ctx context.Context, preloadedRoutes map[int][]preLoadRouteDescriptor, gw gwv1.Gateway) (map[int32][]RouteDescriptor, []RouteData, error) {
117136
// Cache to reduce duplicate route lookups.
118137
// Kind -> [NamespacedName:Previously Loaded Descriptor]
119138
resourceCache := make(map[string]RouteDescriptor)
120-
121139
loadedRouteData := make(map[int32][]RouteDescriptor)
140+
failedRoutes := make([]RouteData, 0)
122141

123142
for port, preloadedRouteList := range preloadedRoutes {
124143
for _, preloadedRoute := range preloadedRouteList {
@@ -137,12 +156,10 @@ func (l *loaderImpl) loadChildResources(ctx context.Context, preloadedRoutes map
137156
for _, lare := range loadAttachedRulesErrors {
138157
var loaderErr LoaderError
139158
if errors.As(lare.Err, &loaderErr) {
140-
l.routeSubmitter.Enqueue(
141-
GenerateRouteData(false, false, string(loaderErr.GetRouteReason()), loaderErr.GetRouteMessage(), preloadedRoute.GetRouteNamespacedName(), preloadedRoute.GetRouteKind(), preloadedRoute.GetRouteGeneration(), gw),
142-
)
159+
failedRoutes = append(failedRoutes, GenerateRouteData(false, false, string(loaderErr.GetRouteReason()), loaderErr.GetRouteMessage(), preloadedRoute.GetRouteNamespacedName(), preloadedRoute.GetRouteKind(), preloadedRoute.GetRouteGeneration(), gw))
143160
}
144161
if lare.Fatal {
145-
return nil, lare.Err
162+
return nil, failedRoutes, lare.Err
146163
}
147164
}
148165
}
@@ -151,5 +168,9 @@ func (l *loaderImpl) loadChildResources(ctx context.Context, preloadedRoutes map
151168
}
152169
}
153170

154-
return loadedRouteData, nil
171+
return loadedRouteData, failedRoutes, nil
172+
}
173+
174+
func generateRouteDataCacheKey(rd RouteData) string {
175+
return fmt.Sprintf("%s-%s-%s-%s-%s", rd.RouteMetadata.RouteName, rd.RouteMetadata.RouteNamespace, rd.RouteMetadata.RouteKind, rd.ParentRefGateway.Name, rd.ParentRefGateway.Namespace)
155176
}

0 commit comments

Comments
 (0)