From 2cf4fca18ae8bf45c1dd6ff51abd74eb28bf0cf8 Mon Sep 17 00:00:00 2001 From: Lin Yang Date: Wed, 18 Sep 2024 15:20:42 +0800 Subject: [PATCH] fix: issue of generating config of gateway filters (#345) * fix: unmarshall filter config Signed-off-by: Lin Yang * fix: generate filter config issue Signed-off-by: Lin Yang --------- Signed-off-by: Lin Yang --- ....gateway.flomesh.io_filterdefinitions.yaml | 2 +- .../extension.gateway.flomesh.io_filters.yaml | 2 +- ...on.gateway.flomesh.io_listenerfilters.yaml | 2 +- pkg/apis/extension/v1alpha1/filter.go | 5 +- .../extension/v1alpha1/filterdefinition.go | 5 +- pkg/apis/extension/v1alpha1/listenerfilter.go | 5 +- pkg/apis/extension/v1alpha1/shared_types.go | 7 ++ .../extension/v1alpha1/filter_controller.go | 3 +- pkg/gateway/fgw/config.go | 64 ++++++++++++++++--- pkg/gateway/fgw/types.go | 2 +- pkg/gateway/processor/v2/filters.go | 2 +- pkg/gateway/processor/v2/gateway.go | 2 +- pkg/gateway/processor/v2/generator.go | 4 +- pkg/gateway/processor/v2/grpcroute.go | 2 +- pkg/gateway/processor/v2/httproute.go | 2 +- 15 files changed, 77 insertions(+), 32 deletions(-) diff --git a/cmd/fsm-bootstrap/crds/extension.gateway.flomesh.io_filterdefinitions.yaml b/cmd/fsm-bootstrap/crds/extension.gateway.flomesh.io_filterdefinitions.yaml index 85a727414..ee0387328 100644 --- a/cmd/fsm-bootstrap/crds/extension.gateway.flomesh.io_filterdefinitions.yaml +++ b/cmd/fsm-bootstrap/crds/extension.gateway.flomesh.io_filterdefinitions.yaml @@ -71,7 +71,7 @@ spec: it should be unique within the namespace maxLength: 63 minLength: 1 - pattern: ^[A-Z](([a-z0-9]+[A-Z]?)*)$ + pattern: ^[A-Z]+(([A-Z]*[a-z0-9]+[A-Z]*)*)$ type: string required: - script diff --git a/cmd/fsm-bootstrap/crds/extension.gateway.flomesh.io_filters.yaml b/cmd/fsm-bootstrap/crds/extension.gateway.flomesh.io_filters.yaml index 072bdb505..baa4b999d 100644 --- a/cmd/fsm-bootstrap/crds/extension.gateway.flomesh.io_filters.yaml +++ b/cmd/fsm-bootstrap/crds/extension.gateway.flomesh.io_filters.yaml @@ -107,7 +107,7 @@ spec: be unique within the namespace maxLength: 63 minLength: 1 - pattern: ^[A-Z](([a-z0-9]+[A-Z]?)*)$ + pattern: ^[A-Z]+(([A-Z]*[a-z0-9]+[A-Z]*)*)$ type: string required: - type diff --git a/cmd/fsm-bootstrap/crds/extension.gateway.flomesh.io_listenerfilters.yaml b/cmd/fsm-bootstrap/crds/extension.gateway.flomesh.io_listenerfilters.yaml index cdfd1c20e..b85df7218 100644 --- a/cmd/fsm-bootstrap/crds/extension.gateway.flomesh.io_listenerfilters.yaml +++ b/cmd/fsm-bootstrap/crds/extension.gateway.flomesh.io_listenerfilters.yaml @@ -143,7 +143,7 @@ spec: it should be unique within the namespace maxLength: 63 minLength: 1 - pattern: ^[A-Z](([a-z0-9]+[A-Z]?)*)$ + pattern: ^[A-Z]+(([A-Z]*[a-z0-9]+[A-Z]*)*)$ type: string required: - targetRefs diff --git a/pkg/apis/extension/v1alpha1/filter.go b/pkg/apis/extension/v1alpha1/filter.go index 37cdbd059..641012c18 100644 --- a/pkg/apis/extension/v1alpha1/filter.go +++ b/pkg/apis/extension/v1alpha1/filter.go @@ -8,10 +8,7 @@ import ( // FilterSpec defines the desired state of Filter type FilterSpec struct { // Type is the type of the Filter in PascalCase, it should be unique within the namespace - // +kubebuilder:validation:Pattern=`^[A-Z](([a-z0-9]+[A-Z]?)*)$` - // +kubebuilder:validation:MinLength=1 - // +kubebuilder:validation:MaxLength=63 - Type string `json:"type"` + Type FilterType `json:"type"` // +optional // DefinitionRef is the reference to the FilterDefinition diff --git a/pkg/apis/extension/v1alpha1/filterdefinition.go b/pkg/apis/extension/v1alpha1/filterdefinition.go index 0b88d343d..51f4e0074 100644 --- a/pkg/apis/extension/v1alpha1/filterdefinition.go +++ b/pkg/apis/extension/v1alpha1/filterdefinition.go @@ -19,10 +19,7 @@ type FilterDefinitionSpec struct { Protocol *FilterProtocol `json:"protocol,omitempty"` // Type is the type of the FilterDefinition in PascalCase, it should be unique within the namespace - // +kubebuilder:validation:Pattern=`^[A-Z](([a-z0-9]+[A-Z]?)*)$` - // +kubebuilder:validation:MinLength=1 - // +kubebuilder:validation:MaxLength=63 - Type string `json:"type"` + Type FilterType `json:"type"` // Script is the list of scripts to be executed // +kubebuilder:validation:MinLength=1 diff --git a/pkg/apis/extension/v1alpha1/listenerfilter.go b/pkg/apis/extension/v1alpha1/listenerfilter.go index b25b090ca..6f0f84eb9 100644 --- a/pkg/apis/extension/v1alpha1/listenerfilter.go +++ b/pkg/apis/extension/v1alpha1/listenerfilter.go @@ -8,10 +8,7 @@ import ( // ListenerFilterSpec defines the desired state of ListenerFilter type ListenerFilterSpec struct { // Type is the type of the ListenerFilter in PascalCase, it should be unique within the namespace - // +kubebuilder:validation:Pattern=`^[A-Z](([a-z0-9]+[A-Z]?)*)$` - // +kubebuilder:validation:MinLength=1 - // +kubebuilder:validation:MaxLength=63 - Type string `json:"type"` + Type FilterType `json:"type"` // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 diff --git a/pkg/apis/extension/v1alpha1/shared_types.go b/pkg/apis/extension/v1alpha1/shared_types.go index babf4bf48..0aac3f3e2 100644 --- a/pkg/apis/extension/v1alpha1/shared_types.go +++ b/pkg/apis/extension/v1alpha1/shared_types.go @@ -18,6 +18,13 @@ type LocalTargetReferenceWithPort struct { Port gwv1.PortNumber `json:"port"` } +// +kubebuilder:validation:Pattern=`^[A-Z]+(([A-Z]*[a-z0-9]+[A-Z]*)*)$` +// +kubebuilder:validation:MinLength=1 +// +kubebuilder:validation:MaxLength=63 + +// FilterType defines the type of filter +type FilterType string + // FilterScope defines the scope of filter type FilterScope string diff --git a/pkg/controllers/extension/v1alpha1/filter_controller.go b/pkg/controllers/extension/v1alpha1/filter_controller.go index c1ab8fa1e..b34c26dc0 100644 --- a/pkg/controllers/extension/v1alpha1/filter_controller.go +++ b/pkg/controllers/extension/v1alpha1/filter_controller.go @@ -89,7 +89,8 @@ func filterDefinitionFilterIndex(obj client.Object) []string { var definitions []string - if filter.Spec.DefinitionRef.Group == extv1alpha1.GroupName && + if filter.Spec.DefinitionRef != nil && + filter.Spec.DefinitionRef.Group == extv1alpha1.GroupName && filter.Spec.DefinitionRef.Kind == constants.GatewayAPIExtensionFilterDefinitionKind { definitions = append(definitions, fmt.Sprintf("%s/%s", filter.Namespace, filter.Spec.DefinitionRef.Name)) } diff --git a/pkg/gateway/fgw/config.go b/pkg/gateway/fgw/config.go index 187cfa9bc..7c3f3bf4d 100644 --- a/pkg/gateway/fgw/config.go +++ b/pkg/gateway/fgw/config.go @@ -1,6 +1,7 @@ package fgw import ( + "encoding/json" "fmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -21,10 +22,10 @@ import ( ) type ConfigSpec struct { - Resources []Resource `json:"resources" hash:"set"` - Secrets map[string]string `json:"secrets"` - Filters map[extv1alpha1.FilterProtocol]map[string]string `json:"filters"` - Version string `json:"version" hash:"ignore"` + Resources []Resource `json:"resources" hash:"set"` + Secrets map[string]string `json:"secrets"` + Filters map[extv1alpha1.FilterProtocol]map[extv1alpha1.FilterType]string `json:"filters"` + Version string `json:"version" hash:"ignore"` } func (c *ConfigSpec) GetVersion() string { @@ -39,7 +40,7 @@ func (c *ConfigSpec) GetSecrets() map[string]string { return c.Secrets } -func (c *ConfigSpec) GetFilters() map[extv1alpha1.FilterProtocol]map[string]string { +func (c *ConfigSpec) GetFilters() map[extv1alpha1.FilterProtocol]map[extv1alpha1.FilterType]string { return c.Filters } @@ -98,11 +99,26 @@ type Listener struct { } type ListenerFilter struct { - Type string `json:"type"` - ExtensionConfig map[string]interface{} `json:",inline,omitempty"` + Type extv1alpha1.FilterType `json:"type"` + ExtensionConfig map[string]interface{} `json:"-"` Key string `json:"key,omitempty"` } +func (f ListenerFilter) MarshalJSON() ([]byte, error) { + type LF ListenerFilter + b, _ := json.Marshal(LF(f)) + + var m map[string]json.RawMessage + _ = json.Unmarshal(b, &m) + + for k, v := range f.ExtensionConfig { + b, _ = json.Marshal(v) + m[k] = b + } + + return json.Marshal(m) +} + type GatewayTLSConfig struct { Mode *gwv1.TLSModeType `json:"mode,omitempty"` Certificates []map[string]string `json:"certificates,omitempty" copier:"-" hash:"set"` @@ -231,10 +247,25 @@ type HTTPRouteFilter struct { RequestMirror *HTTPRequestMirrorFilter `json:"requestMirror,omitempty"` RequestRedirect *gwv1.HTTPRequestRedirectFilter `json:"requestRedirect,omitempty"` URLRewrite *gwv1.HTTPURLRewriteFilter `json:"urlRewrite,omitempty"` - ExtensionConfig map[string]interface{} `json:",inline,omitempty"` + ExtensionConfig map[string]interface{} `json:"-"` Key string `json:"key,omitempty"` } +func (f HTTPRouteFilter) MarshalJSON() ([]byte, error) { + type HRF HTTPRouteFilter + b, _ := json.Marshal(HRF(f)) + + var m map[string]json.RawMessage + _ = json.Unmarshal(b, &m) + + for k, v := range f.ExtensionConfig { + b, _ = json.Marshal(v) + m[k] = b + } + + return json.Marshal(m) +} + // --- type HTTPRequestMirrorFilter struct { @@ -265,10 +296,25 @@ type GRPCRouteFilter struct { RequestHeaderModifier *gwv1.HTTPHeaderFilter `json:"requestHeaderModifier,omitempty"` ResponseHeaderModifier *gwv1.HTTPHeaderFilter `json:"responseHeaderModifier,omitempty"` RequestMirror *HTTPRequestMirrorFilter `json:"requestMirror,omitempty"` - ExtensionConfig map[string]interface{} `json:",inline,omitempty"` + ExtensionConfig map[string]interface{} `json:"-"` Key string `json:"key,omitempty"` } +func (f GRPCRouteFilter) MarshalJSON() ([]byte, error) { + type GRF GRPCRouteFilter + b, _ := json.Marshal(GRF(f)) + + var m map[string]json.RawMessage + _ = json.Unmarshal(b, &m) + + for k, v := range f.ExtensionConfig { + b, _ = json.Marshal(v) + m[k] = b + } + + return json.Marshal(m) +} + // --- type BackendRef struct { diff --git a/pkg/gateway/fgw/types.go b/pkg/gateway/fgw/types.go index 73df669b8..303909e3d 100644 --- a/pkg/gateway/fgw/types.go +++ b/pkg/gateway/fgw/types.go @@ -8,7 +8,7 @@ type Config interface { GetVersion() string GetResources() []Resource GetSecrets() map[string]string - GetFilters() map[extv1alpha1.FilterProtocol]map[string]string + GetFilters() map[extv1alpha1.FilterProtocol]map[extv1alpha1.FilterType]string } type Resource interface { diff --git a/pkg/gateway/processor/v2/filters.go b/pkg/gateway/processor/v2/filters.go index b5eed6c73..7f0e100ee 100644 --- a/pkg/gateway/processor/v2/filters.go +++ b/pkg/gateway/processor/v2/filters.go @@ -17,7 +17,7 @@ import ( "github.com/flomesh-io/fsm/pkg/constants" ) -func (c *ConfigGenerator) resolveFilterDefinition(filterType string, filterScope extv1alpha1.FilterScope, ref *gwv1.LocalObjectReference) *extv1alpha1.FilterDefinition { +func (c *ConfigGenerator) resolveFilterDefinition(filterType extv1alpha1.FilterType, filterScope extv1alpha1.FilterScope, ref *gwv1.LocalObjectReference) *extv1alpha1.FilterDefinition { if ref == nil { return nil } diff --git a/pkg/gateway/processor/v2/gateway.go b/pkg/gateway/processor/v2/gateway.go index 38c22bcd3..3fd2d088d 100644 --- a/pkg/gateway/processor/v2/gateway.go +++ b/pkg/gateway/processor/v2/gateway.go @@ -182,7 +182,7 @@ func (c *ConfigGenerator) processListenerFilters(l gwtypes.Listener, v2l *fgwv2. //} if c.filters[filterProtocol] == nil { - c.filters[filterProtocol] = map[string]string{} + c.filters[filterProtocol] = map[extv1alpha1.FilterType]string{} } if _, ok := c.filters[filterProtocol][filterType]; !ok { c.filters[filterProtocol][filterType] = definition.Spec.Script diff --git a/pkg/gateway/processor/v2/generator.go b/pkg/gateway/processor/v2/generator.go index a37f5c2bc..9913f57a0 100644 --- a/pkg/gateway/processor/v2/generator.go +++ b/pkg/gateway/processor/v2/generator.go @@ -31,7 +31,7 @@ type ConfigGenerator struct { gateway *gwv1.Gateway secretFiles map[string]string services map[string]serviceContext - filters map[extv1alpha1.FilterProtocol]map[string]string + filters map[extv1alpha1.FilterProtocol]map[extv1alpha1.FilterType]string upstreams calculateBackendTargetsFunc backendTLSPolicies map[string]*fgwv2.BackendTLSPolicy backendLBPolicies map[string]*fgwv2.BackendLBPolicy @@ -46,7 +46,7 @@ func NewGatewayConfigGenerator(gateway *gwv1.Gateway, processor processor.Proces gateway: gateway, secretFiles: map[string]string{}, services: map[string]serviceContext{}, - filters: map[extv1alpha1.FilterProtocol]map[string]string{}, + filters: map[extv1alpha1.FilterProtocol]map[extv1alpha1.FilterType]string{}, backendTLSPolicies: map[string]*fgwv2.BackendTLSPolicy{}, backendLBPolicies: map[string]*fgwv2.BackendLBPolicy{}, healthCheckPolicies: map[string]*fgwv2.HealthCheckPolicy{}, diff --git a/pkg/gateway/processor/v2/grpcroute.go b/pkg/gateway/processor/v2/grpcroute.go index aa9a82515..4ab6aa843 100644 --- a/pkg/gateway/processor/v2/grpcroute.go +++ b/pkg/gateway/processor/v2/grpcroute.go @@ -171,7 +171,7 @@ func (c *ConfigGenerator) toV2GRPCRouteFilters(grpcRoute *gwv1.GRPCRoute, routeF } if c.filters[filterProtocol] == nil { - c.filters[filterProtocol] = map[string]string{} + c.filters[filterProtocol] = map[extv1alpha1.FilterType]string{} } if _, ok := c.filters[filterProtocol][filterType]; !ok { c.filters[filterProtocol][filterType] = definition.Spec.Script diff --git a/pkg/gateway/processor/v2/httproute.go b/pkg/gateway/processor/v2/httproute.go index 457fb5a24..145cdee02 100644 --- a/pkg/gateway/processor/v2/httproute.go +++ b/pkg/gateway/processor/v2/httproute.go @@ -170,7 +170,7 @@ func (c *ConfigGenerator) toV2HTTPRouteFilters(httpRoute *gwv1.HTTPRoute, routeF } if c.filters[filterProtocol] == nil { - c.filters[filterProtocol] = map[string]string{} + c.filters[filterProtocol] = map[extv1alpha1.FilterType]string{} } if _, ok := c.filters[filterProtocol][filterType]; !ok { c.filters[filterProtocol][filterType] = definition.Spec.Script