diff --git a/apis/v1alpha2/grpcroute_types.go b/apis/v1alpha2/grpcroute_types.go index dcb501f78e..2d0aa11aac 100644 --- a/apis/v1alpha2/grpcroute_types.go +++ b/apis/v1alpha2/grpcroute_types.go @@ -223,8 +223,8 @@ type GRPCRouteRule struct { // - Implementation-specific custom filters have no API guarantees across // implementations. // - // Specifying a core filter multiple times has unspecified or - // implementation-specific conformance. + // Specifying the same filter multiple times is not supported unless explicitly + // indicated in the filter. // // If an implementation can not support a combinations of filters, they must clearly // document that limitation. In cases where incompatible or unsupported @@ -515,6 +515,10 @@ type GRPCRouteFilter struct { // Requests are sent to the specified destination, but responses from // that destination are ignored. // + // This filter can be used multiple times within the same rule. Note that + // not all implementations will be able to support mirroring to multiple + // backends. + // // Support: Extended // // +optional @@ -527,6 +531,7 @@ type GRPCRouteFilter struct { // // Support: Implementation-specific // + // This filter can be used multiple times within the same rule. // +optional ExtensionRef *LocalObjectReference `json:"extensionRef,omitempty"` } diff --git a/apis/v1alpha2/validation/grpcroute.go b/apis/v1alpha2/validation/grpcroute.go index 62ed859235..d7e452d41c 100644 --- a/apis/v1alpha2/validation/grpcroute.go +++ b/apis/v1alpha2/validation/grpcroute.go @@ -32,6 +32,7 @@ var ( // repeated multiple times in a rule. repeatableGRPCRouteFilters = []gatewayv1a2.GRPCRouteFilterType{ gatewayv1a2.GRPCRouteFilterExtensionRef, + gatewayv1a2.GRPCRouteFilterRequestMirror, } validServiceName = `^(?i)\.?[a-z_][a-z_0-9]*(\.[a-z_][a-z_0-9]*)*$` validServiceNameRegex = regexp.MustCompile(validServiceName) @@ -165,7 +166,7 @@ func validateGRPCRouteFilters(filters []gatewayv1a2.GRPCRouteFilter, path *field } errs = append(errs, validateGRPCRouteFilterType(filter, path.Index(i))...) } - // custom filters don't have any validation + // repeatableGRPCRouteFilters filters can be used more than once for _, key := range repeatableGRPCRouteFilters { delete(counts, key) } diff --git a/apis/v1alpha2/validation/grpcroute_test.go b/apis/v1alpha2/validation/grpcroute_test.go index 9055864b3f..a7c1c8fac4 100644 --- a/apis/v1alpha2/validation/grpcroute_test.go +++ b/apis/v1alpha2/validation/grpcroute_test.go @@ -236,10 +236,38 @@ func TestValidateGRPCRoute(t *testing.T) { }}, }, }, + }, + { + name: "invalid GRPCRoute with duplicate RequestHeaderModifier filters", + rules: []gatewayv1a2.GRPCRouteRule{ + { + Filters: []gatewayv1a2.GRPCRouteFilter{{ + Type: "RequestHeaderModifier", + RequestHeaderModifier: &gatewayv1a2.HTTPHeaderFilter{ + Set: []gatewayv1a2.HTTPHeader{ + { + Name: "special-header", + Value: "foo", + }, + }, + }, + }, { + Type: "RequestHeaderModifier", + RequestHeaderModifier: &gatewayv1a2.HTTPHeaderFilter{ + Add: []gatewayv1a2.HTTPHeader{ + { + Name: "my-header", + Value: "bar", + }, + }, + }, + }}, + }, + }, errs: field.ErrorList{ { Type: field.ErrorTypeInvalid, - BadValue: "RequestMirror", + BadValue: "RequestHeaderModifier", Field: "spec.rules[0].filters", Detail: "cannot be used multiple times in the same rule", }, @@ -305,8 +333,8 @@ func TestValidateGRPCBackendUniqueFilters(t *testing.T) { }, }}, }, { - name: "invalid grpcRoute Rules duplicate mirror filter", - errCount: 1, + name: "valid grpcRoute Rules duplicate mirror filter", + errCount: 0, rules: []gatewayv1a2.GRPCRouteRule{{ BackendRefs: []gatewayv1a2.GRPCBackendRef{ { diff --git a/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml index bc42220b70..d927fd2fd1 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml @@ -331,7 +331,9 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n Support: Implementation-specific \n + This filter can be used multiple times within + the same rule." properties: group: description: Group is the group of the referent. @@ -469,7 +471,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from - that destination are ignored. \n Support: Extended" + that destination are ignored. \n This filter can + be used multiple times within the same rule. Note + that not all implementations will be able to support + mirroring to multiple backends. \n Support: Extended" properties: backendRef: description: "BackendRef references a resource @@ -793,8 +798,8 @@ spec: all implementations that support GRPCRoute. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across implementations. - \n Specifying a core filter multiple times has unspecified - or implementation-specific conformance. \n If an implementation + \n Specifying the same filter multiple times is not supported + unless explicitly indicated in the filter. \n If an implementation can not support a combinations of filters, they must clearly document that limitation. In cases where incompatible or unsupported filters are specified and cause the `Accepted` condition to @@ -815,7 +820,8 @@ spec: extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" + filters. \n Support: Implementation-specific \n This + filter can be used multiple times within the same rule." properties: group: description: Group is the group of the referent. For @@ -945,7 +951,10 @@ spec: description: "RequestMirror defines a schema for a filter that mirrors requests. Requests are sent to the specified destination, but responses from that destination are - ignored. \n Support: Extended" + ignored. \n This filter can be used multiple times within + the same rule. Note that not all implementations will + be able to support mirroring to multiple backends. \n + Support: Extended" properties: backendRef: description: "BackendRef references a resource where