Skip to content

Commit f051302

Browse files
author
Kate Osborn
committed
Set Accepted condition type on Gateway status
1 parent e4cb606 commit f051302

18 files changed

+756
-511
lines changed

docs/gateway-api-compatibility.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,13 @@ Fields:
7171
* `name` - supported.
7272
* `supportedKinds` - not supported.
7373
* `attachedRoutes` - supported.
74-
* `conditions` - partially supported.
74+
* `conditions` - Supported (Condition/Status/Reason):
75+
* `Accepted/True/Accepted`
76+
* `Accepted/True/ListenersNotValid`
77+
* `Accepted/False/Invalid`
78+
* `Accepted/False/ListenersNotValid`
79+
* `Accepted/False/UnsupportedValue`: Custom reason for when a value of a field in a Gateway is invalid or not supported.
80+
* `Accepted/False/GatewayConflict`: Custom reason for when the Gateway is ignored due to a conflicting Gateway. NKG only supports a single Gateway.
7581

7682
### HTTPRoute
7783

internal/state/change_processor_test.go

+158-178
Large diffs are not rendered by default.

internal/state/conditions/conditions.go

+161-78
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,32 @@ import (
88
)
99

1010
const (
11-
// RouteReasonInvalidListener is used with the "Accepted" condition when the Route references an invalid listener.
12-
RouteReasonInvalidListener v1beta1.RouteConditionReason = "InvalidListener"
13-
1411
// ListenerReasonUnsupportedValue is used with the "Accepted" condition when a value of a field in a Listener
1512
// is invalid or not supported.
1613
ListenerReasonUnsupportedValue v1beta1.ListenerConditionReason = "UnsupportedValue"
1714

18-
// ListenerReasonNoValidGatewayClass is used with the "Accepted" condition when there is no valid GatewayClass
19-
// in the cluster.
20-
ListenerReasonNoValidGatewayClass v1beta1.ListenerConditionReason = "NoValidGatewayClass"
21-
2215
// RouteReasonBackendRefUnsupportedValue is used with the "ResolvedRefs" condition when one of the
2316
// Route rules has a backendRef with an unsupported value.
2417
RouteReasonBackendRefUnsupportedValue = "UnsupportedValue"
18+
19+
// RouteReasonInvalidGateway is used with the "Accepted" (false) condition when the Gateway the Route
20+
// references is invalid.
21+
RouteReasonInvalidGateway = "InvalidGateway"
22+
23+
// RouteReasonInvalidListener is used with the "Accepted" condition when the Route references an invalid listener.
24+
RouteReasonInvalidListener v1beta1.RouteConditionReason = "InvalidListener"
25+
26+
// GatewayReasonGatewayConflict indicates there are multiple Gateway resources to choose from,
27+
// and we ignored the resource in question and picked another Gateway as the winner.
28+
// This reason is used with GatewayConditionAccepted (false).
29+
GatewayReasonGatewayConflict v1beta1.GatewayConditionReason = "GatewayConflict"
30+
31+
// GatewayMessageGatewayConflict is message that describes GatewayReasonGatewayConflict.
32+
GatewayMessageGatewayConflict = "The resource is ignored due to a conflicting Gateway resource"
33+
34+
// GatewayReasonUnsupportedValue is used with GatewayConditionAccepted (false) when a value of a field in a Gateway
35+
// is invalid or not supported.
36+
GatewayReasonUnsupportedValue v1beta1.GatewayConditionReason = "UnsupportedValue"
2537
)
2638

2739
// Condition defines a condition to be reported in the status of resources.
@@ -64,6 +76,16 @@ func DeduplicateConditions(conds []Condition) []Condition {
6476
return result
6577
}
6678

79+
// NewTODO returns a Condition that can be used as a placeholder for a condition that is not yet implemented.
80+
func NewTODO(msg string) Condition {
81+
return Condition{
82+
Type: "TODO",
83+
Status: metav1.ConditionTrue,
84+
Reason: "TODO",
85+
Message: fmt.Sprintf("The condition for this has not been implemented yet: %s", msg),
86+
}
87+
}
88+
6789
// NewDefaultRouteConditions returns the default conditions that must be present in the status of an HTTPRoute.
6890
func NewDefaultRouteConditions() []Condition {
6991
return []Condition{
@@ -103,16 +125,6 @@ func NewRouteUnsupportedValue(msg string) Condition {
103125
}
104126
}
105127

106-
// NewTODO returns a Condition that can be used as a placeholder for a condition that is not yet implemented.
107-
func NewTODO(msg string) Condition {
108-
return Condition{
109-
Type: "TODO",
110-
Status: metav1.ConditionTrue,
111-
Reason: "TODO",
112-
Message: fmt.Sprintf("The condition for this has not been implemented yet: %s", msg),
113-
}
114-
}
115-
116128
// NewRouteInvalidListener returns a Condition that indicates that the HTTPRoute is not accepted because of an
117129
// invalid listener.
118130
func NewRouteInvalidListener() Condition {
@@ -124,6 +136,80 @@ func NewRouteInvalidListener() Condition {
124136
}
125137
}
126138

139+
// NewRouteResolvedRefs returns a Condition that indicates that all the references on the Route are resolved.
140+
func NewRouteResolvedRefs() Condition {
141+
return Condition{
142+
Type: string(v1beta1.RouteConditionResolvedRefs),
143+
Status: metav1.ConditionTrue,
144+
Reason: string(v1beta1.RouteReasonResolvedRefs),
145+
Message: "All references are resolved",
146+
}
147+
}
148+
149+
// NewRouteBackendRefInvalidKind returns a Condition that indicates that the Route has a backendRef with an
150+
// invalid kind.
151+
func NewRouteBackendRefInvalidKind(msg string) Condition {
152+
return Condition{
153+
Type: string(v1beta1.RouteConditionResolvedRefs),
154+
Status: metav1.ConditionFalse,
155+
Reason: string(v1beta1.RouteReasonInvalidKind),
156+
Message: msg,
157+
}
158+
}
159+
160+
// NewRouteBackendRefRefNotPermitted returns a Condition that indicates that the Route has a backendRef that
161+
// is not permitted.
162+
func NewRouteBackendRefRefNotPermitted(msg string) Condition {
163+
return Condition{
164+
Type: string(v1beta1.RouteConditionResolvedRefs),
165+
Status: metav1.ConditionFalse,
166+
Reason: string(v1beta1.RouteReasonRefNotPermitted),
167+
Message: msg,
168+
}
169+
}
170+
171+
// NewRouteBackendRefRefBackendNotFound returns a Condition that indicates that the Route has a backendRef that
172+
// points to non-existing backend.
173+
func NewRouteBackendRefRefBackendNotFound(msg string) Condition {
174+
return Condition{
175+
Type: string(v1beta1.RouteConditionResolvedRefs),
176+
Status: metav1.ConditionFalse,
177+
Reason: string(v1beta1.RouteReasonBackendNotFound),
178+
Message: msg,
179+
}
180+
}
181+
182+
// NewRouteBackendRefUnsupportedValue returns a Condition that indicates that the Route has a backendRef with
183+
// an unsupported value.
184+
func NewRouteBackendRefUnsupportedValue(msg string) Condition {
185+
return Condition{
186+
Type: string(v1beta1.RouteConditionResolvedRefs),
187+
Status: metav1.ConditionFalse,
188+
Reason: RouteReasonBackendRefUnsupportedValue,
189+
Message: msg,
190+
}
191+
}
192+
193+
// NewRouteInvalidGateway returns a Condition that indicates that the Route is not Accepted because the Gateway it
194+
// references is invalid.
195+
func NewRouteInvalidGateway() Condition {
196+
return Condition{
197+
Type: string(v1beta1.RouteConditionAccepted),
198+
Status: metav1.ConditionFalse,
199+
Reason: RouteReasonInvalidGateway,
200+
Message: "Gateway is invalid",
201+
}
202+
}
203+
204+
// NewDefaultListenerConditions returns the default Conditions that must be present in the status of a Listener.
205+
func NewDefaultListenerConditions() []Condition {
206+
return []Condition{
207+
NewListenerAccepted(),
208+
NewListenerResolvedRefs(),
209+
NewListenerNoConflicts(),
210+
}
211+
}
212+
127213
// NewListenerPortUnavailable returns a Condition that indicates a port is unavailable in a Listener.
128214
func NewListenerPortUnavailable(msg string) Condition {
129215
return Condition{
@@ -164,15 +250,6 @@ func NewListenerNoConflicts() Condition {
164250
}
165251
}
166252

167-
// NewDefaultListenerConditions returns the default Conditions that must be present in the status of a Listener.
168-
func NewDefaultListenerConditions() []Condition {
169-
return []Condition{
170-
NewListenerAccepted(),
171-
NewListenerResolvedRefs(),
172-
NewListenerNoConflicts(),
173-
}
174-
}
175-
176253
// NewListenerUnsupportedValue returns a Condition that indicates that a field of a Listener has an unsupported value.
177254
// Unsupported means that the value is not supported by the implementation or invalid.
178255
func NewListenerUnsupportedValue(msg string) Condition {
@@ -230,89 +307,95 @@ func NewListenerUnsupportedProtocol(msg string) Condition {
230307
}
231308
}
232309

233-
// NewListenerNoValidGatewayClass returns a Condition that indicates that the Listener is not accepted because
234-
// there is no valid GatewayClass.
235-
func NewListenerNoValidGatewayClass(msg string) Condition {
236-
return Condition{
237-
Type: string(v1beta1.ListenerConditionAccepted),
238-
Status: metav1.ConditionFalse,
239-
Reason: string(ListenerReasonNoValidGatewayClass),
240-
Message: msg,
310+
// NewDefaultGatewayClassConditions returns the default Conditions that must be present in the status of a GatewayClass.
311+
func NewDefaultGatewayClassConditions() []Condition {
312+
return []Condition{
313+
{
314+
Type: string(v1beta1.GatewayClassConditionStatusAccepted),
315+
Status: metav1.ConditionTrue,
316+
Reason: string(v1beta1.GatewayClassReasonAccepted),
317+
Message: "GatewayClass is accepted",
318+
},
241319
}
242320
}
243321

244-
// NewRouteBackendRefInvalidKind returns a Condition that indicates that the Route has a backendRef with an
245-
// invalid kind.
246-
func NewRouteBackendRefInvalidKind(msg string) Condition {
322+
// NewGatewayClassInvalidParameters returns a Condition that indicates that the GatewayClass has invalid parameters.
323+
func NewGatewayClassInvalidParameters(msg string) Condition {
247324
return Condition{
248-
Type: string(v1beta1.RouteConditionResolvedRefs),
325+
Type: string(v1beta1.GatewayClassConditionStatusAccepted),
249326
Status: metav1.ConditionFalse,
250-
Reason: string(v1beta1.RouteReasonInvalidKind),
327+
Reason: string(v1beta1.GatewayClassReasonInvalidParameters),
251328
Message: msg,
252329
}
253330
}
254331

255-
// NewRouteBackendRefRefNotPermitted returns a Condition that indicates that the Route has a backendRef that
256-
// is not permitted.
257-
func NewRouteBackendRefRefNotPermitted(msg string) Condition {
258-
return Condition{
259-
Type: string(v1beta1.RouteConditionResolvedRefs),
260-
Status: metav1.ConditionFalse,
261-
Reason: string(v1beta1.RouteReasonRefNotPermitted),
262-
Message: msg,
332+
// NewDefaultGatewayConditions returns the default Condition that must be present in the status of a Gateway.
333+
func NewDefaultGatewayConditions() []Condition {
334+
return []Condition{
335+
NewGatewayAccepted(),
263336
}
264337
}
265338

266-
// NewRouteBackendRefRefBackendNotFound returns a Condition that indicates that the Route has a backendRef that
267-
// points to non-existing backend.
268-
func NewRouteBackendRefRefBackendNotFound(msg string) Condition {
339+
// NewGatewayAccepted returns a Condition that indicates the Gateway is accepted.
340+
func NewGatewayAccepted() Condition {
269341
return Condition{
270-
Type: string(v1beta1.RouteConditionResolvedRefs),
271-
Status: metav1.ConditionFalse,
272-
Reason: string(v1beta1.RouteReasonBackendNotFound),
273-
Message: msg,
342+
Type: string(v1beta1.GatewayConditionAccepted),
343+
Status: metav1.ConditionTrue,
344+
Reason: string(v1beta1.GatewayReasonAccepted),
345+
Message: "Gateway is accepted",
274346
}
275347
}
276348

277-
// NewRouteBackendRefUnsupportedValue returns a Condition that indicates that the Route has a backendRef with
278-
// an unsupported value.
279-
func NewRouteBackendRefUnsupportedValue(msg string) Condition {
349+
// NewGatewayConflict returns a Condition that indicates the Gateway has a conflict with another Gateway.
350+
func NewGatewayConflict() Condition {
280351
return Condition{
281-
Type: string(v1beta1.RouteConditionResolvedRefs),
352+
Type: string(v1beta1.GatewayConditionAccepted),
282353
Status: metav1.ConditionFalse,
283-
Reason: RouteReasonBackendRefUnsupportedValue,
284-
Message: msg,
354+
Reason: string(GatewayReasonGatewayConflict),
355+
Message: GatewayMessageGatewayConflict,
285356
}
286357
}
287358

288-
// NewRouteResolvedRefs returns a Condition that indicates that all the references on the Route are resolved.
289-
func NewRouteResolvedRefs() Condition {
359+
// NewGatewayAcceptedListenersNotValid returns a Condition that indicates the Gateway is accepted,
360+
// but has at least one listener that is invalid.
361+
func NewGatewayAcceptedListenersNotValid() Condition {
290362
return Condition{
291-
Type: string(v1beta1.RouteConditionResolvedRefs),
363+
Type: string(v1beta1.GatewayConditionAccepted),
292364
Status: metav1.ConditionTrue,
293-
Reason: string(v1beta1.RouteReasonResolvedRefs),
294-
Message: "All references are resolved",
365+
Reason: string(v1beta1.GatewayReasonListenersNotValid),
366+
Message: "Gateway has at least one valid listener",
295367
}
296368
}
297369

298-
// NewGatewayClassInvalidParameters returns a Condition that indicates that the GatewayClass has invalid parameters.
299-
func NewGatewayClassInvalidParameters(msg string) Condition {
370+
// NewGatewayNotAcceptedListenersNotValid returns a Condition that indicates the Gateway is not accepted,
371+
// because all listeners are invalid.
372+
func NewGatewayNotAcceptedListenersNotValid() Condition {
300373
return Condition{
301-
Type: string(v1beta1.GatewayClassConditionStatusAccepted),
374+
Type: string(v1beta1.GatewayConditionAccepted),
302375
Status: metav1.ConditionFalse,
303-
Reason: string(v1beta1.GatewayClassReasonInvalidParameters),
376+
Reason: string(v1beta1.GatewayReasonListenersNotValid),
377+
Message: "Gateway has no valid listeners",
378+
}
379+
}
380+
381+
// NewGatewayInvalid returns a Condition that indicates the Gateway is not accepted because it is
382+
// semantically or syntactically invalid. The provided message contains the details of why the Gateway is invalid.
383+
func NewGatewayInvalid(msg string) Condition {
384+
return Condition{
385+
Type: string(v1beta1.GatewayConditionAccepted),
386+
Status: metav1.ConditionFalse,
387+
Reason: string(v1beta1.GatewayReasonInvalid),
304388
Message: msg,
305389
}
306390
}
307391

308-
// NewDefaultGatewayClassConditions returns the default Conditions that must be present in the status of a GatewayClass.
309-
func NewDefaultGatewayClassConditions() []Condition {
310-
return []Condition{
311-
{
312-
Type: string(v1beta1.GatewayClassConditionStatusAccepted),
313-
Status: metav1.ConditionTrue,
314-
Reason: string(v1beta1.GatewayClassReasonAccepted),
315-
Message: "GatewayClass is accepted",
316-
},
392+
// NewGatewayUnsupportedValue returns a Condition that indicates that a field of the Gateway has an unsupported value.
393+
// Unsupported means that the value is not supported by the implementation or invalid.
394+
func NewGatewayUnsupportedValue(msg string) Condition {
395+
return Condition{
396+
Type: string(v1beta1.GatewayConditionAccepted),
397+
Status: metav1.ConditionFalse,
398+
Reason: string(GatewayReasonUnsupportedValue),
399+
Message: msg,
317400
}
318401
}

internal/state/graph/gateway.go

+37-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import (
44
"sort"
55

66
"k8s.io/apimachinery/pkg/types"
7+
"k8s.io/apimachinery/pkg/util/validation/field"
78
"sigs.k8s.io/controller-runtime/pkg/client"
89
"sigs.k8s.io/gateway-api/apis/v1beta1"
910

1011
nkgsort "github.com/nginxinc/nginx-kubernetes-gateway/internal/sort"
12+
"github.com/nginxinc/nginx-kubernetes-gateway/internal/state/conditions"
1113
"github.com/nginxinc/nginx-kubernetes-gateway/internal/state/secrets"
1214
)
1315

@@ -17,6 +19,10 @@ type Gateway struct {
1719
Source *v1beta1.Gateway
1820
// Listeners include the listeners of the Gateway.
1921
Listeners map[string]*Listener
22+
// Conditions holds the conditions for the Gateway.
23+
Conditions []conditions.Condition
24+
// Valid indicates whether the Gateway Spec is valid.
25+
Valid bool
2026
}
2127

2228
// processedGateways holds the resources that belong to NKG.
@@ -89,8 +95,38 @@ func buildGateway(gw *v1beta1.Gateway, secretMemoryMgr secrets.SecretDiskMemoryM
8995
return nil
9096
}
9197

98+
conds := validateGateway(gw, gc)
99+
100+
if len(conds) > 0 {
101+
return &Gateway{
102+
Source: gw,
103+
Valid: false,
104+
Conditions: conds,
105+
}
106+
}
107+
92108
return &Gateway{
93109
Source: gw,
94-
Listeners: buildListeners(gw, secretMemoryMgr, gc),
110+
Listeners: buildListeners(gw, secretMemoryMgr),
111+
Valid: true,
112+
}
113+
}
114+
115+
func validateGateway(gw *v1beta1.Gateway, gc *GatewayClass) []conditions.Condition {
116+
var conds []conditions.Condition
117+
118+
if gc == nil {
119+
conds = append(conds, conditions.NewGatewayInvalid("GatewayClass doesn't exist"))
120+
} else if !gc.Valid {
121+
conds = append(conds, conditions.NewGatewayInvalid("GatewayClass is invalid"))
122+
}
123+
124+
if len(gw.Spec.Addresses) > 0 {
125+
path := field.NewPath("spec", "addresses")
126+
valErr := field.Forbidden(path, "addresses are not supported")
127+
128+
conds = append(conds, conditions.NewGatewayUnsupportedValue(valErr.Error()))
95129
}
130+
131+
return conds
96132
}

0 commit comments

Comments
 (0)