1
0
Fork 0

gatewayapi: adding support for TCPRoute and TLSRoute

Co-authored-by: Jean-Baptiste Doumenjou <925513+jbdoumenjou@users.noreply.github.com>
This commit is contained in:
Tom Moulard 2021-05-20 11:50:12 +02:00 committed by GitHub
parent e1e1fd640c
commit 56f845c71a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
72 changed files with 6241 additions and 208 deletions

View file

@ -56,6 +56,8 @@ type Client interface {
UpdateGatewayClassStatus(gatewayClass *v1alpha1.GatewayClass, condition metav1.Condition) error
GetGateways() []*v1alpha1.Gateway
GetHTTPRoutes(namespace string, selector labels.Selector) ([]*v1alpha1.HTTPRoute, error)
GetTCPRoutes(namespace string, selector labels.Selector) ([]*v1alpha1.TCPRoute, error)
GetTLSRoutes(namespace string, selector labels.Selector) ([]*v1alpha1.TLSRoute, error)
GetService(namespace, name string) (*corev1.Service, bool, error)
GetSecret(namespace, name string) (*corev1.Secret, bool, error)
@ -176,6 +178,8 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
factoryGateway := externalversions.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, externalversions.WithNamespace(ns))
factoryGateway.Networking().V1alpha1().Gateways().Informer().AddEventHandler(eventHandler)
factoryGateway.Networking().V1alpha1().HTTPRoutes().Informer().AddEventHandler(eventHandler)
factoryGateway.Networking().V1alpha1().TCPRoutes().Informer().AddEventHandler(eventHandler)
factoryGateway.Networking().V1alpha1().TLSRoutes().Informer().AddEventHandler(eventHandler)
factoryKube := informers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, informers.WithNamespace(ns))
factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler)
@ -228,7 +232,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
func (c *clientWrapper) GetHTTPRoutes(namespace string, selector labels.Selector) ([]*v1alpha1.HTTPRoute, error) {
if !c.isWatchedNamespace(namespace) {
return nil, fmt.Errorf("failed to get HTTPRoute %s with labels selector %s: namespace is not within watched namespaces", namespace, selector)
return nil, fmt.Errorf("failed to get HTTPRoutes %s with labels selector %s: namespace is not within watched namespaces", namespace, selector)
}
httpRoutes, err := c.factoriesGateway[c.lookupNamespace(namespace)].Networking().V1alpha1().HTTPRoutes().Lister().HTTPRoutes(namespace).List(selector)
if err != nil {
@ -236,12 +240,46 @@ func (c *clientWrapper) GetHTTPRoutes(namespace string, selector labels.Selector
}
if len(httpRoutes) == 0 {
log.WithoutContext().Debugf("No HTTPRoute found in %q namespace with labels selector %s", namespace, selector)
log.WithoutContext().Debugf("No HTTPRoutes found in %q namespace with labels selector %s", namespace, selector)
}
return httpRoutes, nil
}
func (c *clientWrapper) GetTCPRoutes(namespace string, selector labels.Selector) ([]*v1alpha1.TCPRoute, error) {
if !c.isWatchedNamespace(namespace) {
return nil, fmt.Errorf("failed to get TCPRoutes %s with labels selector %s: namespace is not within watched namespaces", namespace, selector)
}
tcpRoutes, err := c.factoriesGateway[c.lookupNamespace(namespace)].Networking().V1alpha1().TCPRoutes().Lister().TCPRoutes(namespace).List(selector)
if err != nil {
return nil, err
}
if len(tcpRoutes) == 0 {
log.WithoutContext().Debugf("No TCPRoutes found in %q namespace with labels selector %s", namespace, selector)
}
return tcpRoutes, nil
}
func (c *clientWrapper) GetTLSRoutes(namespace string, selector labels.Selector) ([]*v1alpha1.TLSRoute, error) {
if !c.isWatchedNamespace(namespace) {
return nil, fmt.Errorf("failed to get TLSRoutes %s with labels selector %s: namespace is not within watched namespaces", namespace, selector)
}
tlsRoutes, err := c.factoriesGateway[c.lookupNamespace(namespace)].Networking().V1alpha1().TLSRoutes().Lister().TLSRoutes(namespace).List(selector)
if err != nil {
return nil, err
}
if len(tlsRoutes) == 0 {
log.WithoutContext().Debugf("No TLSRoutes found in %q namespace with labels selector %s", namespace, selector)
}
return tlsRoutes, nil
}
func (c *clientWrapper) GetGateways() []*v1alpha1.Gateway {
var result []*v1alpha1.Gateway

View file

@ -35,6 +35,8 @@ type clientMock struct {
gatewayClasses []*v1alpha1.GatewayClass
gateways []*v1alpha1.Gateway
httpRoutes []*v1alpha1.HTTPRoute
tcpRoutes []*v1alpha1.TCPRoute
tlsRoutes []*v1alpha1.TLSRoute
watchChan chan interface{}
}
@ -63,6 +65,10 @@ func newClientMock(paths ...string) clientMock {
c.gateways = append(c.gateways, o)
case *v1alpha1.HTTPRoute:
c.httpRoutes = append(c.httpRoutes, o)
case *v1alpha1.TCPRoute:
c.tcpRoutes = append(c.tcpRoutes, o)
case *v1alpha1.TLSRoute:
c.tlsRoutes = append(c.tlsRoutes, o)
default:
panic(fmt.Sprintf("Unknown runtime object %+v %T", o, o))
}
@ -126,7 +132,7 @@ func (c clientMock) GetGateways() []*v1alpha1.Gateway {
}
func (c clientMock) GetHTTPRoutes(namespace string, selector labels.Selector) ([]*v1alpha1.HTTPRoute, error) {
httpRoutes := make([]*v1alpha1.HTTPRoute, len(c.httpRoutes))
var httpRoutes []*v1alpha1.HTTPRoute
for _, httpRoute := range c.httpRoutes {
if httpRoute.Namespace == namespace && selector.Matches(labels.Set(httpRoute.Labels)) {
@ -136,6 +142,28 @@ func (c clientMock) GetHTTPRoutes(namespace string, selector labels.Selector) ([
return httpRoutes, nil
}
func (c clientMock) GetTCPRoutes(namespace string, selector labels.Selector) ([]*v1alpha1.TCPRoute, error) {
var tcpRoutes []*v1alpha1.TCPRoute
for _, tcpRoute := range c.tcpRoutes {
if tcpRoute.Namespace == namespace && selector.Matches(labels.Set(tcpRoute.Labels)) {
tcpRoutes = append(tcpRoutes, tcpRoute)
}
}
return tcpRoutes, nil
}
func (c clientMock) GetTLSRoutes(namespace string, selector labels.Selector) ([]*v1alpha1.TLSRoute, error) {
var tlsRoutes []*v1alpha1.TLSRoute
for _, tlsRoute := range c.tlsRoutes {
if tlsRoute.Namespace == namespace && selector.Matches(labels.Set(tlsRoute.Labels)) {
tlsRoutes = append(tlsRoutes, tlsRoute)
}
}
return tlsRoutes, nil
}
func (c clientMock) GetService(namespace, name string) (*corev1.Service, bool, error) {
if c.apiServiceError != nil {
return nil, false, c.apiServiceError

View file

@ -22,7 +22,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute

View file

@ -22,7 +22,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute

View file

@ -22,7 +22,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute

View file

@ -22,7 +22,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute
@ -49,4 +50,4 @@ spec:
port: 80
- serviceName: whoami
port: 80
weight: 1
weight: 1

View file

@ -22,7 +22,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute

View file

@ -0,0 +1,47 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: HTTP
port: 80
routes:
kind: HTTPRoute
namespaces:
from: Same
selector:
matchLabels:
app: foo
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-1
namespace: default
labels:
app: foo
spec:
hostnames:
- "foo.com"
rules:
- matches:
- path:
type: ImplementationSpecific
value: /bar
forwardTo:
- serviceName: whoami
port: 80
weight: 1

View file

@ -0,0 +1,47 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: HTTP
port: 443
routes:
kind: HTTPRoute
namespaces:
from: Same
selector:
matchLabels:
app: foo
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-1
namespace: default
labels:
app: foo
spec:
hostnames:
- "foo.com"
rules:
- matches:
- path:
type: Exact
value: /bar
forwardTo:
- serviceName: whoami
port: 80
weight: 1

View file

@ -22,7 +22,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute

View file

@ -22,7 +22,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute

View file

@ -38,7 +38,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute

View file

@ -0,0 +1,64 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: HTTPS
port: 443
tls:
mode: Passthrough
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: HTTPRoute
namespaces:
from: Same
selector:
matchLabels:
app: foo
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-1
namespace: default
labels:
app: foo
spec:
hostnames:
- "foo.com"
rules:
- matches:
- path:
type: Exact
value: /bar
forwardTo:
- serviceName: whoami
port: 80
weight: 1

View file

@ -22,7 +22,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute

View file

@ -0,0 +1,47 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TCP
port: 443
routes:
kind: HTTPRoute
namespaces:
from: Same
selector:
matchLabels:
app: foo
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-1
namespace: default
labels:
app: foo
spec:
hostnames:
- "foo.com"
rules:
- matches:
- path:
type: Exact
value: /bar
forwardTo:
- serviceName: whoami
port: 80
weight: 1

View file

@ -0,0 +1,64 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
port: 443
tls:
mode: Terminate
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: HTTPRoute
namespaces:
from: Same
selector:
matchLabels:
app: foo
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-1
namespace: default
labels:
app: foo
spec:
hostnames:
- "foo.com"
rules:
- matches:
- path:
type: Exact
value: /bar
forwardTo:
- serviceName: whoami
port: 80
weight: 1

View file

@ -22,7 +22,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute

View file

@ -38,7 +38,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: Gateway
@ -56,7 +57,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute

View file

@ -38,7 +38,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
- protocol: HTTP
port: 80
routes:
@ -46,7 +47,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute

View file

@ -22,7 +22,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute

View file

@ -14,7 +14,8 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo
---
kind: HTTPRoute

View file

@ -22,4 +22,5 @@ spec:
namespaces:
from: Same
selector:
app: foo
matchLabels:
app: foo

View file

@ -0,0 +1,131 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: HTTP
port: 9080
routes:
kind: HTTPRoute
namespaces:
from: Same
selector:
matchLabels:
app: http-app
- protocol: HTTPS
port: 9443
tls:
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: HTTPRoute
namespaces:
from: Same
selector:
matchLabels:
app: http-app
- protocol: TCP
port: 9000
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: tcp-app
- protocol: TLS
port: 10000
hostname: tls.foo.example.com
tls:
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: tcp-app
- protocol: TLS
port: 11000
hostname: pass.tls.foo.example.com
tls:
mode: Passthrough
routes:
kind: TLSRoute
namespaces:
from: Same
selector:
matchLabels:
app: tls-app
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-1
namespace: default
labels:
app: http-app
spec:
rules:
- forwardTo:
- serviceName: whoami
port: 80
weight: 1
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-1
namespace: default
labels:
app: tcp-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,41 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners:
- protocol: UNKNOWN
port: 9080
routes:
kind: HTTPRoute
namespaces:
from: Same
selector:
matchLabels:
app: http-app
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-1
namespace: default
labels:
app: http-app
spec:
rules:
- forwardTo:
- serviceName: whoami
port: 80
weight: 1

View file

@ -0,0 +1,41 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners:
- protocol: HTTP
port: 9080
routes:
kind: UnknownRoute
namespaces:
from: Same
selector:
matchLabels:
app: http-app
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-1
namespace: default
labels:
app: http-app
spec:
rules:
- forwardTo:
- serviceName: whoami
port: 80
weight: 1

View file

@ -0,0 +1,41 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners:
- protocol: TLS
port: 9080
routes:
kind: HTTPRoute
namespaces:
from: Same
selector:
matchLabels:
app: http-app
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-1
namespace: default
labels:
app: http-app
spec:
rules:
- forwardTo:
- serviceName: whoami
port: 80
weight: 1

View file

@ -0,0 +1,139 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: HTTP
port: 9080
routes:
kind: HTTPRoute
namespaces:
from: Same
selector:
matchLabels:
app: http-app-1
- protocol: HTTP
port: 9080
routes:
kind: HTTPRoute
namespaces:
from: Same
selector:
matchLabels:
app: http-app-2
- protocol: TCP
port: 9000
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: tcp-app
- protocol: TLS
port: 9000
tls:
mode: Passthrough
routes:
kind: TLSRoute
namespaces:
from: Same
selector:
matchLabels:
app: tls-app
- protocol: TLS
port: 9000
tls:
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: tcp-app
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-1
namespace: default
labels:
app: http-app
spec:
rules:
- forwardTo:
- serviceName: whoami
port: 80
weight: 1
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-2
namespace: default
labels:
app: http-app
spec:
rules:
- forwardTo:
- serviceName: whoami
port: 80
weight: 1
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-1
namespace: default
labels:
app: tcp-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,75 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
namespace: default
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-mixed-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: HTTP
port: 80
routes:
kind: HTTPRoute
selector:
matchLabels:
app: label-tls-app-1
- protocol: TCP
port: 9000
routes:
kind: TCPRoute
selector:
matchLabels:
app: label-tls-app-1
- protocol: TLS
port: 9443
tls:
mode: Passthrough
routes:
kind: TLSRoute
selector:
matchLabels:
app: label-http-app-1
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: label-tls-app-1
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-1
namespace: default
labels:
app: label-http-app-1
spec:
rules:
- matches:
- path:
type: Exact
value: /bar
forwardTo:
- serviceName: whoamitcp
port: 80
weight: 1

View file

@ -107,7 +107,6 @@ spec:
- name: websecure2
port: 8443
targetPort: websecure2
scheme: https
selector:
app: containous
task: whoami3
@ -164,3 +163,39 @@ spec:
- name: https
protocol: TCP
port: 443
---
kind: Endpoints
apiVersion: v1
metadata:
name: whoamitcp
namespace: default
subsets:
- addresses:
- ip: 10.10.0.9
- ip: 10.10.0.10
ports:
- name: tcp-1
protocol: TCP
port: 9000
- name: tcp-2
protocol: TCP
port: 10000
---
apiVersion: v1
kind: Service
metadata:
name: whoamitcp
namespace: default
spec:
ports:
- protocol: TCP
port: 9000
name: tcp-1
- protocol: TCP
port: 10000
name: tcp-2

View file

@ -0,0 +1,41 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: unkown.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TCP
port: 8080
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: foo
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: TCP-app-1
namespace: default
labels:
app: foo
spec:
rules:
- forwardTo:
- serviceName: whoami
port: 80
weight: 1

View file

@ -0,0 +1,40 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
namespace: default
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-tcp-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TCP
port: 9000
routes:
kind: TCPRoute
selector:
matchLabels:
app: whoamitcp
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-1
namespace: default
labels:
app: whoamitcp
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,47 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TCP
port: 9000
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: tcp-app
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-1
namespace: default
labels:
app: tcp-app
spec:
rules:
- forwardTo:
- weight: 1
backendRef:
group: traefik.containo.us
kind: TraefikService
name: service@file
port: 9000
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,62 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
namespace: default
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-tcp-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TCP
port: 9000
routes:
kind: TCPRoute
selector:
matchLabels:
app: label-tcp-app-1
- protocol: TCP
port: 10000
routes:
kind: TCPRoute
selector:
matchLabels:
app: label-tcp-app-2
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-1
namespace: default
labels:
app: label-tcp-app-1
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-2
namespace: default
labels:
app: label-tcp-app-2
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 10000
weight: 1

View file

@ -0,0 +1,44 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
namespace: default
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-tcp-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TCP
port: 9000
routes:
kind: TCPRoute
selector:
matchLabels:
app: label-tcp-app
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app
namespace: default
labels:
app: label-tcp-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
- forwardTo:
- serviceName: whoamitcp
port: 10000
weight: 1

View file

@ -0,0 +1,42 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: HTTP
port: 9000
hostname: foo.example.com
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: tcp-app
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-1
namespace: default
labels:
app: tcp-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,59 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: HTTPS
port: 9000
hostname: foo.example.com
tls:
mode: Terminate # Default mode
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: tcp-app
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-1
namespace: default
labels:
app: tcp-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,59 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
port: 9000
hostname: foo.example.com
tls:
mode: Terminate # Default mode
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: tcp-app
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-1
namespace: default
labels:
app: tcp-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,41 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TCP
port: 8080
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: foo
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: TCP-app-1
namespace: default
labels:
app: foo
spec:
rules:
- forwardTo:
- serviceName: whoami
weight: 1
port: 9000

View file

@ -0,0 +1,33 @@
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TCP
port: 8080
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: foo
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: TCP-app-1
namespace: default
labels:
app: foo
spec:
rules:
- forwardTo:
- serviceName: whoami
port: 80
weight: 1

View file

@ -0,0 +1,26 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TCP
port: 8080
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: foo

View file

@ -0,0 +1,43 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
port: 8080
tls:
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: foo

View file

@ -0,0 +1,57 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: unkown.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
tls:
certificateRef:
kind: Secret
name: supersecret
group: core
port: 8080
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: foo
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: foo
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 80
weight: 1

View file

@ -0,0 +1,57 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
namespace: default
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-tls-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
hostname: foo.example.com
port: 9000
tls:
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: TCPRoute
selector:
matchLabels:
app: whoamitcp
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-1
namespace: default
labels:
app: whoamitcp
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,57 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
namespace: default
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-tls-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
hostname: foo.example.com
port: 9000
tls:
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: TLSRoute
selector:
matchLabels:
app: whoamitls
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: whoamitls
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,54 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
namespace: default
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-tls-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
hostname: foo.example.com
port: 9000
tls:
mode: Passthrough
routes:
kind: TLSRoute
selector:
matchLabels:
app: whoamitcp
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: whoamitcp
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,63 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
port: 9000
tls:
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: tcp-app
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-1
namespace: default
labels:
app: tcp-app
spec:
rules:
- forwardTo:
- weight: 1
backendRef:
group: traefik.containo.us
kind: TraefikService
name: service@file
port: 9000
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,48 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
port: 9001
hostname: foo.example.com
tls:
mode: Passthrough
routes:
kind: TLSRoute
namespaces:
from: Same
selector:
matchLabels:
app: tls-app
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
matches:
- snis:
- foo.bar

View file

@ -0,0 +1,49 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
port: 9001
hostname: foo.example.com
tls:
mode: Passthrough
routes:
kind: TLSRoute
namespaces:
from: Same
selector:
matchLabels:
app: tls-app
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
matches:
- snis:
- foo.bar
- "*"

View file

@ -0,0 +1,49 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
port: 9001
hostname: foo.example.com
tls:
mode: Passthrough
routes:
kind: TLSRoute
namespaces:
from: Same
selector:
matchLabels:
app: tls-app
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
matches:
- snis:
- foo.bar
- fiz.baz

View file

@ -0,0 +1,82 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
namespace: default
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-tls-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
hostname: foo.example.com
port: 9000
tls:
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: TCPRoute
selector:
matchLabels:
app: label-tcp-app-1
- protocol: TLS
port: 10000
tls:
mode: Passthrough
routes:
kind: TLSRoute
selector:
matchLabels:
app: label-tls-app-1
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-1
namespace: default
labels:
app: label-tcp-app-1
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: label-tls-app-1
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 10000
weight: 1

View file

@ -0,0 +1,44 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
port: 9001
hostname: foo.example.com
tls:
mode: Passthrough
routes:
kind: TLSRoute
namespaces:
from: Same
selector:
matchLabels:
app: tls-app
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,60 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
port: 9001
hostname: foo.example.com
tls:
mode: Passthrough
# certificateRef is ignored with mode "Passthrough"
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: TLSRoute
namespaces:
from: Same
selector:
matchLabels:
app: tls-app
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,42 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: HTTP
port: 9001
hostname: foo.example.com
routes:
kind: TLSRoute
namespaces:
from: Same
selector:
matchLabels:
app: tls-app
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,59 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: HTTPS
port: 9001
hostname: foo.example.com
tls:
mode: Terminate # Default mode
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: TLSRoute
namespaces:
from: Same
selector:
matchLabels:
app: tls-app
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,42 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TCP
port: 9001
hostname: foo.example.com
routes:
kind: TLSRoute
namespaces:
from: Same
selector:
matchLabels:
app: tls-app
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-1
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1

View file

@ -0,0 +1,57 @@
---
apiVersion: v1
kind: Secret
metadata:
name: supersecret
namespace: default
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
port: 8080
tls:
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: foo
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-1
namespace: default
labels:
app: foo
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
weight: 1
port: 9001

View file

@ -0,0 +1,33 @@
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
port: 8080
routes:
kind: TCPRoute
namespaces:
from: Same
selector:
matchLabels:
app: foo
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-1
namespace: default
labels:
app: foo
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 8080
weight: 1

View file

@ -0,0 +1,28 @@
---
kind: GatewayClass
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway-class
spec:
controller: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- protocol: TLS
port: 8080
tls:
mode: Passthrough
routes:
kind: TLSRoutes
namespaces:
from: Same
selector:
matchLabels:
app: foo

View file

@ -32,6 +32,9 @@ const (
providerName = "kubernetesgateway"
traefikServiceKind = "TraefikService"
traefikServiceGroupName = "traefik.containo.us"
routeHTTPKind = "HTTPRoute"
routeTCPKind = "TCPRoute"
routeTLSKind = "TLSRoute"
)
// Provider holds configurations of the provider.
@ -222,7 +225,7 @@ func (p *Provider) loadConfigurationFromGateway(ctx context.Context, client Clie
continue
}
cfg, err := p.createGatewayConf(client, gateway)
cfg, err := p.createGatewayConf(ctxLog, client, gateway)
if err != nil {
logger.Error(err)
continue
@ -262,7 +265,7 @@ func (p *Provider) loadConfigurationFromGateway(ctx context.Context, client Clie
return conf
}
func (p *Provider) createGatewayConf(client Client, gateway *v1alpha1.Gateway) (*dynamic.Configuration, error) {
func (p *Provider) createGatewayConf(ctx context.Context, client Client, gateway *v1alpha1.Gateway) (*dynamic.Configuration, error) {
conf := &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
@ -285,7 +288,7 @@ func (p *Provider) createGatewayConf(client Client, gateway *v1alpha1.Gateway) (
// GatewayReasonListenersNotValid is used when one or more
// Listeners have an invalid or unsupported configuration
// and cannot be configured on the Gateway.
listenerStatuses := p.fillGatewayConf(client, gateway, conf, tlsConfigs)
listenerStatuses := p.fillGatewayConf(ctx, client, gateway, conf, tlsConfigs)
gatewayStatus, errG := p.makeGatewayStatus(listenerStatuses)
@ -305,8 +308,10 @@ func (p *Provider) createGatewayConf(client Client, gateway *v1alpha1.Gateway) (
return conf, nil
}
func (p *Provider) fillGatewayConf(client Client, gateway *v1alpha1.Gateway, conf *dynamic.Configuration, tlsConfigs map[string]*tls.CertAndStores) []v1alpha1.ListenerStatus {
func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway *v1alpha1.Gateway, conf *dynamic.Configuration, tlsConfigs map[string]*tls.CertAndStores) []v1alpha1.ListenerStatus {
listenerStatuses := make([]v1alpha1.ListenerStatus, len(gateway.Spec.Listeners))
logger := log.FromContext(ctx)
allocatedPort := map[v1alpha1.PortNumber]v1alpha1.ProtocolType{}
for i, listener := range gateway.Spec.Listeners {
listenerStatuses[i] = v1alpha1.ListenerStatus{
@ -315,7 +320,8 @@ func (p *Provider) fillGatewayConf(client Client, gateway *v1alpha1.Gateway, con
}
// Supported Protocol
if listener.Protocol != v1alpha1.HTTPProtocolType && listener.Protocol != v1alpha1.HTTPSProtocolType {
if listener.Protocol != v1alpha1.HTTPProtocolType && listener.Protocol != v1alpha1.HTTPSProtocolType &&
listener.Protocol != v1alpha1.TCPProtocolType && listener.Protocol != v1alpha1.TLSProtocolType {
// update "Detached" status true with "UnsupportedProtocol" reason
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionDetached),
@ -328,6 +334,50 @@ func (p *Provider) fillGatewayConf(client Client, gateway *v1alpha1.Gateway, con
continue
}
// Supported Route types
if listener.Routes.Kind != routeHTTPKind && listener.Routes.Kind != routeTCPKind && listener.Routes.Kind != routeTLSKind {
// update "ResolvedRefs" status true with "InvalidRoutesRef" reason
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonInvalidRoutesRef),
Message: fmt.Sprintf("Unsupported Route Kind %q", listener.Routes.Kind),
})
continue
}
// Protocol compliant with route type
if listener.Protocol == v1alpha1.HTTPProtocolType && listener.Routes.Kind != routeHTTPKind ||
listener.Protocol == v1alpha1.HTTPSProtocolType && listener.Routes.Kind != routeHTTPKind ||
listener.Protocol == v1alpha1.TCPProtocolType && listener.Routes.Kind != routeTCPKind ||
listener.Protocol == v1alpha1.TLSProtocolType && listener.Routes.Kind != routeTLSKind && listener.Routes.Kind != routeTCPKind {
// update "Detached" status true with "UnsupportedProtocol" reason
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionDetached),
Status: metav1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonUnsupportedProtocol),
Message: fmt.Sprintf("listener protocol %q not supported with route kind %q", listener.Protocol, listener.Routes.Kind),
})
continue
}
if _, ok := allocatedPort[listener.Port]; ok {
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionDetached),
Status: metav1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonPortUnavailable),
Message: fmt.Sprintf("port %d unavailable", listener.Port),
})
continue
}
allocatedPort[listener.Port] = listener.Protocol
ep, err := p.entryPointName(listener.Port, listener.Protocol)
if err != nil {
// update "Detached" status with "PortUnavailable" reason
@ -342,8 +392,9 @@ func (p *Provider) fillGatewayConf(client Client, gateway *v1alpha1.Gateway, con
continue
}
if listener.Protocol == v1alpha1.HTTPSProtocolType {
if listener.TLS == nil {
// TLS
if listener.Protocol == v1alpha1.HTTPSProtocolType || listener.Protocol == v1alpha1.TLSProtocolType {
if listener.TLS == nil || (listener.TLS.CertificateRef == nil && listener.TLS.Mode != v1alpha1.TLSModePassthrough) {
// update "Detached" status with "UnsupportedProtocol" reason
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionDetached),
@ -356,167 +407,397 @@ func (p *Provider) fillGatewayConf(client Client, gateway *v1alpha1.Gateway, con
continue
}
if listener.TLS.CertificateRef.Kind != "Secret" || listener.TLS.CertificateRef.Group != "core" {
// update "ResolvedRefs" status true with "InvalidCertificateRef" reason
if listener.TLS.Mode == v1alpha1.TLSModePassthrough && listener.TLS.CertificateRef != nil {
// https://gateway-api.sigs.k8s.io/guides/tls/
logger.Warnf("In case of Passthrough TLS mode, no TLS settings take effect as the TLS session from the client is NOT terminated at the Gateway")
}
isTLSPassthrough := listener.TLS.Mode == v1alpha1.TLSModePassthrough
// Allowed configurations:
// Protocol TLS -> Passthrough -> TLSRoute
// Protocol TLS -> Terminate -> TCPRoute
// Protocol HTTPS -> Terminate -> HTTPRoute
if !(listener.Protocol == v1alpha1.TLSProtocolType && isTLSPassthrough && listener.Routes.Kind == routeTLSKind ||
listener.Protocol == v1alpha1.TLSProtocolType && !isTLSPassthrough && listener.Routes.Kind == routeTCPKind ||
listener.Protocol == v1alpha1.HTTPSProtocolType && !isTLSPassthrough && listener.Routes.Kind == routeHTTPKind) {
// update "ConditionDetached" status true with "ReasonUnsupportedProtocol" reason
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
Type: string(v1alpha1.ListenerConditionDetached),
Status: metav1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonInvalidCertificateRef),
Message: fmt.Sprintf("Unsupported TLS CertificateRef group/kind : %v/%v", listener.TLS.CertificateRef.Group, listener.TLS.CertificateRef.Kind),
Reason: string(v1alpha1.ListenerReasonUnsupportedProtocol),
Message: fmt.Sprintf("Unsupported route kind %q with %q",
listener.Routes.Kind, listener.TLS.Mode),
})
continue
}
configKey := gateway.Namespace + "/" + listener.TLS.CertificateRef.Name
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
tlsConf, err := getTLS(client, listener.TLS.CertificateRef.Name, gateway.Namespace)
if err != nil {
if !isTLSPassthrough {
if listener.TLS.CertificateRef.Kind != "Secret" || listener.TLS.CertificateRef.Group != "core" {
// update "ResolvedRefs" status true with "InvalidCertificateRef" reason
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonInvalidCertificateRef),
Message: fmt.Sprintf("Error while retrieving certificate: %v", err),
Message: fmt.Sprintf("Unsupported TLS CertificateRef group/kind : %v/%v", listener.TLS.CertificateRef.Group, listener.TLS.CertificateRef.Kind),
})
continue
}
tlsConfigs[configKey] = tlsConf
configKey := gateway.Namespace + "/" + listener.TLS.CertificateRef.Name
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
tlsConf, err := getTLS(client, listener.TLS.CertificateRef.Name, gateway.Namespace)
if err != nil {
// update "ResolvedRefs" status true with "InvalidCertificateRef" reason
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonInvalidCertificateRef),
Message: fmt.Sprintf("Error while retrieving certificate: %v", err),
})
continue
}
tlsConfigs[configKey] = tlsConf
}
}
}
// Supported Route types
if listener.Routes.Kind != "HTTPRoute" {
// update "ResolvedRefs" status true with "InvalidRoutesRef" reason
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonInvalidRoutesRef),
Message: fmt.Sprintf("Unsupported Route Kind %q", listener.Routes.Kind),
})
continue
switch listener.Routes.Kind {
case routeHTTPKind:
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, gatewayHTTPRouteToHTTPConf(ctx, ep, listener, gateway, client, conf)...)
case routeTCPKind:
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, gatewayTCPRouteToTCPConf(ctx, ep, listener, gateway, client, conf)...)
case routeTLSKind:
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, gatewayTLSRouteToTCPConf(ctx, ep, listener, gateway, client, conf)...)
}
}
// TODO: support RouteNamespaces
httpRoutes, err := client.GetHTTPRoutes(gateway.Namespace, labels.SelectorFromSet(listener.Routes.Selector.MatchLabels))
return listenerStatuses
}
func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha1.Listener, gateway *v1alpha1.Gateway, client Client, conf *dynamic.Configuration) []metav1.Condition {
// TODO: support RouteNamespaces
selector := labels.SelectorFromSet(listener.Routes.Selector.MatchLabels)
httpRoutes, err := client.GetHTTPRoutes(gateway.Namespace, selector)
if err != nil {
// update "ResolvedRefs" status true with "InvalidRoutesRef" reason
return []metav1.Condition{{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonInvalidRoutesRef),
Message: fmt.Sprintf("Cannot fetch %ss for namespace %q and matchLabels %v", listener.Routes.Kind, gateway.Namespace, listener.Routes.Selector.MatchLabels),
}}
}
if len(httpRoutes) == 0 {
log.FromContext(ctx).Debugf("No HTTPRoutes found for selector %q", selector)
return nil
}
var conditions []metav1.Condition
for _, httpRoute := range httpRoutes {
hostRule, err := hostRule(httpRoute.Spec)
if err != nil {
// update "ResolvedRefs" status true with "InvalidRoutesRef" reason
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
conditions = append(conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonInvalidRoutesRef),
Message: fmt.Sprintf("Cannot fetch HTTPRoutes for namespace %q and matchLabels %v", gateway.Namespace, listener.Routes.Selector.MatchLabels),
Reason: string(v1alpha1.ListenerReasonDegradedRoutes),
Message: fmt.Sprintf("Skipping HTTPRoute %s: invalid hostname: %v", httpRoute.Name, err),
})
continue
}
for _, httpRoute := range httpRoutes {
// Should never happen
if httpRoute == nil {
continue
}
hostRule, err := hostRule(httpRoute.Spec)
for _, routeRule := range httpRoute.Spec.Rules {
rule, err := extractRule(routeRule, hostRule)
if err != nil {
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
// update "ResolvedRefs" status true with "DroppedRoutes" reason
conditions = append(conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonDegradedRoutes),
Message: fmt.Sprintf("Skipping HTTPRoute %s: invalid hostname: %v", httpRoute.Name, err),
Message: fmt.Sprintf("Skipping %s %s: cannot generate rule: %v", listener.Routes.Kind, httpRoute.Name, err),
})
}
router := dynamic.Router{
Rule: rule,
EntryPoints: []string{ep},
}
if listener.TLS != nil {
// TODO support let's encrypt
router.TLS = &dynamic.RouterTLSConfig{}
}
// Adding the gateway name and the entryPoint name prevents overlapping of routers build from the same routes.
routerName := httpRoute.Name + "-" + gateway.Name + "-" + ep
routerKey, err := makeRouterKey(router.Rule, makeID(httpRoute.Namespace, routerName))
if err != nil {
// update "ResolvedRefs" status true with "DroppedRoutes" reason
conditions = append(conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonDegradedRoutes),
Message: fmt.Sprintf("Skipping %s %s: cannot make router's key with rule %s: %v", listener.Routes.Kind, httpRoute.Name, router.Rule, err),
})
// TODO update the RouteStatus condition / deduplicate conditions on listener
continue
}
for _, routeRule := range httpRoute.Spec.Rules {
rule, err := extractRule(routeRule, hostRule)
if routeRule.ForwardTo == nil {
continue
}
// Traefik internal service can be used only if there is only one ForwardTo service reference.
if len(routeRule.ForwardTo) == 1 && isInternalService(routeRule.ForwardTo[0]) {
router.Service = routeRule.ForwardTo[0].BackendRef.Name
} else {
wrrService, subServices, err := loadServices(client, gateway.Namespace, routeRule.ForwardTo)
if err != nil {
// update "ResolvedRefs" status true with "DroppedRoutes" reason
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
conditions = append(conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonDegradedRoutes),
Message: fmt.Sprintf("Skipping HTTPRoute %s: cannot generate rule: %v", httpRoute.Name, err),
})
continue
}
router := dynamic.Router{
Rule: rule,
EntryPoints: []string{ep},
}
if listener.TLS != nil {
// TODO support let's encrypt
router.TLS = &dynamic.RouterTLSConfig{}
}
// Adding the gateway name and the entryPoint name prevents overlapping of routers build from the same routes.
routerName := httpRoute.Name + "-" + gateway.Name + "-" + ep
routerKey, err := makeRouterKey(router.Rule, makeID(httpRoute.Namespace, routerName))
if err != nil {
// update "ResolvedRefs" status true with "DroppedRoutes" reason
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonDegradedRoutes),
Message: fmt.Sprintf("Skipping HTTPRoute %s: cannot make router's key with rule %s: %v", httpRoute.Name, router.Rule, err),
Message: fmt.Sprintf("Cannot load service from %s %s/%s : %v", listener.Routes.Kind, gateway.Namespace, httpRoute.Name, err),
})
// TODO update the RouteStatus condition / deduplicate conditions on listener
continue
}
if routeRule.ForwardTo != nil {
// Traefik internal service can be used only if there is only one ForwardTo service reference.
if len(routeRule.ForwardTo) == 1 && isInternalService(routeRule.ForwardTo[0]) {
router.Service = routeRule.ForwardTo[0].BackendRef.Name
} else {
wrrService, subServices, err := loadServices(client, gateway.Namespace, routeRule.ForwardTo)
if err != nil {
// update "ResolvedRefs" status true with "DroppedRoutes" reason
listenerStatuses[i].Conditions = append(listenerStatuses[i].Conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonDegradedRoutes),
Message: fmt.Sprintf("Cannot load service from HTTPRoute %s/%s : %v", gateway.Namespace, httpRoute.Name, err),
})
// TODO update the RouteStatus condition / deduplicate conditions on listener
continue
}
for svcName, svc := range subServices {
conf.HTTP.Services[svcName] = svc
}
serviceName := provider.Normalize(routerKey + "-wrr")
conf.HTTP.Services[serviceName] = wrrService
router.Service = serviceName
}
for svcName, svc := range subServices {
conf.HTTP.Services[svcName] = svc
}
if router.Service != "" {
routerKey = provider.Normalize(routerKey)
serviceName := provider.Normalize(routerKey + "-wrr")
conf.HTTP.Services[serviceName] = wrrService
conf.HTTP.Routers[routerKey] = &router
}
router.Service = serviceName
}
routerKey = provider.Normalize(routerKey)
conf.HTTP.Routers[routerKey] = &router
}
}
return listenerStatuses
return conditions
}
func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener v1alpha1.Listener, gateway *v1alpha1.Gateway, client Client, conf *dynamic.Configuration) []metav1.Condition {
// TODO: support RouteNamespaces
selector := labels.SelectorFromSet(listener.Routes.Selector.MatchLabels)
tcpRoutes, err := client.GetTCPRoutes(gateway.Namespace, selector)
if err != nil {
// update "ResolvedRefs" status true with "InvalidRoutesRef" reason
return []metav1.Condition{{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonInvalidRoutesRef),
Message: fmt.Sprintf("Cannot fetch %ss for namespace %q and matchLabels %v", listener.Routes.Kind, gateway.Namespace, listener.Routes.Selector.MatchLabels),
}}
}
if len(tcpRoutes) == 0 {
log.FromContext(ctx).Debugf("No TCPRoutes found for selector %q", selector)
return nil
}
var conditions []metav1.Condition
for _, tcpRoute := range tcpRoutes {
if len(tcpRoute.Spec.Rules) > 1 {
conditions = append(conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonDegradedRoutes),
Message: fmt.Sprintf("Skipping %s %s: multiple rules are not supported", listener.Routes.Kind, tcpRoute.Name),
})
continue
}
for _, routeRule := range tcpRoute.Spec.Rules {
router := dynamic.TCPRouter{
Rule: "HostSNI(`*`)", // Gateway listener hostname not available in TCP
EntryPoints: []string{ep},
}
if listener.TLS != nil {
// TODO support let's encrypt
router.TLS = &dynamic.RouterTCPTLSConfig{}
}
// Adding the gateway name and the entryPoint name prevents overlapping of routers build from the same routes.
routerName := tcpRoute.Name + "-" + gateway.Name + "-" + ep
routerKey, err := makeRouterKey("", makeID(tcpRoute.Namespace, routerName))
if err != nil {
// update "ResolvedRefs" status true with "DroppedRoutes" reason
conditions = append(conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonDegradedRoutes),
Message: fmt.Sprintf("Skipping %s %s: cannot make router's key with rule %s: %v", listener.Routes.Kind, tcpRoute.Name, router.Rule, err),
})
// TODO update the RouteStatus condition / deduplicate conditions on listener
continue
}
// Should not happen due to validation
// https://github.com/kubernetes-sigs/gateway-api/blob/af68a622f072811767d246ef5897135d93af0704/apis/v1alpha1/tcproute_types.go#L76
if routeRule.ForwardTo == nil {
continue
}
wrrService, subServices, err := loadTCPServices(client, gateway.Namespace, routeRule.ForwardTo)
if err != nil {
// update "ResolvedRefs" status true with "DroppedRoutes" reason
conditions = append(conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonDegradedRoutes),
Message: fmt.Sprintf("Cannot load service from %s %s/%s : %v", listener.Routes.Kind, gateway.Namespace, tcpRoute.Name, err),
})
// TODO update the RouteStatus condition / deduplicate conditions on listener
continue
}
for svcName, svc := range subServices {
conf.TCP.Services[svcName] = svc
}
serviceName := provider.Normalize(routerKey + "-wrr")
conf.TCP.Services[serviceName] = wrrService
router.Service = serviceName
routerKey = provider.Normalize(routerKey)
conf.TCP.Routers[routerKey] = &router
}
}
return conditions
}
func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha1.Listener, gateway *v1alpha1.Gateway, client Client, conf *dynamic.Configuration) []metav1.Condition {
// TODO: support RouteNamespaces
selector := labels.SelectorFromSet(listener.Routes.Selector.MatchLabels)
tlsRoutes, err := client.GetTLSRoutes(gateway.Namespace, selector)
if err != nil {
// update "ResolvedRefs" status true with "InvalidRoutesRef" reason
return []metav1.Condition{{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonInvalidRoutesRef),
Message: fmt.Sprintf("Cannot fetch %ss for namespace %q and matchLabels %v", listener.Routes.Kind, gateway.Namespace, listener.Routes.Selector.MatchLabels),
}}
}
if len(tlsRoutes) == 0 {
log.FromContext(ctx).Debugf("No TLSRoutes found for selector %q", selector)
return nil
}
var conditions []metav1.Condition
for _, tlsRoute := range tlsRoutes {
for _, routeRule := range tlsRoute.Spec.Rules {
rule, err := hostSNIRule(routeRule)
if err != nil {
// update "ResolvedRefs" status true with "DroppedRoutes" reason
conditions = append(conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonDegradedRoutes),
Message: fmt.Sprintf("Skipping %s %s: cannot make route's SNI match: %v", listener.Routes.Kind, tlsRoute.Name, err),
})
// TODO update the RouteStatus condition / deduplicate conditions on listener
continue
}
router := dynamic.TCPRouter{
Rule: rule,
EntryPoints: []string{ep},
}
if listener.TLS != nil {
// TODO support let's encrypt
router.TLS = &dynamic.RouterTCPTLSConfig{
Passthrough: listener.TLS.Mode == v1alpha1.TLSModePassthrough,
}
}
// Adding the gateway name and the entryPoint name prevents overlapping of routers build from the same routes.
routerName := tlsRoute.Name + "-" + gateway.Name + "-" + ep
routerKey, err := makeRouterKey(rule, makeID(tlsRoute.Namespace, routerName))
if err != nil {
// update "ResolvedRefs" status true with "DroppedRoutes" reason
conditions = append(conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonDegradedRoutes),
Message: fmt.Sprintf("Skipping %s %s: cannot make router's key with rule %s: %v", listener.Routes.Kind, tlsRoute.Name, router.Rule, err),
})
// TODO update the RouteStatus condition / deduplicate conditions on listener
continue
}
// Should not happen due to validation
// https://github.com/kubernetes-sigs/gateway-api/blob/af68a622f072811767d246ef5897135d93af0704/apis/v1alpha1/tlsroute_types.go#L79
if routeRule.ForwardTo == nil {
continue
}
wrrService, subServices, err := loadTCPServices(client, gateway.Namespace, routeRule.ForwardTo)
if err != nil {
// update "ResolvedRefs" status true with "DroppedRoutes" reason
conditions = append(conditions, metav1.Condition{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonDegradedRoutes),
Message: fmt.Sprintf("Cannot load service from %s %s/%s : %v", listener.Routes.Kind, gateway.Namespace, tlsRoute.Name, err),
})
// TODO update the RouteStatus condition / deduplicate conditions on listener
continue
}
for svcName, svc := range subServices {
conf.TCP.Services[svcName] = svc
}
serviceName := provider.Normalize(routerKey + "-wrr")
conf.TCP.Services[serviceName] = wrrService
router.Service = serviceName
routerKey = provider.Normalize(routerKey)
conf.TCP.Routers[routerKey] = &router
}
}
return conditions
}
func (p *Provider) makeGatewayStatus(listenerStatuses []v1alpha1.ListenerStatus) (v1alpha1.GatewayStatus, error) {
@ -601,7 +882,7 @@ func hostRule(httpRouteSpec v1alpha1.HTTPRouteSpec) (string, error) {
continue
}
// https://gateway-api.sigs.k8s.io/spec/#networking.x-k8s.io/v1alpha1.Hostname
// https://gateway-api.sigs.k8s.io/references/spec/#networking.x-k8s.io/v1alpha1.Hostname
if !strings.HasPrefix(host, "*.") || wildcard > 1 {
return "", fmt.Errorf("invalid rule: %q", host)
}
@ -627,6 +908,38 @@ func hostRule(httpRouteSpec v1alpha1.HTTPRouteSpec) (string, error) {
return hostRegexp, nil
}
func hostSNIRule(rule v1alpha1.TLSRouteRule) (string, error) {
uniqHostnames := map[string]struct{}{}
var hostnames []string
for _, match := range rule.Matches {
for _, hostname := range match.SNIs {
if len(hostname) == 0 {
continue
}
h := string(hostname)
// first naive validation, should be improved
wildcardNb := strings.Count(h, "*")
if wildcardNb != 0 && !strings.HasPrefix(h, "*.") || wildcardNb > 1 {
return "", fmt.Errorf("invalid hostname: %q", h)
}
hostname := "`" + h + "`"
if _, ok := uniqHostnames[hostname]; !ok {
hostnames = append(hostnames, hostname)
uniqHostnames[hostname] = struct{}{}
}
}
}
if len(hostnames) == 0 {
return "HostSNI(`*`)", nil
}
return "HostSNI(" + strings.Join(hostnames, ",") + ")", nil
}
func extractRule(routeRule v1alpha1.HTTPRouteRule, hostRule string) (string, error) {
var rule string
var matchesRules []string
@ -700,6 +1013,7 @@ func (p *Provider) entryPointName(port v1alpha1.PortNumber, protocol v1alpha1.Pr
for name, entryPoint := range p.EntryPoints {
if strings.HasSuffix(entryPoint.Address, ":"+portStr) {
// if the protocol is HTTP the entryPoint must have no TLS conf
// Not relevant for v1alpha1.TLSProtocolType && v1alpha1.TCPProtocolType
if protocol == v1alpha1.HTTPProtocolType && entryPoint.HasHTTPTLSConf {
continue
}
@ -860,13 +1174,11 @@ func loadServices(client Client, namespace string, targets []v1alpha1.HTTPRouteF
continue
}
var portName string
var portSpec corev1.ServicePort
var match bool
for _, p := range service.Spec.Ports {
if forwardTo.Port == nil || p.Port == int32(*forwardTo.Port) {
portName = p.Name
portSpec = p
match = true
break
@ -894,7 +1206,7 @@ func loadServices(client Client, namespace string, targets []v1alpha1.HTTPRouteF
var portStr string
for _, subset := range endpoints.Subsets {
for _, p := range subset.Ports {
if portName == p.Name {
if portSpec.Name == p.Name {
port = p.Port
break
}
@ -904,7 +1216,7 @@ func loadServices(client Client, namespace string, targets []v1alpha1.HTTPRouteF
return nil, nil, errors.New("cannot define a port")
}
protocol := getProtocol(portSpec, portName)
protocol := getProtocol(portSpec)
portStr = strconv.FormatInt(int64(port), 10)
for _, addr := range subset.Addresses {
@ -927,9 +1239,127 @@ func loadServices(client Client, namespace string, targets []v1alpha1.HTTPRouteF
return wrrSvc, services, nil
}
func getProtocol(portSpec corev1.ServicePort, portName string) string {
// loadTCPServices is generating a WRR service, even when there is only one target.
func loadTCPServices(client Client, namespace string, targets []v1alpha1.RouteForwardTo) (*dynamic.TCPService, map[string]*dynamic.TCPService, error) {
services := map[string]*dynamic.TCPService{}
wrrSvc := &dynamic.TCPService{
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{},
},
}
for _, forwardTo := range targets {
weight := int(forwardTo.Weight)
if forwardTo.ServiceName == nil && forwardTo.BackendRef != nil {
if !(forwardTo.BackendRef.Group == traefikServiceGroupName && forwardTo.BackendRef.Kind == traefikServiceKind) {
continue
}
if strings.HasSuffix(forwardTo.BackendRef.Name, "@internal") {
return nil, nil, fmt.Errorf("traefik internal service %s is not allowed in a TCP service", forwardTo.BackendRef.Name)
}
wrrSvc.Weighted.Services = append(wrrSvc.Weighted.Services, dynamic.TCPWRRService{Name: forwardTo.BackendRef.Name, Weight: &weight})
continue
}
if forwardTo.ServiceName == nil {
continue
}
svc := dynamic.TCPService{
LoadBalancer: &dynamic.TCPServersLoadBalancer{},
}
service, exists, err := client.GetService(namespace, *forwardTo.ServiceName)
if err != nil {
return nil, nil, err
}
if !exists {
return nil, nil, errors.New("service not found")
}
if len(service.Spec.Ports) > 1 && forwardTo.Port == nil {
// If the port is unspecified and the backend is a Service
// object consisting of multiple port definitions, the route
// must be dropped from the Gateway. The controller should
// raise the "ResolvedRefs" condition on the Gateway with the
// "DroppedRoutes" reason. The gateway status for this route
// should be updated with a condition that describes the error
// more specifically.
log.WithoutContext().Errorf("A multiple ports Kubernetes Service cannot be used if unspecified forwardTo.Port")
continue
}
var portSpec corev1.ServicePort
var match bool
for _, p := range service.Spec.Ports {
if forwardTo.Port == nil || p.Port == int32(*forwardTo.Port) {
portSpec = p
match = true
break
}
}
if !match {
return nil, nil, errors.New("service port not found")
}
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, *forwardTo.ServiceName)
if endpointsErr != nil {
return nil, nil, endpointsErr
}
if !endpointsExists {
return nil, nil, errors.New("endpoints not found")
}
if len(endpoints.Subsets) == 0 {
return nil, nil, errors.New("subset not found")
}
var port int32
var portStr string
for _, subset := range endpoints.Subsets {
for _, p := range subset.Ports {
if portSpec.Name == p.Name {
port = p.Port
break
}
}
if port == 0 {
return nil, nil, errors.New("cannot define a port")
}
portStr = strconv.FormatInt(int64(port), 10)
for _, addr := range subset.Addresses {
svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, dynamic.TCPServer{
Address: net.JoinHostPort(addr.IP, portStr),
})
}
}
serviceName := provider.Normalize(makeID(service.Namespace, service.Name) + "-" + portStr)
services[serviceName] = &svc
wrrSvc.Weighted.Services = append(wrrSvc.Weighted.Services, dynamic.TCPWRRService{Name: serviceName, Weight: &weight})
}
if len(wrrSvc.Weighted.Services) == 0 {
return nil, nil, errors.New("no service has been created")
}
return wrrSvc, services, nil
}
func getProtocol(portSpec corev1.ServicePort) string {
protocol := "http"
if portSpec.Port == 443 || strings.HasPrefix(portName, "https") {
if portSpec.Port == 443 || strings.HasPrefix(portSpec.Name, "https") {
protocol = "https"
}

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,7 @@ import (
// MustParseYaml parses a YAML to objects.
func MustParseYaml(content []byte) []runtime.Object {
acceptedK8sTypes := regexp.MustCompile(`^(Deployment|Endpoints|Service|Ingress|IngressRoute|IngressRouteTCP|IngressRouteUDP|Middleware|Secret|TLSOption|TLSStore|TraefikService|IngressClass|ServersTransport|GatewayClass|Gateway|HTTPRoute)$`)
acceptedK8sTypes := regexp.MustCompile(`^(Deployment|Endpoints|Service|Ingress|IngressRoute|IngressRouteTCP|IngressRouteUDP|Middleware|Secret|TLSOption|TLSStore|TraefikService|IngressClass|ServersTransport|GatewayClass|Gateway|HTTPRoute|TCPRoute|TLSRoute)$`)
files := strings.Split(string(content), "---")
retVal := make([]runtime.Object, 0, len(files))