Skip to content

Commit a6bc92f

Browse files
authored
Merge branch 'main' into feat/pipeline-certfication-testing
2 parents 8abbf61 + 1bfa2e9 commit a6bc92f

File tree

8 files changed

+697
-4
lines changed

8 files changed

+697
-4
lines changed

internal/controller/state/conditions/conditions.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ const (
3838
// Route rules has a backendRef with an unsupported value.
3939
RouteReasonBackendRefUnsupportedValue v1.RouteConditionReason = "UnsupportedValue"
4040

41+
// RouteReasonUnsupportedField is used with the "Accepted" condition when a Route contains fields that are
42+
// not yet supported.
43+
RouteReasonUnsupportedField v1.RouteConditionReason = "UnsupportedField"
44+
4145
// RouteReasonInvalidGateway is used with the "Accepted" (false) condition when the Gateway the Route
4246
// references is invalid.
4347
RouteReasonInvalidGateway v1.RouteConditionReason = "InvalidGateway"
@@ -62,6 +66,10 @@ const (
6266
// invalid. Used with ResolvedRefs (false).
6367
RouteReasonInvalidFilter v1.RouteConditionReason = "InvalidFilter"
6468

69+
// GatewayReasonUnsupportedField is used with the "Accepted" condition when a Gateway contains fields
70+
// that are not yet supported.
71+
GatewayReasonUnsupportedField v1.GatewayConditionReason = "UnsupportedField"
72+
6573
// GatewayReasonUnsupportedValue is used with GatewayConditionAccepted (false) when a value of a field in a Gateway
6674
// is invalid or not supported.
6775
GatewayReasonUnsupportedValue v1.GatewayConditionReason = "UnsupportedValue"
@@ -354,6 +362,17 @@ func NewRouteUnsupportedValue(msg string) Condition {
354362
}
355363
}
356364

365+
// NewRouteAcceptedUnsupportedField returns a Condition that indicates that the Route is accepted but
366+
// includes an unsupported field.
367+
func NewRouteAcceptedUnsupportedField(msg string) Condition {
368+
return Condition{
369+
Type: string(v1.RouteConditionAccepted),
370+
Status: metav1.ConditionTrue,
371+
Reason: string(RouteReasonUnsupportedField),
372+
Message: fmt.Sprintf("The following unsupported parameters were ignored: %s", msg),
373+
}
374+
}
375+
357376
// NewRoutePartiallyInvalid returns a Condition that indicates that the Route contains a combination
358377
// of both valid and invalid rules.
359378
//
@@ -945,6 +964,17 @@ func NewGatewayInvalidParameters(msg string) Condition {
945964
}
946965
}
947966

967+
// NewGatewayAcceptedUnsupportedField returns a Condition that indicates the Gateway is accepted but
968+
// contains a field that is not supported.
969+
func NewGatewayAcceptedUnsupportedField(msg string) Condition {
970+
return Condition{
971+
Type: string(v1.GatewayConditionAccepted),
972+
Status: metav1.ConditionTrue,
973+
Reason: string(GatewayReasonUnsupportedField),
974+
Message: fmt.Sprintf("Gateway accepted but the following unsupported parameters were ignored: %s", msg),
975+
}
976+
}
977+
948978
// NewPolicyAccepted returns a Condition that indicates that the Policy is accepted.
949979
func NewPolicyAccepted() Condition {
950980
return Condition{

internal/controller/state/graph/gateway.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ func validateGateway(gw *v1.Gateway, gc *GatewayClass, npCfg *NginxProxy) ([]con
193193
// invalidate the entire Gateway.
194194
valid := len(conds) == 0
195195

196+
// Validate unsupported fields - these are warnings, don't affect validity
197+
conds = append(conds, validateUnsupportedGatewayFields(gw)...)
198+
196199
if gw.Spec.Infrastructure != nil && gw.Spec.Infrastructure.ParametersRef != nil {
197200
paramConds := validateGatewayParametersRef(npCfg, *gw.Spec.Infrastructure.ParametersRef)
198201
conds = append(conds, paramConds...)
@@ -267,3 +270,17 @@ func (g *Gateway) collectSnippetsFiltersFromRoute(
267270
}
268271
}
269272
}
273+
274+
func validateUnsupportedGatewayFields(gw *v1.Gateway) []conditions.Condition {
275+
var conds []conditions.Condition
276+
277+
if gw.Spec.AllowedListeners != nil {
278+
conds = append(conds, conditions.NewGatewayAcceptedUnsupportedField("AllowedListeners"))
279+
}
280+
281+
if gw.Spec.BackendTLS != nil {
282+
conds = append(conds, conditions.NewGatewayAcceptedUnsupportedField("BackendTLS"))
283+
}
284+
285+
return conds
286+
}

internal/controller/state/graph/gateway_test.go

Lines changed: 157 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,10 +286,12 @@ func TestBuildGateway(t *testing.T) {
286286
)
287287

288288
type gatewayCfg struct {
289-
name string
290-
ref *v1.LocalParametersReference
291-
listeners []v1.Listener
292-
addresses []v1.GatewaySpecAddress
289+
ref *v1.LocalParametersReference
290+
allowedListeners *v1.AllowedListeners
291+
backendTLS *v1.GatewayBackendTLS
292+
name string
293+
listeners []v1.Listener
294+
addresses []v1.GatewaySpecAddress
293295
}
294296

295297
var lastCreatedGateway *v1.Gateway
@@ -304,6 +306,8 @@ func TestBuildGateway(t *testing.T) {
304306
GatewayClassName: gcName,
305307
Listeners: cfg.listeners,
306308
Addresses: cfg.addresses,
309+
AllowedListeners: cfg.allowedListeners,
310+
BackendTLS: cfg.backendTLS,
307311
},
308312
}
309313

@@ -1513,6 +1517,103 @@ func TestBuildGateway(t *testing.T) {
15131517
},
15141518
},
15151519
},
1520+
{
1521+
name: "One unsupported field + supported fields (valid)",
1522+
gateway: createGateway(gatewayCfg{
1523+
name: "gateway-valid-np",
1524+
listeners: []v1.Listener{foo80Listener1},
1525+
ref: validGwNpRef,
1526+
allowedListeners: &v1.AllowedListeners{},
1527+
}),
1528+
gatewayClass: validGCWithNp,
1529+
expected: map[types.NamespacedName]*Gateway{
1530+
{Namespace: validGwNp.Namespace, Name: "gateway-valid-np"}: {
1531+
Source: getLastCreatedGateway(),
1532+
Listeners: []*Listener{
1533+
{
1534+
Name: "foo-80-1",
1535+
GatewayName: client.ObjectKeyFromObject(getLastCreatedGateway()),
1536+
Source: foo80Listener1,
1537+
Valid: true,
1538+
Attachable: true,
1539+
Routes: map[RouteKey]*L7Route{},
1540+
L4Routes: map[L4RouteKey]*L4Route{},
1541+
SupportedKinds: supportedKindsForListeners,
1542+
},
1543+
},
1544+
DeploymentName: types.NamespacedName{
1545+
Namespace: "test",
1546+
Name: controller.CreateNginxResourceName("gateway-valid-np", gcName),
1547+
},
1548+
Valid: true,
1549+
NginxProxy: &NginxProxy{
1550+
Source: validGwNp,
1551+
Valid: true,
1552+
},
1553+
EffectiveNginxProxy: &EffectiveNginxProxy{
1554+
Logging: &ngfAPIv1alpha2.NginxLogging{
1555+
ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelError),
1556+
},
1557+
IPFamily: helpers.GetPointer(ngfAPIv1alpha2.Dual),
1558+
Metrics: &ngfAPIv1alpha2.Metrics{
1559+
Disable: helpers.GetPointer(false),
1560+
Port: helpers.GetPointer(int32(90)),
1561+
},
1562+
},
1563+
Conditions: []conditions.Condition{
1564+
conditions.NewGatewayAcceptedUnsupportedField("AllowedListeners"),
1565+
conditions.NewGatewayResolvedRefs(),
1566+
},
1567+
},
1568+
},
1569+
},
1570+
{
1571+
name: "One unsupported field + NewGatewayRefInvalid (invalid)",
1572+
gateway: createGateway(gatewayCfg{
1573+
name: "gateway-valid-np",
1574+
listeners: []v1.Listener{foo80Listener1},
1575+
ref: &v1.LocalParametersReference{
1576+
Kind: "wrong-kind", // Invalid reference
1577+
Name: "invalid-ref",
1578+
},
1579+
backendTLS: &v1.GatewayBackendTLS{},
1580+
}),
1581+
gatewayClass: validGCWithNp,
1582+
expected: map[types.NamespacedName]*Gateway{
1583+
{Namespace: validGwNp.Namespace, Name: "gateway-valid-np"}: {
1584+
Source: getLastCreatedGateway(),
1585+
Listeners: []*Listener{
1586+
{
1587+
Name: "foo-80-1",
1588+
GatewayName: client.ObjectKeyFromObject(getLastCreatedGateway()),
1589+
Source: foo80Listener1,
1590+
Valid: true,
1591+
Attachable: true,
1592+
Routes: map[RouteKey]*L7Route{},
1593+
L4Routes: map[L4RouteKey]*L4Route{},
1594+
SupportedKinds: supportedKindsForListeners,
1595+
},
1596+
},
1597+
DeploymentName: types.NamespacedName{
1598+
Namespace: "test",
1599+
Name: controller.CreateNginxResourceName("gateway-valid-np", gcName),
1600+
},
1601+
Valid: true,
1602+
EffectiveNginxProxy: &EffectiveNginxProxy{
1603+
IPFamily: helpers.GetPointer(ngfAPIv1alpha2.Dual),
1604+
},
1605+
Conditions: []conditions.Condition{
1606+
conditions.NewGatewayAcceptedUnsupportedField("BackendTLS"),
1607+
conditions.NewGatewayRefInvalid(
1608+
"spec.infrastructure.parametersRef.kind: Unsupported value: \"wrong-kind\": supported values: \"NginxProxy\"",
1609+
),
1610+
conditions.NewGatewayInvalidParameters(
1611+
"spec.infrastructure.parametersRef.kind: Unsupported value: \"wrong-kind\": supported values: \"NginxProxy\"",
1612+
),
1613+
},
1614+
},
1615+
},
1616+
},
15161617
}
15171618

15181619
secretResolver := newSecretResolver(
@@ -1821,3 +1922,55 @@ func TestGetReferencedSnippetsFilters(t *testing.T) {
18211922
emptyFilterResult := gw.GetReferencedSnippetsFilters(routes, map[types.NamespacedName]*SnippetsFilter{})
18221923
g.Expect(emptyFilterResult).To(BeEmpty())
18231924
}
1925+
1926+
func TestValidateUnsupportedGatewayFields(t *testing.T) {
1927+
t.Parallel()
1928+
1929+
tests := []struct {
1930+
name string
1931+
gateway *v1.Gateway
1932+
expectedConds []conditions.Condition
1933+
}{
1934+
{
1935+
name: "No unsupported fields",
1936+
gateway: &v1.Gateway{
1937+
Spec: v1.GatewaySpec{},
1938+
},
1939+
expectedConds: nil,
1940+
},
1941+
{
1942+
name: "One unsupported field: AllowedListeners",
1943+
gateway: &v1.Gateway{
1944+
Spec: v1.GatewaySpec{
1945+
AllowedListeners: &v1.AllowedListeners{},
1946+
},
1947+
},
1948+
expectedConds: []conditions.Condition{
1949+
conditions.NewGatewayAcceptedUnsupportedField("AllowedListeners"),
1950+
},
1951+
},
1952+
{
1953+
name: "Multiple unsupported fields: AllowedListeners and BackendTLS",
1954+
gateway: &v1.Gateway{
1955+
Spec: v1.GatewaySpec{
1956+
AllowedListeners: &v1.AllowedListeners{},
1957+
BackendTLS: &v1.GatewayBackendTLS{},
1958+
},
1959+
},
1960+
expectedConds: []conditions.Condition{
1961+
conditions.NewGatewayAcceptedUnsupportedField("AllowedListeners"),
1962+
conditions.NewGatewayAcceptedUnsupportedField("BackendTLS"),
1963+
},
1964+
},
1965+
}
1966+
1967+
for _, test := range tests {
1968+
t.Run(test.name, func(t *testing.T) {
1969+
t.Parallel()
1970+
g := NewWithT(t)
1971+
1972+
conds := validateUnsupportedGatewayFields(test.gateway)
1973+
g.Expect(conds).To(Equal(test.expectedConds))
1974+
})
1975+
}
1976+
}

internal/controller/state/graph/grpcroute.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,11 @@ func processGRPCRouteRule(
165165

166166
validMatches := true
167167

168+
unsupportedFieldsErrors := checkForUnsupportedGRPCFields(specRule, rulePath)
169+
if len(unsupportedFieldsErrors) > 0 {
170+
errors.warn = append(errors.warn, unsupportedFieldsErrors...)
171+
}
172+
168173
for j, match := range specRule.Matches {
169174
matchPath := rulePath.Child("matches").Index(j)
170175

@@ -260,6 +265,11 @@ func processGRPCRouteRules(
260265
conds = make([]conditions.Condition, 0, 2)
261266
valid = true
262267

268+
// add warning condition for unsupported fields if any
269+
if len(allRulesErrors.warn) > 0 {
270+
conds = append(conds, conditions.NewRouteAcceptedUnsupportedField(allRulesErrors.warn.ToAggregate().Error()))
271+
}
272+
263273
if len(allRulesErrors.invalid) > 0 {
264274
msg := allRulesErrors.invalid.ToAggregate().Error()
265275

@@ -444,3 +454,26 @@ func validateGRPCHeaderMatch(
444454

445455
return allErrs
446456
}
457+
458+
func checkForUnsupportedGRPCFields(rule v1.GRPCRouteRule, rulePath *field.Path) field.ErrorList {
459+
var ruleErrors field.ErrorList
460+
461+
if rule.Name != nil {
462+
ruleErrors = append(ruleErrors, field.Forbidden(
463+
rulePath.Child("name"),
464+
"Name",
465+
))
466+
}
467+
if rule.SessionPersistence != nil {
468+
ruleErrors = append(ruleErrors, field.Forbidden(
469+
rulePath.Child("sessionPersistence"),
470+
"SessionPersistence",
471+
))
472+
}
473+
474+
if len(ruleErrors) == 0 {
475+
return nil
476+
}
477+
478+
return ruleErrors
479+
}

0 commit comments

Comments
 (0)