Skip to content

Commit 63d1176

Browse files
authored
Kong TCPIngress translation (#86)
* feat: kong's TCPIngress conversion Signed-off-by: Mattia Lavacca <[email protected]> * address review comments Signed-off-by: Mattia Lavacca <[email protected]> * chore: pointer to storage in provider Signed-off-by: Mattia Lavacca <[email protected]> * chore: added comment to MergeGatewayResources Signed-off-by: Mattia Lavacca <[email protected]> --------- Signed-off-by: Mattia Lavacca <[email protected]>
1 parent 1633f2e commit 63d1176

20 files changed

+885
-58
lines changed

go.mod

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ go 1.21
44

55
require (
66
github.com/google/go-cmp v0.6.0
7+
github.com/kong/kubernetes-ingress-controller/v2 v2.12.3
78
github.com/spf13/cobra v1.8.0
8-
github.com/stretchr/testify v1.8.4
9+
github.com/stretchr/testify v1.9.0
10+
istio.io/api v1.20.0
911
k8s.io/api v0.28.4
1012
k8s.io/apimachinery v0.28.4
1113
k8s.io/cli-runtime v0.28.4
@@ -17,12 +19,11 @@ require (
1719

1820
require (
1921
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
20-
github.com/pmezard/go-difflib v1.0.0 // indirect
21-
istio.io/api v1.20.0 // indirect
22+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
2223
)
2324

2425
require (
25-
github.com/davecgh/go-spew v1.1.1 // indirect
26+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
2627
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
2728
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
2829
github.com/evanphx/json-patch/v5 v5.7.0 // indirect
@@ -64,13 +65,13 @@ require (
6465
google.golang.org/appengine v1.6.8 // indirect
6566
google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f // indirect
6667
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect
67-
google.golang.org/protobuf v1.31.0 // indirect
68+
google.golang.org/protobuf v1.31.0
6869
gopkg.in/evanphx/json-patch.v5 v5.7.0 // indirect
6970
gopkg.in/inf.v0 v0.9.1 // indirect
7071
gopkg.in/yaml.v2 v2.4.0 // indirect
7172
gopkg.in/yaml.v3 v3.0.1 // indirect
7273
istio.io/client-go v1.19.0-alpha.1.0.20231130185426-9f1859c8ff42
73-
k8s.io/klog/v2 v2.110.1 // indirect
74+
k8s.io/klog/v2 v2.110.1
7475
k8s.io/kube-openapi v0.0.0-20231113174909-778a5567bc1e // indirect
7576
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
7677
sigs.k8s.io/kustomize/api v0.15.0 // indirect

go.sum

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
55
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
66
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
77
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8-
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
98
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
9+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
10+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1011
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
1112
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
1213
github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI=
@@ -66,6 +67,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
6667
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
6768
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
6869
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
70+
github.com/kong/kubernetes-ingress-controller/v2 v2.12.3 h1:HxQA6vp14rNMC4cIo81SMuNXD2vCUNMihPlQveTT9K4=
71+
github.com/kong/kubernetes-ingress-controller/v2 v2.12.3/go.mod h1:f2wIi3/yrwBYT+C/jtpB8tA+kEzewqLwOUGUwE5n+nk=
6972
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
7073
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
7174
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -88,6 +91,7 @@ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/
8891
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
8992
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
9093
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
94+
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
9195
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
9296
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
9397
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
@@ -96,8 +100,9 @@ github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+v
96100
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
97101
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
98102
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
99-
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
100103
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
104+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
105+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
101106
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
102107
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
103108
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
@@ -117,15 +122,16 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
117122
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
118123
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
119124
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
120-
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
121125
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
126+
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
127+
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
122128
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
123129
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
124130
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
125131
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
126132
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
127-
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
128-
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
133+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
134+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
129135
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
130136
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
131137
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

pkg/i2gw/ingress2gateway.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ package i2gw
1919
import (
2020
"context"
2121
"fmt"
22+
"maps"
2223

24+
"k8s.io/apimachinery/pkg/types"
2325
"k8s.io/apimachinery/pkg/util/validation/field"
2426
"sigs.k8s.io/controller-runtime/pkg/client"
2527
"sigs.k8s.io/controller-runtime/pkg/client/config"
28+
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
29+
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
2630
)
2731

2832
func ToGatewayAPIResources(ctx context.Context, namespace string, inputFile string, providers []string) ([]GatewayResources, error) {
@@ -105,6 +109,7 @@ func constructProviders(conf *ProviderConf, providers []string) (map[ProviderNam
105109
if !ok {
106110
return nil, fmt.Errorf("%s is not a supported provider", requestedProvider)
107111
}
112+
108113
providerByName[requestedProviderName] = newProviderFunc(conf)
109114
}
110115

@@ -127,3 +132,66 @@ func GetSupportedProviders() []string {
127132
}
128133
return supportedProviders
129134
}
135+
136+
// MergeGatewayResources accept multiple GatewayResources and create a unique Resource struct
137+
// built as follows:
138+
// - GatewayClasses, *Routes, and ReferenceGrants are grouped into the same maps
139+
// - Gateways may have the same NamespaceName even if they come from different
140+
// ingresses, as they have a their GatewayClass' name as name. For this reason,
141+
// if there are mutiple gateways named the same, their listeners are merged into
142+
// a unique Gateway.
143+
//
144+
// This behavior is likely to change after https://github.com/kubernetes-sigs/gateway-api/pull/1863 takes place.
145+
func MergeGatewayResources(gatewayResources ...GatewayResources) (GatewayResources, field.ErrorList) {
146+
mergedGatewayResources := GatewayResources{
147+
Gateways: make(map[types.NamespacedName]gatewayv1.Gateway),
148+
GatewayClasses: make(map[types.NamespacedName]gatewayv1.GatewayClass),
149+
HTTPRoutes: make(map[types.NamespacedName]gatewayv1.HTTPRoute),
150+
TLSRoutes: make(map[types.NamespacedName]gatewayv1alpha2.TLSRoute),
151+
TCPRoutes: make(map[types.NamespacedName]gatewayv1alpha2.TCPRoute),
152+
UDPRoutes: make(map[types.NamespacedName]gatewayv1alpha2.UDPRoute),
153+
ReferenceGrants: make(map[types.NamespacedName]gatewayv1alpha2.ReferenceGrant),
154+
}
155+
var errs field.ErrorList
156+
mergedGatewayResources.Gateways, errs = mergeGateways(gatewayResources)
157+
if len(errs) > 0 {
158+
return GatewayResources{}, errs
159+
}
160+
for _, gr := range gatewayResources {
161+
maps.Copy(mergedGatewayResources.GatewayClasses, gr.GatewayClasses)
162+
maps.Copy(mergedGatewayResources.HTTPRoutes, gr.HTTPRoutes)
163+
maps.Copy(mergedGatewayResources.TLSRoutes, gr.TLSRoutes)
164+
maps.Copy(mergedGatewayResources.TCPRoutes, gr.TCPRoutes)
165+
maps.Copy(mergedGatewayResources.UDPRoutes, gr.UDPRoutes)
166+
maps.Copy(mergedGatewayResources.ReferenceGrants, gr.ReferenceGrants)
167+
}
168+
return mergedGatewayResources, errs
169+
}
170+
171+
func mergeGateways(gatewaResources []GatewayResources) (map[types.NamespacedName]gatewayv1.Gateway, field.ErrorList) {
172+
newGateways := map[types.NamespacedName]gatewayv1.Gateway{}
173+
errs := field.ErrorList{}
174+
175+
for _, gr := range gatewaResources {
176+
for _, g := range gr.Gateways {
177+
nn := types.NamespacedName{Namespace: g.Namespace, Name: g.Name}
178+
if existingGateway, ok := newGateways[nn]; ok {
179+
g.Spec.Listeners = append(g.Spec.Listeners, existingGateway.Spec.Listeners...)
180+
g.Spec.Addresses = append(g.Spec.Addresses, existingGateway.Spec.Addresses...)
181+
}
182+
newGateways[nn] = g
183+
// 64 is the maximum number of listeners a Gateway can have
184+
if len(g.Spec.Listeners) > 64 {
185+
fieldPath := field.NewPath(fmt.Sprintf("%s/%s", nn.Namespace, nn.Name)).Child("spec").Child("listeners")
186+
errs = append(errs, field.Invalid(fieldPath, g, "error while merging gateway listeners: a gateway cannot have more than 64 listeners"))
187+
}
188+
// 16 is the maximum number of addresses a Gateway can have
189+
if len(g.Spec.Addresses) > 16 {
190+
fieldPath := field.NewPath(fmt.Sprintf("%s/%s", nn.Namespace, nn.Name)).Child("spec").Child("addresses")
191+
errs = append(errs, field.Invalid(fieldPath, g, "error while merging gateway listeners: a gateway cannot have more than 16 addresses"))
192+
}
193+
}
194+
}
195+
196+
return newGateways, errs
197+
}

pkg/i2gw/providers/common/resource_reader.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import (
3333
)
3434

3535
func ReadIngressesFromCluster(ctx context.Context, client client.Client, ingressClass string) (map[types.NamespacedName]*networkingv1.Ingress, error) {
36-
3736
var ingressList networkingv1.IngressList
3837
err := client.List(ctx, &ingressList)
3938
if err != nil {

pkg/i2gw/providers/common/utils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ func NameFromHost(host string) string {
9595
reg2, _ := regexp.Compile("^[^a-zA-Z0-9]+")
9696
step2 := reg2.ReplaceAllString(step1, "")
9797
// if nothing left, return "all-hosts"
98-
if len(host) == 0 {
98+
if len(host) == 0 || host == "*" {
9999
return "all-hosts"
100100
}
101101
return step2

pkg/i2gw/providers/istio/converter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func newConverter() converter {
4444
}
4545
}
4646

47-
func (c *converter) convert(storage storage) (i2gw.GatewayResources, field.ErrorList) {
47+
func (c *converter) convert(storage *storage) (i2gw.GatewayResources, field.ErrorList) {
4848
var errList field.ErrorList
4949

5050
gatewayResources := i2gw.GatewayResources{

pkg/i2gw/providers/istio/istio.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func init() {
3232
}
3333

3434
type Provider struct {
35-
storage storage
35+
storage *storage
3636
reader reader
3737
converter converter
3838
}
@@ -58,7 +58,7 @@ func (p *Provider) ReadResourcesFromCluster(ctx context.Context) error {
5858
return fmt.Errorf("failed to read resources from cluster: %w", err)
5959
}
6060

61-
p.storage = *storage
61+
p.storage = storage
6262
return nil
6363
}
6464

@@ -67,6 +67,6 @@ func (p *Provider) ReadResourcesFromFile(ctx context.Context, filename string) e
6767
if err != nil {
6868
return fmt.Errorf("failed to read resources from file: %w", err)
6969
}
70-
p.storage = *storage
70+
p.storage = storage
7171
return nil
7272
}

pkg/i2gw/providers/istio/resource_reader.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (r *reader) readResourcesFromCluster(ctx context.Context) (*storage, error)
5858

5959
res.VirtualServices = virtualServices
6060

61-
return &res, nil
61+
return res, nil
6262
}
6363

6464
func (r *reader) readResourcesFromFile(_ context.Context, filename string) (*storage, error) {
@@ -116,7 +116,7 @@ func (r *reader) readUnstructuredObjects(objects []*unstructured.Unstructured) (
116116
}
117117
}
118118

119-
return &res, nil
119+
return res, nil
120120
}
121121

122122
func (r *reader) readGatewaysFromCluster(ctx context.Context) (map[types.NamespacedName]*istiov1beta1.Gateway, error) {

pkg/i2gw/providers/istio/storage.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ type storage struct {
2626
VirtualServices map[types.NamespacedName]*istiov1beta1.VirtualService
2727
}
2828

29-
func newResourcesStorage() storage {
30-
return storage{
29+
func newResourcesStorage() *storage {
30+
return &storage{
3131
Gateways: map[types.NamespacedName]*istiov1beta1.Gateway{},
3232
VirtualServices: map[types.NamespacedName]*istiov1beta1.VirtualService{},
3333
}

pkg/i2gw/providers/kong/annotations.go renamed to pkg/i2gw/providers/kong/consts.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ limitations under the License.
1616

1717
package kong
1818

19-
import "fmt"
19+
import (
20+
"fmt"
21+
22+
"k8s.io/apimachinery/pkg/runtime/schema"
23+
)
2024

2125
const (
2226
annotationPrefix = "konghq.com"
@@ -26,6 +30,23 @@ const (
2630
pluginsKey = "plugins"
2731
)
2832

33+
const (
34+
v1beta1Version = "v1beta1"
35+
36+
kongResourcesGroup = "configuration.konghq.com"
37+
38+
kongPluginKind = "KongPlugin"
39+
tcpIngressKind = "TCPIngress"
40+
)
41+
42+
var (
43+
tcpIngressGVK = schema.GroupVersionKind{
44+
Group: kongResourcesGroup,
45+
Version: v1beta1Version,
46+
Kind: tcpIngressKind,
47+
}
48+
)
49+
2950
func kongAnnotation(suffix string) string {
3051
return fmt.Sprintf("%s/%s", annotationPrefix, suffix)
3152
}

0 commit comments

Comments
 (0)