Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support TCPIngress and UDPIngress expression routes #4612

Merged
merged 2 commits into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ Adding a new version? You'll need three changes:
[#4360](https://github.com/Kong/kubernetes-ingress-controller/pull/4360)
- `konghq.com/rewrite` annotation has been introduced to manage URI rewriting.
[#4360](https://github.com/Kong/kubernetes-ingress-controller/pull/4360)
- Added translator to translate `TCPRoute` and `UDPRoute` in gateway APIs to
expression based kong routes. Similar to ingresses, this translator is only
enabled when feature gate `ExpressionRoutes` is turned on and the managed
Kong gateway runs in router flavor `expressions`, and version is greater or
equal to `3.4`.
- Added support for expression-based Kong routes for `TCPRoute`, `UDPRoute`,
`TCPIngress`, and `UDPIngress`. This requires the `ExpressionRoutes` feature
gate and a Kong 3.4+ install with `KONG_ROUTER_FLAVOR=expressions` set in the
environment.
[#4385](https://github.com/Kong/kubernetes-ingress-controller/pull/4385)
[#4550](https://github.com/Kong/kubernetes-ingress-controller/pull/4550)
[#4612](https://github.com/Kong/kubernetes-ingress-controller/pull/4612)

### Changes

Expand Down
50 changes: 0 additions & 50 deletions internal/dataplane/parser/translate_failures_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/failures"
"github.com/kong/kubernetes-ingress-controller/v2/internal/store"
"github.com/kong/kubernetes-ingress-controller/v2/internal/versions"
kongv1beta1 "github.com/kong/kubernetes-ingress-controller/v2/pkg/apis/configuration/v1beta1"
)

// This file contains unit test functions to test translation failures genreated by parser.
Expand Down Expand Up @@ -61,55 +60,6 @@ func TestTranslationFailureUnsupportedObjectsExpressionRoutes(t *testing.T) {
},
},
},
{
name: "TCPIngresses and UDPIngresses are not supported",
objects: store.FakeObjects{
TCPIngresses: []*kongv1beta1.TCPIngress{
{
TypeMeta: metav1.TypeMeta{
Kind: "TCPIngress",
APIVersion: kongv1beta1.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "tcpingress-1",
Namespace: "default",
Annotations: map[string]string{
annotations.IngressClassKey: annotations.DefaultIngressClass,
},
},
},
},
UDPIngresses: []*kongv1beta1.UDPIngress{
{
TypeMeta: metav1.TypeMeta{
Kind: "UDPIngress",
APIVersion: kongv1beta1.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "udpingress-1",
Namespace: "default",
Annotations: map[string]string{
annotations.IngressClassKey: annotations.DefaultIngressClass,
},
},
},
},
},
causingObjects: []client.Object{
&kongv1beta1.TCPIngress{
ObjectMeta: metav1.ObjectMeta{
Name: "tcpingress-1",
Namespace: "default",
},
},
&kongv1beta1.UDPIngress{
ObjectMeta: metav1.ObjectMeta{
Name: "udpingress-1",
Namespace: "default",
},
},
},
},
{
name: "TLSRoutes in gateway APIs are not supported",
objects: store.FakeObjects{
Expand Down
13 changes: 11 additions & 2 deletions internal/dataplane/parser/translate_kong_l4.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/kongstate"
"github.com/kong/kubernetes-ingress-controller/v2/internal/util"
"github.com/kong/kubernetes-ingress-controller/v2/internal/versions"
)

func (p *Parser) ingressRulesFromTCPIngressV1beta1() ingressRules {
Expand All @@ -26,7 +27,7 @@ func (p *Parser) ingressRulesFromTCPIngressV1beta1() ingressRules {
})

for _, ingress := range ingressList {
if p.featureFlags.ExpressionRoutes {
if p.featureFlags.ExpressionRoutes && p.kongVersion.LT(versions.ExpressionRouterL4Cutoff) {
p.registerResourceFailureNotSupportedForExpressionRoutes(ingress)
continue
}
Expand Down Expand Up @@ -89,6 +90,10 @@ func (p *Parser) ingressRulesFromTCPIngressV1beta1() ingressRules {
}
}

if p.featureFlags.ExpressionRoutes {
applyExpressionToIngressRules(&result)
}

return result
}

Expand All @@ -106,7 +111,7 @@ func (p *Parser) ingressRulesFromUDPIngressV1beta1() ingressRules {
})

for _, ingress := range ingressList {
if p.featureFlags.ExpressionRoutes {
if p.featureFlags.ExpressionRoutes && p.kongVersion.LT(versions.ExpressionRouterL4Cutoff) {
p.registerResourceFailureNotSupportedForExpressionRoutes(ingress)
continue
}
Expand Down Expand Up @@ -157,5 +162,9 @@ func (p *Parser) ingressRulesFromUDPIngressV1beta1() ingressRules {
}
}

if p.featureFlags.ExpressionRoutes {
applyExpressionToIngressRules(&result)
}

return result
}
9 changes: 9 additions & 0 deletions internal/dataplane/parser/translators/l4route_atc.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ func ApplyExpressionToL4KongRoute(r *kongstate.Route) {

// TODO(rodman10): replace with helper function.
portMatchers := make([]atc.Matcher, 0, len(r.Destinations))
// (and (or sources) (or destinations))

// Kong route sources and destinations support IP criteria, but Gateway API routes do not (Listeners apply to all IPs
// assigned to a Gateway) and neither do our TCPIngress and UDPIngress CRs (we simply never added an IP field).
// If we multiplex multiple Gateways (with different assigned IPs) onto a single Kong instance, we would need to add
// IP criteria for full compliance. We already break this rule for HTTP Listeners, since Kong HTTP routes do not
// support sources and destinations.
//
// Neither GWAPI Routes nor TCP/UDPIngress support sources either, so this only adds destinations.
for _, dst := range r.Destinations {
portMatchers = append(portMatchers, atc.NewPredicate(atc.FieldNetDstPort, atc.OpEqual, atc.IntLiteral(*dst.Port)))
}
Expand Down
105 changes: 105 additions & 0 deletions internal/dataplane/parser/translators/l4route_atc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package translators

import (
"testing"

"github.com/kong/go-kong/kong"
"github.com/samber/lo"
"github.com/stretchr/testify/require"

"github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/kongstate"
)

func TestApplyExpressionToL4KongRoute(t *testing.T) {
testCases := []struct {
name string
route kong.Route
subExpr string
}{
{
name: "destination port",
subExpr: "net.dst.port == 1234",
route: kong.Route{
Destinations: []*kong.CIDRPort{
{
Port: lo.ToPtr(1234),
},
},
Protocols: []*string{
lo.ToPtr("tcp"),
},
},
},
{
name: "multiple destination ports",
subExpr: "(net.dst.port == 1234) || (net.dst.port == 5678)",
route: kong.Route{
Destinations: []*kong.CIDRPort{
{
Port: lo.ToPtr(1234),
},
{
Port: lo.ToPtr(5678),
},
},
Protocols: []*string{
lo.ToPtr("tcp"),
},
},
},
{
name: "SNI host",
subExpr: "tls.sni == \"example.com\"",
route: kong.Route{
SNIs: []*string{
lo.ToPtr("example.com"),
},
Protocols: []*string{
lo.ToPtr("tcp"),
},
},
},
{
name: "multiple SNI hosts",
subExpr: "(tls.sni == \"example.com\") || (tls.sni == \"example.net\")",
route: kong.Route{
SNIs: []*string{
lo.ToPtr("example.com"),
lo.ToPtr("example.net"),
},
Protocols: []*string{
lo.ToPtr("tcp"),
},
},
},
{
name: "SNI host and multiple destination ports",
subExpr: "(tls.sni == \"example.com\") && ((net.dst.port == 1234) || (net.dst.port == 5678))",
route: kong.Route{
Destinations: []*kong.CIDRPort{
{
Port: lo.ToPtr(1234),
},
{
Port: lo.ToPtr(5678),
},
},
SNIs: []*string{
lo.ToPtr("example.com"),
},
Protocols: []*string{
lo.ToPtr("tcp"),
},
},
},
}

for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
wrapped := kongstate.Route{Route: tc.route}
ApplyExpressionToL4KongRoute(&wrapped)
require.Contains(t, *wrapped.Route.Expression, tc.subExpr)
})
}
}
1 change: 0 additions & 1 deletion test/integration/tcpingress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ var (
)

func TestTCPIngressEssentials(t *testing.T) {
rainest marked this conversation as resolved.
Show resolved Hide resolved
skipTestForExpressionRouter(t)
ctx := context.Background()

t.Parallel()
Expand Down
1 change: 0 additions & 1 deletion test/integration/udpingress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ var udpMutex sync.Mutex
const coreDNSImage = "registry.k8s.io/coredns/coredns:v1.8.6"

func TestUDPIngressEssentials(t *testing.T) {
rainest marked this conversation as resolved.
Show resolved Hide resolved
skipTestForExpressionRouter(t)
t.Parallel()

// Ensure no other UDP tests run concurrently to avoid fights over the port
Expand Down