From b5bd72ff6b666a4b737ef04e28db33284d98e976 Mon Sep 17 00:00:00 2001 From: Guilherme Cassolato Date: Wed, 2 Oct 2024 17:58:49 +0200 Subject: [PATCH] route selectors moved back to v1beta2 Signed-off-by: Guilherme Cassolato --- api/v1beta2/route_selectors.go | 68 ++++++++++++++++- .../route_selectors_test.go | 2 +- api/v1beta2/zz_generated.deepcopy.go | 33 +++++++- api/v1beta3/route_selectors.go | 75 ------------------- api/v1beta3/zz_generated.deepcopy.go | 28 ------- pkg/rlptools/wasm/utils.go | 3 +- 6 files changed, 98 insertions(+), 111 deletions(-) rename api/{v1beta3 => v1beta2}/route_selectors_test.go (99%) delete mode 100644 api/v1beta3/route_selectors.go diff --git a/api/v1beta2/route_selectors.go b/api/v1beta2/route_selectors.go index 9689391e6..ef494effa 100644 --- a/api/v1beta2/route_selectors.go +++ b/api/v1beta2/route_selectors.go @@ -1,11 +1,73 @@ package v1beta2 import ( - kuadrantv1beta3 "github.com/kuadrant/kuadrant-operator/api/v1beta3" + "github.com/elliotchance/orderedmap/v2" + gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" + + "github.com/kuadrant/kuadrant-operator/pkg/library/kuadrant" + "github.com/kuadrant/kuadrant-operator/pkg/library/utils" ) -// +kubebuilder:object:generate=false -type RouteSelector = kuadrantv1beta3.RouteSelector +// RouteSelector defines semantics for matching an HTTP request based on conditions +// https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.HTTPRouteSpec +type RouteSelector struct { + // Hostnames defines a set of hostname that should match against the HTTP Host header to select a HTTPRoute to process the request + // https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.HTTPRouteSpec + // +optional + Hostnames []gatewayapiv1.Hostname `json:"hostnames,omitempty"` + + // Matches define conditions used for matching the rule against incoming HTTP requests. + // https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.HTTPRouteSpec + // +optional + // +kubebuilder:validation:MaxItems=8 + Matches []gatewayapiv1.HTTPRouteMatch `json:"matches,omitempty"` +} + +// SelectRules returns, from a HTTPRoute, all HTTPRouteRules that either specify no HTTRouteMatches or that contain at +// least one HTTRouteMatch whose statements expressly include (partially or totally) the statements of at least one of +// the matches of the selector. If the selector does not specify any matches, then all HTTPRouteRules are selected. +// +// Additionally, if the selector specifies a non-empty list of hostnames, a non-empty intersection between the literal +// hostnames of the selector and set of hostnames specified in the HTTPRoute must exist. Otherwise, the function +// returns nil. +func (s *RouteSelector) SelectRules(route *gatewayapiv1.HTTPRoute) (rules []gatewayapiv1.HTTPRouteRule) { + rulesIndices := orderedmap.NewOrderedMap[int, gatewayapiv1.HTTPRouteRule]() + if len(s.Hostnames) > 0 && !utils.Intersect(s.Hostnames, route.Spec.Hostnames) { + return nil + } + if len(s.Matches) == 0 { + return route.Spec.Rules + } + for idx := range s.Matches { + routeSelectorMatch := s.Matches[idx] + for idx, rule := range route.Spec.Rules { + rs := kuadrant.HTTPRouteRuleSelector{HTTPRouteMatch: &routeSelectorMatch} + if rs.Selects(rule) { + rulesIndices.Set(idx, rule) + } + } + } + for el := rulesIndices.Front(); el != nil; el = el.Next() { + rules = append(rules, el.Value) + } + return +} + +// HostnamesForConditions allows avoiding building conditions for hostnames that are excluded by the selector +// or when the hostname is irrelevant (i.e. matches all hostnames) +func (s *RouteSelector) HostnamesForConditions(route *gatewayapiv1.HTTPRoute) []gatewayapiv1.Hostname { + hostnames := route.Spec.Hostnames + + if len(s.Hostnames) > 0 { + hostnames = utils.Intersection(s.Hostnames, hostnames) + } + + if utils.SameElements(hostnames, route.Spec.Hostnames) { + return []gatewayapiv1.Hostname{"*"} + } + + return hostnames +} // +kubebuilder:object:generate=false type RouteSelectorsGetter interface { diff --git a/api/v1beta3/route_selectors_test.go b/api/v1beta2/route_selectors_test.go similarity index 99% rename from api/v1beta3/route_selectors_test.go rename to api/v1beta2/route_selectors_test.go index 0b5e48054..c3934b86f 100644 --- a/api/v1beta3/route_selectors_test.go +++ b/api/v1beta2/route_selectors_test.go @@ -1,6 +1,6 @@ //go:build unit -package v1beta3 +package v1beta2 import ( "fmt" diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go index 3f58b7306..bcdb917cb 100644 --- a/api/v1beta2/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -22,9 +22,9 @@ package v1beta2 import ( apiv1beta2 "github.com/kuadrant/authorino/api/v1beta2" - "github.com/kuadrant/kuadrant-operator/api/v1beta3" "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" + apisv1 "sigs.k8s.io/gateway-api/apis/v1" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -59,7 +59,7 @@ func (in *AuthPolicyCommonSpec) DeepCopyInto(out *AuthPolicyCommonSpec) { *out = *in if in.RouteSelectors != nil { in, out := &in.RouteSelectors, &out.RouteSelectors - *out = make([]v1beta3.RouteSelector, len(*in)) + *out = make([]RouteSelector, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -289,7 +289,7 @@ func (in *CommonAuthRuleSpec) DeepCopyInto(out *CommonAuthRuleSpec) { *out = *in if in.RouteSelectors != nil { in, out := &in.RouteSelectors, &out.RouteSelectors - *out = make([]v1beta3.RouteSelector, len(*in)) + *out = make([]RouteSelector, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -365,6 +365,33 @@ func (in *ResponseSpec) DeepCopy() *ResponseSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouteSelector) DeepCopyInto(out *RouteSelector) { + *out = *in + if in.Hostnames != nil { + in, out := &in.Hostnames, &out.Hostnames + *out = make([]apisv1.Hostname, len(*in)) + copy(*out, *in) + } + if in.Matches != nil { + in, out := &in.Matches, &out.Matches + *out = make([]apisv1.HTTPRouteMatch, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteSelector. +func (in *RouteSelector) DeepCopy() *RouteSelector { + if in == nil { + return nil + } + out := new(RouteSelector) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SuccessResponseSpec) DeepCopyInto(out *SuccessResponseSpec) { *out = *in diff --git a/api/v1beta3/route_selectors.go b/api/v1beta3/route_selectors.go deleted file mode 100644 index 24d3c2044..000000000 --- a/api/v1beta3/route_selectors.go +++ /dev/null @@ -1,75 +0,0 @@ -package v1beta3 - -import ( - "github.com/elliotchance/orderedmap/v2" - gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" - - "github.com/kuadrant/kuadrant-operator/pkg/library/kuadrant" - "github.com/kuadrant/kuadrant-operator/pkg/library/utils" -) - -// RouteSelector defines semantics for matching an HTTP request based on conditions -// https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.HTTPRouteSpec -type RouteSelector struct { - // Hostnames defines a set of hostname that should match against the HTTP Host header to select a HTTPRoute to process the request - // https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.HTTPRouteSpec - // +optional - Hostnames []gatewayapiv1.Hostname `json:"hostnames,omitempty"` - - // Matches define conditions used for matching the rule against incoming HTTP requests. - // https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.HTTPRouteSpec - // +optional - // +kubebuilder:validation:MaxItems=8 - Matches []gatewayapiv1.HTTPRouteMatch `json:"matches,omitempty"` -} - -// SelectRules returns, from a HTTPRoute, all HTTPRouteRules that either specify no HTTRouteMatches or that contain at -// least one HTTRouteMatch whose statements expressly include (partially or totally) the statements of at least one of -// the matches of the selector. If the selector does not specify any matches, then all HTTPRouteRules are selected. -// -// Additionally, if the selector specifies a non-empty list of hostnames, a non-empty intersection between the literal -// hostnames of the selector and set of hostnames specified in the HTTPRoute must exist. Otherwise, the function -// returns nil. -func (s *RouteSelector) SelectRules(route *gatewayapiv1.HTTPRoute) (rules []gatewayapiv1.HTTPRouteRule) { - rulesIndices := orderedmap.NewOrderedMap[int, gatewayapiv1.HTTPRouteRule]() - if len(s.Hostnames) > 0 && !utils.Intersect(s.Hostnames, route.Spec.Hostnames) { - return nil - } - if len(s.Matches) == 0 { - return route.Spec.Rules - } - for idx := range s.Matches { - routeSelectorMatch := s.Matches[idx] - for idx, rule := range route.Spec.Rules { - rs := kuadrant.HTTPRouteRuleSelector{HTTPRouteMatch: &routeSelectorMatch} - if rs.Selects(rule) { - rulesIndices.Set(idx, rule) - } - } - } - for el := rulesIndices.Front(); el != nil; el = el.Next() { - rules = append(rules, el.Value) - } - return -} - -// HostnamesForConditions allows avoiding building conditions for hostnames that are excluded by the selector -// or when the hostname is irrelevant (i.e. matches all hostnames) -func (s *RouteSelector) HostnamesForConditions(route *gatewayapiv1.HTTPRoute) []gatewayapiv1.Hostname { - hostnames := route.Spec.Hostnames - - if len(s.Hostnames) > 0 { - hostnames = utils.Intersection(s.Hostnames, hostnames) - } - - if utils.SameElements(hostnames, route.Spec.Hostnames) { - return []gatewayapiv1.Hostname{"*"} - } - - return hostnames -} - -// +kubebuilder:object:generate=false -type RouteSelectorsGetter interface { - GetRouteSelectors() []RouteSelector -} diff --git a/api/v1beta3/zz_generated.deepcopy.go b/api/v1beta3/zz_generated.deepcopy.go index f42b59203..2b2265ee7 100644 --- a/api/v1beta3/zz_generated.deepcopy.go +++ b/api/v1beta3/zz_generated.deepcopy.go @@ -23,7 +23,6 @@ package v1beta3 import ( "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" - apisv1 "sigs.k8s.io/gateway-api/apis/v1" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -217,33 +216,6 @@ func (in *RateLimitPolicyStatus) DeepCopy() *RateLimitPolicyStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouteSelector) DeepCopyInto(out *RouteSelector) { - *out = *in - if in.Hostnames != nil { - in, out := &in.Hostnames, &out.Hostnames - *out = make([]apisv1.Hostname, len(*in)) - copy(*out, *in) - } - if in.Matches != nil { - in, out := &in.Matches, &out.Matches - *out = make([]apisv1.HTTPRouteMatch, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteSelector. -func (in *RouteSelector) DeepCopy() *RouteSelector { - if in == nil { - return nil - } - out := new(RouteSelector) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WhenCondition) DeepCopyInto(out *WhenCondition) { *out = *in diff --git a/pkg/rlptools/wasm/utils.go b/pkg/rlptools/wasm/utils.go index 158aaa908..447fba440 100644 --- a/pkg/rlptools/wasm/utils.go +++ b/pkg/rlptools/wasm/utils.go @@ -18,6 +18,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" + kuadrantv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" kuadrantv1beta3 "github.com/kuadrant/kuadrant-operator/api/v1beta3" "github.com/kuadrant/kuadrant-operator/pkg/common" kuadrantgatewayapi "github.com/kuadrant/kuadrant-operator/pkg/library/gatewayapi" @@ -117,7 +118,7 @@ func conditionsFromLimit(limit *kuadrantv1beta3.Limit, route *gatewayapiv1.HTTPR routeConditions := make([]Condition, 0) // build conditions from all rules if no route selectors are defined - hostnamesForConditions := (&kuadrantv1beta3.RouteSelector{}).HostnamesForConditions(route) + hostnamesForConditions := (&kuadrantv1beta2.RouteSelector{}).HostnamesForConditions(route) for _, rule := range route.Spec.Rules { routeConditions = append(routeConditions, conditionsFromRule(rule, hostnamesForConditions)...) }