gateway api: support RouteNamespaces

Co-authored-by: Jean-Baptiste Doumenjou <925513+jbdoumenjou@users.noreply.github.com>
This commit is contained in:
Tom Moulard 2021-10-04 15:46:08 +02:00 committed by GitHub
parent 9ef3fc84f9
commit 969dd088a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 2629 additions and 95 deletions

View file

@ -424,3 +424,9 @@ Traefik v2.6 introduces the `AdvertisedPort` option,
which allows advertising, in the `Alt-Svc` header, a UDP port different from the one on which Traefik is actually listening (the EntryPoint's port).
By doing so, it introduces a new configuration structure `http3`, which replaces the `enableHTTP3` option (which therefore doesn't exist anymore).
To enable HTTP3 on an EntryPoint, please check out the [HTTP3 configuration](../routing/entrypoints.md#http3) documentation.
### Kubernetes Gateway provider
In `v2.6`, the [Kubernetes Gateway provider](../providers/kubernetes-gateway.md) now supports [route namespaces](https://gateway-api.sigs.k8s.io/v1alpha1/references/spec/#networking.x-k8s.io/v1alpha1.RouteNamespaces) selectors,
which requires Traefik to fetch and watch the cluster namespaces.
Therefore, the RBAC definitions must be updated, please check out the [RBAC configuration reference](../reference/dynamic-configuration/kubernetes-gateway.md#rbac).

View file

@ -4,6 +4,13 @@ kind: ClusterRole
metadata:
name: gateway-role
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- list
- watch
- apiGroups:
- ""
resources:

View file

@ -97,8 +97,13 @@ Depending on the Listener Protocol, different modes and Route types are supporte
port: 80 # [4]
routes: # [8]
kind: HTTPRoute # [9]
selector: # [10]
matchLabels: # [11]
namespaces:
from: Selector # [10]
selector: # [11]
matchLabels:
app: foo
selector: # [12]
matchLabels:
app: foo
```
@ -120,8 +125,13 @@ Depending on the Listener Protocol, different modes and Route types are supporte
name: "mysecret"
routes: # [8]
kind: HTTPRoute # [9]
selector: # [10]
matchLabels: # [11]
namespaces:
from: Selector # [10]
selector: # [11]
matchLabels:
app: foo
selector: # [12]
matchLabels:
app: foo
```
@ -138,8 +148,13 @@ Depending on the Listener Protocol, different modes and Route types are supporte
port: 8000 # [4]
routes: # [8]
kind: TCPRoute # [9]
selector: # [10]
matchLabels: # [11]
namespaces:
from: Selector # [10]
selector: # [11]
matchLabels:
app: footcp
selector: # [12]
matchLabels:
app: footcp
```
@ -162,24 +177,30 @@ Depending on the Listener Protocol, different modes and Route types are supporte
name: "mysecret"
routes: # [8]
kind: TLSRoute # [9]
selector: # [10]
matchLabels: # [11]
namespaces:
from: Selector # [10]
selector: # [11]
matchLabels:
app: footcp
selector: # [12]
matchLabels:
app: footcp
```
| Ref | Attribute | Description |
|------|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| [1] | `gatewayClassName` | GatewayClassName used for this Gateway. This is the name of a GatewayClass resource. |
| [2] | `listeners` | Logical endpoints that are bound on this Gateway's addresses. At least one Listener MUST be specified. |
| [3] | `protocol` | The network protocol this listener expects to receive (only HTTP and HTTPS are implemented). |
| [4] | `port` | The network port. |
| [5] | `hostname` | Hostname specifies the virtual hostname to match for protocol types that define this concept. When unspecified, “”, or *, all hostnames are matched. |
| [6] | `tls` | TLS configuration for the Listener. This field is required if the Protocol field is "HTTPS" or "TLS" and ignored otherwise. |
| [7] | `certificateRef` | The reference to Kubernetes object that contains a TLS certificate and private key. |
| [8] | `routes` | A schema for associating routes with the Listener using selectors. |
| [9] | `kind` | The kind of the referent. |
| [10] | `selector` | Routes in namespaces selected by the selector may be used by this Gateway routes to associate with the Gateway. |
| [11] | `matchLabels` | A set of route labels used for selecting routes to associate with the Gateway. |
| Ref | Attribute | Description |
|------|--------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [1] | `gatewayClassName` | GatewayClassName used for this Gateway. This is the name of a GatewayClass resource. |
| [2] | `listeners` | Logical endpoints that are bound on this Gateway's addresses. At least one Listener MUST be specified. |
| [3] | `protocol` | The network protocol this listener expects to receive (only HTTP and HTTPS are implemented). |
| [4] | `port` | The network port. |
| [5] | `hostname` | Hostname specifies the virtual hostname to match for protocol types that define this concept. When unspecified, “”, or *, all hostnames are matched. |
| [6] | `tls` | TLS configuration for the Listener. This field is required if the Protocol field is "HTTPS" or "TLS" and ignored otherwise. |
| [7] | `certificateRef` | The reference to Kubernetes object that contains a TLS certificate and private key. |
| [8] | `routes` | A schema for associating routes with the Listener using selectors. |
| [9] | `kind` | The kind of the referent. |
| [10] | `from` | From indicates in which namespaces the Routes will be selected for this Gateway. Possible values are `All`, `Same` and `Selector` (Defaults to `Same`). |
| [11] | `selector` | Selector must be specified when From is set to `Selector`. In that case, only Routes in Namespaces matching this Selector will be selected by this Gateway. |
| [12] | `selector` | Selector specifies a set of route labels used for selecting routes to associate with the Gateway. An empty Selector matches all routes. |
### Kind: `HTTPRoute`

View file

@ -55,19 +55,21 @@ type Client interface {
UpdateGatewayStatus(gateway *v1alpha1.Gateway, gatewayStatus v1alpha1.GatewayStatus) error
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)
GetHTTPRoutes(namespaces []string, selector labels.Selector) ([]*v1alpha1.HTTPRoute, error)
GetTCPRoutes(namespaces []string, selector labels.Selector) ([]*v1alpha1.TCPRoute, error)
GetTLSRoutes(namespaces []string, selector labels.Selector) ([]*v1alpha1.TLSRoute, error)
GetService(namespace, name string) (*corev1.Service, bool, error)
GetSecret(namespace, name string) (*corev1.Secret, bool, error)
GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error)
GetNamespaces(selector labels.Selector) ([]string, error)
}
type clientWrapper struct {
csGateway versioned.Interface
csKube kubernetes.Interface
factoryNamespace informers.SharedInformerFactory
factoryGatewayClass externalversions.SharedInformerFactory
factoriesGateway map[string]externalversions.SharedInformerFactory
factoriesKube map[string]informers.SharedInformerFactory
@ -171,6 +173,9 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
options.LabelSelector = c.labelSelector
}
c.factoryNamespace = informers.NewSharedInformerFactory(c.csKube, resyncPeriod)
c.factoryNamespace.Core().V1().Namespaces().Informer().AddEventHandler(eventHandler)
c.factoryGatewayClass = externalversions.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, externalversions.WithTweakListOptions(labelSelectorOptions))
c.factoryGatewayClass.Networking().V1alpha1().GatewayClasses().Informer().AddEventHandler(eventHandler)
@ -193,6 +198,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
c.factoriesSecret[ns] = factorySecret
}
c.factoryNamespace.Start(stopCh)
c.factoryGatewayClass.Start(stopCh)
for _, ns := range namespaces {
@ -201,6 +207,12 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
c.factoriesSecret[ns].Start(stopCh)
}
for t, ok := range c.factoryNamespace.WaitForCacheSync(stopCh) {
if !ok {
return nil, fmt.Errorf("timed out waiting for controller caches to sync %s", t.String())
}
}
for t, ok := range c.factoryGatewayClass.WaitForCacheSync(stopCh) {
if !ok {
return nil, fmt.Errorf("timed out waiting for controller caches to sync %s", t.String())
@ -230,53 +242,90 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
return eventCh, nil
}
func (c *clientWrapper) GetHTTPRoutes(namespace string, selector labels.Selector) ([]*v1alpha1.HTTPRoute, error) {
if !c.isWatchedNamespace(namespace) {
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)
func (c *clientWrapper) GetNamespaces(selector labels.Selector) ([]string, error) {
ns, err := c.factoryNamespace.Core().V1().Namespaces().Lister().List(selector)
if err != nil {
return nil, err
}
if len(httpRoutes) == 0 {
log.WithoutContext().Debugf("No HTTPRoutes found in %q namespace with labels selector %s", namespace, selector)
var namespaces []string
for _, namespace := range ns {
if !c.isWatchedNamespace(namespace.Name) {
log.WithoutContext().Warnf("Namespace %q is not within watched namespaces", selector, namespace)
continue
}
namespaces = append(namespaces, namespace.Name)
}
return namespaces, nil
}
func (c *clientWrapper) GetHTTPRoutes(namespaces []string, selector labels.Selector) ([]*v1alpha1.HTTPRoute, error) {
var httpRoutes []*v1alpha1.HTTPRoute
for _, namespace := range namespaces {
if !c.isWatchedNamespace(namespace) {
log.WithoutContext().Warnf("Failed to get HTTPRoutes with labels selector %s: %q is not within watched namespaces", selector, namespace)
continue
}
routes, err := c.factoriesGateway[c.lookupNamespace(namespace)].Networking().V1alpha1().HTTPRoutes().Lister().HTTPRoutes(namespace).List(selector)
if err != nil {
return nil, err
}
if len(routes) == 0 {
log.WithoutContext().Debugf("No HTTPRoutes found in %q namespace with labels selector %s", namespace, selector)
continue
}
httpRoutes = append(httpRoutes, routes...)
}
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)
}
func (c *clientWrapper) GetTCPRoutes(namespaces []string, selector labels.Selector) ([]*v1alpha1.TCPRoute, error) {
var tcpRoutes []*v1alpha1.TCPRoute
for _, namespace := range namespaces {
if !c.isWatchedNamespace(namespace) {
log.WithoutContext().Warnf("Failed to get TCPRoutes with labels selector %s: %q is not within watched namespaces", selector, namespace)
continue
}
tcpRoutes, err := c.factoriesGateway[c.lookupNamespace(namespace)].Networking().V1alpha1().TCPRoutes().Lister().TCPRoutes(namespace).List(selector)
if err != nil {
return nil, err
}
routes, 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)
}
if len(routes) == 0 {
log.WithoutContext().Debugf("No TCPRoutes found in %q namespace with labels selector %s", namespace, selector)
continue
}
tcpRoutes = append(tcpRoutes, routes...)
}
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)
}
func (c *clientWrapper) GetTLSRoutes(namespaces []string, selector labels.Selector) ([]*v1alpha1.TLSRoute, error) {
var tlsRoutes []*v1alpha1.TLSRoute
for _, namespace := range namespaces {
if !c.isWatchedNamespace(namespace) {
log.WithoutContext().Warnf("Failed to get TLSRoutes with labels selector %s: %q is not within watched namespaces", selector, namespace)
continue
}
tlsRoutes, err := c.factoriesGateway[c.lookupNamespace(namespace)].Networking().V1alpha1().TLSRoutes().Lister().TLSRoutes(namespace).List(selector)
if err != nil {
return nil, err
}
routes, 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)
}
if len(routes) == 0 {
log.WithoutContext().Debugf("No TLSRoutes found in %q namespace with labels selector %s", namespace, selector)
continue
}
tlsRoutes = append(tlsRoutes, routes...)
}
return tlsRoutes, nil
}

View file

@ -24,9 +24,10 @@ func init() {
}
type clientMock struct {
services []*corev1.Service
secrets []*corev1.Secret
endpoints []*corev1.Endpoints
services []*corev1.Service
secrets []*corev1.Secret
endpoints []*corev1.Endpoints
namespaces []*corev1.Namespace
apiServiceError error
apiSecretError error
@ -57,6 +58,8 @@ func newClientMock(paths ...string) clientMock {
c.services = append(c.services, o)
case *corev1.Secret:
c.secrets = append(c.secrets, o)
case *corev1.Namespace:
c.namespaces = append(c.namespaces, o)
case *corev1.Endpoints:
c.endpoints = append(c.endpoints, o)
case *v1alpha1.GatewayClass:
@ -131,34 +134,51 @@ func (c clientMock) GetGateways() []*v1alpha1.Gateway {
return c.gateways
}
func (c clientMock) GetHTTPRoutes(namespace string, selector labels.Selector) ([]*v1alpha1.HTTPRoute, error) {
var httpRoutes []*v1alpha1.HTTPRoute
func inNamespace(m metav1.ObjectMeta, s string) bool {
return s == metav1.NamespaceAll || m.Namespace == s
}
for _, httpRoute := range c.httpRoutes {
if httpRoute.Namespace == namespace && selector.Matches(labels.Set(httpRoute.Labels)) {
httpRoutes = append(httpRoutes, httpRoute)
func (c clientMock) GetNamespaces(selector labels.Selector) ([]string, error) {
var ns []string
for _, namespace := range c.namespaces {
if selector.Matches(labels.Set(namespace.Labels)) {
ns = append(ns, namespace.Name)
}
}
return ns, nil
}
func (c clientMock) GetHTTPRoutes(namespaces []string, selector labels.Selector) ([]*v1alpha1.HTTPRoute, error) {
var httpRoutes []*v1alpha1.HTTPRoute
for _, namespace := range namespaces {
for _, httpRoute := range c.httpRoutes {
if inNamespace(httpRoute.ObjectMeta, namespace) && selector.Matches(labels.Set(httpRoute.Labels)) {
httpRoutes = append(httpRoutes, httpRoute)
}
}
}
return httpRoutes, nil
}
func (c clientMock) GetTCPRoutes(namespace string, selector labels.Selector) ([]*v1alpha1.TCPRoute, error) {
func (c clientMock) GetTCPRoutes(namespaces []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)
for _, namespace := range namespaces {
for _, tcpRoute := range c.tcpRoutes {
if inNamespace(tcpRoute.ObjectMeta, 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) {
func (c clientMock) GetTLSRoutes(namespaces []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)
for _, namespace := range namespaces {
for _, tlsRoute := range c.tlsRoutes {
if inNamespace(tlsRoute.ObjectMeta, namespace) && selector.Matches(labels.Set(tlsRoute.Labels)) {
tlsRoutes = append(tlsRoutes, tlsRoute)
}
}
}
return tlsRoutes, nil
@ -170,7 +190,7 @@ func (c clientMock) GetService(namespace, name string) (*corev1.Service, bool, e
}
for _, service := range c.services {
if service.Namespace == namespace && service.Name == name {
if inNamespace(service.ObjectMeta, namespace) && service.Name == name {
return service, true, nil
}
}
@ -183,7 +203,7 @@ func (c clientMock) GetEndpoints(namespace, name string) (*corev1.Endpoints, boo
}
for _, endpoints := range c.endpoints {
if endpoints.Namespace == namespace && endpoints.Name == name {
if inNamespace(endpoints.ObjectMeta, namespace) && endpoints.Name == name {
return endpoints, true, nil
}
}
@ -197,7 +217,7 @@ func (c clientMock) GetSecret(namespace, name string) (*corev1.Secret, bool, err
}
for _, secret := range c.secrets {
if secret.Namespace == namespace && secret.Name == name {
if inNamespace(secret.ObjectMeta, namespace) && secret.Name == name {
return secret, true, nil
}
}

View file

@ -0,0 +1,68 @@
---
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: All
selector:
matchLabels:
app: foo
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-default
namespace: default
labels:
app: foo
spec:
hostnames:
- "foo.com"
rules:
- matches:
- path:
type: Exact
value: /foo
forwardTo:
- serviceName: whoami
port: 80
weight: 1
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-bar
namespace: bar
labels:
app: foo
spec:
hostnames:
- "bar.com"
rules:
- matches:
- path:
type: Exact
value: /bar
forwardTo:
- serviceName: whoami-bar
port: 80
weight: 1

View file

@ -0,0 +1,68 @@
---
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-default
namespace: default
labels:
app: foo
spec:
hostnames:
- "foo.com"
rules:
- matches:
- path:
type: Exact
value: /foo
forwardTo:
- serviceName: whoami
port: 80
weight: 1
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-bar
namespace: bar
labels:
app: foo
spec:
hostnames:
- "bar.com"
rules:
- matches:
- path:
type: Exact
value: /bar
forwardTo:
- serviceName: whoami-bar
port: 80
weight: 1

View file

@ -0,0 +1,79 @@
---
kind: Namespace
apiVersion: v1
metadata:
name: bar
labels:
foo: bar
---
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: Selector
selector:
matchLabels:
foo: bar
selector:
matchLabels:
app: foo
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-default
namespace: default
labels:
app: foo
spec:
hostnames:
- "foo.com"
rules:
- matches:
- path:
type: Exact
value: /foo
forwardTo:
- serviceName: whoami
port: 80
weight: 1
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-bar
namespace: bar
labels:
app: foo
spec:
hostnames:
- "bar.com"
rules:
- matches:
- path:
type: Exact
value: /bar
forwardTo:
- serviceName: whoami-bar
port: 80
weight: 1

View file

@ -100,6 +100,7 @@ spec:
- serviceName: whoami
port: 80
weight: 1
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1

View file

@ -93,6 +93,7 @@ spec:
- serviceName: whoami
port: 80
weight: 1
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1

View file

@ -0,0 +1,177 @@
---
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: All
selector:
matchLabels:
app: http-app
- protocol: HTTPS
port: 9443
tls:
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: HTTPRoute
namespaces:
from: All
selector:
matchLabels:
app: http-app
- protocol: TCP
port: 9000
routes:
kind: TCPRoute
namespaces:
from: All
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: All
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-default
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-default
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-default
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-bar
namespace: bar
labels:
app: http-app
spec:
rules:
- forwardTo:
- serviceName: whoami-bar
port: 80
weight: 1
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-bar
namespace: bar
labels:
app: tcp-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp-bar
port: 9000
weight: 1
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-bar
namespace: bar
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp-bar
port: 9000
weight: 1

View file

@ -0,0 +1,177 @@
---
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-default
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-default
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-default
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-bar
namespace: bar
labels:
app: http-app
spec:
rules:
- forwardTo:
- serviceName: whoami-bar
port: 80
weight: 1
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-bar
namespace: bar
labels:
app: tcp-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp-bar
port: 9000
weight: 1
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-bar
namespace: bar
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp-bar
port: 9000
weight: 1

View file

@ -0,0 +1,201 @@
---
kind: Namespace
apiVersion: v1
metadata:
name: bar
labels:
foo: bar
---
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: Selector
selector:
matchLabels:
foo: bar
selector:
matchLabels:
app: http-app
- protocol: HTTPS
port: 9443
tls:
certificateRef:
kind: Secret
name: supersecret
group: core
routes:
kind: HTTPRoute
namespaces:
from: Selector
selector:
matchLabels:
foo: bar
selector:
matchLabels:
app: http-app
- protocol: TCP
port: 9000
routes:
kind: TCPRoute
namespaces:
from: Selector
selector:
matchLabels:
foo: bar
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: Selector
selector:
matchLabels:
foo: bar
selector:
matchLabels:
app: tcp-app
- protocol: TLS
port: 11000
hostname: pass.tls.foo.example.com
tls:
mode: Passthrough
routes:
kind: TLSRoute
namespaces:
from: Selector
selector:
matchLabels:
foo: bar
selector:
matchLabels:
app: tls-app
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-default
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-default
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-default
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
---
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-bar
namespace: bar
labels:
app: http-app
spec:
rules:
- forwardTo:
- serviceName: whoami-bar
port: 80
weight: 1
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-bar
namespace: bar
labels:
app: tcp-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp-bar
port: 9000
weight: 1
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-bar
namespace: bar
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp-bar
port: 9000
weight: 1

View file

@ -33,6 +33,42 @@ subsets:
- name: web2
port: 8000
---
apiVersion: v1
kind: Service
metadata:
name: whoami-bar
namespace: bar
spec:
ports:
- name: web2
port: 8000
targetPort: web2
- name: web
port: 80
targetPort: web
selector:
app: containous
task: whoami
---
kind: Endpoints
apiVersion: v1
metadata:
name: whoami-bar
namespace: bar
subsets:
- addresses:
- ip: 10.10.0.11
- ip: 10.10.0.12
ports:
- name: web
port: 80
- name: web2
port: 8000
---
apiVersion: v1
kind: Service
@ -164,7 +200,6 @@ spec:
protocol: TCP
port: 443
---
kind: Endpoints
apiVersion: v1
@ -199,3 +234,38 @@ spec:
- protocol: TCP
port: 10000
name: tcp-2
---
kind: Endpoints
apiVersion: v1
metadata:
name: whoamitcp-bar
namespace: bar
subsets:
- addresses:
- ip: 10.10.0.13
- ip: 10.10.0.14
ports:
- name: tcp-1
protocol: TCP
port: 9000
- name: tcp-2
protocol: TCP
port: 10000
---
apiVersion: v1
kind: Service
metadata:
name: whoamitcp-bar
namespace: bar
spec:
ports:
- protocol: TCP
port: 9000
name: tcp-1
- protocol: TCP
port: 10000
name: tcp-2

View file

@ -0,0 +1,57 @@
---
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
namespaces:
from: All
selector:
matchLabels:
app: whoamitcp
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-default
namespace: default
labels:
app: whoamitcp
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-bar
namespace: bar
labels:
app: whoamitcp
spec:
rules:
- forwardTo:
- serviceName: whoamitcp-bar
port: 9000
weight: 1

View file

@ -0,0 +1,57 @@
---
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
namespaces:
from: Same
selector:
matchLabels:
app: whoamitcp
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-default
namespace: default
labels:
app: whoamitcp
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-bar
namespace: bar
labels:
app: whoamitcp
spec:
rules:
- forwardTo:
- serviceName: whoamitcp-bar
port: 9000
weight: 1

View file

@ -0,0 +1,68 @@
---
kind: Namespace
apiVersion: v1
metadata:
name: bar
labels:
foo: bar
---
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
namespaces:
from: Selector
selector:
matchLabels:
foo: bar
selector:
matchLabels:
app: whoamitcp
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-default
namespace: default
labels:
app: whoamitcp
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tcp-app-bar
namespace: bar
labels:
app: whoamitcp
spec:
rules:
- forwardTo:
- serviceName: whoamitcp-bar
port: 9000
weight: 1

View file

@ -50,7 +50,6 @@ spec:
matchLabels:
app: label-tls-app-1
---
kind: TCPRoute
apiVersion: networking.x-k8s.io/v1alpha1

View file

@ -0,0 +1,66 @@
---
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: All
selector:
matchLabels:
app: tls-app
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-default
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
matches:
- snis:
- foo.default
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-bar
namespace: bar
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp-bar
port: 9000
weight: 1
matches:
- snis:
- foo.bar

View file

@ -0,0 +1,65 @@
---
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-default
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
matches:
- snis:
- foo.default
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-bar
namespace: bar
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp-bar
port: 9000
weight: 1
matches:
- snis:
- foo.bar

View file

@ -0,0 +1,76 @@
---
kind: Namespace
apiVersion: v1
metadata:
name: bar
labels:
foo: bar
---
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: Selector
selector:
matchLabels:
foo: bar
selector:
matchLabels:
app: tls-app
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-default
namespace: default
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp
port: 9000
weight: 1
matches:
- snis:
- foo.default
---
kind: TLSRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: tls-app-bar
namespace: bar
labels:
app: tls-app
spec:
rules:
- forwardTo:
- serviceName: whoamitcp-bar
port: 9000
weight: 1
matches:
- snis:
- foo.bar

View file

@ -492,13 +492,23 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway *
}
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.Everything()
if listener.Routes.Selector != nil {
selector = labels.SelectorFromSet(listener.Routes.Selector.MatchLabels)
var err error
selector, err = metav1.LabelSelectorAsSelector(listener.Routes.Selector)
if err != nil {
return []metav1.Condition{{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonInvalidRoutesRef),
Message: fmt.Sprintf("Invalid routes selector: %v", err),
}}
}
}
httpRoutes, err := client.GetHTTPRoutes(gateway.Namespace, selector)
namespaces, err := getRouteBindingSelectorNamespace(client, gateway.Namespace, listener.Routes.Namespaces)
if err != nil {
// update "ResolvedRefs" status true with "InvalidRoutesRef" reason
return []metav1.Condition{{
@ -506,7 +516,19 @@ func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha
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),
Message: fmt.Sprintf("Invalid route namespaces selector: %v", err),
}}
}
httpRoutes, err := client.GetHTTPRoutes(namespaces, 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: %v", listener.Routes.Kind, err),
}}
}
@ -577,7 +599,7 @@ func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha
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)
wrrService, subServices, err := loadServices(client, httpRoute.Namespace, routeRule.ForwardTo)
if err != nil {
// update "ResolvedRefs" status true with "DroppedRoutes" reason
conditions = append(conditions, metav1.Condition{
@ -585,7 +607,7 @@ func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha
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, httpRoute.Name, err),
Message: fmt.Sprintf("Cannot load service from %s %s/%s: %v", listener.Routes.Kind, httpRoute.Namespace, httpRoute.Name, err),
})
// TODO update the RouteStatus condition / deduplicate conditions on listener
@ -611,13 +633,23 @@ func gatewayHTTPRouteToHTTPConf(ctx context.Context, ep string, listener v1alpha
}
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.Everything()
if listener.Routes.Selector != nil {
selector = labels.SelectorFromSet(listener.Routes.Selector.MatchLabels)
var err error
selector, err = metav1.LabelSelectorAsSelector(listener.Routes.Selector)
if err != nil {
return []metav1.Condition{{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonInvalidRoutesRef),
Message: fmt.Sprintf("Invalid routes selector: %v", err),
}}
}
}
tcpRoutes, err := client.GetTCPRoutes(gateway.Namespace, selector)
namespaces, err := getRouteBindingSelectorNamespace(client, gateway.Namespace, listener.Routes.Namespaces)
if err != nil {
// update "ResolvedRefs" status true with "InvalidRoutesRef" reason
return []metav1.Condition{{
@ -625,7 +657,19 @@ func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener v1alpha1.
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),
Message: fmt.Sprintf("Invalid route namespaces selector: %v", err),
}}
}
tcpRoutes, err := client.GetTCPRoutes(namespaces, 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: %v", listener.Routes.Kind, err),
}}
}
@ -681,7 +725,7 @@ func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener v1alpha1.
continue
}
wrrService, subServices, err := loadTCPServices(client, gateway.Namespace, routeRule.ForwardTo)
wrrService, subServices, err := loadTCPServices(client, tcpRoute.Namespace, routeRule.ForwardTo)
if err != nil {
// update "ResolvedRefs" status true with "DroppedRoutes" reason
conditions = append(conditions, metav1.Condition{
@ -689,7 +733,7 @@ func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener v1alpha1.
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),
Message: fmt.Sprintf("Cannot load service from %s %s/%s: %v", listener.Routes.Kind, tcpRoute.Namespace, tcpRoute.Name, err),
})
// TODO update the RouteStatus condition / deduplicate conditions on listener
@ -714,13 +758,23 @@ func gatewayTCPRouteToTCPConf(ctx context.Context, ep string, listener v1alpha1.
}
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.Everything()
if listener.Routes.Selector != nil {
selector = labels.SelectorFromSet(listener.Routes.Selector.MatchLabels)
var err error
selector, err = metav1.LabelSelectorAsSelector(listener.Routes.Selector)
if err != nil {
return []metav1.Condition{{
Type: string(v1alpha1.ListenerConditionResolvedRefs),
Status: metav1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: string(v1alpha1.ListenerReasonInvalidRoutesRef),
Message: fmt.Sprintf("Invalid routes selector: %v", err),
}}
}
}
tlsRoutes, err := client.GetTLSRoutes(gateway.Namespace, selector)
namespaces, err := getRouteBindingSelectorNamespace(client, gateway.Namespace, listener.Routes.Namespaces)
if err != nil {
// update "ResolvedRefs" status true with "InvalidRoutesRef" reason
return []metav1.Condition{{
@ -728,7 +782,19 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha1.
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),
Message: fmt.Sprintf("Invalid route namespaces selector: %v", err),
}}
}
tlsRoutes, err := client.GetTLSRoutes(namespaces, 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: %v", listener.Routes.Kind, err),
}}
}
@ -786,7 +852,7 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha1.
continue
}
wrrService, subServices, err := loadTCPServices(client, gateway.Namespace, routeRule.ForwardTo)
wrrService, subServices, err := loadTCPServices(client, tlsRoute.Namespace, routeRule.ForwardTo)
if err != nil {
// update "ResolvedRefs" status true with "DroppedRoutes" reason
conditions = append(conditions, metav1.Condition{
@ -794,7 +860,7 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha1.
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),
Message: fmt.Sprintf("Cannot load service from %s %s/%s: %v", listener.Routes.Kind, tlsRoute.Namespace, tlsRoute.Name, err),
})
// TODO update the RouteStatus condition / deduplicate conditions on listener
@ -818,6 +884,30 @@ func gatewayTLSRouteToTCPConf(ctx context.Context, ep string, listener v1alpha1.
return conditions
}
func getRouteBindingSelectorNamespace(client Client, gatewayNamespace string, routeNamespaces *v1alpha1.RouteNamespaces) ([]string, error) {
if routeNamespaces == nil || routeNamespaces.From == nil {
return []string{gatewayNamespace}, nil
}
switch *routeNamespaces.From {
case v1alpha1.RouteSelectAll:
return []string{metav1.NamespaceAll}, nil
case v1alpha1.RouteSelectSame:
return []string{gatewayNamespace}, nil
case v1alpha1.RouteSelectSelector:
selector, err := metav1.LabelSelectorAsSelector(routeNamespaces.Selector)
if err != nil {
return nil, fmt.Errorf("malformed selector: %w", err)
}
return client.GetNamespaces(selector)
}
return nil, fmt.Errorf("unsupported RouteSelectType: %q", *routeNamespaces.From)
}
func (p *Provider) makeGatewayStatus(listenerStatuses []v1alpha1.ListenerStatus) (v1alpha1.GatewayStatus, error) {
// As Status.Addresses are not implemented yet, we initialize an empty array to follow the API expectations.
gatewayStatus := v1alpha1.GatewayStatus{

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|MiddlewareTCP|Secret|TLSOption|TLSStore|TraefikService|IngressClass|ServersTransport|GatewayClass|Gateway|HTTPRoute|TCPRoute|TLSRoute)$`)
acceptedK8sTypes := regexp.MustCompile(`^(Namespace|Deployment|Endpoints|Service|Ingress|IngressRoute|IngressRouteTCP|IngressRouteUDP|Middleware|MiddlewareTCP|Secret|TLSOption|TLSStore|TraefikService|IngressClass|ServersTransport|GatewayClass|Gateway|HTTPRoute|TCPRoute|TLSRoute)$`)
files := strings.Split(string(content), "---")
retVal := make([]runtime.Object, 0, len(files))