diff --git a/apis/v1/grpcroute_types.go b/apis/v1/grpcroute_types.go index 8f7090386d..543b34644f 100644 --- a/apis/v1/grpcroute_types.go +++ b/apis/v1/grpcroute_types.go @@ -144,7 +144,7 @@ type GRPCRouteSpec struct { // +optional // +kubebuilder:validation:MaxItems=16 // +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" - // +kubebuilder: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))" + // Rules []GRPCRouteRule `json:"rules,omitempty"` } diff --git a/apis/v1/httproute_types.go b/apis/v1/httproute_types.go index 2a92536258..b6c2e936ef 100644 --- a/apis/v1/httproute_types.go +++ b/apis/v1/httproute_types.go @@ -117,7 +117,7 @@ type HTTPRouteSpec struct { // Rules are a list of HTTP matchers, filters and actions. // // +optional - // +kubebuilder: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))" + // // +kubebuilder:validation:MaxItems=16 // +kubebuilder:default={{matches: {{path: {type: "PathPrefix", value: "/"}}}}} // +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 ? self[0].matches.size() : 0) + (self.size() > 1 ? self[1].matches.size() : 0) + (self.size() > 2 ? self[2].matches.size() : 0) + (self.size() > 3 ? self[3].matches.size() : 0) + (self.size() > 4 ? self[4].matches.size() : 0) + (self.size() > 5 ? self[5].matches.size() : 0) + (self.size() > 6 ? self[6].matches.size() : 0) + (self.size() > 7 ? self[7].matches.size() : 0) + (self.size() > 8 ? self[8].matches.size() : 0) + (self.size() > 9 ? self[9].matches.size() : 0) + (self.size() > 10 ? self[10].matches.size() : 0) + (self.size() > 11 ? self[11].matches.size() : 0) + (self.size() > 12 ? self[12].matches.size() : 0) + (self.size() > 13 ? self[13].matches.size() : 0) + (self.size() > 14 ? self[14].matches.size() : 0) + (self.size() > 15 ? self[15].matches.size() : 0) <= 128" diff --git a/apis/v1alpha2/tcproute_types.go b/apis/v1alpha2/tcproute_types.go index 15e11c747f..b79253dd33 100644 --- a/apis/v1alpha2/tcproute_types.go +++ b/apis/v1alpha2/tcproute_types.go @@ -49,7 +49,7 @@ type TCPRouteSpec struct { // // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 - // +kubebuilder: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))" + // Rules []TCPRouteRule `json:"rules"` } diff --git a/apis/v1alpha2/tlsroute_types.go b/apis/v1alpha2/tlsroute_types.go index efa0e7d422..26dfde77c7 100644 --- a/apis/v1alpha2/tlsroute_types.go +++ b/apis/v1alpha2/tlsroute_types.go @@ -90,7 +90,7 @@ type TLSRouteSpec struct { // // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 - // +kubebuilder: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))" + // Rules []TLSRouteRule `json:"rules"` } diff --git a/apis/v1alpha2/udproute_types.go b/apis/v1alpha2/udproute_types.go index b090602ff3..9e7fe3ff80 100644 --- a/apis/v1alpha2/udproute_types.go +++ b/apis/v1alpha2/udproute_types.go @@ -49,7 +49,7 @@ type UDPRouteSpec struct { // // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 - // +kubebuilder: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))" + // Rules []UDPRouteRule `json:"rules"` } diff --git a/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml index 0f60969fe1..e47547eac1 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml @@ -441,7 +441,10 @@ spec: || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port == p2.port)))) rules: - description: Rules are a list of GRPC matchers, filters and actions. + description: |+ + Rules are a list of GRPC matchers, filters and actions. + + items: description: |- GRPCRouteRule defines the semantics for matching a gRPC request based on @@ -2061,6 +2064,9 @@ spec: : 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' + - 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)) type: object status: description: Status defines the current state of GRPCRoute. @@ -2799,7 +2805,10 @@ spec: || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port == p2.port)))) rules: - description: Rules are a list of GRPC matchers, filters and actions. + description: |+ + Rules are a list of GRPC matchers, filters and actions. + + items: description: |- GRPCRouteRule defines the semantics for matching a gRPC request based on @@ -4419,6 +4428,9 @@ spec: : 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' + - 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)) type: object status: description: Status defines the current state of GRPCRoute. diff --git a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml index 6d130fdf9e..18ace973b6 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml @@ -424,7 +424,10 @@ spec: - path: type: PathPrefix value: / - description: Rules are a list of HTTP matchers, filters and actions. + description: |+ + Rules are a list of HTTP matchers, filters and actions. + + items: description: |- HTTPRouteRule defines semantics for matching an HTTP request based on @@ -2954,6 +2957,9 @@ spec: : 0) + (self.size() > 12 ? self[12].matches.size() : 0) + (self.size() > 13 ? self[13].matches.size() : 0) + (self.size() > 14 ? self[14].matches.size() : 0) + (self.size() > 15 ? self[15].matches.size() : 0) <= 128' + - 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)) type: object status: description: Status defines the current state of HTTPRoute. @@ -3681,7 +3687,10 @@ spec: - path: type: PathPrefix value: / - description: Rules are a list of HTTP matchers, filters and actions. + description: |+ + Rules are a list of HTTP matchers, filters and actions. + + items: description: |- HTTPRouteRule defines semantics for matching an HTTP request based on @@ -6211,6 +6220,9 @@ spec: : 0) + (self.size() > 12 ? self[12].matches.size() : 0) + (self.size() > 13 ? self[13].matches.size() : 0) + (self.size() > 14 ? self[14].matches.size() : 0) + (self.size() > 15 ? self[15].matches.size() : 0) <= 128' + - 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)) type: object status: description: Status defines the current state of HTTPRoute. diff --git a/config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml index 05af632b91..81ae85c566 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml @@ -324,7 +324,10 @@ spec: || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port == p2.port)))) rules: - description: Rules are a list of TCP matchers and actions. + description: |+ + Rules are a list of TCP matchers and actions. + + items: description: TCPRouteRule is the configuration for a given rule. properties: @@ -500,6 +503,10 @@ spec: maxItems: 16 minItems: 1 type: array + x-kubernetes-validations: + - 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)) required: - rules type: object diff --git a/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml index 54a25a95bd..aadc14594c 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml @@ -394,7 +394,10 @@ spec: || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port == p2.port)))) rules: - description: Rules are a list of TLS matchers and actions. + description: |+ + Rules are a list of TLS matchers and actions. + + items: description: TLSRouteRule is the configuration for a given rule. properties: @@ -573,6 +576,10 @@ spec: maxItems: 16 minItems: 1 type: array + x-kubernetes-validations: + - 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)) required: - rules type: object diff --git a/config/crd/experimental/gateway.networking.k8s.io_udproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_udproutes.yaml index 4cfdeb8e7a..45e28da0bb 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_udproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_udproutes.yaml @@ -324,7 +324,10 @@ spec: || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port == p2.port)))) rules: - description: Rules are a list of UDP matchers and actions. + description: |+ + Rules are a list of UDP matchers and actions. + + items: description: UDPRouteRule is the configuration for a given rule. properties: @@ -500,6 +503,10 @@ spec: maxItems: 16 minItems: 1 type: array + x-kubernetes-validations: + - 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)) required: - rules type: object diff --git a/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml b/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml index 4763f3c94b..01fc863825 100644 --- a/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml @@ -412,7 +412,10 @@ spec: == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName)))) rules: - description: Rules are a list of GRPC matchers, filters and actions. + description: |+ + Rules are a list of GRPC matchers, filters and actions. + + items: description: |- GRPCRouteRule defines the semantics for matching a gRPC request based on @@ -2616,7 +2619,10 @@ spec: == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName)))) rules: - description: Rules are a list of GRPC matchers, filters and actions. + description: |+ + Rules are a list of GRPC matchers, filters and actions. + + items: description: |- GRPCRouteRule defines the semantics for matching a gRPC request based on diff --git a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml index dcbae42b7e..6a4a9b6fe1 100644 --- a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml @@ -395,7 +395,10 @@ spec: - path: type: PathPrefix value: / - description: Rules are a list of HTTP matchers, filters and actions. + description: |+ + Rules are a list of HTTP matchers, filters and actions. + + items: description: |- HTTPRouteRule defines semantics for matching an HTTP request based on @@ -3498,7 +3501,10 @@ spec: - path: type: PathPrefix value: / - description: Rules are a list of HTTP matchers, filters and actions. + description: |+ + Rules are a list of HTTP matchers, filters and actions. + + items: description: |- HTTPRouteRule defines semantics for matching an HTTP request based on diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 9a73c5729c..b57c621df3 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -3386,7 +3386,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCRouteSpec(ref common.ReferenceCall }, "rules": { SchemaProps: spec.SchemaProps{ - Description: "Rules are a list of GRPC matchers, filters and actions.", + Description: "Rules are a list of GRPC matchers, filters and actions.\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -4774,7 +4774,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteSpec(ref common.ReferenceCall }, "rules": { SchemaProps: spec.SchemaProps{ - Description: "Rules are a list of HTTP matchers, filters and actions.", + Description: "Rules are a list of HTTP matchers, filters and actions.\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -6182,7 +6182,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TCPRouteSpec(ref common.Referenc }, "rules": { SchemaProps: spec.SchemaProps{ - Description: "Rules are a list of TCP matchers and actions.", + Description: "Rules are a list of TCP matchers and actions.\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -6406,7 +6406,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TLSRouteSpec(ref common.Referenc }, "rules": { SchemaProps: spec.SchemaProps{ - Description: "Rules are a list of TLS matchers and actions.", + Description: "Rules are a list of TLS matchers and actions.\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -6615,7 +6615,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_UDPRouteSpec(ref common.Referenc }, "rules": { SchemaProps: spec.SchemaProps{ - Description: "Rules are a list of UDP matchers and actions.", + Description: "Rules are a list of UDP matchers and actions.\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ diff --git a/pkg/test/cel/httproute_test.go b/pkg/test/cel/httproute_test.go index 8927c5ad06..a20a70cf27 100644 --- a/pkg/test/cel/httproute_test.go +++ b/pkg/test/cel/httproute_test.go @@ -24,6 +24,7 @@ import ( "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" )