Skip to content

Commit 78496d8

Browse files
authored
Fix OpenAPI validations by adding API list markers (#3964)
1 parent 5836f6f commit 78496d8

28 files changed

+403
-10
lines changed

.golangci-kal.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ linters:
1717
- "nomaps" # Ensure maps are not used.
1818
- "nophase" # Phase fields are discouraged by the Kube API conventions, use conditions instead.
1919
- "optionalorrequired" # Every field should be marked as `+optional` or `+required`.
20+
- "ssatags" # Ensure proper Server-Side Apply (SSA) tags on array fields.
2021
- "statussubresource" # All root objects that have a `status` field should have a status subresource.
2122
- "uniquemarkers" # Ensure that types and fields do not contain more than a single definition of a marker that should only be present once.
2223
disable:

apis/v1/gateway_types.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ type GatewaySpec struct {
265265
// Support: Extended
266266
//
267267
// +optional
268+
// +listType=atomic
268269
// <gateway:validateIPAddress>
269270
// +kubebuilder:validation:MaxItems=16
270271
// +kubebuilder:validation:XValidation:message="IPAddress values must be unique",rule="self.all(a1, a1.type == 'IPAddress' ? self.exists_one(a2, a2.type == a1.type && a2.value == a1.value) : true )"
@@ -573,6 +574,7 @@ type GatewayTLSConfig struct {
573574
// Support: Implementation-specific (More than one reference or other resource types)
574575
//
575576
// +optional
577+
// +listType=atomic
576578
// +kubebuilder:validation:MaxItems=64
577579
CertificateRefs []SecretObjectReference `json:"certificateRefs,omitempty"`
578580

@@ -647,9 +649,10 @@ type FrontendTLSValidation struct {
647649
// "ResolvedRefs" condition MUST be set to False for this listener with the
648650
// "RefNotPermitted" reason.
649651
//
652+
// +required
653+
// +listType=atomic
650654
// +kubebuilder:validation:MaxItems=8
651655
// +kubebuilder:validation:MinItems=1
652-
// +required
653656
CACertificateRefs []ObjectReference `json:"caCertificateRefs,omitempty"`
654657
}
655658

@@ -661,6 +664,7 @@ type AllowedRoutes struct {
661664
// Support: Core
662665
//
663666
// +optional
667+
// +listType=atomic
664668
// +kubebuilder:default={from: Same}
665669
Namespaces *RouteNamespaces `json:"namespaces,omitempty"`
666670

@@ -677,6 +681,7 @@ type AllowedRoutes struct {
677681
// Support: Core
678682
//
679683
// +optional
684+
// +listType=atomic
680685
// +kubebuilder:validation:MaxItems=8
681686
Kinds []RouteGroupKind `json:"kinds,omitempty"`
682687
}
@@ -795,6 +800,7 @@ type GatewayStatus struct {
795800
// * a specified address was unusable (e.g. already in use)
796801
//
797802
// +optional
803+
// +listType=atomic
798804
// <gateway:validateIPAddress>
799805
// +kubebuilder:validation:MaxItems=16
800806
Addresses []GatewayStatusAddress `json:"addresses,omitempty"`
@@ -1127,8 +1133,9 @@ type ListenerStatus struct {
11271133
// and invalid Route kinds are specified, the implementation MUST
11281134
// reference the valid Route kinds that have been specified.
11291135
//
1130-
// +kubebuilder:validation:MaxItems=8
11311136
// +required
1137+
// +listType=atomic
1138+
// +kubebuilder:validation:MaxItems=8
11321139
SupportedKinds []RouteGroupKind `json:"supportedKinds"`
11331140

11341141
// AttachedRoutes represents the total number of Routes that have been

apis/v1/grpcroute_types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,14 @@ type GRPCRouteSpec struct {
139139
// Support: Core
140140
//
141141
// +optional
142+
// +listType=atomic
142143
// +kubebuilder:validation:MaxItems=16
143144
Hostnames []Hostname `json:"hostnames,omitempty"`
144145

145146
// Rules are a list of GRPC matchers, filters and actions.
146147
//
147148
// +optional
149+
// +listType=atomic
148150
// +kubebuilder:validation:MaxItems=16
149151
// +kubebuilder:validation:XValidation:message="While 16 rules and 64 matches per rule are allowed, the total number of matches across all rules in a route must be less than 128",rule="(self.size() > 0 ? (has(self[0].matches) ? self[0].matches.size() : 0) : 0) + (self.size() > 1 ? (has(self[1].matches) ? self[1].matches.size() : 0) : 0) + (self.size() > 2 ? (has(self[2].matches) ? self[2].matches.size() : 0) : 0) + (self.size() > 3 ? (has(self[3].matches) ? self[3].matches.size() : 0) : 0) + (self.size() > 4 ? (has(self[4].matches) ? self[4].matches.size() : 0) : 0) + (self.size() > 5 ? (has(self[5].matches) ? self[5].matches.size() : 0) : 0) + (self.size() > 6 ? (has(self[6].matches) ? self[6].matches.size() : 0) : 0) + (self.size() > 7 ? (has(self[7].matches) ? self[7].matches.size() : 0) : 0) + (self.size() > 8 ? (has(self[8].matches) ? self[8].matches.size() : 0) : 0) + (self.size() > 9 ? (has(self[9].matches) ? self[9].matches.size() : 0) : 0) + (self.size() > 10 ? (has(self[10].matches) ? self[10].matches.size() : 0) : 0) + (self.size() > 11 ? (has(self[11].matches) ? self[11].matches.size() : 0) : 0) + (self.size() > 12 ? (has(self[12].matches) ? self[12].matches.size() : 0) : 0) + (self.size() > 13 ? (has(self[13].matches) ? self[13].matches.size() : 0) : 0) + (self.size() > 14 ? (has(self[14].matches) ? self[14].matches.size() : 0) : 0) + (self.size() > 15 ? (has(self[15].matches) ? self[15].matches.size() : 0) : 0) <= 128"
150152
// <gateway:experimental:validation:XValidation:message="Rule name must be unique within the route",rule="self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name))">
@@ -212,6 +214,7 @@ type GRPCRouteRule struct {
212214
// the above criteria.
213215
//
214216
// +optional
217+
// +listType=atomic
215218
// +kubebuilder:validation:MaxItems=64
216219
Matches []GRPCRouteMatch `json:"matches,omitempty"`
217220

@@ -241,6 +244,7 @@ type GRPCRouteRule struct {
241244
// Support: Core
242245
//
243246
// +optional
247+
// +listType=atomic
244248
// +kubebuilder:validation:MaxItems=16
245249
// +kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"
246250
// +kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1"
@@ -276,6 +280,7 @@ type GRPCRouteRule struct {
276280
// Support for weight: Core
277281
//
278282
// +optional
283+
// +listType=atomic
279284
// +kubebuilder:validation:MaxItems=16
280285
BackendRefs []GRPCBackendRef `json:"backendRefs,omitempty"`
281286

@@ -636,6 +641,7 @@ type GRPCBackendRef struct {
636641
// Filters field in GRPCRouteRule.)
637642
//
638643
// +optional
644+
// +listType=atomic
639645
// +kubebuilder:validation:MaxItems=16
640646
// +kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"
641647
// +kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1"

apis/v1/httproute_types.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,14 @@ type HTTPRouteSpec struct {
114114
// Support: Core
115115
//
116116
// +optional
117+
// +listType=atomic
117118
// +kubebuilder:validation:MaxItems=16
118119
Hostnames []Hostname `json:"hostnames,omitempty"`
119120

120121
// Rules are a list of HTTP matchers, filters and actions.
121122
//
122123
// +optional
124+
// +listType=atomic
123125
// <gateway:experimental:validation:XValidation:message="Rule name must be unique within the route",rule="self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name))">
124126
// +kubebuilder:validation:MaxItems=16
125127
// +kubebuilder:default={{matches: {{path: {type: "PathPrefix", value: "/"}}}}}
@@ -201,6 +203,7 @@ type HTTPRouteRule struct {
201203
// parent a request is coming from, a HTTP 404 status code MUST be returned.
202204
//
203205
// +optional
206+
// +listType=atomic
204207
// +kubebuilder:validation:MaxItems=64
205208
// +kubebuilder:default={{path:{ type: "PathPrefix", value: "/"}}}
206209
Matches []HTTPRouteMatch `json:"matches,omitempty"`
@@ -243,6 +246,7 @@ type HTTPRouteRule struct {
243246
// Support: Core
244247
//
245248
// +optional
249+
// +listType=atomic
246250
// +kubebuilder:validation:MaxItems=16
247251
// +kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))"
248252
// +kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"
@@ -288,6 +292,7 @@ type HTTPRouteRule struct {
288292
// Support for weight: Core
289293
//
290294
// +optional
295+
// +listType=atomic
291296
// +kubebuilder:validation:MaxItems=16
292297
BackendRefs []HTTPBackendRef `json:"backendRefs,omitempty"`
293298

@@ -382,6 +387,7 @@ type HTTPRouteRetry struct {
382387
// Support: Extended
383388
//
384389
// +optional
390+
// +listType=atomic
385391
Codes []HTTPRouteRetryStatusCode `json:"codes,omitempty"`
386392

387393
// Attempts specifies the maximum number of times an individual request
@@ -1606,6 +1612,7 @@ type HTTPBackendRef struct {
16061612
// Filters field in HTTPRouteRule.)
16071613
//
16081614
// +optional
1615+
// +listType=atomic
16091616
// +kubebuilder:validation:MaxItems=16
16101617
// +kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))"
16111618
// +kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"

apis/v1/shared_types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ type CommonRouteSpec struct {
222222
// </gateway:experimental:description>
223223
//
224224
// +optional
225+
// +listType=atomic
225226
// +kubebuilder:validation:MaxItems=32
226227
// <gateway:standard:validation:XValidation:message="sectionName must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '')) : true))">
227228
// <gateway:standard:validation:XValidation:message="sectionName must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName))))">
@@ -502,8 +503,9 @@ type RouteStatus struct {
502503
// A maximum of 32 Gateways will be represented in this list. An empty list
503504
// means the route has not been attached to any Gateway.
504505
//
505-
// +kubebuilder:validation:MaxItems=32
506506
// +required
507+
// +listType=atomic
508+
// +kubebuilder:validation:MaxItems=32
507509
Parents []RouteParentStatus `json:"parents"`
508510
}
509511

apis/v1alpha2/policy_types.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ type PolicyStatus struct {
242242
// additional Gateways would be able to reference the Service targeted by
243243
// the BackendTLSPolicy.
244244
//
245-
// +kubebuilder:validation:MaxItems=16
246245
// +required
246+
// +listType=atomic
247+
// +kubebuilder:validation:MaxItems=16
247248
Ancestors []PolicyAncestorStatus `json:"ancestors"`
248249
}

apis/v1alpha2/tcproute_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type TCPRouteSpec struct {
5151
// Rules are a list of TCP matchers and actions.
5252
//
5353
// +required
54+
// +listType=atomic
5455
// +kubebuilder:validation:MinItems=1
5556
// +kubebuilder:validation:MaxItems=16
5657
// <gateway:experimental:validation:XValidation:message="Rule name must be unique within the route",rule="self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name))">
@@ -86,6 +87,7 @@ type TCPRouteRule struct {
8687
// Support for weight: Extended
8788
//
8889
// +required
90+
// +listType=atomic
8991
// +kubebuilder:validation:MinItems=1
9092
// +kubebuilder:validation:MaxItems=16
9193
BackendRefs []BackendRef `json:"backendRefs,omitempty"`

apis/v1alpha2/tlsroute_types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,14 @@ type TLSRouteSpec struct {
8585
// Support: Core
8686
//
8787
// +optional
88+
// +listType=atomic
8889
// +kubebuilder:validation:MaxItems=16
8990
Hostnames []Hostname `json:"hostnames,omitempty"`
9091

9192
// Rules are a list of TLS matchers and actions.
9293
//
9394
// +required
95+
// +listType=atomic
9496
// +kubebuilder:validation:MinItems=1
9597
// +kubebuilder:validation:MaxItems=16
9698
// <gateway:experimental:validation:XValidation:message="Rule name must be unique within the route",rule="self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name))">
@@ -129,6 +131,7 @@ type TLSRouteRule struct {
129131
// Support for weight: Extended
130132
//
131133
// +required
134+
// +listType=atomic
132135
// +kubebuilder:validation:MinItems=1
133136
// +kubebuilder:validation:MaxItems=16
134137
BackendRefs []BackendRef `json:"backendRefs,omitempty"`

apis/v1alpha2/udproute_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type UDPRouteSpec struct {
5151
// Rules are a list of UDP matchers and actions.
5252
//
5353
// +required
54+
// +listType=atomic
5455
// +kubebuilder:validation:MinItems=1
5556
// +kubebuilder:validation:MaxItems=16
5657
// <gateway:experimental:validation:XValidation:message="Rule name must be unique within the route",rule="self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name))">
@@ -86,6 +87,7 @@ type UDPRouteRule struct {
8687
// Support for weight: Extended
8788
//
8889
// +required
90+
// +listType=atomic
8991
// +kubebuilder:validation:MinItems=1
9092
// +kubebuilder:validation:MaxItems=16
9193
BackendRefs []BackendRef `json:"backendRefs,omitempty"`

apis/v1alpha3/backendtlspolicy_types.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,10 @@ type BackendTLSPolicySpec struct {
8080
//
8181
// Support: Implementation-specific for any other resource
8282
//
83+
// +required
84+
// +listType=atomic
8385
// +kubebuilder:validation:MinItems=1
8486
// +kubebuilder:validation:MaxItems=16
85-
// +required
8687
// +kubebuilder:validation:XValidation:message="sectionName must be specified when targetRefs includes 2 or more references to the same target",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '')) : true))"
8788
// +kubebuilder:validation:XValidation:message="sectionName must be unique when targetRefs includes 2 or more references to the same target",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName))))"
8889
TargetRefs []v1alpha2.LocalPolicyTargetReferenceWithSectionName `json:"targetRefs"`
@@ -133,8 +134,9 @@ type BackendTLSPolicyValidation struct {
133134
// Support: Implementation-specific (More than one reference, or other kinds
134135
// of resources).
135136
//
136-
// +kubebuilder:validation:MaxItems=8
137137
// +optional
138+
// +listType=atomic
139+
// +kubebuilder:validation:MaxItems=8
138140
CACertificateRefs []v1.LocalObjectReference `json:"caCertificateRefs,omitempty"`
139141

140142
// WellKnownCACertificates specifies whether system CA certificates may be used in
@@ -150,6 +152,7 @@ type BackendTLSPolicyValidation struct {
150152
// Support: Implementation-specific
151153
//
152154
// +optional
155+
// +listType=atomic
153156
WellKnownCACertificates *WellKnownCACertificatesType `json:"wellKnownCACertificates,omitempty"`
154157

155158
// Hostname is used for two purposes in the connection between Gateways and
@@ -170,6 +173,7 @@ type BackendTLSPolicyValidation struct {
170173
// Support: Extended
171174
//
172175
// +optional
176+
// +listType=atomic
173177
// +kubebuilder:validation:MaxItems=5
174178
SubjectAltNames []SubjectAltName `json:"subjectAltNames,omitempty"`
175179
}

0 commit comments

Comments
 (0)