diff --git a/apis/applyconfiguration/apis/v1/fraction.go b/apis/applyconfiguration/apis/v1/fraction.go new file mode 100644 index 0000000000..5d828f6178 --- /dev/null +++ b/apis/applyconfiguration/apis/v1/fraction.go @@ -0,0 +1,48 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// FractionApplyConfiguration represents an declarative configuration of the Fraction type for use +// with apply. +type FractionApplyConfiguration struct { + Numerator *int32 `json:"numerator,omitempty"` + Denominator *int32 `json:"denominator,omitempty"` +} + +// FractionApplyConfiguration constructs an declarative configuration of the Fraction type for use with +// apply. +func Fraction() *FractionApplyConfiguration { + return &FractionApplyConfiguration{} +} + +// WithNumerator sets the Numerator field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Numerator field is set to the value of the last call. +func (b *FractionApplyConfiguration) WithNumerator(value int32) *FractionApplyConfiguration { + b.Numerator = &value + return b +} + +// WithDenominator sets the Denominator field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Denominator field is set to the value of the last call. +func (b *FractionApplyConfiguration) WithDenominator(value int32) *FractionApplyConfiguration { + b.Denominator = &value + return b +} diff --git a/apis/applyconfiguration/apis/v1/httprequestmirrorfilter.go b/apis/applyconfiguration/apis/v1/httprequestmirrorfilter.go index 1809ff078a..55c2246b34 100644 --- a/apis/applyconfiguration/apis/v1/httprequestmirrorfilter.go +++ b/apis/applyconfiguration/apis/v1/httprequestmirrorfilter.go @@ -22,6 +22,8 @@ package v1 // with apply. type HTTPRequestMirrorFilterApplyConfiguration struct { BackendRef *BackendObjectReferenceApplyConfiguration `json:"backendRef,omitempty"` + Percent *int32 `json:"percent,omitempty"` + Fraction *FractionApplyConfiguration `json:"fraction,omitempty"` } // HTTPRequestMirrorFilterApplyConfiguration constructs an declarative configuration of the HTTPRequestMirrorFilter type for use with @@ -37,3 +39,19 @@ func (b *HTTPRequestMirrorFilterApplyConfiguration) WithBackendRef(value *Backen b.BackendRef = value return b } + +// WithPercent sets the Percent field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Percent field is set to the value of the last call. +func (b *HTTPRequestMirrorFilterApplyConfiguration) WithPercent(value int32) *HTTPRequestMirrorFilterApplyConfiguration { + b.Percent = &value + return b +} + +// WithFraction sets the Fraction field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Fraction field is set to the value of the last call. +func (b *HTTPRequestMirrorFilterApplyConfiguration) WithFraction(value *FractionApplyConfiguration) *HTTPRequestMirrorFilterApplyConfiguration { + b.Fraction = value + return b +} diff --git a/apis/applyconfiguration/internal/internal.go b/apis/applyconfiguration/internal/internal.go index 31e4bb33e6..56a2995ce2 100644 --- a/apis/applyconfiguration/internal/internal.go +++ b/apis/applyconfiguration/internal/internal.go @@ -282,6 +282,16 @@ var schemaYAML = typed.YAMLObject(`types: - name: lifetimeType type: scalar: string +- name: io.k8s.sigs.gateway-api.apis.v1.Fraction + map: + fields: + - name: denominator + type: + scalar: numeric + - name: numerator + type: + scalar: numeric + default: 0 - name: io.k8s.sigs.gateway-api.apis.v1.FrontendTLSValidation map: fields: @@ -756,6 +766,13 @@ var schemaYAML = typed.YAMLObject(`types: type: namedType: io.k8s.sigs.gateway-api.apis.v1.BackendObjectReference default: {} + - name: fraction + type: + namedType: io.k8s.sigs.gateway-api.apis.v1.Fraction + default: {} + - name: percent + type: + scalar: numeric - name: io.k8s.sigs.gateway-api.apis.v1.HTTPRequestRedirectFilter map: fields: diff --git a/apis/applyconfiguration/utils.go b/apis/applyconfiguration/utils.go index e457c32b52..c88ae790dd 100644 --- a/apis/applyconfiguration/utils.go +++ b/apis/applyconfiguration/utils.go @@ -45,6 +45,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apisv1.CommonRouteSpecApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("CookieConfig"): return &apisv1.CookieConfigApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("Fraction"): + return &apisv1.FractionApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("FrontendTLSValidation"): return &apisv1.FrontendTLSValidationApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("Gateway"): diff --git a/apis/v1/grpcroute_types.go b/apis/v1/grpcroute_types.go index 543b34644f..953ba0243b 100644 --- a/apis/v1/grpcroute_types.go +++ b/apis/v1/grpcroute_types.go @@ -550,6 +550,8 @@ type GRPCRouteFilter struct { // Support: Extended // // +optional + // + // RequestMirror *HTTPRequestMirrorFilter `json:"requestMirror,omitempty"` // ExtensionRef is an optional, implementation-specific extension to the diff --git a/apis/v1/httproute_types.go b/apis/v1/httproute_types.go index b6c2e936ef..4c4f5457f8 100644 --- a/apis/v1/httproute_types.go +++ b/apis/v1/httproute_types.go @@ -757,6 +757,8 @@ type HTTPRouteFilter struct { // Support: Extended // // +optional + // + // RequestMirror *HTTPRequestMirrorFilter `json:"requestMirror,omitempty"` // RequestRedirect defines a schema for a filter that responds to the @@ -1153,6 +1155,29 @@ type HTTPRequestMirrorFilter struct { // // Support: Implementation-specific for any other resource BackendRef BackendObjectReference `json:"backendRef"` + + // Percent represents the percentage of requests that should be + // mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + // requests) and its maximum value is 100 (indicating 100% of requests). + // + // Only one of Fraction or Percent may be specified. If neither field + // is specified, 100% of requests will be mirrored. + // + // +optional + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=100 + // + Percent *int32 `json:"percent,omitempty"` + + // Fraction represents the fraction of requests that should be + // mirrored to BackendRef. + // + // Only one of Fraction or Percent may be specified. If neither field + // is specified, 100% of requests will be mirrored. + // + // +optional + // + Fraction Fraction `json:"fraction,omitempty"` } // HTTPBackendRef defines how a HTTPRoute forwards a HTTP request. diff --git a/apis/v1/shared_types.go b/apis/v1/shared_types.go index 954c605428..7eeec85f84 100644 --- a/apis/v1/shared_types.go +++ b/apis/v1/shared_types.go @@ -855,3 +855,14 @@ const ( // Support: Extended PermanentCookieLifetimeType CookieLifetimeType = "Permanent" ) + +// +kubebuilder:validation:XValidation:message="numerator must be less than or equal to denominator",rule="self.numerator <= self.denominator" +type Fraction struct { + // +kubebuilder:validation:Minimum=0 + Numerator int32 `json:"numerator"` + + // +optional + // +kubebuilder:default=100 + // +kubebuilder:validation:Minimum=1 + Denominator *int32 `json:"denominator,omitempty"` +} diff --git a/apis/v1/zz_generated.deepcopy.go b/apis/v1/zz_generated.deepcopy.go index 02906dc1a6..6f54fec488 100644 --- a/apis/v1/zz_generated.deepcopy.go +++ b/apis/v1/zz_generated.deepcopy.go @@ -150,6 +150,26 @@ func (in *CookieConfig) DeepCopy() *CookieConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Fraction) DeepCopyInto(out *Fraction) { + *out = *in + if in.Denominator != nil { + in, out := &in.Denominator, &out.Denominator + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Fraction. +func (in *Fraction) DeepCopy() *Fraction { + if in == nil { + return nil + } + out := new(Fraction) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FrontendTLSValidation) DeepCopyInto(out *FrontendTLSValidation) { *out = *in @@ -971,6 +991,12 @@ func (in *HTTPQueryParamMatch) DeepCopy() *HTTPQueryParamMatch { func (in *HTTPRequestMirrorFilter) DeepCopyInto(out *HTTPRequestMirrorFilter) { *out = *in in.BackendRef.DeepCopyInto(&out.BackendRef) + if in.Percent != nil { + in, out := &in.Percent, &out.Percent + *out = new(int32) + **out = **in + } + in.Fraction.DeepCopyInto(&out.Fraction) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRequestMirrorFilter. diff --git a/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml index e47547eac1..f0c6cbc77d 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml @@ -725,7 +725,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -737,6 +737,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -843,9 +845,55 @@ spec: - message: Must have port for Service reference rule: '(size(self.group) == 0 && self.kind == ''Service'') ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal + to denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + format: int32 + maximum: 100 + minimum: 0 + type: integer required: - backendRef type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be + specified in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' responseHeaderModifier: description: |- ResponseHeaderModifier defines a schema for a filter that modifies response @@ -1395,7 +1443,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -1407,6 +1455,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -1513,9 +1563,55 @@ spec: - message: Must have port for Service reference rule: '(size(self.group) == 0 && self.kind == ''Service'') ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal to + denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + format: int32 + maximum: 100 + minimum: 0 + type: integer required: - backendRef type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be specified + in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' responseHeaderModifier: description: |- ResponseHeaderModifier defines a schema for a filter that modifies response @@ -3089,7 +3185,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -3101,6 +3197,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -3207,9 +3305,55 @@ spec: - message: Must have port for Service reference rule: '(size(self.group) == 0 && self.kind == ''Service'') ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal + to denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + format: int32 + maximum: 100 + minimum: 0 + type: integer required: - backendRef type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be + specified in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' responseHeaderModifier: description: |- ResponseHeaderModifier defines a schema for a filter that modifies response @@ -3759,7 +3903,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -3771,6 +3915,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -3877,9 +4023,55 @@ spec: - message: Must have port for Service reference rule: '(size(self.group) == 0 && self.kind == ''Service'') ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal to + denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + format: int32 + maximum: 100 + minimum: 0 + type: integer required: - backendRef type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be specified + in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' responseHeaderModifier: description: |- ResponseHeaderModifier defines a schema for a filter that modifies response diff --git a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml index 18ace973b6..797bcf2b4a 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml @@ -717,7 +717,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -729,6 +729,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -835,9 +837,55 @@ spec: - message: Must have port for Service reference rule: '(size(self.group) == 0 && self.kind == ''Service'') ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal + to denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + format: int32 + maximum: 100 + minimum: 0 + type: integer required: - backendRef type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be + specified in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' requestRedirect: description: |- RequestRedirect defines a schema for a filter that responds to the @@ -1728,7 +1776,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -1740,6 +1788,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -1846,9 +1896,55 @@ spec: - message: Must have port for Service reference rule: '(size(self.group) == 0 && self.kind == ''Service'') ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal to + denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + format: int32 + maximum: 100 + minimum: 0 + type: integer required: - backendRef type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be specified + in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' requestRedirect: description: |- RequestRedirect defines a schema for a filter that responds to the @@ -3980,7 +4076,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -3992,6 +4088,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -4098,9 +4196,55 @@ spec: - message: Must have port for Service reference rule: '(size(self.group) == 0 && self.kind == ''Service'') ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal + to denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + format: int32 + maximum: 100 + minimum: 0 + type: integer required: - backendRef type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be + specified in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' requestRedirect: description: |- RequestRedirect defines a schema for a filter that responds to the @@ -4991,7 +5135,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -5003,6 +5147,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -5109,9 +5255,55 @@ spec: - message: Must have port for Service reference rule: '(size(self.group) == 0 && self.kind == ''Service'') ? has(self.port) : true' + fraction: + description: |+ + Fraction represents the fraction of requests that should be + mirrored to BackendRef. + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + properties: + denominator: + default: 100 + format: int32 + minimum: 1 + type: integer + numerator: + format: int32 + minimum: 0 + type: integer + required: + - numerator + type: object + x-kubernetes-validations: + - message: numerator must be less than or equal to + denominator + rule: self.numerator <= self.denominator + percent: + description: |+ + Percent represents the percentage of requests that should be + mirrored to BackendRef. Its minimum value is 0 (indicating 0% of + requests) and its maximum value is 100 (indicating 100% of requests). + + + Only one of Fraction or Percent may be specified. If neither field + is specified, 100% of requests will be mirrored. + + + format: int32 + maximum: 100 + minimum: 0 + type: integer required: - backendRef type: object + x-kubernetes-validations: + - message: Only one of percent or fraction may be specified + in HTTPRequestMirrorFilter + rule: '!(has(self.percent) && has(self.fraction))' requestRedirect: description: |- RequestRedirect defines a schema for a filter that responds to the diff --git a/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml b/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml index 01fc863825..d11f0b279b 100644 --- a/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml @@ -696,7 +696,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -708,6 +708,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -1366,7 +1368,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -1378,6 +1380,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -2903,7 +2907,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -2915,6 +2919,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -3573,7 +3579,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -3585,6 +3591,8 @@ spec: Support: Extended + + properties: backendRef: description: |- diff --git a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml index 6a4a9b6fe1..88aacdec03 100644 --- a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml @@ -688,7 +688,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -700,6 +700,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -1699,7 +1701,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -1711,6 +1713,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -3794,7 +3798,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -3806,6 +3810,8 @@ spec: Support: Extended + + properties: backendRef: description: |- @@ -4805,7 +4811,7 @@ spec: x-kubernetes-list-type: map type: object requestMirror: - description: |- + 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. @@ -4817,6 +4823,8 @@ spec: Support: Extended + + properties: backendRef: description: |- diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index b57c621df3..fc61854014 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -86,6 +86,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "sigs.k8s.io/gateway-api/apis/v1.BackendRef": schema_sigsk8sio_gateway_api_apis_v1_BackendRef(ref), "sigs.k8s.io/gateway-api/apis/v1.CommonRouteSpec": schema_sigsk8sio_gateway_api_apis_v1_CommonRouteSpec(ref), "sigs.k8s.io/gateway-api/apis/v1.CookieConfig": schema_sigsk8sio_gateway_api_apis_v1_CookieConfig(ref), + "sigs.k8s.io/gateway-api/apis/v1.Fraction": schema_sigsk8sio_gateway_api_apis_v1_Fraction(ref), "sigs.k8s.io/gateway-api/apis/v1.FrontendTLSValidation": schema_sigsk8sio_gateway_api_apis_v1_FrontendTLSValidation(ref), "sigs.k8s.io/gateway-api/apis/v1.GRPCBackendRef": schema_sigsk8sio_gateway_api_apis_v1_GRPCBackendRef(ref), "sigs.k8s.io/gateway-api/apis/v1.GRPCHeaderMatch": schema_sigsk8sio_gateway_api_apis_v1_GRPCHeaderMatch(ref), @@ -2916,6 +2917,32 @@ func schema_sigsk8sio_gateway_api_apis_v1_CookieConfig(ref common.ReferenceCallb } } +func schema_sigsk8sio_gateway_api_apis_v1_Fraction(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "numerator": { + SchemaProps: spec.SchemaProps{ + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "denominator": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + Required: []string{"numerator"}, + }, + }, + } +} + func schema_sigsk8sio_gateway_api_apis_v1_FrontendTLSValidation(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -3167,7 +3194,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCRouteFilter(ref common.ReferenceCa }, "requestMirror": { SchemaProps: spec.SchemaProps{ - 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\nThis 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\nSupport: Extended", + 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\nThis 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\nSupport: Extended\n\n\n", Ref: ref("sigs.k8s.io/gateway-api/apis/v1.HTTPRequestMirrorFilter"), }, }, @@ -4371,12 +4398,26 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRequestMirrorFilter(ref common.Ref Ref: ref("sigs.k8s.io/gateway-api/apis/v1.BackendObjectReference"), }, }, + "percent": { + SchemaProps: spec.SchemaProps{ + Description: "Percent represents the percentage of requests that should be mirrored to BackendRef. Its minimum value is 0 (indicating 0% of requests) and its maximum value is 100 (indicating 100% of requests).\n\nOnly one of Fraction or Percent may be specified. If neither field is specified, 100% of requests will be mirrored.\n\n", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "fraction": { + SchemaProps: spec.SchemaProps{ + Description: "Fraction represents the fraction of requests that should be mirrored to BackendRef.\n\nOnly one of Fraction or Percent may be specified. If neither field is specified, 100% of requests will be mirrored.\n\n", + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.Fraction"), + }, + }, }, Required: []string{"backendRef"}, }, }, Dependencies: []string{ - "sigs.k8s.io/gateway-api/apis/v1.BackendObjectReference"}, + "sigs.k8s.io/gateway-api/apis/v1.BackendObjectReference", "sigs.k8s.io/gateway-api/apis/v1.Fraction"}, } } @@ -4508,7 +4549,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteFilter(ref common.ReferenceCa }, "requestMirror": { SchemaProps: spec.SchemaProps{ - 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\nThis 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\nSupport: Extended", + 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\nThis 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\nSupport: Extended\n\n\n", Ref: ref("sigs.k8s.io/gateway-api/apis/v1.HTTPRequestMirrorFilter"), }, }, diff --git a/pkg/test/cel/grcproute_experimental_test.go b/pkg/test/cel/grcproute_experimental_test.go new file mode 100644 index 0000000000..d7aca2abf5 --- /dev/null +++ b/pkg/test/cel/grcproute_experimental_test.go @@ -0,0 +1,90 @@ +//go:build experimental +// +build experimental + +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "testing" + "time" + + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// +// How are tests named? Where to add new tests? +// +// Ensure that tests for newly added CEL validations are added in the correctly +// named test function. For example, if you added a test at the +// `HTTPRouteFilter` hierarchy (i.e. either at the struct level, or on one of +// the immediate descendent fields), then the test will go in the +// TestHTTPRouteFilter function. If the appropriate test function does not +// exist, please create one. +// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +func TestHTTPRequestMirrorFilterForGRPCRouteExperimental(t *testing.T) { + var percent int32 = 42 + var denominator int32 = 1000 + testService := gatewayv1.ObjectName("test-service") + tests := []struct { + name string + wantErrors []string + rules []gatewayv1.GRPCRouteRule + }{ + { + name: "GRPCRoute - Invalid because both percent and fraction are specified", + wantErrors: []string{"Only one of percent or fraction may be specified in HTTPRequestMirrorFilter"}, + rules: []gatewayv1.GRPCRouteRule{{ + Filters: []gatewayv1.GRPCRouteFilter{{ + Type: gatewayv1.GRPCRouteFilterRequestMirror, + RequestMirror: &gatewayv1.HTTPRequestMirrorFilter{ + BackendRef: gatewayv1.BackendObjectReference{ + Name: testService, + Port: ptrTo(gatewayv1.PortNumber(8081)), + }, + Percent: &percent, + Fraction: gatewayv1.Fraction{ + Numerator: 83, + Denominator: &denominator, + }, + }, + }}, + }}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + route := &gatewayv1.GRPCRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("foo-%v", time.Now().UnixNano()), + Namespace: metav1.NamespaceDefault, + }, + Spec: gatewayv1.GRPCRouteSpec{Rules: tc.rules}, + } + validateGRPCRoute(t, route, tc.wantErrors) + }) + } +} diff --git a/pkg/test/cel/httproute_experimental_test.go b/pkg/test/cel/httproute_experimental_test.go index e46ee9299f..7c09c9a0d2 100644 --- a/pkg/test/cel/httproute_experimental_test.go +++ b/pkg/test/cel/httproute_experimental_test.go @@ -432,3 +432,48 @@ func TestHTTPRouteRuleExperimental(t *testing.T) { }) } } + +func TestHTTPRequestMirrorFilterExperimental(t *testing.T) { + var percent int32 = 42 + var denominator int32 = 1000 + testService := gatewayv1.ObjectName("test-service") + tests := []struct { + name string + wantErrors []string + rules []gatewayv1.HTTPRouteRule + }{ + { + name: "HTTPRoute - Invalid because both percent and fraction are specified", + wantErrors: []string{"Only one of percent or fraction may be specified in HTTPRequestMirrorFilter"}, + rules: []gatewayv1.HTTPRouteRule{{ + Filters: []gatewayv1.HTTPRouteFilter{{ + Type: gatewayv1.HTTPRouteFilterRequestMirror, + RequestMirror: &gatewayv1.HTTPRequestMirrorFilter{ + BackendRef: gatewayv1.BackendObjectReference{ + Name: testService, + Port: ptrTo(gatewayv1.PortNumber(8081)), + }, + Percent: &percent, + Fraction: gatewayv1.Fraction{ + Numerator: 83, + Denominator: &denominator, + }, + }, + }}, + }}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + route := &gatewayv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("foo-%v", time.Now().UnixNano()), + Namespace: metav1.NamespaceDefault, + }, + Spec: gatewayv1.HTTPRouteSpec{Rules: tc.rules}, + } + validateHTTPRoute(t, route, tc.wantErrors) + }) + } +}