From 14f252f9781be9ec378f71ebfbb22d85425bf2a3 Mon Sep 17 00:00:00 2001 From: Mattia Lavacca Date: Thu, 26 Oct 2023 15:44:38 +0200 Subject: [PATCH 1/5] feat: kong implementationSpecific pathType Signed-off-by: Mattia Lavacca --- pkg/i2gw/providers/common/converter.go | 30 ++++--- pkg/i2gw/providers/common/converter_test.go | 34 ++++---- pkg/i2gw/providers/common/utils.go | 4 + pkg/i2gw/providers/ingressnginx/converter.go | 2 +- pkg/i2gw/providers/kong/converter.go | 33 ++++++- pkg/i2gw/providers/kong/converter_test.go | 87 +++++++++++++++++++ .../providers/kong/header_matching_test.go | 2 +- .../providers/kong/method_matching_test.go | 2 +- 8 files changed, 161 insertions(+), 33 deletions(-) diff --git a/pkg/i2gw/providers/common/converter.go b/pkg/i2gw/providers/common/converter.go index 6ce814ee..081641fc 100644 --- a/pkg/i2gw/providers/common/converter.go +++ b/pkg/i2gw/providers/common/converter.go @@ -30,9 +30,13 @@ import ( gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) +// ToHTTPRouteMatchOption is an option to give the providers the possibility to customize +// HTTPRouteMatch support. +type ToHTTPRouteMatchOption func(routePath networkingv1.HTTPIngressPath, path *field.Path) (*gatewayv1beta1.HTTPRouteMatch, *field.Error) + // ToGateway converts the received ingresses to i2gw.GatewayResources, // without taking into consideration any provider specific logic. -func ToGateway(ingresses []networkingv1.Ingress) (i2gw.GatewayResources, field.ErrorList) { +func ToGateway(ingresses []networkingv1.Ingress, toHTTPRouteMatchCustom ToHTTPRouteMatchOption) (i2gw.GatewayResources, field.ErrorList) { aggregator := ingressAggregator{ruleGroups: map[ruleGroupKey]*ingressRuleGroup{}} var errs field.ErrorList @@ -43,7 +47,7 @@ func ToGateway(ingresses []networkingv1.Ingress) (i2gw.GatewayResources, field.E return i2gw.GatewayResources{}, errs } - routes, gateways, errs := aggregator.toHTTPRoutesAndGateways() + routes, gateways, errs := aggregator.toHTTPRoutesAndGateways(toHTTPRouteMatchCustom) if len(errs) > 0 { return i2gw.GatewayResources{}, errs } @@ -157,7 +161,7 @@ func (a *ingressAggregator) addIngressRule(namespace, name, ingressClass string, rg.rules = append(rg.rules, ingressRule{rule: rule}) } -func (a *ingressAggregator) toHTTPRoutesAndGateways() ([]gatewayv1beta1.HTTPRoute, []gatewayv1beta1.Gateway, field.ErrorList) { +func (a *ingressAggregator) toHTTPRoutesAndGateways(toHTTPRouteMatchCustom ToHTTPRouteMatchOption) ([]gatewayv1beta1.HTTPRoute, []gatewayv1beta1.Gateway, field.ErrorList) { var httpRoutes []gatewayv1beta1.HTTPRoute var errors field.ErrorList listenersByNamespacedGateway := map[string][]gatewayv1beta1.Listener{} @@ -178,7 +182,7 @@ func (a *ingressAggregator) toHTTPRoutesAndGateways() ([]gatewayv1beta1.HTTPRout } gwKey := fmt.Sprintf("%s/%s", rg.namespace, rg.ingressClass) listenersByNamespacedGateway[gwKey] = append(listenersByNamespacedGateway[gwKey], listener) - httpRoute, errs := rg.toHTTPRoute() + httpRoute, errs := rg.toHTTPRoute(toHTTPRouteMatchCustom) httpRoutes = append(httpRoutes, httpRoute) errors = append(errors, errs...) } @@ -269,7 +273,7 @@ func (a *ingressAggregator) toHTTPRoutesAndGateways() ([]gatewayv1beta1.HTTPRout return httpRoutes, gateways, errors } -func (rg *ingressRuleGroup) toHTTPRoute() (gatewayv1beta1.HTTPRoute, field.ErrorList) { +func (rg *ingressRuleGroup) toHTTPRoute(toHTTPRouteMatchCustom ToHTTPRouteMatchOption) (gatewayv1beta1.HTTPRoute, field.ErrorList) { pathsByMatchGroup := map[pathMatchKey][]ingressPath{} var errors field.ErrorList @@ -305,7 +309,13 @@ func (rg *ingressRuleGroup) toHTTPRoute() (gatewayv1beta1.HTTPRoute, field.Error for _, paths := range pathsByMatchGroup { path := paths[0] fieldPath := field.NewPath("spec", "rules").Index(path.ruleIdx).Child(path.ruleType).Child("paths").Index(path.pathIdx) - match, err := toHTTPRouteMatch(path, fieldPath) + var match *gatewayv1beta1.HTTPRouteMatch + var err *field.Error + if toHTTPRouteMatchCustom != nil { + match, err = toHTTPRouteMatchCustom(path.path, fieldPath) + } else { + match, err = toHTTPRouteMatch(path.path, fieldPath) + } if err != nil { errors = append(errors, err) continue @@ -348,20 +358,20 @@ func getPathMatchKey(ip ingressPath) pathMatchKey { return pathMatchKey(fmt.Sprintf("%s/%s", pathType, ip.path.Path)) } -func toHTTPRouteMatch(ip ingressPath, path *field.Path) (*gatewayv1beta1.HTTPRouteMatch, *field.Error) { +func toHTTPRouteMatch(routePath networkingv1.HTTPIngressPath, path *field.Path) (*gatewayv1beta1.HTTPRouteMatch, *field.Error) { pmPrefix := gatewayv1beta1.PathMatchPathPrefix pmExact := gatewayv1beta1.PathMatchExact - match := &gatewayv1beta1.HTTPRouteMatch{Path: &gatewayv1beta1.HTTPPathMatch{Value: &ip.path.Path}} + match := &gatewayv1beta1.HTTPRouteMatch{Path: &gatewayv1beta1.HTTPPathMatch{Value: &routePath.Path}} //exhaustive:ignore -explicit-exhaustive-switch // networkingv1.PathTypeImplementationSpecific is not supported here, hence it goes into default case. - switch *ip.path.PathType { + switch *routePath.PathType { case networkingv1.PathTypePrefix: match.Path.Type = &pmPrefix case networkingv1.PathTypeExact: match.Path.Type = &pmExact default: - return nil, field.Invalid(path.Child("pathType"), ip.path.PathType, fmt.Sprintf("unsupported path match type: %s", *ip.path.PathType)) + return nil, field.Invalid(path.Child("pathType"), routePath.PathType, fmt.Sprintf("unsupported path match type: %s", *routePath.PathType)) } return match, nil diff --git a/pkg/i2gw/providers/common/converter_test.go b/pkg/i2gw/providers/common/converter_test.go index c41f8028..5014607d 100644 --- a/pkg/i2gw/providers/common/converter_test.go +++ b/pkg/i2gw/providers/common/converter_test.go @@ -85,7 +85,7 @@ func Test_ingresses2GatewaysAndHttpRoutes(t *testing.T) { Name: "example-com-http", Port: 80, Protocol: gatewayv1beta1.HTTPProtocolType, - Hostname: ptrTo(gatewayv1beta1.Hostname("example.com")), + Hostname: PtrTo(gatewayv1beta1.Hostname("example.com")), }}, }, }, @@ -104,14 +104,14 @@ func Test_ingresses2GatewaysAndHttpRoutes(t *testing.T) { Matches: []gatewayv1beta1.HTTPRouteMatch{{ Path: &gatewayv1beta1.HTTPPathMatch{ Type: &gPathPrefix, - Value: ptrTo("/foo"), + Value: PtrTo("/foo"), }, }}, BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ BackendRef: gatewayv1beta1.BackendRef{ BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Name: "example", - Port: ptrTo(gatewayv1beta1.PortNumber(3000)), + Port: PtrTo(gatewayv1beta1.PortNumber(3000)), }, }, }}, @@ -162,12 +162,12 @@ func Test_ingresses2GatewaysAndHttpRoutes(t *testing.T) { Name: "example-com-http", Port: 80, Protocol: gatewayv1beta1.HTTPProtocolType, - Hostname: ptrTo(gatewayv1beta1.Hostname("example.com")), + Hostname: PtrTo(gatewayv1beta1.Hostname("example.com")), }, { Name: "example-com-https", Port: 443, Protocol: gatewayv1beta1.HTTPSProtocolType, - Hostname: ptrTo(gatewayv1beta1.Hostname("example.com")), + Hostname: PtrTo(gatewayv1beta1.Hostname("example.com")), TLS: &gatewayv1beta1.GatewayTLSConfig{ CertificateRefs: []gatewayv1beta1.SecretObjectReference{{ Name: "example-cert", @@ -191,14 +191,14 @@ func Test_ingresses2GatewaysAndHttpRoutes(t *testing.T) { Matches: []gatewayv1beta1.HTTPRouteMatch{{ Path: &gatewayv1beta1.HTTPPathMatch{ Type: &gPathPrefix, - Value: ptrTo("/foo"), + Value: PtrTo("/foo"), }, }}, BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ BackendRef: gatewayv1beta1.BackendRef{ BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Name: "example", - Port: ptrTo(gatewayv1beta1.PortNumber(3000)), + Port: PtrTo(gatewayv1beta1.PortNumber(3000)), }, }, }}, @@ -214,7 +214,7 @@ func Test_ingresses2GatewaysAndHttpRoutes(t *testing.T) { ingresses: []networkingv1.Ingress{{ ObjectMeta: metav1.ObjectMeta{Name: "net", Namespace: "different"}, Spec: networkingv1.IngressSpec{ - IngressClassName: ptrTo("example-proxy"), + IngressClassName: PtrTo("example-proxy"), Rules: []networkingv1.IngressRule{{ Host: "example.net", IngressRuleValue: networkingv1.IngressRuleValue{ @@ -226,7 +226,7 @@ func Test_ingresses2GatewaysAndHttpRoutes(t *testing.T) { Resource: &corev1.TypedLocalObjectReference{ Name: "custom", Kind: "StorageBucket", - APIGroup: ptrTo("vendor.example.com"), + APIGroup: PtrTo("vendor.example.com"), }, }, }}, @@ -253,7 +253,7 @@ func Test_ingresses2GatewaysAndHttpRoutes(t *testing.T) { Name: "example-net-http", Port: 80, Protocol: gatewayv1beta1.HTTPProtocolType, - Hostname: ptrTo(gatewayv1beta1.Hostname("example.net")), + Hostname: PtrTo(gatewayv1beta1.Hostname("example.net")), }}, }, }, @@ -272,15 +272,15 @@ func Test_ingresses2GatewaysAndHttpRoutes(t *testing.T) { Matches: []gatewayv1beta1.HTTPRouteMatch{{ Path: &gatewayv1beta1.HTTPPathMatch{ Type: &gExact, - Value: ptrTo("/bar"), + Value: PtrTo("/bar"), }, }}, BackendRefs: []gatewayv1beta1.HTTPBackendRef{{ BackendRef: gatewayv1beta1.BackendRef{ BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Name: "custom", - Group: ptrTo(gatewayv1beta1.Group("vendor.example.com")), - Kind: ptrTo(gatewayv1beta1.Kind("StorageBucket")), + Group: PtrTo(gatewayv1beta1.Group("vendor.example.com")), + Kind: PtrTo(gatewayv1beta1.Kind("StorageBucket")), }, }, }}, @@ -300,7 +300,7 @@ func Test_ingresses2GatewaysAndHttpRoutes(t *testing.T) { BackendRef: gatewayv1beta1.BackendRef{ BackendObjectReference: gatewayv1beta1.BackendObjectReference{ Name: "default", - Port: ptrTo(gatewayv1beta1.PortNumber(8080)), + Port: PtrTo(gatewayv1beta1.PortNumber(8080)), }, }}, }}, @@ -316,7 +316,7 @@ func Test_ingresses2GatewaysAndHttpRoutes(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - gatewayResources, errs := ToGateway(tc.ingresses) + gatewayResources, errs := ToGateway(tc.ingresses, nil) if len(gatewayResources.HTTPRoutes) != len(tc.expectedGatewayResources.HTTPRoutes) { t.Errorf("Expected %d HTTPRoutes, got %d: %+v", @@ -358,7 +358,3 @@ func Test_ingresses2GatewaysAndHttpRoutes(t *testing.T) { }) } } - -func ptrTo[T any](a T) *T { - return &a -} diff --git a/pkg/i2gw/providers/common/utils.go b/pkg/i2gw/providers/common/utils.go index ef472fec..dcc91306 100644 --- a/pkg/i2gw/providers/common/utils.go +++ b/pkg/i2gw/providers/common/utils.go @@ -126,3 +126,7 @@ func ToBackendRef(ib networkingv1.IngressBackend, path *field.Path) (*gatewayv1b }, }, nil } + +func PtrTo[T any](a T) *T { + return &a +} diff --git a/pkg/i2gw/providers/ingressnginx/converter.go b/pkg/i2gw/providers/ingressnginx/converter.go index 6216e5eb..ef43128b 100644 --- a/pkg/i2gw/providers/ingressnginx/converter.go +++ b/pkg/i2gw/providers/ingressnginx/converter.go @@ -45,7 +45,7 @@ func (c *converter) ToGatewayAPI(resources i2gw.InputResources) (i2gw.GatewayRes // Convert plain ingress resources to gateway resources, ignoring all // provider-specific features. - gatewayResources, errs := common.ToGateway(resources.Ingresses) + gatewayResources, errs := common.ToGateway(resources.Ingresses, nil) if len(errs) > 0 { return i2gw.GatewayResources{}, errs } diff --git a/pkg/i2gw/providers/kong/converter.go b/pkg/i2gw/providers/kong/converter.go index c683af23..10c77134 100644 --- a/pkg/i2gw/providers/kong/converter.go +++ b/pkg/i2gw/providers/kong/converter.go @@ -17,9 +17,14 @@ limitations under the License. package kong import ( + "fmt" + "strings" + "github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw" "github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/providers/common" + networkingv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/util/validation/field" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) // converter implements the ToGatewayAPI function of i2gw.ResourceConverter interface. @@ -47,7 +52,7 @@ func (c *converter) ToGatewayAPI(resources i2gw.InputResources) (i2gw.GatewayRes // Convert plain ingress resources to gateway resources, ignoring all // provider-specific features. - gatewayResources, errs := common.ToGateway(resources.Ingresses) + gatewayResources, errs := common.ToGateway(resources.Ingresses, toHTTPRouteMatchOption) if len(errs) > 0 { return i2gw.GatewayResources{}, errs } @@ -61,3 +66,29 @@ func (c *converter) ToGatewayAPI(resources i2gw.InputResources) (i2gw.GatewayRes return gatewayResources, errs } + +func toHTTPRouteMatchOption(routePath networkingv1.HTTPIngressPath, path *field.Path) (*gatewayv1beta1.HTTPRouteMatch, *field.Error) { + pmPrefix := gatewayv1beta1.PathMatchPathPrefix + pmExact := gatewayv1beta1.PathMatchExact + pmRegex := gatewayv1beta1.PathMatchRegularExpression + + match := &gatewayv1beta1.HTTPRouteMatch{Path: &gatewayv1beta1.HTTPPathMatch{Value: &routePath.Path}} + switch *routePath.PathType { + case networkingv1.PathTypePrefix: + match.Path.Type = &pmPrefix + case networkingv1.PathTypeExact: + match.Path.Type = &pmExact + case networkingv1.PathTypeImplementationSpecific: + if strings.HasPrefix(routePath.Path, "/~") { + match.Path.Type = &pmRegex + match.Path.Value = common.PtrTo(strings.TrimPrefix(*match.Path.Value, "/~")) + } else { + match.Path.Type = &pmPrefix + } + + default: + return nil, field.Invalid(path.Child("pathType"), routePath.PathType, fmt.Sprintf("unsupported path match type: %s", *routePath.PathType)) + } + + return match, nil +} diff --git a/pkg/i2gw/providers/kong/converter_test.go b/pkg/i2gw/providers/kong/converter_test.go index 6ff01316..88e84257 100644 --- a/pkg/i2gw/providers/kong/converter_test.go +++ b/pkg/i2gw/providers/kong/converter_test.go @@ -33,7 +33,9 @@ import ( func Test_ToGateway(t *testing.T) { iPrefix := networkingv1.PathTypePrefix + isPathType := networkingv1.PathTypeImplementationSpecific gPathPrefix := gatewayv1beta1.PathMatchPathPrefix + gPathRegex := gatewayv1beta1.PathMatchRegularExpression testCases := []struct { name string @@ -322,6 +324,91 @@ func Test_ToGateway(t *testing.T) { }, expectedErrors: field.ErrorList{}, }, + { + name: "ImplementationSpecific HTTPRouteMatching", + ingresses: []networkingv1.Ingress{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "implementation-specific-regex", + Namespace: "default", + }, + Spec: networkingv1.IngressSpec{ + IngressClassName: ptrTo("ingress-kong"), + Rules: []networkingv1.IngressRule{{ + Host: "test.mydomain.com", + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{{ + Path: "/~/echo/**/test", + PathType: &isPathType, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }}, + }, + }, + }}, + }, + }, + }, + expectedGatewayResources: i2gw.GatewayResources{ + Gateways: map[types.NamespacedName]gatewayv1beta1.Gateway{ + {Namespace: "default", Name: "ingress-kong"}: { + ObjectMeta: metav1.ObjectMeta{Name: "ingress-kong", Namespace: "default"}, + Spec: gatewayv1beta1.GatewaySpec{ + GatewayClassName: "ingress-kong", + Listeners: []gatewayv1beta1.Listener{{ + Name: "test-mydomain-com-http", + Port: 80, + Protocol: gatewayv1beta1.HTTPProtocolType, + Hostname: ptrTo(gatewayv1beta1.Hostname("test.mydomain.com")), + }}, + }, + }, + }, + HTTPRoutes: map[types.NamespacedName]gatewayv1beta1.HTTPRoute{ + {Namespace: "default", Name: "test-mydomain-com"}: { + ObjectMeta: metav1.ObjectMeta{Name: "test-mydomain-com", Namespace: "default"}, + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Name: "ingress-kong", + }}, + }, + Hostnames: []gatewayv1beta1.Hostname{"test.mydomain.com"}, + Rules: []gatewayv1beta1.HTTPRouteRule{ + { + Matches: []gatewayv1beta1.HTTPRouteMatch{ + { + Path: &gatewayv1beta1.HTTPPathMatch{ + Type: &gPathRegex, + Value: ptrTo("/echo/**/test"), + }, + }, + }, + BackendRefs: []gatewayv1beta1.HTTPBackendRef{ + { + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: "test", + Port: ptrTo(gatewayv1beta1.PortNumber(80)), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + expectedErrors: field.ErrorList{}, + }, } for _, tc := range testCases { diff --git a/pkg/i2gw/providers/kong/header_matching_test.go b/pkg/i2gw/providers/kong/header_matching_test.go index 6337972d..17052800 100644 --- a/pkg/i2gw/providers/kong/header_matching_test.go +++ b/pkg/i2gw/providers/kong/header_matching_test.go @@ -246,7 +246,7 @@ func TestHeaderMatchingFeature(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses) + gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses, toHTTPRouteMatchOption) if len(errs) != 0 { t.Errorf("Expected no errors, got %d: %+v", len(errs), errs) } diff --git a/pkg/i2gw/providers/kong/method_matching_test.go b/pkg/i2gw/providers/kong/method_matching_test.go index aaa461d4..7e30f772 100644 --- a/pkg/i2gw/providers/kong/method_matching_test.go +++ b/pkg/i2gw/providers/kong/method_matching_test.go @@ -189,7 +189,7 @@ func TestMethodMatchingFeature(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses) + gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses, toHTTPRouteMatchOption) if len(errs) != 0 { t.Errorf("Expected no errors, got %d: %+v", len(errs), errs) } From ed3aee33a540e9e01f8061500e70bbd18e0fe680 Mon Sep 17 00:00:00 2001 From: Mattia Lavacca Date: Sat, 11 Nov 2023 09:02:36 +0100 Subject: [PATCH 2/5] implementation-specific options A new options struct has been introduced. Such a struct can be customized by providers to implement provider-specific API features. Signed-off-by: Mattia Lavacca --- pkg/i2gw/provider.go | 10 +++++ pkg/i2gw/providers/common/converter.go | 32 ++++++-------- pkg/i2gw/providers/common/converter_test.go | 2 +- pkg/i2gw/providers/ingressnginx/converter.go | 2 +- .../providers/ingressnginx/converter_test.go | 44 +++++++++++++++++++ pkg/i2gw/providers/kong/README.md | 12 ++++- pkg/i2gw/providers/kong/converter.go | 35 ++------------- pkg/i2gw/providers/kong/converter_test.go | 4 +- .../providers/kong/header_matching_test.go | 4 +- .../providers/kong/implementation_specific.go | 35 +++++++++++++++ .../providers/kong/method_matching_test.go | 4 +- 11 files changed, 126 insertions(+), 58 deletions(-) create mode 100644 pkg/i2gw/providers/kong/implementation_specific.go diff --git a/pkg/i2gw/provider.go b/pkg/i2gw/provider.go index 6dcf9e8b..235a8da0 100644 --- a/pkg/i2gw/provider.go +++ b/pkg/i2gw/provider.go @@ -73,6 +73,16 @@ type ResourceConverter interface { ToGatewayAPI(resources InputResources) (GatewayResources, field.ErrorList) } +// HTTPPathMatchOption is an option to customize the ingress implementationSpecific +// match type conversion. +type HTTPPathMatchOption func(*gatewayv1beta1.HTTPPathMatch) + +// ImplementationSpecificOptions contains all the pointers to implementation-specific +// customization functions. +type ImplementationSpecificOptions struct { + HTTPPathmatch HTTPPathMatchOption +} + // InputResources contains all Ingress objects, and Provider specific // custom resources. type InputResources struct { diff --git a/pkg/i2gw/providers/common/converter.go b/pkg/i2gw/providers/common/converter.go index 081641fc..a023bf50 100644 --- a/pkg/i2gw/providers/common/converter.go +++ b/pkg/i2gw/providers/common/converter.go @@ -30,13 +30,9 @@ import ( gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) -// ToHTTPRouteMatchOption is an option to give the providers the possibility to customize -// HTTPRouteMatch support. -type ToHTTPRouteMatchOption func(routePath networkingv1.HTTPIngressPath, path *field.Path) (*gatewayv1beta1.HTTPRouteMatch, *field.Error) - // ToGateway converts the received ingresses to i2gw.GatewayResources, // without taking into consideration any provider specific logic. -func ToGateway(ingresses []networkingv1.Ingress, toHTTPRouteMatchCustom ToHTTPRouteMatchOption) (i2gw.GatewayResources, field.ErrorList) { +func ToGateway(ingresses []networkingv1.Ingress, options i2gw.ImplementationSpecificOptions) (i2gw.GatewayResources, field.ErrorList) { aggregator := ingressAggregator{ruleGroups: map[ruleGroupKey]*ingressRuleGroup{}} var errs field.ErrorList @@ -47,7 +43,7 @@ func ToGateway(ingresses []networkingv1.Ingress, toHTTPRouteMatchCustom ToHTTPRo return i2gw.GatewayResources{}, errs } - routes, gateways, errs := aggregator.toHTTPRoutesAndGateways(toHTTPRouteMatchCustom) + routes, gateways, errs := aggregator.toHTTPRoutesAndGateways(options) if len(errs) > 0 { return i2gw.GatewayResources{}, errs } @@ -161,7 +157,7 @@ func (a *ingressAggregator) addIngressRule(namespace, name, ingressClass string, rg.rules = append(rg.rules, ingressRule{rule: rule}) } -func (a *ingressAggregator) toHTTPRoutesAndGateways(toHTTPRouteMatchCustom ToHTTPRouteMatchOption) ([]gatewayv1beta1.HTTPRoute, []gatewayv1beta1.Gateway, field.ErrorList) { +func (a *ingressAggregator) toHTTPRoutesAndGateways(options i2gw.ImplementationSpecificOptions) ([]gatewayv1beta1.HTTPRoute, []gatewayv1beta1.Gateway, field.ErrorList) { var httpRoutes []gatewayv1beta1.HTTPRoute var errors field.ErrorList listenersByNamespacedGateway := map[string][]gatewayv1beta1.Listener{} @@ -182,7 +178,7 @@ func (a *ingressAggregator) toHTTPRoutesAndGateways(toHTTPRouteMatchCustom ToHTT } gwKey := fmt.Sprintf("%s/%s", rg.namespace, rg.ingressClass) listenersByNamespacedGateway[gwKey] = append(listenersByNamespacedGateway[gwKey], listener) - httpRoute, errs := rg.toHTTPRoute(toHTTPRouteMatchCustom) + httpRoute, errs := rg.toHTTPRoute(options) httpRoutes = append(httpRoutes, httpRoute) errors = append(errors, errs...) } @@ -273,7 +269,7 @@ func (a *ingressAggregator) toHTTPRoutesAndGateways(toHTTPRouteMatchCustom ToHTT return httpRoutes, gateways, errors } -func (rg *ingressRuleGroup) toHTTPRoute(toHTTPRouteMatchCustom ToHTTPRouteMatchOption) (gatewayv1beta1.HTTPRoute, field.ErrorList) { +func (rg *ingressRuleGroup) toHTTPRoute(options i2gw.ImplementationSpecificOptions) (gatewayv1beta1.HTTPRoute, field.ErrorList) { pathsByMatchGroup := map[pathMatchKey][]ingressPath{} var errors field.ErrorList @@ -311,11 +307,7 @@ func (rg *ingressRuleGroup) toHTTPRoute(toHTTPRouteMatchCustom ToHTTPRouteMatchO fieldPath := field.NewPath("spec", "rules").Index(path.ruleIdx).Child(path.ruleType).Child("paths").Index(path.pathIdx) var match *gatewayv1beta1.HTTPRouteMatch var err *field.Error - if toHTTPRouteMatchCustom != nil { - match, err = toHTTPRouteMatchCustom(path.path, fieldPath) - } else { - match, err = toHTTPRouteMatch(path.path, fieldPath) - } + match, err = toHTTPRouteMatch(path.path, fieldPath, options.HTTPPathmatch) if err != nil { errors = append(errors, err) continue @@ -358,20 +350,22 @@ func getPathMatchKey(ip ingressPath) pathMatchKey { return pathMatchKey(fmt.Sprintf("%s/%s", pathType, ip.path.Path)) } -func toHTTPRouteMatch(routePath networkingv1.HTTPIngressPath, path *field.Path) (*gatewayv1beta1.HTTPRouteMatch, *field.Error) { +func toHTTPRouteMatch(routePath networkingv1.HTTPIngressPath, path *field.Path, implementationSpecificPath i2gw.HTTPPathMatchOption) (*gatewayv1beta1.HTTPRouteMatch, *field.Error) { pmPrefix := gatewayv1beta1.PathMatchPathPrefix pmExact := gatewayv1beta1.PathMatchExact match := &gatewayv1beta1.HTTPRouteMatch{Path: &gatewayv1beta1.HTTPPathMatch{Value: &routePath.Path}} - //exhaustive:ignore -explicit-exhaustive-switch - // networkingv1.PathTypeImplementationSpecific is not supported here, hence it goes into default case. switch *routePath.PathType { case networkingv1.PathTypePrefix: match.Path.Type = &pmPrefix case networkingv1.PathTypeExact: match.Path.Type = &pmExact - default: - return nil, field.Invalid(path.Child("pathType"), routePath.PathType, fmt.Sprintf("unsupported path match type: %s", *routePath.PathType)) + case networkingv1.PathTypeImplementationSpecific: + if implementationSpecificPath != nil { + implementationSpecificPath(match.Path) + } else { + return nil, field.Invalid(path.Child("pathType"), routePath.PathType, fmt.Sprintf("unsupported path match type: %s", *routePath.PathType)) + } } return match, nil diff --git a/pkg/i2gw/providers/common/converter_test.go b/pkg/i2gw/providers/common/converter_test.go index 5014607d..cff81d59 100644 --- a/pkg/i2gw/providers/common/converter_test.go +++ b/pkg/i2gw/providers/common/converter_test.go @@ -316,7 +316,7 @@ func Test_ingresses2GatewaysAndHttpRoutes(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - gatewayResources, errs := ToGateway(tc.ingresses, nil) + gatewayResources, errs := ToGateway(tc.ingresses, i2gw.ImplementationSpecificOptions{}) if len(gatewayResources.HTTPRoutes) != len(tc.expectedGatewayResources.HTTPRoutes) { t.Errorf("Expected %d HTTPRoutes, got %d: %+v", diff --git a/pkg/i2gw/providers/ingressnginx/converter.go b/pkg/i2gw/providers/ingressnginx/converter.go index ef43128b..7a5e5121 100644 --- a/pkg/i2gw/providers/ingressnginx/converter.go +++ b/pkg/i2gw/providers/ingressnginx/converter.go @@ -45,7 +45,7 @@ func (c *converter) ToGatewayAPI(resources i2gw.InputResources) (i2gw.GatewayRes // Convert plain ingress resources to gateway resources, ignoring all // provider-specific features. - gatewayResources, errs := common.ToGateway(resources.Ingresses, nil) + gatewayResources, errs := common.ToGateway(resources.Ingresses, i2gw.ImplementationSpecificOptions{}) if len(errs) > 0 { return i2gw.GatewayResources{}, errs } diff --git a/pkg/i2gw/providers/ingressnginx/converter_test.go b/pkg/i2gw/providers/ingressnginx/converter_test.go index 745cf172..71ac1fb2 100644 --- a/pkg/i2gw/providers/ingressnginx/converter_test.go +++ b/pkg/i2gw/providers/ingressnginx/converter_test.go @@ -29,6 +29,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/utils/pointer" gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) @@ -36,6 +37,7 @@ func Test_ToGateway(t *testing.T) { iPrefix := networkingv1.PathTypePrefix //iExact := networkingv1.PathTypeExact gPathPrefix := gatewayv1beta1.PathMatchPathPrefix + isPathType := networkingv1.PathTypeImplementationSpecific //gExact := gatewayv1beta1.PathMatchExact testCases := []struct { @@ -164,6 +166,48 @@ func Test_ToGateway(t *testing.T) { }, expectedErrors: field.ErrorList{}, }, + { + name: "ImplementationSpecific HTTPRouteMatching", + ingresses: []networkingv1.Ingress{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "implementation-specific-regex", + Namespace: "default", + }, + Spec: networkingv1.IngressSpec{ + IngressClassName: ptrTo("ingress-kong"), + Rules: []networkingv1.IngressRule{{ + Host: "test.mydomain.com", + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{{ + Path: "/~/echo/**/test", + PathType: &isPathType, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }}, + }, + }, + }}, + }, + }, + }, + expectedGatewayResources: i2gw.GatewayResources{}, + expectedErrors: field.ErrorList{ + { + Type: field.ErrorTypeInvalid, + Field: "spec.rules[0].http.paths[0].pathType", + BadValue: pointer.String("ImplementationSpecific"), + Detail: "unsupported path match type: ImplementationSpecific", + }, + }, + }, } for _, tc := range testCases { diff --git a/pkg/i2gw/providers/kong/README.md b/pkg/i2gw/providers/kong/README.md index 16055d1d..3844afbb 100644 --- a/pkg/i2gw/providers/kong/README.md +++ b/pkg/i2gw/providers/kong/README.md @@ -1,6 +1,8 @@ # Ingress Kong Provider -The project supports translating kong specific annotations. +## Annotations supported + +The project supports translating Kong-specific annotations. Current supported annotations: @@ -17,3 +19,11 @@ Current supported annotations: by separating values with commas. Example: `konghq.com/plugins: "plugin1,plugin2"`. If you are reliant on any annotations not listed above, please open an issue. + +## Implementation-specific features + +The following implementation-specific features are supported: + +- The ingress `ImplementationSpecific` match type is properly converted to + - `RegularExpression` HTTPRoute match type when the path has the prefix `/~`. + - `PathPrefix` HTTPRoute match type when there is no prefix `/~`. diff --git a/pkg/i2gw/providers/kong/converter.go b/pkg/i2gw/providers/kong/converter.go index 10c77134..3909eb0a 100644 --- a/pkg/i2gw/providers/kong/converter.go +++ b/pkg/i2gw/providers/kong/converter.go @@ -17,14 +17,9 @@ limitations under the License. package kong import ( - "fmt" - "strings" - "github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw" "github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/providers/common" - networkingv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/util/validation/field" - gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) // converter implements the ToGatewayAPI function of i2gw.ResourceConverter interface. @@ -52,7 +47,9 @@ func (c *converter) ToGatewayAPI(resources i2gw.InputResources) (i2gw.GatewayRes // Convert plain ingress resources to gateway resources, ignoring all // provider-specific features. - gatewayResources, errs := common.ToGateway(resources.Ingresses, toHTTPRouteMatchOption) + gatewayResources, errs := common.ToGateway(resources.Ingresses, i2gw.ImplementationSpecificOptions{ + HTTPPathmatch: httpPathMatch, + }) if len(errs) > 0 { return i2gw.GatewayResources{}, errs } @@ -66,29 +63,3 @@ func (c *converter) ToGatewayAPI(resources i2gw.InputResources) (i2gw.GatewayRes return gatewayResources, errs } - -func toHTTPRouteMatchOption(routePath networkingv1.HTTPIngressPath, path *field.Path) (*gatewayv1beta1.HTTPRouteMatch, *field.Error) { - pmPrefix := gatewayv1beta1.PathMatchPathPrefix - pmExact := gatewayv1beta1.PathMatchExact - pmRegex := gatewayv1beta1.PathMatchRegularExpression - - match := &gatewayv1beta1.HTTPRouteMatch{Path: &gatewayv1beta1.HTTPPathMatch{Value: &routePath.Path}} - switch *routePath.PathType { - case networkingv1.PathTypePrefix: - match.Path.Type = &pmPrefix - case networkingv1.PathTypeExact: - match.Path.Type = &pmExact - case networkingv1.PathTypeImplementationSpecific: - if strings.HasPrefix(routePath.Path, "/~") { - match.Path.Type = &pmRegex - match.Path.Value = common.PtrTo(strings.TrimPrefix(*match.Path.Value, "/~")) - } else { - match.Path.Type = &pmPrefix - } - - default: - return nil, field.Invalid(path.Child("pathType"), routePath.PathType, fmt.Sprintf("unsupported path match type: %s", *routePath.PathType)) - } - - return match, nil -} diff --git a/pkg/i2gw/providers/kong/converter_test.go b/pkg/i2gw/providers/kong/converter_test.go index 88e84257..4f904915 100644 --- a/pkg/i2gw/providers/kong/converter_test.go +++ b/pkg/i2gw/providers/kong/converter_test.go @@ -372,8 +372,8 @@ func Test_ToGateway(t *testing.T) { }, }, HTTPRoutes: map[types.NamespacedName]gatewayv1beta1.HTTPRoute{ - {Namespace: "default", Name: "test-mydomain-com"}: { - ObjectMeta: metav1.ObjectMeta{Name: "test-mydomain-com", Namespace: "default"}, + {Namespace: "default", Name: "implementation-specific-regex-test-mydomain-com"}: { + ObjectMeta: metav1.ObjectMeta{Name: "implementation-specific-regex-test-mydomain-com", Namespace: "default"}, Spec: gatewayv1beta1.HTTPRouteSpec{ CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ ParentRefs: []gatewayv1beta1.ParentReference{{ diff --git a/pkg/i2gw/providers/kong/header_matching_test.go b/pkg/i2gw/providers/kong/header_matching_test.go index 17052800..d2efc2d1 100644 --- a/pkg/i2gw/providers/kong/header_matching_test.go +++ b/pkg/i2gw/providers/kong/header_matching_test.go @@ -246,7 +246,9 @@ func TestHeaderMatchingFeature(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses, toHTTPRouteMatchOption) + gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses, i2gw.ImplementationSpecificOptions{ + HTTPPathmatch: httpPathMatch, + }) if len(errs) != 0 { t.Errorf("Expected no errors, got %d: %+v", len(errs), errs) } diff --git a/pkg/i2gw/providers/kong/implementation_specific.go b/pkg/i2gw/providers/kong/implementation_specific.go new file mode 100644 index 00000000..6f9484a6 --- /dev/null +++ b/pkg/i2gw/providers/kong/implementation_specific.go @@ -0,0 +1,35 @@ +/* +Copyright 2023 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 kong + +import ( + "strings" + + "github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/providers/common" + gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" +) + +func httpPathMatch(path *gatewayv1beta1.HTTPPathMatch) { + pmPrefix := gatewayv1beta1.PathMatchPathPrefix + pmRegex := gatewayv1beta1.PathMatchRegularExpression + if strings.HasPrefix(*path.Value, "/~") { + path.Type = &pmRegex + path.Value = common.PtrTo(strings.TrimPrefix(*path.Value, "/~")) + } else { + path.Type = &pmPrefix + } +} diff --git a/pkg/i2gw/providers/kong/method_matching_test.go b/pkg/i2gw/providers/kong/method_matching_test.go index 7e30f772..4790a484 100644 --- a/pkg/i2gw/providers/kong/method_matching_test.go +++ b/pkg/i2gw/providers/kong/method_matching_test.go @@ -189,7 +189,9 @@ func TestMethodMatchingFeature(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses, toHTTPRouteMatchOption) + gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses, i2gw.ImplementationSpecificOptions{ + HTTPPathmatch: httpPathMatch, + }) if len(errs) != 0 { t.Errorf("Expected no errors, got %d: %+v", len(errs), errs) } From 08daf0c8562b935c102480c22e7b917bf79299e2 Mon Sep 17 00:00:00 2001 From: Mattia Lavacca Date: Mon, 13 Nov 2023 11:50:10 +0100 Subject: [PATCH 3/5] feat: reviews comments addressed Signed-off-by: Mattia Lavacca --- pkg/i2gw/provider.go | 13 +-- pkg/i2gw/providers/common/converter.go | 19 ++-- pkg/i2gw/providers/common/converter_test.go | 2 +- pkg/i2gw/providers/ingressnginx/converter.go | 2 +- .../providers/ingressnginx/converter_test.go | 2 +- pkg/i2gw/providers/kong/README.md | 6 +- pkg/i2gw/providers/kong/converter.go | 4 +- pkg/i2gw/providers/kong/converter_test.go | 91 ++++++++++++++++++- .../providers/kong/header_matching_test.go | 4 +- .../providers/kong/implementation_specific.go | 2 +- .../providers/kong/method_matching_test.go | 4 +- 11 files changed, 118 insertions(+), 31 deletions(-) diff --git a/pkg/i2gw/provider.go b/pkg/i2gw/provider.go index 235a8da0..d8bc625c 100644 --- a/pkg/i2gw/provider.go +++ b/pkg/i2gw/provider.go @@ -73,14 +73,15 @@ type ResourceConverter interface { ToGatewayAPI(resources InputResources) (GatewayResources, field.ErrorList) } -// HTTPPathMatchOption is an option to customize the ingress implementationSpecific +// ImplementationSpecificHTTPPathMatchOption is an option to customize the ingress implementationSpecific // match type conversion. -type HTTPPathMatchOption func(*gatewayv1beta1.HTTPPathMatch) +type ImplementationSpecificHTTPPathMatchOption func(*gatewayv1beta1.HTTPPathMatch) -// ImplementationSpecificOptions contains all the pointers to implementation-specific -// customization functions. -type ImplementationSpecificOptions struct { - HTTPPathmatch HTTPPathMatchOption +// ProviderImplementationSpecificOptions contains all the pointers to implementation-specific +// customization functions. Such functions will be called by the common package to customize +// the provider-specific behavior for all the implementation-specific fields of the API. +type ProviderImplementationSpecificOptions struct { + ToImplementationSpecificHTTPPathMatch ImplementationSpecificHTTPPathMatchOption } // InputResources contains all Ingress objects, and Provider specific diff --git a/pkg/i2gw/providers/common/converter.go b/pkg/i2gw/providers/common/converter.go index a023bf50..fa26ef44 100644 --- a/pkg/i2gw/providers/common/converter.go +++ b/pkg/i2gw/providers/common/converter.go @@ -32,7 +32,7 @@ import ( // ToGateway converts the received ingresses to i2gw.GatewayResources, // without taking into consideration any provider specific logic. -func ToGateway(ingresses []networkingv1.Ingress, options i2gw.ImplementationSpecificOptions) (i2gw.GatewayResources, field.ErrorList) { +func ToGateway(ingresses []networkingv1.Ingress, options i2gw.ProviderImplementationSpecificOptions) (i2gw.GatewayResources, field.ErrorList) { aggregator := ingressAggregator{ruleGroups: map[ruleGroupKey]*ingressRuleGroup{}} var errs field.ErrorList @@ -157,7 +157,7 @@ func (a *ingressAggregator) addIngressRule(namespace, name, ingressClass string, rg.rules = append(rg.rules, ingressRule{rule: rule}) } -func (a *ingressAggregator) toHTTPRoutesAndGateways(options i2gw.ImplementationSpecificOptions) ([]gatewayv1beta1.HTTPRoute, []gatewayv1beta1.Gateway, field.ErrorList) { +func (a *ingressAggregator) toHTTPRoutesAndGateways(options i2gw.ProviderImplementationSpecificOptions) ([]gatewayv1beta1.HTTPRoute, []gatewayv1beta1.Gateway, field.ErrorList) { var httpRoutes []gatewayv1beta1.HTTPRoute var errors field.ErrorList listenersByNamespacedGateway := map[string][]gatewayv1beta1.Listener{} @@ -269,7 +269,7 @@ func (a *ingressAggregator) toHTTPRoutesAndGateways(options i2gw.ImplementationS return httpRoutes, gateways, errors } -func (rg *ingressRuleGroup) toHTTPRoute(options i2gw.ImplementationSpecificOptions) (gatewayv1beta1.HTTPRoute, field.ErrorList) { +func (rg *ingressRuleGroup) toHTTPRoute(options i2gw.ProviderImplementationSpecificOptions) (gatewayv1beta1.HTTPRoute, field.ErrorList) { pathsByMatchGroup := map[pathMatchKey][]ingressPath{} var errors field.ErrorList @@ -305,9 +305,7 @@ func (rg *ingressRuleGroup) toHTTPRoute(options i2gw.ImplementationSpecificOptio for _, paths := range pathsByMatchGroup { path := paths[0] fieldPath := field.NewPath("spec", "rules").Index(path.ruleIdx).Child(path.ruleType).Child("paths").Index(path.pathIdx) - var match *gatewayv1beta1.HTTPRouteMatch - var err *field.Error - match, err = toHTTPRouteMatch(path.path, fieldPath, options.HTTPPathmatch) + match, err := toHTTPRouteMatch(path.path, fieldPath, options.ToImplementationSpecificHTTPPathMatch) if err != nil { errors = append(errors, err) continue @@ -350,7 +348,7 @@ func getPathMatchKey(ip ingressPath) pathMatchKey { return pathMatchKey(fmt.Sprintf("%s/%s", pathType, ip.path.Path)) } -func toHTTPRouteMatch(routePath networkingv1.HTTPIngressPath, path *field.Path, implementationSpecificPath i2gw.HTTPPathMatchOption) (*gatewayv1beta1.HTTPRouteMatch, *field.Error) { +func toHTTPRouteMatch(routePath networkingv1.HTTPIngressPath, path *field.Path, toImplementationSpecificPathMatch i2gw.ImplementationSpecificHTTPPathMatchOption) (*gatewayv1beta1.HTTPRouteMatch, *field.Error) { pmPrefix := gatewayv1beta1.PathMatchPathPrefix pmExact := gatewayv1beta1.PathMatchExact @@ -360,9 +358,12 @@ func toHTTPRouteMatch(routePath networkingv1.HTTPIngressPath, path *field.Path, match.Path.Type = &pmPrefix case networkingv1.PathTypeExact: match.Path.Type = &pmExact + // In case the path type is ImplementationSpecific, the path value and type + // will be set by the provider-specific customization function. If such function + // is not given by the provider, an error is returned. case networkingv1.PathTypeImplementationSpecific: - if implementationSpecificPath != nil { - implementationSpecificPath(match.Path) + if toImplementationSpecificPathMatch != nil { + toImplementationSpecificPathMatch(match.Path) } else { return nil, field.Invalid(path.Child("pathType"), routePath.PathType, fmt.Sprintf("unsupported path match type: %s", *routePath.PathType)) } diff --git a/pkg/i2gw/providers/common/converter_test.go b/pkg/i2gw/providers/common/converter_test.go index cff81d59..da858914 100644 --- a/pkg/i2gw/providers/common/converter_test.go +++ b/pkg/i2gw/providers/common/converter_test.go @@ -316,7 +316,7 @@ func Test_ingresses2GatewaysAndHttpRoutes(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - gatewayResources, errs := ToGateway(tc.ingresses, i2gw.ImplementationSpecificOptions{}) + gatewayResources, errs := ToGateway(tc.ingresses, i2gw.ProviderImplementationSpecificOptions{}) if len(gatewayResources.HTTPRoutes) != len(tc.expectedGatewayResources.HTTPRoutes) { t.Errorf("Expected %d HTTPRoutes, got %d: %+v", diff --git a/pkg/i2gw/providers/ingressnginx/converter.go b/pkg/i2gw/providers/ingressnginx/converter.go index 7a5e5121..8bb16784 100644 --- a/pkg/i2gw/providers/ingressnginx/converter.go +++ b/pkg/i2gw/providers/ingressnginx/converter.go @@ -45,7 +45,7 @@ func (c *converter) ToGatewayAPI(resources i2gw.InputResources) (i2gw.GatewayRes // Convert plain ingress resources to gateway resources, ignoring all // provider-specific features. - gatewayResources, errs := common.ToGateway(resources.Ingresses, i2gw.ImplementationSpecificOptions{}) + gatewayResources, errs := common.ToGateway(resources.Ingresses, i2gw.ProviderImplementationSpecificOptions{}) if len(errs) > 0 { return i2gw.GatewayResources{}, errs } diff --git a/pkg/i2gw/providers/ingressnginx/converter_test.go b/pkg/i2gw/providers/ingressnginx/converter_test.go index 71ac1fb2..dceb35e4 100644 --- a/pkg/i2gw/providers/ingressnginx/converter_test.go +++ b/pkg/i2gw/providers/ingressnginx/converter_test.go @@ -175,7 +175,7 @@ func Test_ToGateway(t *testing.T) { Namespace: "default", }, Spec: networkingv1.IngressSpec{ - IngressClassName: ptrTo("ingress-kong"), + IngressClassName: ptrTo("ingress-nginx"), Rules: []networkingv1.IngressRule{{ Host: "test.mydomain.com", IngressRuleValue: networkingv1.IngressRuleValue{ diff --git a/pkg/i2gw/providers/kong/README.md b/pkg/i2gw/providers/kong/README.md index 3844afbb..f9e6c842 100644 --- a/pkg/i2gw/providers/kong/README.md +++ b/pkg/i2gw/providers/kong/README.md @@ -1,4 +1,4 @@ -# Ingress Kong Provider +# Kong Provider ## Annotations supported @@ -11,7 +11,7 @@ Current supported annotations: be specified by separating values with commas. Example: `konghq.com/methods: "POST,GET"`. - `konghq.com/headers.*`: If specified, the values of this annotation are used to perform header matching on the associated ingress rules. The header name is specified - in the annotation key after `.`, and the annotations value can contain multiple + in the annotation key after `.`, and the annotation value can contain multiple header values separated by commas. All the header values for a specific header name are intended to be ORed. Example: `konghq.com/headers.x-routing: "alpha,bravo"`. - `konghq.com/plugins`: If specified, the values of this annotation are used to @@ -26,4 +26,4 @@ The following implementation-specific features are supported: - The ingress `ImplementationSpecific` match type is properly converted to - `RegularExpression` HTTPRoute match type when the path has the prefix `/~`. - - `PathPrefix` HTTPRoute match type when there is no prefix `/~`. + - `PathPrefix` HTTPRoute match type when there is no `/~` prefix. diff --git a/pkg/i2gw/providers/kong/converter.go b/pkg/i2gw/providers/kong/converter.go index 3909eb0a..c29d215a 100644 --- a/pkg/i2gw/providers/kong/converter.go +++ b/pkg/i2gw/providers/kong/converter.go @@ -47,8 +47,8 @@ func (c *converter) ToGatewayAPI(resources i2gw.InputResources) (i2gw.GatewayRes // Convert plain ingress resources to gateway resources, ignoring all // provider-specific features. - gatewayResources, errs := common.ToGateway(resources.Ingresses, i2gw.ImplementationSpecificOptions{ - HTTPPathmatch: httpPathMatch, + gatewayResources, errs := common.ToGateway(resources.Ingresses, i2gw.ProviderImplementationSpecificOptions{ + ToImplementationSpecificHTTPPathMatch: implementationSpecificHTTPPathMatch, }) if len(errs) > 0 { return i2gw.GatewayResources{}, errs diff --git a/pkg/i2gw/providers/kong/converter_test.go b/pkg/i2gw/providers/kong/converter_test.go index 4f904915..4d01238e 100644 --- a/pkg/i2gw/providers/kong/converter_test.go +++ b/pkg/i2gw/providers/kong/converter_test.go @@ -33,7 +33,7 @@ import ( func Test_ToGateway(t *testing.T) { iPrefix := networkingv1.PathTypePrefix - isPathType := networkingv1.PathTypeImplementationSpecific + ImplSpecPathType := networkingv1.PathTypeImplementationSpecific gPathPrefix := gatewayv1beta1.PathMatchPathPrefix gPathRegex := gatewayv1beta1.PathMatchRegularExpression @@ -325,7 +325,7 @@ func Test_ToGateway(t *testing.T) { expectedErrors: field.ErrorList{}, }, { - name: "ImplementationSpecific HTTPRouteMatching", + name: "ImplementationSpecific HTTPRouteMatching with regex", ingresses: []networkingv1.Ingress{ { ObjectMeta: metav1.ObjectMeta{ @@ -340,7 +340,7 @@ func Test_ToGateway(t *testing.T) { HTTP: &networkingv1.HTTPIngressRuleValue{ Paths: []networkingv1.HTTPIngressPath{{ Path: "/~/echo/**/test", - PathType: &isPathType, + PathType: &ImplSpecPathType, Backend: networkingv1.IngressBackend{ Service: &networkingv1.IngressServiceBackend{ Name: "test", @@ -409,6 +409,91 @@ func Test_ToGateway(t *testing.T) { }, expectedErrors: field.ErrorList{}, }, + { + name: "ImplementationSpecific HTTPRouteMatching without regex", + ingresses: []networkingv1.Ingress{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "implementation-specific-no-regex", + Namespace: "default", + }, + Spec: networkingv1.IngressSpec{ + IngressClassName: ptrTo("ingress-kong"), + Rules: []networkingv1.IngressRule{{ + Host: "test.mydomain.com", + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{{ + Path: "/echo", + PathType: &ImplSpecPathType, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "test", + Port: networkingv1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }}, + }, + }, + }}, + }, + }, + }, + expectedGatewayResources: i2gw.GatewayResources{ + Gateways: map[types.NamespacedName]gatewayv1beta1.Gateway{ + {Namespace: "default", Name: "ingress-kong"}: { + ObjectMeta: metav1.ObjectMeta{Name: "ingress-kong", Namespace: "default"}, + Spec: gatewayv1beta1.GatewaySpec{ + GatewayClassName: "ingress-kong", + Listeners: []gatewayv1beta1.Listener{{ + Name: "test-mydomain-com-http", + Port: 80, + Protocol: gatewayv1beta1.HTTPProtocolType, + Hostname: ptrTo(gatewayv1beta1.Hostname("test.mydomain.com")), + }}, + }, + }, + }, + HTTPRoutes: map[types.NamespacedName]gatewayv1beta1.HTTPRoute{ + {Namespace: "default", Name: "implementation-specific-no-regex-test-mydomain-com"}: { + ObjectMeta: metav1.ObjectMeta{Name: "implementation-specific-no-regex-test-mydomain-com", Namespace: "default"}, + Spec: gatewayv1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayv1beta1.CommonRouteSpec{ + ParentRefs: []gatewayv1beta1.ParentReference{{ + Name: "ingress-kong", + }}, + }, + Hostnames: []gatewayv1beta1.Hostname{"test.mydomain.com"}, + Rules: []gatewayv1beta1.HTTPRouteRule{ + { + Matches: []gatewayv1beta1.HTTPRouteMatch{ + { + Path: &gatewayv1beta1.HTTPPathMatch{ + Type: &gPathPrefix, + Value: ptrTo("/echo"), + }, + }, + }, + BackendRefs: []gatewayv1beta1.HTTPBackendRef{ + { + BackendRef: gatewayv1beta1.BackendRef{ + BackendObjectReference: gatewayv1beta1.BackendObjectReference{ + Name: "test", + Port: ptrTo(gatewayv1beta1.PortNumber(80)), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + expectedErrors: field.ErrorList{}, + }, } for _, tc := range testCases { diff --git a/pkg/i2gw/providers/kong/header_matching_test.go b/pkg/i2gw/providers/kong/header_matching_test.go index d2efc2d1..c6b057ac 100644 --- a/pkg/i2gw/providers/kong/header_matching_test.go +++ b/pkg/i2gw/providers/kong/header_matching_test.go @@ -246,8 +246,8 @@ func TestHeaderMatchingFeature(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses, i2gw.ImplementationSpecificOptions{ - HTTPPathmatch: httpPathMatch, + gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses, i2gw.ProviderImplementationSpecificOptions{ + ToImplementationSpecificHTTPPathMatch: implementationSpecificHTTPPathMatch, }) if len(errs) != 0 { t.Errorf("Expected no errors, got %d: %+v", len(errs), errs) diff --git a/pkg/i2gw/providers/kong/implementation_specific.go b/pkg/i2gw/providers/kong/implementation_specific.go index 6f9484a6..9292385a 100644 --- a/pkg/i2gw/providers/kong/implementation_specific.go +++ b/pkg/i2gw/providers/kong/implementation_specific.go @@ -23,7 +23,7 @@ import ( gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) -func httpPathMatch(path *gatewayv1beta1.HTTPPathMatch) { +func implementationSpecificHTTPPathMatch(path *gatewayv1beta1.HTTPPathMatch) { pmPrefix := gatewayv1beta1.PathMatchPathPrefix pmRegex := gatewayv1beta1.PathMatchRegularExpression if strings.HasPrefix(*path.Value, "/~") { diff --git a/pkg/i2gw/providers/kong/method_matching_test.go b/pkg/i2gw/providers/kong/method_matching_test.go index 4790a484..dae4ba2b 100644 --- a/pkg/i2gw/providers/kong/method_matching_test.go +++ b/pkg/i2gw/providers/kong/method_matching_test.go @@ -189,8 +189,8 @@ func TestMethodMatchingFeature(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses, i2gw.ImplementationSpecificOptions{ - HTTPPathmatch: httpPathMatch, + gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses, i2gw.ProviderImplementationSpecificOptions{ + ToImplementationSpecificHTTPPathMatch: implementationSpecificHTTPPathMatch, }) if len(errs) != 0 { t.Errorf("Expected no errors, got %d: %+v", len(errs), errs) From d586b064c5082c6f5d4e2b28a849491619077f02 Mon Sep 17 00:00:00 2001 From: Mattia Lavacca Date: Tue, 14 Nov 2023 08:20:39 +0100 Subject: [PATCH 4/5] options moved to converter. Signed-off-by: Mattia Lavacca --- pkg/i2gw/providers/common/converter.go | 2 +- pkg/i2gw/providers/ingressnginx/converter_test.go | 2 +- pkg/i2gw/providers/kong/converter.go | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pkg/i2gw/providers/common/converter.go b/pkg/i2gw/providers/common/converter.go index fa26ef44..f1ae5a5e 100644 --- a/pkg/i2gw/providers/common/converter.go +++ b/pkg/i2gw/providers/common/converter.go @@ -365,7 +365,7 @@ func toHTTPRouteMatch(routePath networkingv1.HTTPIngressPath, path *field.Path, if toImplementationSpecificPathMatch != nil { toImplementationSpecificPathMatch(match.Path) } else { - return nil, field.Invalid(path.Child("pathType"), routePath.PathType, fmt.Sprintf("unsupported path match type: %s", *routePath.PathType)) + return nil, field.Invalid(path.Child("pathType"), routePath.PathType, "implementationSpecific path type is not supported in generic translation, and your provider does not provide custom support to translate it") } } diff --git a/pkg/i2gw/providers/ingressnginx/converter_test.go b/pkg/i2gw/providers/ingressnginx/converter_test.go index dceb35e4..e2bbfa63 100644 --- a/pkg/i2gw/providers/ingressnginx/converter_test.go +++ b/pkg/i2gw/providers/ingressnginx/converter_test.go @@ -204,7 +204,7 @@ func Test_ToGateway(t *testing.T) { Type: field.ErrorTypeInvalid, Field: "spec.rules[0].http.paths[0].pathType", BadValue: pointer.String("ImplementationSpecific"), - Detail: "unsupported path match type: ImplementationSpecific", + Detail: "implementationSpecific path type is not supported in generic translation, and your provider does not provide custom support to translate it", }, }, }, diff --git a/pkg/i2gw/providers/kong/converter.go b/pkg/i2gw/providers/kong/converter.go index c29d215a..3403ba0a 100644 --- a/pkg/i2gw/providers/kong/converter.go +++ b/pkg/i2gw/providers/kong/converter.go @@ -26,7 +26,8 @@ import ( type converter struct { conf *i2gw.ProviderConf - featureParsers []i2gw.FeatureParser + featureParsers []i2gw.FeatureParser + ImplementationSpecificOptions i2gw.ProviderImplementationSpecificOptions } // newConverter returns an kong converter instance. @@ -38,6 +39,9 @@ func newConverter(conf *i2gw.ProviderConf) *converter { methodMatchingFeature, pluginsFeature, }, + ImplementationSpecificOptions: i2gw.ProviderImplementationSpecificOptions{ + ToImplementationSpecificHTTPPathMatch: implementationSpecificHTTPPathMatch, + }, } } @@ -47,9 +51,7 @@ func (c *converter) ToGatewayAPI(resources i2gw.InputResources) (i2gw.GatewayRes // Convert plain ingress resources to gateway resources, ignoring all // provider-specific features. - gatewayResources, errs := common.ToGateway(resources.Ingresses, i2gw.ProviderImplementationSpecificOptions{ - ToImplementationSpecificHTTPPathMatch: implementationSpecificHTTPPathMatch, - }) + gatewayResources, errs := common.ToGateway(resources.Ingresses, c.ImplementationSpecificOptions) if len(errs) > 0 { return i2gw.GatewayResources{}, errs } From 94e1d82ce4fc5aed8eabfbcc14f7a9acaea153ab Mon Sep 17 00:00:00 2001 From: Mattia Lavacca Date: Wed, 15 Nov 2023 11:32:40 +0100 Subject: [PATCH 5/5] reviews' comments addressed Signed-off-by: Mattia Lavacca --- PROVIDER.md | 9 ++++++++- pkg/i2gw/provider.go | 12 ++++++------ pkg/i2gw/providers/common/converter.go | 9 +++++++-- pkg/i2gw/providers/kong/converter.go | 8 ++++---- pkg/i2gw/providers/kong/converter_test.go | 6 +++--- pkg/i2gw/providers/kong/header_matching_test.go | 2 +- pkg/i2gw/providers/kong/implementation_specific.go | 2 +- pkg/i2gw/providers/kong/method_matching_test.go | 2 +- 8 files changed, 31 insertions(+), 19 deletions(-) diff --git a/PROVIDER.md b/PROVIDER.md index ee867ac1..4340e877 100644 --- a/PROVIDER.md +++ b/PROVIDER.md @@ -61,7 +61,10 @@ func (r *resourceReader) ReadResourcesFromFiles(ctx context.Context, customResou ``` 3. Create a struct named `converter` which implements the `ResourceConverter` interface in a file named `converter.go`. The implemented `ToGatewayAPI` function should simply call every registered `featureParser` function, one by one. -Take a look at `ingressnginx/converter.go` for example. +Take a look at `ingressnginx/converter.go` for an example. +The `ImplementationSpecificOptions` struct contains the handlers to customize native ingress implementation-specific fields. +Take a look at `kong/converter.go` for an example. + ```go package examplegateway @@ -74,6 +77,7 @@ type converter struct { conf *i2gw.ProviderConf featureParsers []i2gw.FeatureParser + implementationSpecificOptions i2gw.ProviderImplementationSpecificOptions } // newConverter returns an ingress-nginx converter instance. @@ -83,6 +87,9 @@ func newConverter(conf *i2gw.ProviderConf) *converter { featureParsers: []i2gw.FeatureParser{ // The list of feature parsers comes here. }, + implementationSpecificOptions: i2gw.ProviderImplementationSpecificOptions{ + // The list of the implementationSpecific ingress fields options comes here. + }, } } ``` diff --git a/pkg/i2gw/provider.go b/pkg/i2gw/provider.go index d8bc625c..215b04c7 100644 --- a/pkg/i2gw/provider.go +++ b/pkg/i2gw/provider.go @@ -73,15 +73,15 @@ type ResourceConverter interface { ToGatewayAPI(resources InputResources) (GatewayResources, field.ErrorList) } -// ImplementationSpecificHTTPPathMatchOption is an option to customize the ingress implementationSpecific +// ImplementationSpecificHTTPPathTypeMatchConverter is an option to customize the ingress implementationSpecific // match type conversion. -type ImplementationSpecificHTTPPathMatchOption func(*gatewayv1beta1.HTTPPathMatch) +type ImplementationSpecificHTTPPathTypeMatchConverter func(*gatewayv1beta1.HTTPPathMatch) -// ProviderImplementationSpecificOptions contains all the pointers to implementation-specific -// customization functions. Such functions will be called by the common package to customize -// the provider-specific behavior for all the implementation-specific fields of the API. +// ProviderImplementationSpecificOptions contains customized implementation-specific fields and functions. +// These will be used by the common package to customize the provider-specific behavior for all the +// implementation-specific fields of the ingress API. type ProviderImplementationSpecificOptions struct { - ToImplementationSpecificHTTPPathMatch ImplementationSpecificHTTPPathMatchOption + ToImplementationSpecificHTTPPathTypeMatch ImplementationSpecificHTTPPathTypeMatchConverter } // InputResources contains all Ingress objects, and Provider specific diff --git a/pkg/i2gw/providers/common/converter.go b/pkg/i2gw/providers/common/converter.go index f1ae5a5e..f3ffe35c 100644 --- a/pkg/i2gw/providers/common/converter.go +++ b/pkg/i2gw/providers/common/converter.go @@ -305,7 +305,7 @@ func (rg *ingressRuleGroup) toHTTPRoute(options i2gw.ProviderImplementationSpeci for _, paths := range pathsByMatchGroup { path := paths[0] fieldPath := field.NewPath("spec", "rules").Index(path.ruleIdx).Child(path.ruleType).Child("paths").Index(path.pathIdx) - match, err := toHTTPRouteMatch(path.path, fieldPath, options.ToImplementationSpecificHTTPPathMatch) + match, err := toHTTPRouteMatch(path.path, fieldPath, options.ToImplementationSpecificHTTPPathTypeMatch) if err != nil { errors = append(errors, err) continue @@ -348,7 +348,7 @@ func getPathMatchKey(ip ingressPath) pathMatchKey { return pathMatchKey(fmt.Sprintf("%s/%s", pathType, ip.path.Path)) } -func toHTTPRouteMatch(routePath networkingv1.HTTPIngressPath, path *field.Path, toImplementationSpecificPathMatch i2gw.ImplementationSpecificHTTPPathMatchOption) (*gatewayv1beta1.HTTPRouteMatch, *field.Error) { +func toHTTPRouteMatch(routePath networkingv1.HTTPIngressPath, path *field.Path, toImplementationSpecificPathMatch i2gw.ImplementationSpecificHTTPPathTypeMatchConverter) (*gatewayv1beta1.HTTPRouteMatch, *field.Error) { pmPrefix := gatewayv1beta1.PathMatchPathPrefix pmExact := gatewayv1beta1.PathMatchExact @@ -367,6 +367,11 @@ func toHTTPRouteMatch(routePath networkingv1.HTTPIngressPath, path *field.Path, } else { return nil, field.Invalid(path.Child("pathType"), routePath.PathType, "implementationSpecific path type is not supported in generic translation, and your provider does not provide custom support to translate it") } + default: + // default should never hit, as all the possible cases are already checked + // via proper switch cases. + return nil, field.Invalid(path.Child("pathType"), match.Path.Type, fmt.Sprintf("unsupported path match type: %s", *match.Path.Type)) + } return match, nil diff --git a/pkg/i2gw/providers/kong/converter.go b/pkg/i2gw/providers/kong/converter.go index 3403ba0a..d628d212 100644 --- a/pkg/i2gw/providers/kong/converter.go +++ b/pkg/i2gw/providers/kong/converter.go @@ -27,7 +27,7 @@ type converter struct { conf *i2gw.ProviderConf featureParsers []i2gw.FeatureParser - ImplementationSpecificOptions i2gw.ProviderImplementationSpecificOptions + implementationSpecificOptions i2gw.ProviderImplementationSpecificOptions } // newConverter returns an kong converter instance. @@ -39,8 +39,8 @@ func newConverter(conf *i2gw.ProviderConf) *converter { methodMatchingFeature, pluginsFeature, }, - ImplementationSpecificOptions: i2gw.ProviderImplementationSpecificOptions{ - ToImplementationSpecificHTTPPathMatch: implementationSpecificHTTPPathMatch, + implementationSpecificOptions: i2gw.ProviderImplementationSpecificOptions{ + ToImplementationSpecificHTTPPathTypeMatch: implementationSpecificHTTPPathTypeMatch, }, } } @@ -51,7 +51,7 @@ func (c *converter) ToGatewayAPI(resources i2gw.InputResources) (i2gw.GatewayRes // Convert plain ingress resources to gateway resources, ignoring all // provider-specific features. - gatewayResources, errs := common.ToGateway(resources.Ingresses, c.ImplementationSpecificOptions) + gatewayResources, errs := common.ToGateway(resources.Ingresses, c.implementationSpecificOptions) if len(errs) > 0 { return i2gw.GatewayResources{}, errs } diff --git a/pkg/i2gw/providers/kong/converter_test.go b/pkg/i2gw/providers/kong/converter_test.go index 4d01238e..ad381ca0 100644 --- a/pkg/i2gw/providers/kong/converter_test.go +++ b/pkg/i2gw/providers/kong/converter_test.go @@ -33,7 +33,7 @@ import ( func Test_ToGateway(t *testing.T) { iPrefix := networkingv1.PathTypePrefix - ImplSpecPathType := networkingv1.PathTypeImplementationSpecific + ImplSpecificPathType := networkingv1.PathTypeImplementationSpecific gPathPrefix := gatewayv1beta1.PathMatchPathPrefix gPathRegex := gatewayv1beta1.PathMatchRegularExpression @@ -340,7 +340,7 @@ func Test_ToGateway(t *testing.T) { HTTP: &networkingv1.HTTPIngressRuleValue{ Paths: []networkingv1.HTTPIngressPath{{ Path: "/~/echo/**/test", - PathType: &ImplSpecPathType, + PathType: &ImplSpecificPathType, Backend: networkingv1.IngressBackend{ Service: &networkingv1.IngressServiceBackend{ Name: "test", @@ -425,7 +425,7 @@ func Test_ToGateway(t *testing.T) { HTTP: &networkingv1.HTTPIngressRuleValue{ Paths: []networkingv1.HTTPIngressPath{{ Path: "/echo", - PathType: &ImplSpecPathType, + PathType: &ImplSpecificPathType, Backend: networkingv1.IngressBackend{ Service: &networkingv1.IngressServiceBackend{ Name: "test", diff --git a/pkg/i2gw/providers/kong/header_matching_test.go b/pkg/i2gw/providers/kong/header_matching_test.go index c6b057ac..6e79f74f 100644 --- a/pkg/i2gw/providers/kong/header_matching_test.go +++ b/pkg/i2gw/providers/kong/header_matching_test.go @@ -247,7 +247,7 @@ func TestHeaderMatchingFeature(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses, i2gw.ProviderImplementationSpecificOptions{ - ToImplementationSpecificHTTPPathMatch: implementationSpecificHTTPPathMatch, + ToImplementationSpecificHTTPPathTypeMatch: implementationSpecificHTTPPathTypeMatch, }) if len(errs) != 0 { t.Errorf("Expected no errors, got %d: %+v", len(errs), errs) diff --git a/pkg/i2gw/providers/kong/implementation_specific.go b/pkg/i2gw/providers/kong/implementation_specific.go index 9292385a..8d5a0de5 100644 --- a/pkg/i2gw/providers/kong/implementation_specific.go +++ b/pkg/i2gw/providers/kong/implementation_specific.go @@ -23,7 +23,7 @@ import ( gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" ) -func implementationSpecificHTTPPathMatch(path *gatewayv1beta1.HTTPPathMatch) { +func implementationSpecificHTTPPathTypeMatch(path *gatewayv1beta1.HTTPPathMatch) { pmPrefix := gatewayv1beta1.PathMatchPathPrefix pmRegex := gatewayv1beta1.PathMatchRegularExpression if strings.HasPrefix(*path.Value, "/~") { diff --git a/pkg/i2gw/providers/kong/method_matching_test.go b/pkg/i2gw/providers/kong/method_matching_test.go index dae4ba2b..c26173ac 100644 --- a/pkg/i2gw/providers/kong/method_matching_test.go +++ b/pkg/i2gw/providers/kong/method_matching_test.go @@ -190,7 +190,7 @@ func TestMethodMatchingFeature(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { gatewayResources, errs := common.ToGateway(tc.inputResources.Ingresses, i2gw.ProviderImplementationSpecificOptions{ - ToImplementationSpecificHTTPPathMatch: implementationSpecificHTTPPathMatch, + ToImplementationSpecificHTTPPathTypeMatch: implementationSpecificHTTPPathTypeMatch, }) if len(errs) != 0 { t.Errorf("Expected no errors, got %d: %+v", len(errs), errs)