Improve kubernetes external name service support
Co-authored-by: jbdoumenjou <jb.doumenjou@gmail.com>
This commit is contained in:
parent
e511cfe2e4
commit
3b85dc9618
17 changed files with 876 additions and 48 deletions
|
@ -355,25 +355,25 @@ Register the `IngressRoute` [kind](../../reference/dynamic-configuration/kuberne
|
||||||
- b.foo.com
|
- b.foo.com
|
||||||
```
|
```
|
||||||
|
|
||||||
| Ref | Attribute | Purpose |
|
| Ref | Attribute | Purpose |
|
||||||
|------|----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|------|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| [1] | `entryPoints` | List of [entry points](../routers/index.md#entrypoints) names |
|
| [1] | `entryPoints` | List of [entry points](../routers/index.md#entrypoints) names |
|
||||||
| [2] | `routes` | List of routes |
|
| [2] | `routes` | List of routes |
|
||||||
| [3] | `routes[n].match` | Defines the [rule](../routers/index.md#rule) corresponding to an underlying router. |
|
| [3] | `routes[n].match` | Defines the [rule](../routers/index.md#rule) corresponding to an underlying router. |
|
||||||
| [4] | `routes[n].priority` | [Disambiguate](../routers/index.md#priority) rules of the same length, for route matching |
|
| [4] | `routes[n].priority` | [Disambiguate](../routers/index.md#priority) rules of the same length, for route matching |
|
||||||
| [5] | `routes[n].middlewares` | List of reference to [Middleware](#kind-middleware) |
|
| [5] | `routes[n].middlewares` | List of reference to [Middleware](#kind-middleware) |
|
||||||
| [6] | `middlewares[n].name` | Defines the [Middleware](#kind-middleware) name |
|
| [6] | `middlewares[n].name` | Defines the [Middleware](#kind-middleware) name |
|
||||||
| [7] | `middlewares[n].namespace` | Defines the [Middleware](#kind-middleware) namespace |
|
| [7] | `middlewares[n].namespace` | Defines the [Middleware](#kind-middleware) namespace |
|
||||||
| [8] | `routes[n].services` | List of any combination of [TraefikService](#kind-traefikservice) and reference to a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) |
|
| [8] | `routes[n].services` | List of any combination of [TraefikService](#kind-traefikservice) and reference to a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) (See below for `ExternalName Service` setup) |
|
||||||
| [9] | `tls` | Defines [TLS](../routers/index.md#tls) certificate configuration |
|
| [9] | `tls` | Defines [TLS](../routers/index.md#tls) certificate configuration |
|
||||||
| [10] | `tls.secretName` | Defines the [secret](https://kubernetes.io/docs/concepts/configuration/secret/) name used to store the certificate (in the `IngressRoute` namespace) |
|
| [10] | `tls.secretName` | Defines the [secret](https://kubernetes.io/docs/concepts/configuration/secret/) name used to store the certificate (in the `IngressRoute` namespace) |
|
||||||
| [11] | `tls.options` | Defines the reference to a [TLSOption](#kind-tlsoption) |
|
| [11] | `tls.options` | Defines the reference to a [TLSOption](#kind-tlsoption) |
|
||||||
| [12] | `options.name` | Defines the [TLSOption](#kind-tlsoption) name |
|
| [12] | `options.name` | Defines the [TLSOption](#kind-tlsoption) name |
|
||||||
| [13] | `options.namespace` | Defines the [TLSOption](#kind-tlsoption) namespace |
|
| [13] | `options.namespace` | Defines the [TLSOption](#kind-tlsoption) namespace |
|
||||||
| [14] | `tls.certResolver` | Defines the reference to a [CertResolver](../routers/index.md#certresolver) |
|
| [14] | `tls.certResolver` | Defines the reference to a [CertResolver](../routers/index.md#certresolver) |
|
||||||
| [15] | `tls.domains` | List of [domains](../routers/index.md#domains) |
|
| [15] | `tls.domains` | List of [domains](../routers/index.md#domains) |
|
||||||
| [16] | `domains[n].main` | Defines the main domain name |
|
| [16] | `domains[n].main` | Defines the main domain name |
|
||||||
| [17] | `domains[n].sans` | List of SANs (alternative domains) |
|
| [17] | `domains[n].sans` | List of SANs (alternative domains) |
|
||||||
|
|
||||||
??? example "Declaring an IngressRoute"
|
??? example "Declaring an IngressRoute"
|
||||||
|
|
||||||
|
@ -468,6 +468,112 @@ Register the `IngressRoute` [kind](../../reference/dynamic-configuration/kuberne
|
||||||
|
|
||||||
If you do not configure the above, Traefik will assume an http connection.
|
If you do not configure the above, Traefik will assume an http connection.
|
||||||
|
|
||||||
|
|
||||||
|
!!! important "Using Kubernetes ExternalName Service"
|
||||||
|
|
||||||
|
Traefik backends creation needs a port to be set, however Kubernetes [ExternalName Service](https://kubernetes.io/fr/docs/concepts/services-networking/service/#externalname) could be defined without any port.
|
||||||
|
Accordingly, Traefik supports defining a port in two ways:
|
||||||
|
|
||||||
|
- only on `IngressRoute` service
|
||||||
|
- on both sides, you'll be warned if the ports don't match, and the `IngressRoute` service port is used
|
||||||
|
|
||||||
|
Thus, in case of two sides port definition, Traefik expects a match between ports.
|
||||||
|
|
||||||
|
??? example "Examples"
|
||||||
|
|
||||||
|
```yaml tab="IngressRoute"
|
||||||
|
---
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- foo
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: Host(`foo.com`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: external-svc
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: external-svc
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
externalName: external.domain
|
||||||
|
type: ExternalName
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="ExternalName Service"
|
||||||
|
---
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- foo
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: Host(`foo.com`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: external-svc
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: external-svc
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
externalName: external.domain
|
||||||
|
type: ExternalName
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Both sides"
|
||||||
|
---
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- foo
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: Host(`foo.com`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: external-svc
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: external-svc
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
externalName: external.domain
|
||||||
|
type: ExternalName
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
```
|
||||||
|
|
||||||
### Kind: `Middleware`
|
### Kind: `Middleware`
|
||||||
|
|
||||||
`Middleware` is the CRD implementation of a [Traefik middleware](../../middlewares/overview.md).
|
`Middleware` is the CRD implementation of a [Traefik middleware](../../middlewares/overview.md).
|
||||||
|
@ -853,7 +959,7 @@ Register the `IngressRouteTCP` [kind](../../reference/dynamic-configuration/kube
|
||||||
| [1] | `entryPoints` | List of [entrypoints](../routers/index.md#entrypoints_1) names |
|
| [1] | `entryPoints` | List of [entrypoints](../routers/index.md#entrypoints_1) names |
|
||||||
| [2] | `routes` | List of routes |
|
| [2] | `routes` | List of routes |
|
||||||
| [3] | `routes[n].match` | Defines the [rule](../routers/index.md#rule_1) corresponding to an underlying router |
|
| [3] | `routes[n].match` | Defines the [rule](../routers/index.md#rule_1) corresponding to an underlying router |
|
||||||
| [4] | `routes[n].services` | List of [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) definitions |
|
| [4] | `routes[n].services` | List of [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) definitions (See below for `ExternalName Service` setup) |
|
||||||
| [5] | `services[n].name` | Defines the name of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) |
|
| [5] | `services[n].name` | Defines the name of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) |
|
||||||
| [6] | `services[n].port` | Defines the port of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) |
|
| [6] | `services[n].port` | Defines the port of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) |
|
||||||
| [7] | `services[n].weight` | Defines the weight to apply to the server load balancing |
|
| [7] | `services[n].weight` | Defines the weight to apply to the server load balancing |
|
||||||
|
@ -928,6 +1034,111 @@ Register the `IngressRouteTCP` [kind](../../reference/dynamic-configuration/kube
|
||||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
|
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
|
||||||
```
|
```
|
||||||
|
|
||||||
|
!!! important "Using Kubernetes ExternalName Service"
|
||||||
|
|
||||||
|
Traefik backends creation needs a port to be set, however Kubernetes [ExternalName Service](https://kubernetes.io/fr/docs/concepts/services-networking/service/#externalname) could be defined without any port.
|
||||||
|
Accordingly, Traefik supports defining a port in two ways:
|
||||||
|
|
||||||
|
- only on `IngressRouteTCP` service
|
||||||
|
- on both sides, you'll be warned if the ports don't match, and the `IngressRouteTCP` service port is used
|
||||||
|
|
||||||
|
Thus, in case of two sides port definition, Traefik expects a match between ports.
|
||||||
|
|
||||||
|
??? example "Examples"
|
||||||
|
|
||||||
|
```yaml tab="IngressRouteTCP"
|
||||||
|
---
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRouteTCP
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- foo
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: HostSNI(`*`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: external-svc
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: external-svc
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
externalName: external.domain
|
||||||
|
type: ExternalName
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="ExternalName Service"
|
||||||
|
---
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRouteTCP
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- foo
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: HostSNI(`*`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: external-svc
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: external-svc
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
externalName: external.domain
|
||||||
|
type: ExternalName
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Both sides"
|
||||||
|
---
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRouteTCP
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- foo
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: HostSNI(`*`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: external-svc
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: external-svc
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
externalName: external.domain
|
||||||
|
type: ExternalName
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
```
|
||||||
|
|
||||||
### Kind `IngressRouteUDP`
|
### Kind `IngressRouteUDP`
|
||||||
|
|
||||||
`IngressRouteUDP` is the CRD implementation of a [Traefik UDP router](../routers/index.md#configuring-udp-routers).
|
`IngressRouteUDP` is the CRD implementation of a [Traefik UDP router](../routers/index.md#configuring-udp-routers).
|
||||||
|
|
|
@ -126,3 +126,13 @@ spec:
|
||||||
selector:
|
selector:
|
||||||
app: containous
|
app: containous
|
||||||
task: whoamiudp
|
task: whoamiudp
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: externalname-svc
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
externalName: domain.com
|
||||||
|
type: ExternalName
|
|
@ -13,6 +13,8 @@ spec:
|
||||||
- name: whoamitcp
|
- name: whoamitcp
|
||||||
namespace: default
|
namespace: default
|
||||||
port: 8080
|
port: 8080
|
||||||
|
- name: externalname-svc
|
||||||
|
port: 9090
|
||||||
tls:
|
tls:
|
||||||
options:
|
options:
|
||||||
name: mytlsoption
|
name: mytlsoption
|
||||||
|
|
30
integration/testdata/rawdata-crd.json
vendored
30
integration/testdata/rawdata-crd.json
vendored
|
@ -194,18 +194,44 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tcpServices": {
|
"tcpServices": {
|
||||||
"default-test3.route-673acf455cb2dab0b43a@kubernetescrd": {
|
"default-test3.route-673acf455cb2dab0b43a-externalname-svc-9090@kubernetescrd": {
|
||||||
"loadBalancer": {
|
"loadBalancer": {
|
||||||
"terminationDelay": 100,
|
"terminationDelay": 100,
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"address": "10.42.0.4:8080"
|
"address": "domain.com:9090"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"status": "enabled"
|
||||||
|
},
|
||||||
|
"default-test3.route-673acf455cb2dab0b43a-whoamitcp-8080@kubernetescrd": {
|
||||||
|
"loadBalancer": {
|
||||||
|
"terminationDelay": 100,
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"address": "10.42.0.3:8080"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "10.42.0.8:8080"
|
"address": "10.42.0.8:8080"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"status": "enabled"
|
||||||
|
},
|
||||||
|
"default-test3.route-673acf455cb2dab0b43a@kubernetescrd": {
|
||||||
|
"weighted": {
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"name": "default-test3.route-673acf455cb2dab0b43a-whoamitcp-8080",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "default-test3.route-673acf455cb2dab0b43a-externalname-svc-9090",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"default-test3.route-673acf455cb2dab0b43a@kubernetescrd"
|
"default-test3.route-673acf455cb2dab0b43a@kubernetescrd"
|
||||||
|
|
|
@ -118,3 +118,44 @@ subsets:
|
||||||
ports:
|
ports:
|
||||||
- name: websecure2
|
- name: websecure2
|
||||||
port: 8443
|
port: 8443
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: external-svc
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
externalName: external.domain
|
||||||
|
type: ExternalName
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: external-svc-with-http
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
externalName: external.domain
|
||||||
|
type: ExternalName
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
protocol: TCP
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: external-svc-with-https
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
externalName: external.domain
|
||||||
|
type: ExternalName
|
||||||
|
ports:
|
||||||
|
- name: https
|
||||||
|
protocol: TCP
|
||||||
|
port: 443
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -131,3 +131,40 @@ subsets:
|
||||||
ports:
|
ports:
|
||||||
- name: myapp4
|
- name: myapp4
|
||||||
port: 8084
|
port: 8084
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: external-svc
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
externalName: external.domain
|
||||||
|
type: ExternalName
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: external.service.with.port
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
externalName: external.domain
|
||||||
|
type: ExternalName
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
protocol: TCP
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: external.service.without.port
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
externalName: external.domain
|
||||||
|
type: ExternalName
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
protocol: TCP
|
|
@ -0,0 +1,15 @@
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRouteTCP
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- foo
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: HostSNI(`foo.com`)
|
||||||
|
services:
|
||||||
|
- name: external-svc
|
||||||
|
port: 8000
|
|
@ -0,0 +1,15 @@
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRouteTCP
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- foo
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: HostSNI(`foo.com`)
|
||||||
|
services:
|
||||||
|
- name: external.service.with.port
|
||||||
|
port: 80
|
|
@ -0,0 +1,14 @@
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRouteTCP
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- foo
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: HostSNI(`foo.com`)
|
||||||
|
services:
|
||||||
|
- name: external-svc
|
16
pkg/provider/kubernetes/crd/fixtures/with_externalname.yml
Normal file
16
pkg/provider/kubernetes/crd/fixtures/with_externalname.yml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- foo
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: Host(`foo.com`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: external-svc
|
||||||
|
port: 80
|
|
@ -0,0 +1,16 @@
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- foo
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: Host(`foo.com`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: external-svc-with-http
|
||||||
|
port: 80
|
|
@ -0,0 +1,16 @@
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- foo
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: Host(`foo.com`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: external-svc-with-https
|
||||||
|
port: 443
|
|
@ -0,0 +1,15 @@
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- foo
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: Host(`foo.com`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: external-svc
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -248,6 +249,38 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
|
||||||
return conf
|
return conf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getServicePort(svc *corev1.Service, port int32) (*corev1.ServicePort, error) {
|
||||||
|
if svc == nil {
|
||||||
|
return nil, errors.New("service is not defined")
|
||||||
|
}
|
||||||
|
|
||||||
|
if port == 0 {
|
||||||
|
return nil, errors.New("ingressRoute service port not defined")
|
||||||
|
}
|
||||||
|
|
||||||
|
hasValidPort := false
|
||||||
|
for _, p := range svc.Spec.Ports {
|
||||||
|
if p.Port == port {
|
||||||
|
return &p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Port != 0 {
|
||||||
|
hasValidPort = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if svc.Spec.Type != corev1.ServiceTypeExternalName {
|
||||||
|
return nil, fmt.Errorf("service port not found: %d", port)
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasValidPort {
|
||||||
|
log.WithoutContext().
|
||||||
|
Warning("The port %d from IngressRoute doesn't match with ports defined in the ExternalName service %s/%s.", port, svc.Namespace, svc.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &corev1.ServicePort{Port: port}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func createErrorPageMiddleware(client Client, namespace string, errorPage *v1alpha1.ErrorPage) (*dynamic.ErrorPage, *dynamic.Service, error) {
|
func createErrorPageMiddleware(client Client, namespace string, errorPage *v1alpha1.ErrorPage) (*dynamic.ErrorPage, *dynamic.Service, error) {
|
||||||
if errorPage == nil {
|
if errorPage == nil {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
|
|
|
@ -294,27 +294,20 @@ func (c configBuilder) loadServers(fallbackNamespace string, svc v1alpha1.LoadBa
|
||||||
return nil, fmt.Errorf("kubernetes service not found: %s/%s", namespace, sanitizedName)
|
return nil, fmt.Errorf("kubernetes service not found: %s/%s", namespace, sanitizedName)
|
||||||
}
|
}
|
||||||
|
|
||||||
confPort := svc.Port
|
svcPort, err := getServicePort(service, svc.Port)
|
||||||
var portSpec *corev1.ServicePort
|
if err != nil {
|
||||||
for _, p := range service.Spec.Ports {
|
return nil, err
|
||||||
if confPort == p.Port {
|
|
||||||
portSpec = &p
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if portSpec == nil {
|
|
||||||
return nil, errors.New("service port not found")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var servers []dynamic.Server
|
var servers []dynamic.Server
|
||||||
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
||||||
protocol, err := parseServiceProtocol(svc.Scheme, portSpec.Name, portSpec.Port)
|
protocol, err := parseServiceProtocol(svc.Scheme, svcPort.Name, svcPort.Port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return append(servers, dynamic.Server{
|
return append(servers, dynamic.Server{
|
||||||
URL: fmt.Sprintf("%s://%s:%d", protocol, service.Spec.ExternalName, portSpec.Port),
|
URL: fmt.Sprintf("%s://%s:%d", protocol, service.Spec.ExternalName, svcPort.Port),
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,7 +325,7 @@ func (c configBuilder) loadServers(fallbackNamespace string, svc v1alpha1.LoadBa
|
||||||
var port int32
|
var port int32
|
||||||
for _, subset := range endpoints.Subsets {
|
for _, subset := range endpoints.Subsets {
|
||||||
for _, p := range subset.Ports {
|
for _, p := range subset.Ports {
|
||||||
if portSpec.Name == p.Name {
|
if svcPort.Name == p.Name {
|
||||||
port = p.Port
|
port = p.Port
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -342,7 +335,7 @@ func (c configBuilder) loadServers(fallbackNamespace string, svc v1alpha1.LoadBa
|
||||||
return nil, fmt.Errorf("cannot define a port for %s/%s", namespace, sanitizedName)
|
return nil, fmt.Errorf("cannot define a port for %s/%s", namespace, sanitizedName)
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol, err := parseServiceProtocol(svc.Scheme, portSpec.Name, portSpec.Port)
|
protocol, err := parseServiceProtocol(svc.Scheme, svcPort.Name, svcPort.Port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,22 +162,15 @@ func loadTCPServers(client Client, namespace string, svc v1alpha1.ServiceTCP) ([
|
||||||
return nil, errors.New("service not found")
|
return nil, errors.New("service not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
var portSpec *corev1.ServicePort
|
svcPort, err := getServicePort(service, svc.Port)
|
||||||
for _, p := range service.Spec.Ports {
|
if err != nil {
|
||||||
if svc.Port == p.Port {
|
return nil, err
|
||||||
portSpec = &p
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if portSpec == nil {
|
|
||||||
return nil, errors.New("service port not found")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var servers []dynamic.TCPServer
|
var servers []dynamic.TCPServer
|
||||||
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
||||||
servers = append(servers, dynamic.TCPServer{
|
servers = append(servers, dynamic.TCPServer{
|
||||||
Address: fmt.Sprintf("%s:%d", service.Spec.ExternalName, portSpec.Port),
|
Address: fmt.Sprintf("%s:%d", service.Spec.ExternalName, svcPort.Port),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
||||||
|
@ -196,7 +189,7 @@ func loadTCPServers(client Client, namespace string, svc v1alpha1.ServiceTCP) ([
|
||||||
var port int32
|
var port int32
|
||||||
for _, subset := range endpoints.Subsets {
|
for _, subset := range endpoints.Subsets {
|
||||||
for _, p := range subset.Ports {
|
for _, p := range subset.Ports {
|
||||||
if portSpec.Name == p.Name {
|
if svcPort.Name == p.Name {
|
||||||
port = p.Port
|
port = p.Port
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||||
"github.com/containous/traefik/v2/pkg/provider"
|
"github.com/containous/traefik/v2/pkg/provider"
|
||||||
"github.com/containous/traefik/v2/pkg/tls"
|
"github.com/containous/traefik/v2/pkg/tls"
|
||||||
|
@ -906,6 +908,106 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "Simple Ingress Route, with externalName service",
|
||||||
|
paths: []string{"tcp/services.yml", "tcp/with_externalname.yml"},
|
||||||
|
expected: &dynamic.Configuration{
|
||||||
|
UDP: &dynamic.UDPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.UDPRouter{},
|
||||||
|
Services: map[string]*dynamic.UDPService{},
|
||||||
|
},
|
||||||
|
TCP: &dynamic.TCPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.TCPRouter{
|
||||||
|
"default-test.route-fdd3e9338e47a45efefc": {
|
||||||
|
EntryPoints: []string{"foo"},
|
||||||
|
Service: "default-test.route-fdd3e9338e47a45efefc",
|
||||||
|
Rule: "HostSNI(`foo.com`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Services: map[string]*dynamic.TCPService{
|
||||||
|
"default-test.route-fdd3e9338e47a45efefc": {
|
||||||
|
LoadBalancer: &dynamic.TCPServersLoadBalancer{
|
||||||
|
Servers: []dynamic.TCPServer{
|
||||||
|
{
|
||||||
|
Address: "external.domain:8000",
|
||||||
|
Port: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{},
|
||||||
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
Services: map[string]*dynamic.Service{},
|
||||||
|
},
|
||||||
|
TLS: &dynamic.TLSConfiguration{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Ingress Route, externalName service with port",
|
||||||
|
paths: []string{"tcp/services.yml", "tcp/with_externalname_with_port.yml"},
|
||||||
|
expected: &dynamic.Configuration{
|
||||||
|
UDP: &dynamic.UDPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.UDPRouter{},
|
||||||
|
Services: map[string]*dynamic.UDPService{},
|
||||||
|
},
|
||||||
|
TCP: &dynamic.TCPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.TCPRouter{
|
||||||
|
"default-test.route-fdd3e9338e47a45efefc": {
|
||||||
|
EntryPoints: []string{"foo"},
|
||||||
|
Service: "default-test.route-fdd3e9338e47a45efefc",
|
||||||
|
Rule: "HostSNI(`foo.com`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Services: map[string]*dynamic.TCPService{
|
||||||
|
"default-test.route-fdd3e9338e47a45efefc": {
|
||||||
|
LoadBalancer: &dynamic.TCPServersLoadBalancer{
|
||||||
|
Servers: []dynamic.TCPServer{
|
||||||
|
{
|
||||||
|
Address: "external.domain:80",
|
||||||
|
Port: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{},
|
||||||
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
Services: map[string]*dynamic.Service{},
|
||||||
|
},
|
||||||
|
TLS: &dynamic.TLSConfiguration{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Ingress Route, externalName service without port",
|
||||||
|
paths: []string{"tcp/services.yml", "tcp/with_externalname_without_ports.yml"},
|
||||||
|
expected: &dynamic.Configuration{
|
||||||
|
UDP: &dynamic.UDPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.UDPRouter{},
|
||||||
|
Services: map[string]*dynamic.UDPService{},
|
||||||
|
},
|
||||||
|
TCP: &dynamic.TCPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.TCPRouter{
|
||||||
|
"default-test.route-fdd3e9338e47a45efefc": {
|
||||||
|
EntryPoints: []string{"foo"},
|
||||||
|
Service: "default-test.route-fdd3e9338e47a45efefc",
|
||||||
|
Rule: "HostSNI(`foo.com`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Services: map[string]*dynamic.TCPService{},
|
||||||
|
},
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{},
|
||||||
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
Services: map[string]*dynamic.Service{},
|
||||||
|
},
|
||||||
|
TLS: &dynamic.TLSConfiguration{},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
|
@ -2860,6 +2962,134 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
{
|
{
|
||||||
desc: "port selected by name (TODO)",
|
desc: "port selected by name (TODO)",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "Simple Ingress Route, with externalName service",
|
||||||
|
paths: []string{"services.yml", "with_externalname.yml"},
|
||||||
|
expected: &dynamic.Configuration{
|
||||||
|
UDP: &dynamic.UDPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.UDPRouter{},
|
||||||
|
Services: map[string]*dynamic.UDPService{},
|
||||||
|
},
|
||||||
|
TCP: &dynamic.TCPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.TCPRouter{},
|
||||||
|
Services: map[string]*dynamic.TCPService{},
|
||||||
|
},
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"default-test-route-6f97418635c7e18853da": {
|
||||||
|
EntryPoints: []string{"foo"},
|
||||||
|
Service: "default-test-route-6f97418635c7e18853da",
|
||||||
|
Rule: "Host(`foo.com`)",
|
||||||
|
}},
|
||||||
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
Services: map[string]*dynamic.Service{
|
||||||
|
"default-test-route-6f97418635c7e18853da": {
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Servers: []dynamic.Server{
|
||||||
|
{
|
||||||
|
URL: "http://external.domain:80",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PassHostHeader: Bool(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TLS: &dynamic.TLSConfiguration{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Ingress Route, externalName service with http",
|
||||||
|
paths: []string{"services.yml", "with_externalname_with_http.yml"},
|
||||||
|
expected: &dynamic.Configuration{
|
||||||
|
UDP: &dynamic.UDPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.UDPRouter{},
|
||||||
|
Services: map[string]*dynamic.UDPService{},
|
||||||
|
},
|
||||||
|
TCP: &dynamic.TCPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.TCPRouter{},
|
||||||
|
Services: map[string]*dynamic.TCPService{},
|
||||||
|
},
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"default-test-route-6f97418635c7e18853da": {
|
||||||
|
EntryPoints: []string{"foo"},
|
||||||
|
Service: "default-test-route-6f97418635c7e18853da",
|
||||||
|
Rule: "Host(`foo.com`)",
|
||||||
|
}},
|
||||||
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
Services: map[string]*dynamic.Service{
|
||||||
|
"default-test-route-6f97418635c7e18853da": {
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Servers: []dynamic.Server{
|
||||||
|
{
|
||||||
|
URL: "http://external.domain:80",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PassHostHeader: Bool(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TLS: &dynamic.TLSConfiguration{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Ingress Route, externalName service with https",
|
||||||
|
paths: []string{"services.yml", "with_externalname_with_https.yml"},
|
||||||
|
expected: &dynamic.Configuration{
|
||||||
|
UDP: &dynamic.UDPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.UDPRouter{},
|
||||||
|
Services: map[string]*dynamic.UDPService{},
|
||||||
|
},
|
||||||
|
TCP: &dynamic.TCPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.TCPRouter{},
|
||||||
|
Services: map[string]*dynamic.TCPService{},
|
||||||
|
},
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"default-test-route-6f97418635c7e18853da": {
|
||||||
|
EntryPoints: []string{"foo"},
|
||||||
|
Service: "default-test-route-6f97418635c7e18853da",
|
||||||
|
Rule: "Host(`foo.com`)",
|
||||||
|
}},
|
||||||
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
Services: map[string]*dynamic.Service{
|
||||||
|
"default-test-route-6f97418635c7e18853da": {
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Servers: []dynamic.Server{
|
||||||
|
{
|
||||||
|
URL: "https://external.domain:443",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PassHostHeader: Bool(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TLS: &dynamic.TLSConfiguration{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Ingress Route, externalName service without ports",
|
||||||
|
paths: []string{"services.yml", "with_externalname_without_ports.yml"},
|
||||||
|
expected: &dynamic.Configuration{
|
||||||
|
UDP: &dynamic.UDPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.UDPRouter{},
|
||||||
|
Services: map[string]*dynamic.UDPService{},
|
||||||
|
},
|
||||||
|
TCP: &dynamic.TCPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.TCPRouter{},
|
||||||
|
Services: map[string]*dynamic.TCPService{},
|
||||||
|
},
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{},
|
||||||
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
Services: map[string]*dynamic.Service{},
|
||||||
|
},
|
||||||
|
TLS: &dynamic.TLSConfiguration{},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
|
@ -3255,3 +3485,148 @@ func TestParseServiceProtocol(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetServicePort(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
svc *corev1.Service
|
||||||
|
port int32
|
||||||
|
expected *corev1.ServicePort
|
||||||
|
expectError bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Basic",
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Matching ports, with no service type",
|
||||||
|
svc: &corev1.Service{
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Ports: []corev1.ServicePort{
|
||||||
|
{
|
||||||
|
Port: 80,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
port: 80,
|
||||||
|
expected: &corev1.ServicePort{
|
||||||
|
Port: 80,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Matching ports 0",
|
||||||
|
svc: &corev1.Service{
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Ports: []corev1.ServicePort{
|
||||||
|
{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Matching ports 0 (with external name)",
|
||||||
|
svc: &corev1.Service{
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Type: corev1.ServiceTypeExternalName,
|
||||||
|
Ports: []corev1.ServicePort{
|
||||||
|
{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Mismatching, only port(Ingress) defined",
|
||||||
|
svc: &corev1.Service{
|
||||||
|
Spec: corev1.ServiceSpec{},
|
||||||
|
},
|
||||||
|
port: 80,
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Mismatching, only port(Ingress) defined with external name",
|
||||||
|
svc: &corev1.Service{
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Type: corev1.ServiceTypeExternalName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
port: 80,
|
||||||
|
expected: &corev1.ServicePort{
|
||||||
|
Port: 80,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Mismatching, only Service port defined",
|
||||||
|
svc: &corev1.Service{
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Ports: []corev1.ServicePort{
|
||||||
|
{
|
||||||
|
Port: 80,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Mismatching, only Service port defined with external name",
|
||||||
|
svc: &corev1.Service{
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Type: corev1.ServiceTypeExternalName,
|
||||||
|
Ports: []corev1.ServicePort{
|
||||||
|
{
|
||||||
|
Port: 80,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Two different ports defined",
|
||||||
|
svc: &corev1.Service{
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Ports: []corev1.ServicePort{
|
||||||
|
{
|
||||||
|
Port: 80,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
port: 443,
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Two different ports defined (with external name)",
|
||||||
|
svc: &corev1.Service{
|
||||||
|
Spec: corev1.ServiceSpec{
|
||||||
|
Type: corev1.ServiceTypeExternalName,
|
||||||
|
Ports: []corev1.ServicePort{
|
||||||
|
{
|
||||||
|
Port: 80,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
port: 443,
|
||||||
|
expected: &corev1.ServicePort{
|
||||||
|
Port: 443,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
actual, err := getServicePort(test.svc, test.port)
|
||||||
|
if test.expectError {
|
||||||
|
assert.Error(t, err)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, test.expected, actual)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue