Merge branch 'master' of github.com:traefik/traefik
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
commit
fd015c5a9b
101 changed files with 20922 additions and 13475 deletions
|
@ -35,12 +35,18 @@ rules:
|
|||
- ""
|
||||
resources:
|
||||
- services
|
||||
- endpoints
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- discovery.k8s.io
|
||||
resources:
|
||||
- endpointslices
|
||||
verbs:
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- extensions
|
||||
- networking.k8s.io
|
||||
|
|
53
docs/content/migration/v3.md
Normal file
53
docs/content/migration/v3.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
title: "Traefik Migration Documentation"
|
||||
description: "Learn the steps needed to migrate to new Traefik Proxy v3 versions. Read the technical documentation."
|
||||
---
|
||||
|
||||
# Migration: Steps needed between the versions
|
||||
|
||||
## v3.0 to v3.1
|
||||
|
||||
### Kubernetes Provider RBACs
|
||||
|
||||
Starting with v3.1, the Kubernetes Providers now use the [EndpointSlices API](https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/) (Kubernetes >=v1.21) to discover service endpoint addresses.
|
||||
|
||||
Therefore, in the corresponding RBACs (see [KubernetesIngress](../routing/providers/kubernetes-ingress.md#configuration-example), [KubernetesCRD](../reference/dynamic-configuration/kubernetes-crd.md#rbac), and [KubernetesGateway](../reference/dynamic-configuration/kubernetes-gateway.md#rbac) provider RBACs),
|
||||
the `endpoints` right has to be removed and the following `endpointslices` right has to be added.
|
||||
|
||||
```yaml
|
||||
...
|
||||
- apiGroups:
|
||||
- discovery.k8s.io
|
||||
resources:
|
||||
- endpointslices
|
||||
verbs:
|
||||
- list
|
||||
- watch
|
||||
...
|
||||
```
|
||||
|
||||
#### Gateway API: KubernetesGateway Provider
|
||||
|
||||
In v3.1, the KubernetesGateway Provider is no longer an experimental feature.
|
||||
It can be enabled without the associated `experimental.kubernetesgateway` option, which is now deprecated.
|
||||
|
||||
??? example "An example of the experimental `kubernetesgateway` option"
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
experimental:
|
||||
kubernetesgateway: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[experimental]
|
||||
kubernetesgateway=true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--experimental.kubernetesgateway=true
|
||||
```
|
||||
|
||||
##### Remediation
|
||||
|
||||
The `kubernetesgateway` option should be removed from the experimental section of the static configuration.
|
||||
To configure `kubernetesgateway`, please check out the [KubernetesGateway Provider documentation](../providers/kubernetes-gateway.md).
|
|
@ -183,7 +183,7 @@ _Optional, Default: ""_
|
|||
|
||||
A label selector can be defined to filter on specific resource objects only,
|
||||
this applies only to Traefik [Custom Resources](../routing/providers/kubernetes-crd.md#custom-resource-definition-crd)
|
||||
and has no effect on Kubernetes `Secrets`, `Endpoints` and `Services`.
|
||||
and has no effect on Kubernetes `Secrets`, `EndpointSlices` and `Services`.
|
||||
If left empty, Traefik processes all resource objects in the configured namespaces.
|
||||
|
||||
See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details.
|
||||
|
|
|
@ -8,13 +8,19 @@ rules:
|
|||
- ""
|
||||
resources:
|
||||
- services
|
||||
- endpoints
|
||||
- secrets
|
||||
- nodes
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- discovery.k8s.io
|
||||
resources:
|
||||
- endpointslices
|
||||
verbs:
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- extensions
|
||||
- networking.k8s.io
|
||||
|
|
|
@ -15,12 +15,18 @@ rules:
|
|||
- ""
|
||||
resources:
|
||||
- services
|
||||
- endpoints
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- discovery.k8s.io
|
||||
resources:
|
||||
- endpointslices
|
||||
verbs:
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- gateway.networking.k8s.io
|
||||
resources:
|
||||
|
|
|
@ -211,7 +211,7 @@ WriteTimeout is the maximum duration before timing out writes of the response. I
|
|||
Timeout defines how long to wait on an idle session before releasing the related resources. (Default: ```3```)
|
||||
|
||||
`--experimental.kubernetesgateway`:
|
||||
Allow the Kubernetes gateway api provider usage. (Default: ```false```)
|
||||
(Deprecated) Allow the Kubernetes gateway api provider usage. (Default: ```false```)
|
||||
|
||||
`--experimental.localplugins.<name>`:
|
||||
Local plugins configuration. (Default: ```false```)
|
||||
|
|
|
@ -211,7 +211,7 @@ WriteTimeout is the maximum duration before timing out writes of the response. I
|
|||
Timeout defines how long to wait on an idle session before releasing the related resources. (Default: ```3```)
|
||||
|
||||
`TRAEFIK_EXPERIMENTAL_KUBERNETESGATEWAY`:
|
||||
Allow the Kubernetes gateway api provider usage. (Default: ```false```)
|
||||
(Deprecated) Allow the Kubernetes gateway api provider usage. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_EXPERIMENTAL_LOCALPLUGINS_<NAME>`:
|
||||
Local plugins configuration. (Default: ```false```)
|
||||
|
|
|
@ -29,12 +29,18 @@ which in turn will create the resulting routers, services, handlers, etc.
|
|||
- ""
|
||||
resources:
|
||||
- services
|
||||
- endpoints
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- discovery.k8s.io
|
||||
resources:
|
||||
- endpointslices
|
||||
verbs:
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- extensions
|
||||
- networking.k8s.io
|
||||
|
@ -427,12 +433,19 @@ This way, any Ingress attached to this Entrypoint will have TLS termination by d
|
|||
- ""
|
||||
resources:
|
||||
- services
|
||||
- endpoints
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- discovery.k8s.io
|
||||
resources:
|
||||
- endpointslices
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- extensions
|
||||
- networking.k8s.io
|
||||
|
@ -612,12 +625,19 @@ For more options, please refer to the available [annotations](#on-ingress).
|
|||
- ""
|
||||
resources:
|
||||
- services
|
||||
- endpoints
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- discovery.k8s.io
|
||||
resources:
|
||||
- endpointslices
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- extensions
|
||||
- networking.k8s.io
|
||||
|
|
|
@ -172,6 +172,7 @@ nav:
|
|||
- 'HTTP Challenge': 'user-guides/docker-compose/acme-http/index.md'
|
||||
- 'DNS Challenge': 'user-guides/docker-compose/acme-dns/index.md'
|
||||
- 'Migration':
|
||||
- 'Traefik v3 minor migrations': 'migration/v3.md'
|
||||
- 'Traefik v2 to v3':
|
||||
- 'Migration guide': 'migration/v2-to-v3.md'
|
||||
- 'Configuration changes for v3': 'migration/v2-to-v3-details.md'
|
||||
|
|
42
go.mod
42
go.mod
|
@ -1,6 +1,6 @@
|
|||
module github.com/traefik/traefik/v3
|
||||
|
||||
go 1.22
|
||||
go 1.22.4
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.4.0
|
||||
|
@ -22,7 +22,7 @@ require (
|
|||
github.com/golang/protobuf v1.5.4
|
||||
github.com/google/go-github/v28 v28.1.1
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/gorilla/websocket v1.5.1
|
||||
github.com/hashicorp/consul/api v1.26.1
|
||||
github.com/hashicorp/go-hclog v1.6.3
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
|
@ -79,7 +79,7 @@ require (
|
|||
go.opentelemetry.io/otel/sdk v1.27.0
|
||||
go.opentelemetry.io/otel/sdk/metric v1.27.0
|
||||
go.opentelemetry.io/otel/trace v1.27.0
|
||||
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f
|
||||
golang.org/x/mod v0.18.0
|
||||
golang.org/x/net v0.26.0
|
||||
golang.org/x/sys v0.21.0
|
||||
|
@ -88,14 +88,14 @@ require (
|
|||
golang.org/x/tools v0.22.0
|
||||
google.golang.org/grpc v1.64.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/api v0.29.2
|
||||
k8s.io/apiextensions-apiserver v0.28.3
|
||||
k8s.io/apimachinery v0.29.2
|
||||
k8s.io/client-go v0.29.2
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
|
||||
k8s.io/api v0.30.0
|
||||
k8s.io/apiextensions-apiserver v0.30.0
|
||||
k8s.io/apimachinery v0.30.0
|
||||
k8s.io/client-go v0.30.0
|
||||
k8s.io/utils v0.0.0-20240423183400-0849a56e8f22
|
||||
mvdan.cc/xurls/v2 v2.5.0
|
||||
sigs.k8s.io/controller-runtime v0.16.3
|
||||
sigs.k8s.io/gateway-api v1.0.0
|
||||
sigs.k8s.io/controller-runtime v0.18.0
|
||||
sigs.k8s.io/gateway-api v1.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -165,9 +165,9 @@ require (
|
|||
github.com/distribution/reference v0.5.0 // indirect
|
||||
github.com/dnsimple/dnsimple-go v1.7.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
|
||||
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.7.0 // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
|
||||
github.com/exoscale/egoscale v0.102.3 // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
|
@ -178,11 +178,11 @@ require (
|
|||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-logr/zapr v1.2.4 // indirect
|
||||
github.com/go-logr/zapr v1.3.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.20.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.22.4 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-resty/resty/v2 v2.11.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0 // indirect
|
||||
|
@ -316,9 +316,9 @@ require (
|
|||
github.com/yandex-cloud/go-sdk v0.0.0-20240318084659-dfa50323a0b4 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
github.com/zeebo/errs v1.2.2 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.9 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.9 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.10 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.10 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/aws v1.27.0 // indirect
|
||||
|
@ -347,8 +347,8 @@ require (
|
|||
gopkg.in/ns1/ns1-go.v2 v2.9.1 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/klog/v2 v2.110.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
|
||||
k8s.io/klog/v2 v2.120.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108 // indirect
|
||||
nhooyr.io/websocket v1.8.7 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
|
||||
|
|
96
go.sum
96
go.sum
|
@ -151,7 +151,6 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 h1:M/1u4HBpwLuMtjlxuI2y6HoVLzF
|
|||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.12/go.mod h1:kcfd+eTdEi/40FIbLq4Hif3XMXnl5b/+t/KTfLt9xIk=
|
||||
github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
|
||||
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
|
@ -282,8 +281,8 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP
|
|||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
|
||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk=
|
||||
github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
|
@ -295,8 +294,8 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.
|
|||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI=
|
||||
github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc=
|
||||
github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
||||
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
|
||||
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
||||
github.com/exoscale/egoscale v0.102.3 h1:DYqN2ipoLKpiFoprRGQkp2av/Ze7sUYYlGhi1N62tfY=
|
||||
github.com/exoscale/egoscale v0.102.3/go.mod h1:RPf2Gah6up+6kAEayHTQwqapzXlm93f0VQas/UEGU5c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
|
@ -349,26 +348,22 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
|
|||
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
|
||||
github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
|
||||
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
||||
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
|
||||
github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
|
||||
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
|
@ -519,8 +514,8 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51
|
|||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf h1:C1GPyPJrOlJlIrcaBBiBpDsqZena2Ks8spa5xZqr1XQ=
|
||||
github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf/go.mod h1:zXqxTI6jXDdKnlf8s+nT+3c8LrwUEy3yNpO4XJL90lA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
|
@ -874,8 +869,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
|
|||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo=
|
||||
github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0=
|
||||
github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk=
|
||||
github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
|
@ -1168,12 +1163,12 @@ github.com/zeebo/errs v1.2.2/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtC
|
|||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs=
|
||||
go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4=
|
||||
go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E=
|
||||
go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA=
|
||||
go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k=
|
||||
go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U=
|
||||
go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao=
|
||||
go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
|
@ -1221,18 +1216,15 @@ go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naR
|
|||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/ratelimit v0.3.0 h1:IdZd9wqvFXnvLvSEBo0KPcGfkoBGNkpTHlrE3Rcjkjw=
|
||||
|
@ -1240,7 +1232,6 @@ go.uber.org/ratelimit v0.3.0/go.mod h1:So5LG7CV1zWpY1sHe+DXTJqQvOx+FFPFaAs2SnoyB
|
|||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
||||
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
|
@ -1280,8 +1271,8 @@ golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL
|
|||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8=
|
||||
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
|
@ -1507,7 +1498,6 @@ golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4X
|
|||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
|
@ -1517,8 +1507,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM=
|
||||
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
||||
|
@ -1650,20 +1638,20 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A=
|
||||
k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0=
|
||||
k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08=
|
||||
k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc=
|
||||
k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8=
|
||||
k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU=
|
||||
k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg=
|
||||
k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA=
|
||||
k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
|
||||
k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
|
||||
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
|
||||
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
k8s.io/api v0.30.0 h1:siWhRq7cNjy2iHssOB9SCGNCl2spiF1dO3dABqZ8niA=
|
||||
k8s.io/api v0.30.0/go.mod h1:OPlaYhoHs8EQ1ql0R/TsUgaRPhpKNxIMrKQfWUp8QSE=
|
||||
k8s.io/apiextensions-apiserver v0.30.0 h1:jcZFKMqnICJfRxTgnC4E+Hpcq8UEhT8B2lhBcQ+6uAs=
|
||||
k8s.io/apiextensions-apiserver v0.30.0/go.mod h1:N9ogQFGcrbWqAY9p2mUAL5mGxsLqwgtUce127VtRX5Y=
|
||||
k8s.io/apimachinery v0.30.0 h1:qxVPsyDM5XS96NIh9Oj6LavoVFYff/Pon9cZeDIkHHA=
|
||||
k8s.io/apimachinery v0.30.0/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
|
||||
k8s.io/client-go v0.30.0 h1:sB1AGGlhY/o7KCyCEQ0bPWzYDL0pwOZO4vAtTSh/gJQ=
|
||||
k8s.io/client-go v0.30.0/go.mod h1:g7li5O5256qe6TYdAMyX/otJqMhIiGgTapdLchhmOaY=
|
||||
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
|
||||
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108 h1:Q8Z7VlGhcJgBHJHYugJ/K/7iB8a2eSxCyxdVjJp+lLY=
|
||||
k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
|
||||
k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 h1:ao5hUqGhsqdm+bYbjH/pRkCs0unBGe9UyDahzs9zQzQ=
|
||||
k8s.io/utils v0.0.0-20240423183400-0849a56e8f22/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
mvdan.cc/xurls/v2 v2.5.0 h1:lyBNOm8Wo71UknhUs4QTFUNNMyxy2JEIaKKo0RWOh+8=
|
||||
mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE=
|
||||
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
|
||||
|
@ -1671,10 +1659,10 @@ nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0
|
|||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4=
|
||||
sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0=
|
||||
sigs.k8s.io/gateway-api v1.0.0 h1:iPTStSv41+d9p0xFydll6d7f7MOBGuqXM6p2/zVYMAs=
|
||||
sigs.k8s.io/gateway-api v1.0.0/go.mod h1:4cUgr0Lnp5FZ0Cdq8FdRwCvpiWws7LVhLHGIudLlf4c=
|
||||
sigs.k8s.io/controller-runtime v0.18.0 h1:Z7jKuX784TQSUL1TIyeuF7j8KXZ4RtSX0YgtjKcSTME=
|
||||
sigs.k8s.io/controller-runtime v0.18.0/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw=
|
||||
sigs.k8s.io/gateway-api v1.1.0 h1:DsLDXCi6jR+Xz8/xd0Z1PYl2Pn0TyaFMOPPZIj4inDM=
|
||||
sigs.k8s.io/gateway-api v1.1.0/go.mod h1:ZH4lHrL2sDi0FHZ9jjneb8kKnGzFWyrTya35sWUTrRs=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
|
||||
|
|
File diff suppressed because it is too large
Load diff
18317
integration/fixtures/k8s-conformance/00-experimental-v1.1.0.yml
Normal file
18317
integration/fixtures/k8s-conformance/00-experimental-v1.1.0.yml
Normal file
File diff suppressed because it is too large
Load diff
|
@ -15,12 +15,19 @@ rules:
|
|||
- ""
|
||||
resources:
|
||||
- services
|
||||
- endpoints
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- discovery.k8s.io
|
||||
resources:
|
||||
- endpointslices
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- gateway.networking.k8s.io
|
||||
resources:
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
|
@ -18,6 +19,7 @@ import (
|
|||
"github.com/traefik/traefik/v3/integration/try"
|
||||
"github.com/traefik/traefik/v3/pkg/version"
|
||||
"gopkg.in/yaml.v3"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
kclientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
@ -27,10 +29,12 @@ import (
|
|||
gatev1 "sigs.k8s.io/gateway-api/apis/v1"
|
||||
gatev1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
|
||||
gatev1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
|
||||
conformanceV1alpha1 "sigs.k8s.io/gateway-api/conformance/apis/v1alpha1"
|
||||
"sigs.k8s.io/gateway-api/conformance"
|
||||
v1 "sigs.k8s.io/gateway-api/conformance/apis/v1"
|
||||
"sigs.k8s.io/gateway-api/conformance/tests"
|
||||
"sigs.k8s.io/gateway-api/conformance/utils/config"
|
||||
ksuite "sigs.k8s.io/gateway-api/conformance/utils/suite"
|
||||
"sigs.k8s.io/gateway-api/pkg/features"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -84,7 +88,7 @@ func (s *K8sConformanceSuite) SetupSuite() {
|
|||
|
||||
s.k3sContainer, err = k3s.RunContainer(ctx,
|
||||
testcontainers.WithImage(k3sImage),
|
||||
k3s.WithManifest("./fixtures/k8s-conformance/00-experimental-v1.0.0.yml"),
|
||||
k3s.WithManifest("./fixtures/k8s-conformance/00-experimental-v1.1.0.yml"),
|
||||
k3s.WithManifest("./fixtures/k8s-conformance/01-rbac.yml"),
|
||||
k3s.WithManifest("./fixtures/k8s-conformance/02-traefik.yml"),
|
||||
network.WithNetwork(nil, s.network),
|
||||
|
@ -122,15 +126,19 @@ func (s *K8sConformanceSuite) SetupSuite() {
|
|||
s.T().Fatalf("Error initializing Kubernetes REST client: %v", err)
|
||||
}
|
||||
|
||||
if err = gatev1alpha2.AddToScheme(s.kubeClient.Scheme()); err != nil {
|
||||
if err = gatev1alpha2.Install(s.kubeClient.Scheme()); err != nil {
|
||||
s.T().Fatal(err)
|
||||
}
|
||||
|
||||
if err = gatev1beta1.AddToScheme(s.kubeClient.Scheme()); err != nil {
|
||||
if err = gatev1beta1.Install(s.kubeClient.Scheme()); err != nil {
|
||||
s.T().Fatal(err)
|
||||
}
|
||||
|
||||
if err = gatev1.AddToScheme(s.kubeClient.Scheme()); err != nil {
|
||||
if err = gatev1.Install(s.kubeClient.Scheme()); err != nil {
|
||||
s.T().Fatal(err)
|
||||
}
|
||||
|
||||
if err = apiextensionsv1.AddToScheme(s.kubeClient.Scheme()); err != nil {
|
||||
s.T().Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -169,81 +177,54 @@ func (s *K8sConformanceSuite) TestK8sGatewayAPIConformance() {
|
|||
err = try.GetRequest("http://"+k3sContainerIP+":9000/api/entrypoints", 10*time.Second, try.BodyContains(`"name":"web"`))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
opts := ksuite.Options{
|
||||
Client: s.kubeClient,
|
||||
Clientset: s.clientSet,
|
||||
GatewayClassName: "traefik",
|
||||
Debug: true,
|
||||
CleanupBaseResources: true,
|
||||
TimeoutConfig: config.TimeoutConfig{
|
||||
CreateTimeout: 5 * time.Second,
|
||||
DeleteTimeout: 5 * time.Second,
|
||||
GetTimeout: 5 * time.Second,
|
||||
GatewayMustHaveAddress: 5 * time.Second,
|
||||
GatewayMustHaveCondition: 5 * time.Second,
|
||||
GatewayStatusMustHaveListeners: 10 * time.Second,
|
||||
GatewayListenersMustHaveCondition: 5 * time.Second,
|
||||
GWCMustBeAccepted: 60 * time.Second, // Pod creation in k3s cluster can be long.
|
||||
HTTPRouteMustNotHaveParents: 5 * time.Second,
|
||||
HTTPRouteMustHaveCondition: 5 * time.Second,
|
||||
TLSRouteMustHaveCondition: 5 * time.Second,
|
||||
RouteMustHaveParents: 5 * time.Second,
|
||||
ManifestFetchTimeout: 5 * time.Second,
|
||||
MaxTimeToConsistency: 5 * time.Second,
|
||||
NamespacesMustBeReady: 60 * time.Second, // Pod creation in k3s cluster can be long.
|
||||
RequestTimeout: 5 * time.Second,
|
||||
LatestObservedGenerationSet: 5 * time.Second,
|
||||
RequiredConsecutiveSuccesses: 0,
|
||||
},
|
||||
SupportedFeatures: sets.New(ksuite.SupportGateway,
|
||||
ksuite.SupportGatewayPort8080,
|
||||
ksuite.SupportHTTPRoute,
|
||||
ksuite.SupportHTTPRouteQueryParamMatching,
|
||||
ksuite.SupportHTTPRouteMethodMatching,
|
||||
ksuite.SupportHTTPRoutePortRedirect,
|
||||
ksuite.SupportHTTPRouteSchemeRedirect,
|
||||
ksuite.SupportHTTPRouteHostRewrite,
|
||||
ksuite.SupportHTTPRoutePathRewrite,
|
||||
ksuite.SupportHTTPRoutePathRedirect,
|
||||
),
|
||||
ExemptFeatures: sets.New(
|
||||
ksuite.SupportHTTPRouteRequestTimeout,
|
||||
ksuite.SupportHTTPRouteBackendTimeout,
|
||||
ksuite.SupportHTTPRouteResponseHeaderModification,
|
||||
ksuite.SupportHTTPRouteRequestMirror,
|
||||
ksuite.SupportHTTPRouteRequestMultipleMirrors,
|
||||
),
|
||||
cSuite, err := ksuite.NewConformanceTestSuite(ksuite.ConformanceOptions{
|
||||
Client: s.kubeClient,
|
||||
Clientset: s.clientSet,
|
||||
GatewayClassName: "traefik",
|
||||
Debug: true,
|
||||
CleanupBaseResources: true,
|
||||
TimeoutConfig: config.DefaultTimeoutConfig(),
|
||||
ManifestFS: []fs.FS{&conformance.Manifests},
|
||||
EnableAllSupportedFeatures: false,
|
||||
RunTest: *k8sConformanceRunTest,
|
||||
// Until the feature are all supported, following tests are skipped.
|
||||
SkipTests: []string{
|
||||
tests.HTTPRouteMethodMatching.ShortName,
|
||||
tests.HTTPRouteQueryParamMatching.ShortName,
|
||||
},
|
||||
}
|
||||
|
||||
cSuite, err := ksuite.NewExperimentalConformanceTestSuite(ksuite.ExperimentalConformanceOptions{
|
||||
Options: opts,
|
||||
Implementation: conformanceV1alpha1.Implementation{
|
||||
Implementation: v1.Implementation{
|
||||
Organization: "traefik",
|
||||
Project: "traefik",
|
||||
URL: "https://traefik.io/",
|
||||
Version: version.Version,
|
||||
Contact: []string{"@traefik/maintainers"},
|
||||
},
|
||||
ConformanceProfiles: sets.New(ksuite.HTTPConformanceProfileName),
|
||||
ConformanceProfiles: sets.New(ksuite.GatewayHTTPConformanceProfileName),
|
||||
SupportedFeatures: sets.New(
|
||||
features.SupportGateway,
|
||||
features.SupportGatewayPort8080,
|
||||
features.SupportHTTPRoute,
|
||||
features.SupportHTTPRouteQueryParamMatching,
|
||||
features.SupportHTTPRouteMethodMatching,
|
||||
features.SupportHTTPRoutePortRedirect,
|
||||
features.SupportHTTPRouteSchemeRedirect,
|
||||
features.SupportHTTPRouteHostRewrite,
|
||||
features.SupportHTTPRoutePathRewrite,
|
||||
features.SupportHTTPRoutePathRedirect,
|
||||
),
|
||||
ExemptFeatures: sets.New(
|
||||
features.SupportHTTPRouteRequestTimeout,
|
||||
features.SupportHTTPRouteBackendTimeout,
|
||||
features.SupportHTTPRouteResponseHeaderModification,
|
||||
features.SupportHTTPRouteRequestMirror,
|
||||
features.SupportHTTPRouteRequestMultipleMirrors,
|
||||
),
|
||||
})
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
cSuite.Setup(s.T())
|
||||
cSuite.Setup(s.T(), tests.ConformanceTests)
|
||||
|
||||
err = cSuite.Run(s.T(), tests.ConformanceTests)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
report, err := cSuite.Report()
|
||||
require.NoError(s.T(), err, "failed generating conformance report")
|
||||
|
||||
report.GatewayAPIVersion = "1.0.0"
|
||||
|
||||
rawReport, err := yaml.Marshal(report)
|
||||
require.NoError(s.T(), err)
|
||||
s.T().Logf("Conformance report:\n%s", string(rawReport))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
server:
|
||||
image: rancher/k3s:v1.20.15-k3s1
|
||||
image: rancher/k3s:v1.21.14-k3s1
|
||||
privileged: true
|
||||
command:
|
||||
- server
|
||||
|
@ -26,7 +26,7 @@ services:
|
|||
- ./fixtures/k8s:/var/lib/rancher/k3s/server/manifests
|
||||
|
||||
node:
|
||||
image: rancher/k3s:v1.20.15-k3s1
|
||||
image: rancher/k3s:v1.21.14-k3s1
|
||||
privileged: true
|
||||
environment:
|
||||
K3S_TOKEN: somethingtotallyrandom
|
||||
|
|
|
@ -458,7 +458,8 @@ func (h *http) deprecationNotice(logger zerolog.Logger) bool {
|
|||
}
|
||||
|
||||
type experimental struct {
|
||||
HTTP3 *bool `json:"http3,omitempty" toml:"http3,omitempty" yaml:"http3,omitempty"`
|
||||
HTTP3 *bool `json:"http3,omitempty" toml:"http3,omitempty" yaml:"http3,omitempty"`
|
||||
KubernetesGateway *bool `json:"kubernetesGateway,omitempty" toml:"kubernetesGateway,omitempty" yaml:"kubernetesGateway,omitempty"`
|
||||
}
|
||||
|
||||
func (e *experimental) deprecationNotice(logger zerolog.Logger) bool {
|
||||
|
@ -469,11 +470,17 @@ func (e *experimental) deprecationNotice(logger zerolog.Logger) bool {
|
|||
if e.HTTP3 != nil {
|
||||
logger.Error().Msg("HTTP3 is not an experimental feature in v3 and the associated enablement has been removed." +
|
||||
"Please remove its usage from the static configuration for Traefik to start." +
|
||||
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#http3-experimental-configuration")
|
||||
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3-details/#http3")
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if e.KubernetesGateway != nil {
|
||||
logger.Error().Msg("KubernetesGateway provider is not an experimental feature starting with v3.1." +
|
||||
"Please remove its usage from the static configuration." +
|
||||
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.0/migration/v3/#gateway-api-kubernetesgateway-provider")
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,9 @@ func ptr[T any](t T) *T {
|
|||
|
||||
func TestDeprecationNotice(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
config configuration
|
||||
desc string
|
||||
config configuration
|
||||
wantCompatible bool
|
||||
}{
|
||||
{
|
||||
desc: "Docker provider swarmMode option is incompatible",
|
||||
|
@ -196,6 +197,15 @@ func TestDeprecationNotice(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Experimental KubernetesGateway enablement configuration is compatible",
|
||||
config: configuration{
|
||||
Experimental: &experimental{
|
||||
KubernetesGateway: ptr(true),
|
||||
},
|
||||
},
|
||||
wantCompatible: true,
|
||||
},
|
||||
{
|
||||
desc: "Tracing SpanNameLimit option is incompatible",
|
||||
config: configuration{
|
||||
|
@ -278,7 +288,8 @@ func TestDeprecationNotice(t *testing.T) {
|
|||
})
|
||||
|
||||
logger := log.With().Logger().Hook(testHook)
|
||||
assert.True(t, test.config.deprecationNotice(logger))
|
||||
|
||||
assert.Equal(t, !test.wantCompatible, test.config.deprecationNotice(logger))
|
||||
assert.True(t, gotLog)
|
||||
assert.Equal(t, zerolog.ErrorLevel, gotLevel)
|
||||
})
|
||||
|
|
|
@ -7,5 +7,6 @@ type Experimental struct {
|
|||
Plugins map[string]plugins.Descriptor `description:"Plugins configuration." json:"plugins,omitempty" toml:"plugins,omitempty" yaml:"plugins,omitempty" export:"true"`
|
||||
LocalPlugins map[string]plugins.LocalDescriptor `description:"Local plugins configuration." json:"localPlugins,omitempty" toml:"localPlugins,omitempty" yaml:"localPlugins,omitempty" export:"true"`
|
||||
|
||||
KubernetesGateway bool `description:"Allow the Kubernetes gateway api provider usage." json:"kubernetesGateway,omitempty" toml:"kubernetesGateway,omitempty" yaml:"kubernetesGateway,omitempty" export:"true"`
|
||||
// Deprecated: KubernetesGateway provider is not an experimental feature starting with v3.1. Please remove its usage from the static configuration.
|
||||
KubernetesGateway bool `description:"(Deprecated) Allow the Kubernetes gateway api provider usage." json:"kubernetesGateway,omitempty" toml:"kubernetesGateway,omitempty" yaml:"kubernetesGateway,omitempty" export:"true"`
|
||||
}
|
||||
|
|
|
@ -17,9 +17,11 @@ import (
|
|||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
"github.com/traefik/traefik/v3/pkg/version"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
discoveryv1 "k8s.io/api/discovery/v1"
|
||||
kerror "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
kinformers "k8s.io/client-go/informers"
|
||||
kclientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
|
@ -46,7 +48,7 @@ type Client interface {
|
|||
GetTLSStores() []*traefikv1alpha1.TLSStore
|
||||
GetService(namespace, name string) (*corev1.Service, bool, error)
|
||||
GetSecret(namespace, name string) (*corev1.Secret, bool, error)
|
||||
GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error)
|
||||
GetEndpointSlicesForService(namespace, serviceName string) ([]*discoveryv1.EndpointSlice, error)
|
||||
GetNodes() ([]*corev1.Node, bool, error)
|
||||
}
|
||||
|
||||
|
@ -219,7 +221,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = factoryKube.Core().V1().Endpoints().Informer().AddEventHandler(eventHandler)
|
||||
_, err = factoryKube.Discovery().V1().EndpointSlices().Informer().AddEventHandler(eventHandler)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -444,15 +446,20 @@ func (c *clientWrapper) GetService(namespace, name string) (*corev1.Service, boo
|
|||
return service, exist, err
|
||||
}
|
||||
|
||||
// GetEndpoints returns the named endpoints from the given namespace.
|
||||
func (c *clientWrapper) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
||||
// GetEndpointSlicesForService returns the EndpointSlices for the given service name in the given namespace.
|
||||
func (c *clientWrapper) GetEndpointSlicesForService(namespace, serviceName string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get endpoints %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
return nil, fmt.Errorf("failed to get endpointslices for service %s/%s: namespace is not within watched namespaces", namespace, serviceName)
|
||||
}
|
||||
|
||||
endpoint, err := c.factoriesKube[c.lookupNamespace(namespace)].Core().V1().Endpoints().Lister().Endpoints(namespace).Get(name)
|
||||
exist, err := translateNotFoundError(err)
|
||||
return endpoint, exist, err
|
||||
serviceLabelRequirement, err := labels.NewRequirement(discoveryv1.LabelServiceName, selection.Equals, []string{serviceName})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create service label selector requirement: %w", err)
|
||||
}
|
||||
serviceSelector := labels.NewSelector()
|
||||
serviceSelector = serviceSelector.Add(*serviceLabelRequirement)
|
||||
|
||||
return c.factoriesKube[c.lookupNamespace(namespace)].Discovery().V1().EndpointSlices().Lister().EndpointSlices(namespace).List(serviceSelector)
|
||||
}
|
||||
|
||||
// GetSecret returns the named secret from the given namespace.
|
||||
|
|
|
@ -13,19 +13,24 @@ spec:
|
|||
task: whoami
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami
|
||||
name: whoami-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -43,19 +48,24 @@ spec:
|
|||
task: whoami2
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami2
|
||||
name: whoami2-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami2
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -74,19 +84,24 @@ spec:
|
|||
task: whoami2
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamitls
|
||||
name: whoamitls-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamitls
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: websecure
|
||||
port: 8443
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.5
|
||||
- ip: 10.10.0.6
|
||||
ports:
|
||||
- name: websecure
|
||||
port: 8443
|
||||
- 10.10.0.5
|
||||
- 10.10.0.6
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -99,25 +114,29 @@ spec:
|
|||
ports:
|
||||
- name: websecure2
|
||||
port: 8443
|
||||
scheme: https
|
||||
selector:
|
||||
app: traefiklabs
|
||||
task: whoami3
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami3
|
||||
name: whoami3-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami3
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: websecure2
|
||||
port: 8443
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.7
|
||||
- ip: 10.10.0.8
|
||||
ports:
|
||||
- name: websecure2
|
||||
port: 8443
|
||||
- 10.10.0.7
|
||||
- 10.10.0.8
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -135,18 +154,23 @@ spec:
|
|||
task: whoami-ipv6
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami-ipv6
|
||||
name: whoami-ipv6-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami-ipv6
|
||||
|
||||
subsets:
|
||||
addressType: IPv6
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: "2001:db8:85a3:8d3:1319:8a2e:370:7348"
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- "2001:db8:85a3:8d3:1319:8a2e:370:7348"
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -216,25 +240,30 @@ spec:
|
|||
task: whoami
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami-svc
|
||||
name: whoami-svc-abc
|
||||
namespace: cross-ns
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami-svc
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami-without-endpoints-subsets
|
||||
name: whoami-without-endpointslice-endpoints
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
|
@ -247,11 +276,16 @@ spec:
|
|||
task: whoami
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami-without-endpoints-subsets
|
||||
name: whoami-without-endpointslice-endpoints-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami-without-endpointslice-endpoints
|
||||
|
||||
addressType: IPv4
|
||||
endpoints: []
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
|
|
@ -13,19 +13,24 @@ spec:
|
|||
task: whoamitcp
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamitcp
|
||||
name: whoamitcp-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamitcp
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: myapp
|
||||
port: 8000
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: myapp
|
||||
port: 8000
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -43,19 +48,24 @@ spec:
|
|||
task: whoamitcp2
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamitcp2
|
||||
name: whoamitcp2-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamitcp2
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: myapp2
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: myapp2
|
||||
port: 8080
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -73,19 +83,24 @@ spec:
|
|||
task: whoamitcptls2
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamitcptls
|
||||
name: whoamitcptls-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamitcptls
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: websecure
|
||||
port: 443
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.5
|
||||
- ip: 10.10.0.6
|
||||
ports:
|
||||
- name: websecure
|
||||
port: 443
|
||||
- 10.10.0.5
|
||||
- 10.10.0.6
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -103,34 +118,44 @@ spec:
|
|||
task: whoamitcp3
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamitcp3
|
||||
name: whoamitcp3-abc
|
||||
namespace: ns3
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamitcp3
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: myapp3
|
||||
port: 8083
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.7
|
||||
- ip: 10.10.0.8
|
||||
ports:
|
||||
- name: myapp3
|
||||
port: 8083
|
||||
- 10.10.0.7
|
||||
- 10.10.0.8
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamitcp3
|
||||
name: whoamitcp3-abc
|
||||
namespace: ns4
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamitcp3
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: myapp4
|
||||
port: 8084
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.9
|
||||
- ip: 10.10.0.10
|
||||
ports:
|
||||
- name: myapp4
|
||||
port: 8084
|
||||
- 10.10.0.9
|
||||
- 10.10.0.10
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -148,19 +173,24 @@ spec:
|
|||
task: whoamitcp-ipv6
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamitcp-ipv6
|
||||
name: whoamitcp-ipv6-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamitcp-ipv6
|
||||
|
||||
subsets:
|
||||
addressType: IPv6
|
||||
ports:
|
||||
- name: myapp-ipv6
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: "fd00:10:244:0:1::3"
|
||||
- ip: "2001:db8:85a3:8d3:1319:8a2e:370:7348"
|
||||
ports:
|
||||
- name: myapp-ipv6
|
||||
port: 8080
|
||||
- "fd00:10:244:0:1::3"
|
||||
- "2001:db8:85a3:8d3:1319:8a2e:370:7348"
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -212,25 +242,30 @@ spec:
|
|||
task: whoamitcp
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamitcp-cross-ns
|
||||
name: whoamitcp-cross-ns-abc
|
||||
namespace: cross-ns
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamitcp-cross-ns
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: myapp
|
||||
port: 8000
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: myapp
|
||||
port: 8000
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoamitcp-without-endpoints-subsets
|
||||
name: whoamitcp-without-endpointslice-endpoints
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
|
@ -243,11 +278,16 @@ spec:
|
|||
task: whoamitcp
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamitcp-without-endpoints-subsets
|
||||
name: whoamitcp-without-endpointslice-endpoints-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamitcp-without-endpointslice-endpoints
|
||||
|
||||
addressType: IPv4
|
||||
endpoints: []
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
|
|
@ -11,5 +11,5 @@ spec:
|
|||
routes:
|
||||
- match: HostSNI(`foo.com`)
|
||||
services:
|
||||
- name: whoamitcp-without-endpoints-subsets
|
||||
- name: whoamitcp-without-endpointslice-endpoints
|
||||
port: 8000
|
||||
|
|
|
@ -13,19 +13,24 @@ spec:
|
|||
task: whoamiudp
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamiudp
|
||||
name: whoamiudp-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamiudp
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: myapp
|
||||
port: 8000
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: myapp
|
||||
port: 8000
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -43,19 +48,24 @@ spec:
|
|||
task: whoamiudp2
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamiudp2
|
||||
name: whoamiudp2-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamiudp2
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: myapp2
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: myapp2
|
||||
port: 8080
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -73,34 +83,44 @@ spec:
|
|||
task: whoamiudp3
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamiudp3
|
||||
name: whoamiudp3-abc
|
||||
namespace: ns3
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamiudp3
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: myapp3
|
||||
port: 8083
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.7
|
||||
- ip: 10.10.0.8
|
||||
ports:
|
||||
- name: myapp3
|
||||
port: 8083
|
||||
- 10.10.0.7
|
||||
- 10.10.0.8
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamiudp3
|
||||
name: whoamiudp3-abc
|
||||
namespace: ns4
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamiudp3
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: myapp4
|
||||
port: 8084
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.9
|
||||
- ip: 10.10.0.10
|
||||
ports:
|
||||
- name: myapp4
|
||||
port: 8084
|
||||
- 10.10.0.9
|
||||
- 10.10.0.10
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -118,18 +138,23 @@ spec:
|
|||
task: whoamiudp-ipv6
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamiudp-ipv6
|
||||
name: whoamiudp-ipv6-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamiudp-ipv6
|
||||
|
||||
subsets:
|
||||
addressType: IPv6
|
||||
ports:
|
||||
- name: myapp-ipv6
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: "fd00:10:244:0:1::3"
|
||||
ports:
|
||||
- name: myapp-ipv6
|
||||
port: 8080
|
||||
- "fd00:10:244:0:1::3"
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -171,25 +196,30 @@ spec:
|
|||
port: 80
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamiudp-cross-ns
|
||||
name: whoamiudp-cross-ns-abc
|
||||
namespace: cross-ns
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamiudp-cross-ns
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: myapp
|
||||
port: 8000
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: myapp
|
||||
port: 8000
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoamiudp-without-endpoints-subsets
|
||||
name: whoamiudp-without-endpointslice-endpoints
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
|
@ -202,11 +232,16 @@ spec:
|
|||
task: whoamiudp
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamiudp-without-endpoints-subsets
|
||||
name: whoamiudp-without-endpointslice-endpoints-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamiudp-without-endpointslice-endpoints
|
||||
|
||||
addressType: IPv4
|
||||
endpoints: []
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
|
|
@ -10,5 +10,5 @@ spec:
|
|||
|
||||
routes:
|
||||
- services:
|
||||
- name: whoamiudp-without-endpoints-subsets
|
||||
- name: whoamiudp-without-endpointslice-endpoints
|
||||
port: 8000
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami-svc-duplicated-endpointaddresses
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
selector:
|
||||
app: traefiklabs
|
||||
task: whoami
|
||||
|
||||
---
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami-svc-duplicated-endpointaddresses-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami-svc-duplicated-endpointaddresses
|
||||
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami-svc-duplicated-endpointaddresses-def
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami-svc-duplicated-endpointaddresses
|
||||
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami-svc-duplicated-endpointaddresses
|
||||
port: 8080
|
|
@ -13,5 +13,5 @@ spec:
|
|||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami-without-endpoints-subsets
|
||||
- name: whoami-without-endpointslice-endpoints
|
||||
port: 80
|
||||
|
|
|
@ -30,7 +30,7 @@ metadata:
|
|||
spec:
|
||||
weighted:
|
||||
services:
|
||||
- name: whoami-without-endpoints-subsets
|
||||
- name: whoami-without-endpointslice-endpoints
|
||||
weight: 1
|
||||
port: 80
|
||||
|
||||
|
@ -43,10 +43,10 @@ metadata:
|
|||
|
||||
spec:
|
||||
mirroring:
|
||||
name: whoami-without-endpoints-subsets
|
||||
name: whoami-without-endpointslice-endpoints
|
||||
port: 80
|
||||
mirrors:
|
||||
- name: whoami-without-endpoints-subsets
|
||||
- name: whoami-without-endpointslice-endpoints
|
||||
port: 80
|
||||
- name: test-weighted
|
||||
kind: TraefikService
|
||||
|
@ -61,5 +61,5 @@ metadata:
|
|||
spec:
|
||||
errors:
|
||||
service:
|
||||
name: whoami-without-endpoints-subsets
|
||||
name: whoami-without-endpointslice-endpoints
|
||||
port: 80
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami4
|
||||
name: whoami4-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami4
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -28,20 +33,25 @@ spec:
|
|||
app: traefiklabs
|
||||
task: whoami4
|
||||
|
||||
------
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
---
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami5
|
||||
name: whoami5-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami5
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami4
|
||||
name: whoami4-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami4
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -28,20 +33,25 @@ spec:
|
|||
app: traefiklabs
|
||||
task: whoami4
|
||||
|
||||
------
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
---
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami5
|
||||
name: whoami5-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami5
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami-svc-multiple-endpointaddresses
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
selector:
|
||||
app: traefiklabs
|
||||
task: whoami
|
||||
|
||||
---
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami-svc-multiple-endpointaddresses-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami-svc-multiple-endpointaddresses
|
||||
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
endpoints:
|
||||
- addresses:
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
- addresses:
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: false
|
||||
serving: true
|
||||
- addresses:
|
||||
- 10.10.0.5
|
||||
- 10.10.0.6
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami-svc-multiple-endpointaddresses
|
||||
port: 80
|
|
@ -0,0 +1,94 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami-svc-multiple-endpointslices
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
- name: web2
|
||||
port: 8080
|
||||
selector:
|
||||
app: traefiklabs
|
||||
task: whoami
|
||||
|
||||
---
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami-svc-multiple-endpointslices-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami-svc-multiple-endpointslices
|
||||
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
endpoints:
|
||||
- addresses:
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami-svc-multiple-endpointslices-def
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami-svc-multiple-endpointslices
|
||||
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web2
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami-svc-multiple-endpointslices-ghi
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami-svc-multiple-endpointslices
|
||||
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web2
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- 10.10.0.5
|
||||
- 10.10.0.6
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami-svc-multiple-endpointslices
|
||||
port: 8080
|
|
@ -1,54 +0,0 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami-svc-multiple-subsets
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
- name: web2
|
||||
port: 8080
|
||||
selector:
|
||||
app: traefiklabs
|
||||
task: whoami
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: whoami-svc-multiple-subsets
|
||||
namespace: default
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: web2
|
||||
port: 8080
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.route
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami-svc-multiple-subsets
|
||||
port: 8080
|
|
@ -1,47 +1,62 @@
|
|||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami6
|
||||
name: whoami6-abc
|
||||
namespace: baz
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami6
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.5
|
||||
- ip: 10.10.0.6
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.5
|
||||
- 10.10.0.6
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami5
|
||||
name: whoami5-abc
|
||||
namespace: foo
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami5
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami4
|
||||
name: whoami4-abc
|
||||
namespace: foo
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami4
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami5
|
||||
name: whoami5-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami5
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
|
|
@ -1,62 +1,82 @@
|
|||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami4
|
||||
name: whoami4-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami4
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami5
|
||||
name: whoami5-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami5
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami6
|
||||
name: whoami6-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami6
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.5
|
||||
- ip: 10.10.0.6
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
- 10.10.0.5
|
||||
- 10.10.0.6
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami7
|
||||
name: whoami7-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami7
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.7
|
||||
- ip: 10.10.0.8
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.7
|
||||
- 10.10.0.8
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami5
|
||||
name: whoami5-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami5
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
|
|
|
@ -1,32 +1,42 @@
|
|||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami5
|
||||
name: whoami5-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami5
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami4
|
||||
name: whoami4-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami4
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami5
|
||||
name: whoami5-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami5
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
|
|
@ -409,9 +409,8 @@ func (c configBuilder) loadServers(parentNamespace string, svc traefikv1alpha1.L
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var servers []dynamic.Server
|
||||
if service.Spec.Type != corev1.ServiceTypeExternalName && svc.HealthCheck != nil {
|
||||
return nil, fmt.Errorf("HealthCheck allowed only for ExternalName services: %s/%s", namespace, sanitizedName)
|
||||
return nil, fmt.Errorf("healthCheck allowed only for ExternalName services: %s/%s", namespace, sanitizedName)
|
||||
}
|
||||
|
||||
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
||||
|
@ -426,9 +425,7 @@ func (c configBuilder) loadServers(parentNamespace string, svc traefikv1alpha1.L
|
|||
|
||||
hostPort := net.JoinHostPort(service.Spec.ExternalName, strconv.Itoa(int(svcPort.Port)))
|
||||
|
||||
return append(servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("%s://%s", protocol, hostPort),
|
||||
}), nil
|
||||
return []dynamic.Server{{URL: fmt.Sprintf("%s://%s", protocol, hostPort)}}, nil
|
||||
}
|
||||
|
||||
nativeLB := c.NativeLBByDefault
|
||||
|
@ -449,6 +446,7 @@ func (c configBuilder) loadServers(parentNamespace string, svc traefikv1alpha1.L
|
|||
return []dynamic.Server{{URL: fmt.Sprintf("%s://%s", protocol, address)}}, nil
|
||||
}
|
||||
|
||||
var servers []dynamic.Server
|
||||
if service.Spec.Type == corev1.ServiceTypeNodePort && svc.NodePortLB {
|
||||
nodes, nodesExists, nodesErr := c.client.GetNodes()
|
||||
if nodesErr != nil {
|
||||
|
@ -482,27 +480,20 @@ func (c configBuilder) loadServers(parentNamespace string, svc traefikv1alpha1.L
|
|||
return servers, nil
|
||||
}
|
||||
|
||||
endpoints, endpointsExists, endpointsErr := c.client.GetEndpoints(namespace, sanitizedName)
|
||||
if endpointsErr != nil {
|
||||
return nil, endpointsErr
|
||||
}
|
||||
if !endpointsExists {
|
||||
return nil, fmt.Errorf("endpoints not found for %s/%s", namespace, sanitizedName)
|
||||
endpointSlices, err := c.client.GetEndpointSlicesForService(namespace, sanitizedName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting endpointslices: %w", err)
|
||||
}
|
||||
|
||||
if len(endpoints.Subsets) == 0 && !c.allowEmptyServices {
|
||||
return nil, fmt.Errorf("subset not found for %s/%s", namespace, sanitizedName)
|
||||
}
|
||||
|
||||
for _, subset := range endpoints.Subsets {
|
||||
addresses := map[string]struct{}{}
|
||||
for _, endpointSlice := range endpointSlices {
|
||||
var port int32
|
||||
for _, p := range subset.Ports {
|
||||
if svcPort.Name == p.Name {
|
||||
port = p.Port
|
||||
for _, p := range endpointSlice.Ports {
|
||||
if svcPort.Name == *p.Name {
|
||||
port = *p.Port
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
continue
|
||||
}
|
||||
|
@ -512,15 +503,28 @@ func (c configBuilder) loadServers(parentNamespace string, svc traefikv1alpha1.L
|
|||
return nil, err
|
||||
}
|
||||
|
||||
for _, addr := range subset.Addresses {
|
||||
hostPort := net.JoinHostPort(addr.IP, strconv.Itoa(int(port)))
|
||||
for _, endpoint := range endpointSlice.Endpoints {
|
||||
if endpoint.Conditions.Ready == nil || !*endpoint.Conditions.Ready {
|
||||
continue
|
||||
}
|
||||
|
||||
servers = append(servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("%s://%s", protocol, hostPort),
|
||||
})
|
||||
for _, address := range endpoint.Addresses {
|
||||
if _, ok := addresses[address]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
addresses[address] = struct{}{}
|
||||
servers = append(servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(address, strconv.Itoa(int(port)))),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(servers) == 0 && !c.allowEmptyServices {
|
||||
return nil, fmt.Errorf("no servers found for %s/%s", namespace, sanitizedName)
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -238,7 +238,6 @@ func (p *Provider) loadTCPServers(client Client, namespace string, svc traefikv1
|
|||
}
|
||||
|
||||
var servers []dynamic.TCPServer
|
||||
|
||||
if service.Spec.Type == corev1.ServiceTypeNodePort && svc.NodePortLB {
|
||||
nodes, nodesExists, nodesErr := client.GetNodes()
|
||||
if nodesErr != nil {
|
||||
|
@ -284,40 +283,47 @@ func (p *Provider) loadTCPServers(client Client, namespace string, svc traefikv1
|
|||
return []dynamic.TCPServer{{Address: address}}, nil
|
||||
}
|
||||
|
||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
||||
if endpointsErr != nil {
|
||||
return nil, endpointsErr
|
||||
endpointSlices, err := client.GetEndpointSlicesForService(namespace, svc.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting endpointslices: %w", err)
|
||||
}
|
||||
|
||||
if !endpointsExists {
|
||||
return nil, errors.New("endpoints not found")
|
||||
}
|
||||
|
||||
if len(endpoints.Subsets) == 0 && !p.AllowEmptyServices {
|
||||
return nil, errors.New("subset not found")
|
||||
}
|
||||
|
||||
var port int32
|
||||
for _, subset := range endpoints.Subsets {
|
||||
for _, p := range subset.Ports {
|
||||
if svcPort.Name == p.Name {
|
||||
port = p.Port
|
||||
addresses := map[string]struct{}{}
|
||||
for _, endpointSlice := range endpointSlices {
|
||||
var port int32
|
||||
for _, p := range endpointSlice.Ports {
|
||||
if svcPort.Name == *p.Name {
|
||||
port = *p.Port
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
return nil, errors.New("cannot define a port")
|
||||
continue
|
||||
}
|
||||
|
||||
for _, addr := range subset.Addresses {
|
||||
servers = append(servers, dynamic.TCPServer{
|
||||
Address: net.JoinHostPort(addr.IP, strconv.Itoa(int(port))),
|
||||
})
|
||||
for _, endpoint := range endpointSlice.Endpoints {
|
||||
if endpoint.Conditions.Ready == nil || !*endpoint.Conditions.Ready {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, address := range endpoint.Addresses {
|
||||
if _, ok := addresses[address]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
addresses[address] = struct{}{}
|
||||
servers = append(servers, dynamic.TCPServer{
|
||||
Address: net.JoinHostPort(address, strconv.Itoa(int(port))),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(servers) == 0 && !p.AllowEmptyServices {
|
||||
return nil, fmt.Errorf("no servers found for %s/%s", namespace, svc.Name)
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -4620,9 +4620,9 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
desc: "IngressRoute, service with multiple subsets",
|
||||
desc: "IngressRoute, service with multiple endpoint addresses on endpointslice",
|
||||
allowEmptyServices: true,
|
||||
paths: []string{"services.yml", "with_multiple_subsets.yml"},
|
||||
paths: []string{"services.yml", "with_multiple_endpointaddresses.yml"},
|
||||
expected: &dynamic.Configuration{
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
|
@ -4648,6 +4648,66 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
"default-test-route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.5:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.6:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: Bool(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "IngressRoute, service with duplicated endpointaddresses",
|
||||
allowEmptyServices: true,
|
||||
paths: []string{"services.yml", "with_duplicated_endpointaddresses.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{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-test-route-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Service: "default-test-route-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-test-route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:8080",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:8080",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.3:8080",
|
||||
},
|
||||
|
@ -4726,7 +4786,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "default-whoami-without-endpoints-subsets-80",
|
||||
Name: "default-whoami-without-endpointslice-endpoints-80",
|
||||
Weight: func(i int) *int { return &i }(1),
|
||||
},
|
||||
},
|
||||
|
@ -4734,10 +4794,10 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
},
|
||||
"default-test-mirror": {
|
||||
Mirroring: &dynamic.Mirroring{
|
||||
Service: "default-whoami-without-endpoints-subsets-80",
|
||||
Service: "default-whoami-without-endpointslice-endpoints-80",
|
||||
Mirrors: []dynamic.MirrorService{
|
||||
{
|
||||
Name: "default-whoami-without-endpoints-subsets-80",
|
||||
Name: "default-whoami-without-endpointslice-endpoints-80",
|
||||
},
|
||||
{
|
||||
Name: "default-test-weighted",
|
||||
|
@ -4745,7 +4805,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
"default-whoami-without-endpoints-subsets-80": {
|
||||
"default-whoami-without-endpointslice-endpoints-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
|
@ -4799,6 +4859,87 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestLoadIngressRoutes_multipleEndpointAddresses(t *testing.T) {
|
||||
wantConf := &dynamic.Configuration{
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-test-route-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Service: "default-test-route-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-test-route-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
PassHostHeader: Bool(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
}
|
||||
wantServers := []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.3:8080",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.4:8080",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.5:8080",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.6:8080",
|
||||
},
|
||||
}
|
||||
|
||||
k8sObjects, crdObjects := readResources(t, []string{"services.yml", "with_multiple_endpointslices.yml"})
|
||||
|
||||
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
|
||||
crdClient := traefikcrdfake.NewSimpleClientset(crdObjects...)
|
||||
|
||||
client := newClientImpl(kubeClient, crdClient)
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
|
||||
eventCh, err := client.WatchAll(nil, stopCh)
|
||||
require.NoError(t, err)
|
||||
|
||||
if k8sObjects != nil || crdObjects != nil {
|
||||
// just wait for the first event
|
||||
<-eventCh
|
||||
}
|
||||
|
||||
p := Provider{}
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), client)
|
||||
|
||||
service, ok := conf.HTTP.Services["default-test-route-6b204d94623b3df4370c"]
|
||||
require.True(t, ok)
|
||||
require.NotNil(t, service)
|
||||
require.NotNil(t, service.LoadBalancer)
|
||||
assert.ElementsMatch(t, wantServers, service.LoadBalancer.Servers)
|
||||
|
||||
service.LoadBalancer.Servers = nil
|
||||
assert.Equal(t, wantConf, conf)
|
||||
}
|
||||
|
||||
func TestLoadIngressRouteUDPs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
|
|
@ -122,7 +122,6 @@ func (p *Provider) loadUDPServers(client Client, namespace string, svc traefikv1
|
|||
}
|
||||
|
||||
var servers []dynamic.UDPServer
|
||||
|
||||
if service.Spec.Type == corev1.ServiceTypeNodePort && svc.NodePortLB {
|
||||
nodes, nodesExists, nodesErr := client.GetNodes()
|
||||
if nodesErr != nil {
|
||||
|
@ -168,39 +167,46 @@ func (p *Provider) loadUDPServers(client Client, namespace string, svc traefikv1
|
|||
return []dynamic.UDPServer{{Address: address}}, nil
|
||||
}
|
||||
|
||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
||||
if endpointsErr != nil {
|
||||
return nil, endpointsErr
|
||||
endpointSlices, err := client.GetEndpointSlicesForService(namespace, svc.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting endpointslices: %w", err)
|
||||
}
|
||||
|
||||
if !endpointsExists {
|
||||
return nil, errors.New("endpoints not found")
|
||||
}
|
||||
|
||||
if len(endpoints.Subsets) == 0 && !p.AllowEmptyServices {
|
||||
return nil, errors.New("subset not found")
|
||||
}
|
||||
|
||||
var port int32
|
||||
for _, subset := range endpoints.Subsets {
|
||||
for _, p := range subset.Ports {
|
||||
if svcPort.Name == p.Name {
|
||||
port = p.Port
|
||||
addresses := map[string]struct{}{}
|
||||
for _, endpointSlice := range endpointSlices {
|
||||
var port int32
|
||||
for _, p := range endpointSlice.Ports {
|
||||
if svcPort.Name == *p.Name {
|
||||
port = *p.Port
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
return nil, errors.New("cannot define a port")
|
||||
continue
|
||||
}
|
||||
|
||||
for _, addr := range subset.Addresses {
|
||||
servers = append(servers, dynamic.UDPServer{
|
||||
Address: net.JoinHostPort(addr.IP, strconv.Itoa(int(port))),
|
||||
})
|
||||
for _, endpoint := range endpointSlice.Endpoints {
|
||||
if endpoint.Conditions.Ready == nil || !*endpoint.Conditions.Ready {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, address := range endpoint.Addresses {
|
||||
if _, ok := addresses[address]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
addresses[address] = struct{}{}
|
||||
servers = append(servers, dynamic.UDPServer{
|
||||
Address: net.JoinHostPort(address, strconv.Itoa(int(port))),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(servers) == 0 && !p.AllowEmptyServices {
|
||||
return nil, fmt.Errorf("no servers found for %s/%s", namespace, svc.Name)
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
|
|
@ -11,9 +11,11 @@ import (
|
|||
"github.com/rs/zerolog/log"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
discoveryv1 "k8s.io/api/discovery/v1"
|
||||
kerror "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
ktypes "k8s.io/apimachinery/pkg/types"
|
||||
kinformers "k8s.io/client-go/informers"
|
||||
kclientset "k8s.io/client-go/kubernetes"
|
||||
|
@ -61,9 +63,9 @@ type Client interface {
|
|||
ListTLSRoutes() ([]*gatev1alpha2.TLSRoute, error)
|
||||
ListNamespaces(selector labels.Selector) ([]string, error)
|
||||
ListReferenceGrants(namespace string) ([]*gatev1beta1.ReferenceGrant, error)
|
||||
ListEndpointSlicesForService(namespace, serviceName string) ([]*discoveryv1.EndpointSlice, 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)
|
||||
}
|
||||
|
||||
type clientWrapper struct {
|
||||
|
@ -222,7 +224,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = factoryKube.Core().V1().Endpoints().Informer().AddEventHandler(eventHandler)
|
||||
_, err = factoryKube.Discovery().V1().EndpointSlices().Informer().AddEventHandler(eventHandler)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -543,16 +545,20 @@ func (c *clientWrapper) GetService(namespace, name string) (*corev1.Service, boo
|
|||
return service, exist, err
|
||||
}
|
||||
|
||||
// GetEndpoints returns the named endpoints from the given namespace.
|
||||
func (c *clientWrapper) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
||||
// ListEndpointSlicesForService returns the EndpointSlices for the given service name in the given namespace.
|
||||
func (c *clientWrapper) ListEndpointSlicesForService(namespace, serviceName string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get endpoints %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
return nil, fmt.Errorf("failed to get endpointslices for service %s/%s: namespace is not within watched namespaces", namespace, serviceName)
|
||||
}
|
||||
|
||||
endpoint, err := c.factoriesKube[c.lookupNamespace(namespace)].Core().V1().Endpoints().Lister().Endpoints(namespace).Get(name)
|
||||
exist, err := translateNotFoundError(err)
|
||||
serviceLabelRequirement, err := labels.NewRequirement(discoveryv1.LabelServiceName, selection.Equals, []string{serviceName})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create service label selector requirement: %w", err)
|
||||
}
|
||||
serviceSelector := labels.NewSelector()
|
||||
serviceSelector = serviceSelector.Add(*serviceLabelRequirement)
|
||||
|
||||
return endpoint, exist, err
|
||||
return c.factoriesKube[c.lookupNamespace(namespace)].Discovery().V1().EndpointSlices().Lister().EndpointSlices(namespace).List(serviceSelector)
|
||||
}
|
||||
|
||||
// GetSecret returns the named secret from the given namespace.
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
kind: GatewayClass
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway-class
|
||||
spec:
|
||||
controllerName: traefik.io/gateway-controller
|
||||
|
||||
---
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: my-gateway-class
|
||||
listeners: # Use GatewayClass defaults for listener definition.
|
||||
- name: http
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: Same
|
||||
|
||||
---
|
||||
kind: HTTPRoute
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: http-app-1
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: my-gateway
|
||||
kind: Gateway
|
||||
group: gateway.networking.k8s.io
|
||||
hostnames:
|
||||
- "foo.com"
|
||||
rules:
|
||||
- matches:
|
||||
- method: GET
|
||||
path:
|
||||
type: PathPrefix
|
||||
value: /foo
|
||||
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
weight: 1
|
||||
kind: Service
|
||||
group: ""
|
|
@ -0,0 +1,56 @@
|
|||
---
|
||||
kind: GatewayClass
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway-class
|
||||
spec:
|
||||
controllerName: traefik.io/gateway-controller
|
||||
|
||||
---
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: my-gateway-class
|
||||
listeners: # Use GatewayClass defaults for listener definition.
|
||||
- name: http
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: Same
|
||||
|
||||
---
|
||||
kind: HTTPRoute
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: http-app-1
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: my-gateway
|
||||
kind: Gateway
|
||||
group: gateway.networking.k8s.io
|
||||
hostnames:
|
||||
- "foo.com"
|
||||
rules:
|
||||
- matches:
|
||||
- queryParams:
|
||||
- type: Exact
|
||||
name: foo
|
||||
value: bar
|
||||
- type: RegularExpression
|
||||
name: baz
|
||||
value: buz
|
||||
path:
|
||||
type: PathPrefix
|
||||
value: /foo
|
||||
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
weight: 1
|
||||
kind: Service
|
||||
group: ""
|
|
@ -17,21 +17,26 @@ spec:
|
|||
task: whoami
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami
|
||||
name: whoami-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
- name: web2
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
- name: web2
|
||||
port: 8000
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -53,21 +58,26 @@ spec:
|
|||
task: whoami
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami-bar
|
||||
name: whoami-bar-abc
|
||||
namespace: bar
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami-bar
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
- name: web2
|
||||
port: 8000
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.11
|
||||
- ip: 10.10.0.12
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
- name: web2
|
||||
port: 8000
|
||||
- 10.10.0.11
|
||||
- 10.10.0.12
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -86,19 +96,24 @@ spec:
|
|||
task: whoami2
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami2
|
||||
name: whoami2-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami2
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
- 10.10.0.3
|
||||
- 10.10.0.4
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -117,19 +132,24 @@ spec:
|
|||
task: whoami2
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamitls
|
||||
name: whoamitls-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamitls
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: websecure
|
||||
port: 8443
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.5
|
||||
- ip: 10.10.0.6
|
||||
ports:
|
||||
- name: websecure
|
||||
port: 8443
|
||||
- 10.10.0.5
|
||||
- 10.10.0.6
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -148,19 +168,24 @@ spec:
|
|||
task: whoami3
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoami3
|
||||
name: whoami3-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoami3
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: websecure2
|
||||
port: 8443
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.7
|
||||
- ip: 10.10.0.8
|
||||
ports:
|
||||
- name: websecure2
|
||||
port: 8443
|
||||
- 10.10.0.7
|
||||
- 10.10.0.8
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -201,23 +226,28 @@ spec:
|
|||
port: 443
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamitcp
|
||||
name: whoamitcp-abc
|
||||
namespace: default
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamitcp
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: tcp-1
|
||||
protocol: TCP
|
||||
port: 9000
|
||||
- name: tcp-2
|
||||
protocol: TCP
|
||||
port: 10000
|
||||
endpoints:
|
||||
- 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
|
||||
- 10.10.0.9
|
||||
- 10.10.0.10
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -236,23 +266,28 @@ spec:
|
|||
name: tcp-2
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: whoamitcp-bar
|
||||
name: whoamitcp-bar-abc
|
||||
namespace: bar
|
||||
labels:
|
||||
kubernetes.io/service-name: whoamitcp-bar
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: tcp-1
|
||||
protocol: TCP
|
||||
port: 9000
|
||||
- name: tcp-2
|
||||
protocol: TCP
|
||||
port: 10000
|
||||
endpoints:
|
||||
- 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
|
||||
- 10.10.0.13
|
||||
- 10.10.0.14
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
|
|
@ -370,6 +370,10 @@ func (p *Provider) loadHTTPRouteFilterExtensionRef(namespace string, extensionRe
|
|||
}
|
||||
|
||||
func (p *Provider) loadHTTPServers(namespace string, backendRef gatev1.HTTPBackendRef) (*dynamic.ServersLoadBalancer, error) {
|
||||
if backendRef.Port == nil {
|
||||
return nil, errors.New("port is required for Kubernetes Service reference")
|
||||
}
|
||||
|
||||
service, exists, err := p.client.GetService(namespace, string(backendRef.Name))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting service: %w", err)
|
||||
|
@ -378,56 +382,58 @@ func (p *Provider) loadHTTPServers(namespace string, backendRef gatev1.HTTPBacke
|
|||
return nil, errors.New("service not found")
|
||||
}
|
||||
|
||||
var portSpec corev1.ServicePort
|
||||
var match bool
|
||||
|
||||
var svcPort *corev1.ServicePort
|
||||
for _, p := range service.Spec.Ports {
|
||||
if backendRef.Port == nil || p.Port == int32(*backendRef.Port) {
|
||||
portSpec = p
|
||||
match = true
|
||||
if p.Port == int32(*backendRef.Port) {
|
||||
svcPort = &p
|
||||
break
|
||||
}
|
||||
}
|
||||
if !match {
|
||||
return nil, errors.New("service port not found")
|
||||
if svcPort == nil {
|
||||
return nil, fmt.Errorf("service port %d not found", *backendRef.Port)
|
||||
}
|
||||
|
||||
endpoints, endpointsExists, err := p.client.GetEndpoints(namespace, string(backendRef.Name))
|
||||
endpointSlices, err := p.client.ListEndpointSlicesForService(namespace, string(backendRef.Name))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting endpoints: %w", err)
|
||||
return nil, fmt.Errorf("getting endpointslices: %w", err)
|
||||
}
|
||||
if !endpointsExists {
|
||||
return nil, errors.New("endpoints not found")
|
||||
}
|
||||
|
||||
if len(endpoints.Subsets) == 0 {
|
||||
return nil, errors.New("subset not found")
|
||||
if len(endpointSlices) == 0 {
|
||||
return nil, errors.New("endpointslices not found")
|
||||
}
|
||||
|
||||
lb := &dynamic.ServersLoadBalancer{}
|
||||
lb.SetDefaults()
|
||||
|
||||
var port int32
|
||||
var portStr string
|
||||
for _, subset := range endpoints.Subsets {
|
||||
for _, p := range subset.Ports {
|
||||
if portSpec.Name == p.Name {
|
||||
port = p.Port
|
||||
protocol := getProtocol(*svcPort)
|
||||
|
||||
addresses := map[string]struct{}{}
|
||||
for _, endpointSlice := range endpointSlices {
|
||||
var port int32
|
||||
for _, p := range endpointSlice.Ports {
|
||||
if svcPort.Name == *p.Name {
|
||||
port = *p.Port
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
return nil, errors.New("cannot define a port")
|
||||
continue
|
||||
}
|
||||
|
||||
protocol := getProtocol(portSpec)
|
||||
for _, endpoint := range endpointSlice.Endpoints {
|
||||
if endpoint.Conditions.Ready == nil || !*endpoint.Conditions.Ready {
|
||||
continue
|
||||
}
|
||||
|
||||
portStr = strconv.FormatInt(int64(port), 10)
|
||||
for _, addr := range subset.Addresses {
|
||||
lb.Servers = append(lb.Servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(addr.IP, portStr)),
|
||||
})
|
||||
for _, address := range endpoint.Addresses {
|
||||
if _, ok := addresses[address]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
addresses[address] = struct{}{}
|
||||
lb.Servers = append(lb.Servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(address, strconv.Itoa(int(port)))),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -469,11 +475,11 @@ func buildHostRule(hostnames []gatev1.Hostname) (string, int) {
|
|||
// The current priority computing is rather naive but aims to fulfill Conformance tests suite requirement.
|
||||
// The priority is computed to match the following precedence order:
|
||||
//
|
||||
// * "Exact" path match. (+100000)
|
||||
// * "Prefix" path match with largest number of characters. (+10000) PathRegex (+1000)
|
||||
// * Method match. (not implemented)
|
||||
// * Largest number of header matches. (+100 each) or with PathRegex (+10 each)
|
||||
// * Largest number of query param matches. (not implemented)
|
||||
// * "Exact" path match (+100000).
|
||||
// * "Prefix" path match with largest number of characters (+10000 + nb_characters*100).
|
||||
// * Method match (+1000).
|
||||
// * Largest number of header matches (+100 each).
|
||||
// * Largest number of query param matches (+10 each).
|
||||
//
|
||||
// In case of multiple matches for a route, the maximum priority among all matches is retain.
|
||||
func buildMatchRule(hostnames []gatev1.Hostname, match gatev1.HTTPRouteMatch) (string, int) {
|
||||
|
@ -489,10 +495,19 @@ func buildMatchRule(hostnames []gatev1.Hostname, match gatev1.HTTPRouteMatch) (s
|
|||
matchRules = append(matchRules, pathRule)
|
||||
priority += pathPriority
|
||||
|
||||
if match.Method != nil {
|
||||
matchRules = append(matchRules, fmt.Sprintf("Method(`%s`)", *match.Method))
|
||||
priority += 1000
|
||||
}
|
||||
|
||||
headerRules, headersPriority := buildHeaderRules(match.Headers)
|
||||
matchRules = append(matchRules, headerRules...)
|
||||
priority += headersPriority
|
||||
|
||||
queryParamRules, queryParamsPriority := buildQueryParamRules(match.QueryParams)
|
||||
matchRules = append(matchRules, queryParamRules...)
|
||||
priority += queryParamsPriority
|
||||
|
||||
matchRulesStr := strings.Join(matchRules, " && ")
|
||||
|
||||
hostRule, hostPriority := buildHostRule(hostnames)
|
||||
|
@ -525,7 +540,7 @@ func buildPathRule(pathMatch gatev1.HTTPPathMatch) (string, int) {
|
|||
return fmt.Sprintf("(Path(`%[1]s`) || PathPrefix(`%[1]s/`))", pv), 10000 + len(pathValue)*100
|
||||
|
||||
case gatev1.PathMatchRegularExpression:
|
||||
return fmt.Sprintf("PathRegexp(`%s`)", pathValue), 1000 + len(pathValue)*100
|
||||
return fmt.Sprintf("PathRegexp(`%s`)", pathValue), 10000 + len(pathValue)*100
|
||||
|
||||
default:
|
||||
return "PathPrefix(`/`)", 1
|
||||
|
@ -533,18 +548,38 @@ func buildPathRule(pathMatch gatev1.HTTPPathMatch) (string, int) {
|
|||
}
|
||||
|
||||
func buildHeaderRules(headers []gatev1.HTTPHeaderMatch) ([]string, int) {
|
||||
var rules []string
|
||||
var priority int
|
||||
var (
|
||||
rules []string
|
||||
priority int
|
||||
)
|
||||
for _, header := range headers {
|
||||
typ := ptr.Deref(header.Type, gatev1.HeaderMatchExact)
|
||||
switch typ {
|
||||
case gatev1.HeaderMatchExact:
|
||||
rules = append(rules, fmt.Sprintf("Header(`%s`,`%s`)", header.Name, header.Value))
|
||||
priority += 100
|
||||
case gatev1.HeaderMatchRegularExpression:
|
||||
rules = append(rules, fmt.Sprintf("HeaderRegexp(`%s`,`%s`)", header.Name, header.Value))
|
||||
priority += 10
|
||||
}
|
||||
priority += 100
|
||||
}
|
||||
|
||||
return rules, priority
|
||||
}
|
||||
|
||||
func buildQueryParamRules(queryParams []gatev1.HTTPQueryParamMatch) ([]string, int) {
|
||||
var (
|
||||
rules []string
|
||||
priority int
|
||||
)
|
||||
for _, qp := range queryParams {
|
||||
typ := ptr.Deref(qp.Type, gatev1.QueryParamMatchExact)
|
||||
switch typ {
|
||||
case gatev1.QueryParamMatchExact:
|
||||
rules = append(rules, fmt.Sprintf("Query(`%s`,`%s`)", qp.Name, qp.Value))
|
||||
case gatev1.QueryParamMatchRegularExpression:
|
||||
rules = append(rules, fmt.Sprintf("QueryRegexp(`%s`,`%s`)", qp.Name, qp.Value))
|
||||
}
|
||||
priority += 10
|
||||
}
|
||||
|
||||
return rules, priority
|
||||
|
|
|
@ -1288,7 +1288,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
|||
"default-http-app-1-my-gateway-web-2-d23f7039bc8036fb918c": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: "Host(`foo.com`) && PathRegexp(`^/buzz/[0-9]+$`)",
|
||||
Priority: 2408,
|
||||
Priority: 11408,
|
||||
RuleSyntax: "v3",
|
||||
Service: "default-http-app-1-my-gateway-web-2-wrr",
|
||||
},
|
||||
|
@ -1354,6 +1354,128 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
|||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple HTTPRoute, with method matching",
|
||||
paths: []string{"services.yml", "httproute/with_method_matching.yml"},
|
||||
entryPoints: map[string]Entrypoint{"web": {
|
||||
Address: ":80",
|
||||
}},
|
||||
expected: &dynamic.Configuration{
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-http-app-1-my-gateway-web-0-74ad70a7cf090becdd3c": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: "Host(`foo.com`) && (Path(`/foo`) || PathPrefix(`/foo/`)) && Method(`GET`)",
|
||||
Priority: 11408,
|
||||
RuleSyntax: "v3",
|
||||
Service: "default-http-app-1-my-gateway-web-0-wrr",
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-http-app-1-my-gateway-web-0-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "default-whoami-80",
|
||||
Weight: ptr.To(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"default-whoami-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: ptr.To(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple HTTPRoute, with query param matching",
|
||||
paths: []string{"services.yml", "httproute/with_query_param_matching.yml"},
|
||||
entryPoints: map[string]Entrypoint{"web": {
|
||||
Address: ":80",
|
||||
}},
|
||||
expected: &dynamic.Configuration{
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-http-app-1-my-gateway-web-0-bb7b03c9610e982fd627": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: "Host(`foo.com`) && (Path(`/foo`) || PathPrefix(`/foo/`)) && Query(`foo`,`bar`) && QueryRegexp(`baz`,`buz`)",
|
||||
Priority: 10428,
|
||||
RuleSyntax: "v3",
|
||||
Service: "default-http-app-1-my-gateway-web-0-wrr",
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-http-app-1-my-gateway-web-0-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "default-whoami-80",
|
||||
Weight: ptr.To(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"default-whoami-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: ptr.To(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "HTTPRoute with Same namespace selector",
|
||||
paths: []string{"services.yml", "httproute/with_namespace_same.yml"},
|
||||
|
|
|
@ -206,82 +206,71 @@ func (p *Provider) loadTCPServices(namespace string, backendRefs []gatev1.Backen
|
|||
return nil, nil, fmt.Errorf("unsupported BackendRef %s/%s/%s", *backendRef.Group, *backendRef.Kind, backendRef.Name)
|
||||
}
|
||||
|
||||
svc := dynamic.TCPService{
|
||||
LoadBalancer: &dynamic.TCPServersLoadBalancer{},
|
||||
if backendRef.Port == nil {
|
||||
return nil, nil, errors.New("port is required for Kubernetes Service reference")
|
||||
}
|
||||
|
||||
service, exists, err := p.client.GetService(namespace, string(backendRef.Name))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, fmt.Errorf("getting service: %w", err)
|
||||
}
|
||||
|
||||
if !exists {
|
||||
return nil, nil, errors.New("service not found")
|
||||
}
|
||||
|
||||
if len(service.Spec.Ports) > 1 && backendRef.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.Error().Msg("A multiple ports Kubernetes Service cannot be used if unspecified backendRef.Port")
|
||||
continue
|
||||
}
|
||||
|
||||
var portSpec corev1.ServicePort
|
||||
var match bool
|
||||
|
||||
var svcPort *corev1.ServicePort
|
||||
for _, p := range service.Spec.Ports {
|
||||
if backendRef.Port == nil || p.Port == int32(*backendRef.Port) {
|
||||
portSpec = p
|
||||
match = true
|
||||
if p.Port == int32(*backendRef.Port) {
|
||||
svcPort = &p
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !match {
|
||||
return nil, nil, errors.New("service port not found")
|
||||
if svcPort == nil {
|
||||
return nil, nil, fmt.Errorf("service port %d not found", *backendRef.Port)
|
||||
}
|
||||
|
||||
endpoints, endpointsExists, endpointsErr := p.client.GetEndpoints(namespace, string(backendRef.Name))
|
||||
if endpointsErr != nil {
|
||||
return nil, nil, endpointsErr
|
||||
endpointSlices, err := p.client.ListEndpointSlicesForService(namespace, string(backendRef.Name))
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("getting endpointslices: %w", err)
|
||||
}
|
||||
if len(endpointSlices) == 0 {
|
||||
return nil, nil, errors.New("endpointslices not found")
|
||||
}
|
||||
|
||||
if !endpointsExists {
|
||||
return nil, nil, errors.New("endpoints not found")
|
||||
}
|
||||
svc := dynamic.TCPService{LoadBalancer: &dynamic.TCPServersLoadBalancer{}}
|
||||
|
||||
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
|
||||
addresses := map[string]struct{}{}
|
||||
for _, endpointSlice := range endpointSlices {
|
||||
var port int32
|
||||
for _, p := range endpointSlice.Ports {
|
||||
if svcPort.Name == *p.Name {
|
||||
port = *p.Port
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
return nil, nil, errors.New("cannot define a port")
|
||||
continue
|
||||
}
|
||||
|
||||
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),
|
||||
})
|
||||
for _, endpoint := range endpointSlice.Endpoints {
|
||||
if endpoint.Conditions.Ready == nil || !*endpoint.Conditions.Ready {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, address := range endpoint.Addresses {
|
||||
if _, ok := addresses[address]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
addresses[address] = struct{}{}
|
||||
svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, dynamic.TCPServer{
|
||||
Address: net.JoinHostPort(address, strconv.Itoa(int(port))),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serviceName := provider.Normalize(service.Namespace + "-" + service.Name + "-" + portStr)
|
||||
serviceName := provider.Normalize(service.Namespace + "-" + service.Name + "-" + strconv.Itoa(int(svcPort.Port)))
|
||||
services[serviceName] = &svc
|
||||
|
||||
wrrSvc.Weighted.Services = append(wrrSvc.Weighted.Services, dynamic.TCPWRRService{Name: serviceName, Weight: &weight})
|
||||
|
|
|
@ -16,10 +16,12 @@ import (
|
|||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
traefikversion "github.com/traefik/traefik/v3/pkg/version"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
discoveryv1 "k8s.io/api/discovery/v1"
|
||||
netv1 "k8s.io/api/networking/v1"
|
||||
kerror "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
kinformers "k8s.io/client-go/informers"
|
||||
kclientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
|
@ -41,7 +43,7 @@ type Client interface {
|
|||
GetService(namespace, name string) (*corev1.Service, bool, error)
|
||||
GetSecret(namespace, name string) (*corev1.Secret, bool, error)
|
||||
GetNodes() ([]*corev1.Node, bool, error)
|
||||
GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error)
|
||||
GetEndpointSlicesForService(namespace, serviceName string) ([]*discoveryv1.EndpointSlice, error)
|
||||
UpdateIngressStatus(ing *netv1.Ingress, ingStatus []netv1.IngressLoadBalancerIngress) error
|
||||
}
|
||||
|
||||
|
@ -185,7 +187,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = factoryKube.Core().V1().Endpoints().Informer().AddEventHandler(eventHandler)
|
||||
_, err = factoryKube.Discovery().V1().EndpointSlices().Informer().AddEventHandler(eventHandler)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -340,15 +342,20 @@ func (c *clientWrapper) GetService(namespace, name string) (*corev1.Service, boo
|
|||
return service, exist, err
|
||||
}
|
||||
|
||||
// GetEndpoints returns the named endpoints from the given namespace.
|
||||
func (c *clientWrapper) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
||||
// GetEndpointSlicesForService returns the EndpointSlices for the given service name in the given namespace.
|
||||
func (c *clientWrapper) GetEndpointSlicesForService(namespace, serviceName string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get endpoints %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
return nil, fmt.Errorf("failed to get endpointslices for service %s/%s: namespace is not within watched namespaces", namespace, serviceName)
|
||||
}
|
||||
|
||||
endpoint, err := c.factoriesKube[c.lookupNamespace(namespace)].Core().V1().Endpoints().Lister().Endpoints(namespace).Get(name)
|
||||
exist, err := translateNotFoundError(err)
|
||||
return endpoint, exist, err
|
||||
serviceLabelRequirement, err := labels.NewRequirement(discoveryv1.LabelServiceName, selection.Equals, []string{serviceName})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create service label selector requirement: %w", err)
|
||||
}
|
||||
serviceSelector := labels.NewSelector()
|
||||
serviceSelector = serviceSelector.Add(*serviceLabelRequirement)
|
||||
|
||||
return c.factoriesKube[c.lookupNamespace(namespace)].Discovery().V1().EndpointSlices().Lister().EndpointSlices(namespace).List(serviceSelector)
|
||||
}
|
||||
|
||||
// GetSecret returns the named secret from the given namespace.
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
discoveryv1 "k8s.io/api/discovery/v1"
|
||||
netv1 "k8s.io/api/networking/v1"
|
||||
)
|
||||
|
||||
|
@ -15,15 +16,15 @@ type clientMock struct {
|
|||
ingresses []*netv1.Ingress
|
||||
services []*corev1.Service
|
||||
secrets []*corev1.Secret
|
||||
endpoints []*corev1.Endpoints
|
||||
endpointSlices []*discoveryv1.EndpointSlice
|
||||
nodes []*corev1.Node
|
||||
ingressClasses []*netv1.IngressClass
|
||||
|
||||
apiServiceError error
|
||||
apiSecretError error
|
||||
apiEndpointsError error
|
||||
apiNodesError error
|
||||
apiIngressStatusError error
|
||||
apiServiceError error
|
||||
apiSecretError error
|
||||
apiEndpointSlicesError error
|
||||
apiNodesError error
|
||||
apiIngressStatusError error
|
||||
|
||||
watchChan chan interface{}
|
||||
}
|
||||
|
@ -43,8 +44,8 @@ func newClientMock(path string) clientMock {
|
|||
c.services = append(c.services, o)
|
||||
case *corev1.Secret:
|
||||
c.secrets = append(c.secrets, o)
|
||||
case *corev1.Endpoints:
|
||||
c.endpoints = append(c.endpoints, o)
|
||||
case *discoveryv1.EndpointSlice:
|
||||
c.endpointSlices = append(c.endpointSlices, o)
|
||||
case *corev1.Node:
|
||||
c.nodes = append(c.nodes, o)
|
||||
case *netv1.Ingress:
|
||||
|
@ -76,18 +77,19 @@ func (c clientMock) GetService(namespace, name string) (*corev1.Service, bool, e
|
|||
return nil, false, c.apiServiceError
|
||||
}
|
||||
|
||||
func (c clientMock) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
||||
if c.apiEndpointsError != nil {
|
||||
return nil, false, c.apiEndpointsError
|
||||
func (c clientMock) GetEndpointSlicesForService(namespace, serviceName string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
if c.apiEndpointSlicesError != nil {
|
||||
return nil, c.apiEndpointSlicesError
|
||||
}
|
||||
|
||||
for _, endpoints := range c.endpoints {
|
||||
if endpoints.Namespace == namespace && endpoints.Name == name {
|
||||
return endpoints, true, nil
|
||||
var result []*discoveryv1.EndpointSlice
|
||||
for _, endpointSlice := range c.endpointSlices {
|
||||
if endpointSlice.Namespace == namespace && endpointSlice.Labels[discoveryv1.LabelServiceName] == serviceName {
|
||||
result = append(result, endpointSlice)
|
||||
}
|
||||
}
|
||||
|
||||
return &corev1.Endpoints{}, false, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c clientMock) GetNodes() ([]*corev1.Node, bool, error) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
discoveryv1 "k8s.io/api/discovery/v1"
|
||||
netv1 "k8s.io/api/networking/v1"
|
||||
kerror "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@ -188,10 +189,10 @@ func TestClientIgnoresHelmOwnedSecrets(t *testing.T) {
|
|||
assert.False(t, found)
|
||||
}
|
||||
|
||||
func TestClientIgnoresEmptyEndpointUpdates(t *testing.T) {
|
||||
emptyEndpoint := &corev1.Endpoints{
|
||||
func TestClientIgnoresEmptyEndpointSliceUpdates(t *testing.T) {
|
||||
emptyEndpointSlice := &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "empty-endpoint",
|
||||
Name: "empty-endpointslice",
|
||||
Namespace: "test",
|
||||
ResourceVersion: "1244",
|
||||
Annotations: map[string]string{
|
||||
|
@ -200,25 +201,31 @@ func TestClientIgnoresEmptyEndpointUpdates(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
filledEndpoint := &corev1.Endpoints{
|
||||
samplePortName := "testing"
|
||||
samplePortNumber := int32(1337)
|
||||
samplePortProtocol := corev1.ProtocolTCP
|
||||
sampleAddressReady := true
|
||||
filledEndpointSlice := &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "filled-endpoint",
|
||||
Name: "filled-endpointslice",
|
||||
Namespace: "test",
|
||||
ResourceVersion: "1234",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{{
|
||||
IP: "10.13.37.1",
|
||||
}},
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Name: "testing",
|
||||
Port: 1337,
|
||||
Protocol: "tcp",
|
||||
}},
|
||||
AddressType: discoveryv1.AddressTypeIPv4,
|
||||
Endpoints: []discoveryv1.Endpoint{{
|
||||
Addresses: []string{"10.13.37.1"},
|
||||
Conditions: discoveryv1.EndpointConditions{
|
||||
Ready: &sampleAddressReady,
|
||||
},
|
||||
}},
|
||||
Ports: []discoveryv1.EndpointPort{{
|
||||
Name: &samplePortName,
|
||||
Port: &samplePortNumber,
|
||||
Protocol: &samplePortProtocol,
|
||||
}},
|
||||
}
|
||||
|
||||
kubeClient := kubefake.NewSimpleClientset(emptyEndpoint, filledEndpoint)
|
||||
kubeClient := kubefake.NewSimpleClientset(emptyEndpointSlice, filledEndpointSlice)
|
||||
|
||||
discovery, _ := kubeClient.Discovery().(*discoveryfake.FakeDiscovery)
|
||||
discovery.FakedServerVersion = &kversion.Info{
|
||||
|
@ -234,50 +241,72 @@ func TestClientIgnoresEmptyEndpointUpdates(t *testing.T) {
|
|||
|
||||
select {
|
||||
case event := <-eventCh:
|
||||
ep, ok := event.(*corev1.Endpoints)
|
||||
ep, ok := event.(*discoveryv1.EndpointSlice)
|
||||
require.True(t, ok)
|
||||
|
||||
assert.True(t, ep.Name == "empty-endpoint" || ep.Name == "filled-endpoint")
|
||||
assert.True(t, ep.Name == "empty-endpointslice" || ep.Name == "filled-endpointslice")
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
assert.Fail(t, "expected to receive event for endpoints")
|
||||
assert.Fail(t, "expected to receive event for endpointslices")
|
||||
}
|
||||
|
||||
emptyEndpoint, err = kubeClient.CoreV1().Endpoints("test").Get(context.TODO(), "empty-endpoint", metav1.GetOptions{})
|
||||
emptyEndpointSlice, err = kubeClient.DiscoveryV1().EndpointSlices("test").Get(context.TODO(), "empty-endpointslice", metav1.GetOptions{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Update endpoint annotation and resource version (apparently not done by fake client itself)
|
||||
// to show an update that should not trigger an update event on our eventCh.
|
||||
// This reflects the behavior of kubernetes controllers which use endpoint annotations for leader election.
|
||||
emptyEndpoint.Annotations["test-annotation"] = "___"
|
||||
emptyEndpoint.ResourceVersion = "1245"
|
||||
_, err = kubeClient.CoreV1().Endpoints("test").Update(context.TODO(), emptyEndpoint, metav1.UpdateOptions{})
|
||||
emptyEndpointSlice.Annotations["test-annotation"] = "___"
|
||||
emptyEndpointSlice.ResourceVersion = "1245"
|
||||
_, err = kubeClient.DiscoveryV1().EndpointSlices("test").Update(context.TODO(), emptyEndpointSlice, metav1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
select {
|
||||
case event := <-eventCh:
|
||||
ep, ok := event.(*corev1.Endpoints)
|
||||
ep, ok := event.(*discoveryv1.EndpointSlice)
|
||||
require.True(t, ok)
|
||||
|
||||
assert.Fail(t, "didn't expect to receive event for empty endpoint update", ep.Name)
|
||||
assert.Fail(t, "didn't expect to receive event for empty endpointslice update", ep.Name)
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
}
|
||||
|
||||
filledEndpoint, err = kubeClient.CoreV1().Endpoints("test").Get(context.TODO(), "filled-endpoint", metav1.GetOptions{})
|
||||
filledEndpointSlice, err = kubeClient.DiscoveryV1().EndpointSlices("test").Get(context.TODO(), "filled-endpointslice", metav1.GetOptions{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
filledEndpoint.Subsets[0].Addresses[0].IP = "10.13.37.2"
|
||||
filledEndpoint.ResourceVersion = "1235"
|
||||
_, err = kubeClient.CoreV1().Endpoints("test").Update(context.TODO(), filledEndpoint, metav1.UpdateOptions{})
|
||||
filledEndpointSlice.Endpoints[0].Addresses[0] = "10.13.37.2"
|
||||
filledEndpointSlice.ResourceVersion = "1235"
|
||||
_, err = kubeClient.DiscoveryV1().EndpointSlices("test").Update(context.TODO(), filledEndpointSlice, metav1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
select {
|
||||
case event := <-eventCh:
|
||||
ep, ok := event.(*corev1.Endpoints)
|
||||
ep, ok := event.(*discoveryv1.EndpointSlice)
|
||||
require.True(t, ok)
|
||||
|
||||
assert.Equal(t, "filled-endpoint", ep.Name)
|
||||
assert.Equal(t, "filled-endpointslice", ep.Name)
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
assert.Fail(t, "expected to receive event for filled endpoint")
|
||||
assert.Fail(t, "expected to receive event for filled endpointslice")
|
||||
}
|
||||
|
||||
select {
|
||||
case <-eventCh:
|
||||
assert.Fail(t, "received more than one event")
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
}
|
||||
|
||||
newPortNumber := int32(42)
|
||||
filledEndpointSlice.Ports[0].Port = &newPortNumber
|
||||
filledEndpointSlice.ResourceVersion = "1236"
|
||||
_, err = kubeClient.DiscoveryV1().EndpointSlices("test").Update(context.TODO(), filledEndpointSlice, metav1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
select {
|
||||
case event := <-eventCh:
|
||||
ep, ok := event.(*discoveryv1.EndpointSlice)
|
||||
require.True(t, ok)
|
||||
|
||||
assert.Equal(t, "filled-endpointslice", ep.Name)
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
assert.Fail(t, "expected to receive event for filled endpointslice")
|
||||
}
|
||||
|
||||
select {
|
||||
|
|
|
@ -1,32 +1,42 @@
|
|||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: toto
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.11.0.1
|
||||
- ip: 10.11.0.2
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
- 10.11.0.1
|
||||
- 10.11.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: Ingress
|
||||
|
|
|
@ -50,35 +50,41 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiversion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.30.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.41.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.30.0.1
|
||||
- 10.41.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiversion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service2
|
||||
name: service2-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service2
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -40,18 +40,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -37,18 +37,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -30,18 +30,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -36,18 +36,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -52,15 +52,20 @@ spec:
|
|||
externalName: "2001:0db8:3c4d:0015:0000:0000:1a2f:2a3b"
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service-bar
|
||||
name: service-bar-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service-bar
|
||||
|
||||
subsets:
|
||||
addressType: IPv6
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: "2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b"
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
- "2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b"
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -30,18 +30,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8443
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8443
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8443
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
|
@ -31,20 +31,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -31,20 +31,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: https-foo
|
||||
port: 8443
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- name: https-foo
|
||||
port: 8443
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- name: https-foo
|
||||
port: 8443
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -29,18 +29,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -33,23 +33,42 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1-def
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: carotte
|
||||
port: 8090
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
- ip: 10.10.0.3
|
||||
ports:
|
||||
- name: carotte
|
||||
port: 8090
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
- 10.10.0.3
|
||||
conditions:
|
||||
ready: true
|
|
@ -53,18 +53,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -41,18 +41,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -37,18 +37,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -31,14 +31,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -36,27 +36,38 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 80
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 80
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: defaultservice
|
||||
name: defaultservice-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: defaultservice
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -30,14 +30,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -28,14 +28,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -30,14 +30,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -30,14 +30,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -31,14 +31,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -37,15 +37,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -64,14 +64,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -29,14 +29,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -64,14 +64,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -29,15 +29,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: foobar
|
||||
port: 4711
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- name: foobar
|
||||
port: 4711
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -31,14 +31,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -31,15 +31,20 @@ spec:
|
|||
type: ClusterIP
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: example-com
|
||||
name: example-com-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: example-com
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.11.0.1
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
- 10.11.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -30,8 +30,14 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
addressType: IPv4
|
||||
ports: null
|
||||
endpoints: []
|
||||
|
|
|
@ -40,24 +40,43 @@ spec:
|
|||
type: ClusterIP
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Endpoints
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
subsets:
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: http-admin
|
||||
port: 8079
|
||||
protocol: TCP
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.0.0.1
|
||||
nodeName: admin.whoami.service1
|
||||
ports:
|
||||
- name: http-admin
|
||||
port: 8079
|
||||
protocol: TCP
|
||||
- 10.0.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
nodeName: admin.whoami.service1
|
||||
|
||||
---
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1-def
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
protocol: TCP
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.0.0.1
|
||||
nodeName: whoami.service1
|
||||
# targetRef:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
protocol: TCP
|
||||
- 10.0.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
nodeName: whoami.service1
|
|
@ -33,18 +33,23 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: carotte
|
||||
port: 8090
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: carotte
|
||||
port: 8090
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -33,24 +33,23 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: carotte
|
||||
port: 8090
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- name: carotte
|
||||
port: 8090
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- name: carotte
|
||||
port: 8090
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -33,24 +33,23 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: carotte
|
||||
port: 8090
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- name: carotte
|
||||
port: 8090
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- name: carotte
|
||||
port: 8090
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -28,14 +28,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -38,18 +38,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -40,18 +40,23 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: carotte
|
||||
port: 8090
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: carotte
|
||||
port: 8090
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
- 10.10.0.1
|
||||
- 10.10.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -52,35 +52,41 @@ spec:
|
|||
clusterIP: 10.1.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service2
|
||||
name: service2-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service2
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.2
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.2
|
||||
- 10.21.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -30,15 +30,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8089
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.11.0.1
|
||||
- ip: 10.11.0.2
|
||||
ports:
|
||||
- port: 8089
|
||||
- 10.11.0.1
|
||||
- 10.11.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -30,15 +30,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8089
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.11.0.1
|
||||
- ip: 10.11.0.2
|
||||
ports:
|
||||
- port: 8089
|
||||
- 10.11.0.1
|
||||
- 10.11.0.2
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -30,14 +30,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -31,14 +31,20 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -24,18 +24,21 @@ spec:
|
|||
clusterIP: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: service1
|
||||
name: service1-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: service1
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- port: 8080
|
||||
name: ""
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- 10.10.0.1
|
||||
- 10.21.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -83,15 +83,20 @@ spec:
|
|||
type: ClusterIP
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
kind: EndpointSlice
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
metadata:
|
||||
name: example-com
|
||||
name: example-com-abc
|
||||
namespace: testing
|
||||
labels:
|
||||
kubernetes.io/service-name: example-com
|
||||
|
||||
subsets:
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
endpoints:
|
||||
- addresses:
|
||||
- ip: 10.11.0.1
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
- 10.11.0.1
|
||||
conditions:
|
||||
ready: true
|
||||
|
|
|
@ -651,36 +651,41 @@ func (p *Provider) loadService(client Client, namespace string, backend netv1.In
|
|||
return svc, nil
|
||||
}
|
||||
|
||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, backend.Service.Name)
|
||||
if endpointsErr != nil {
|
||||
return nil, endpointsErr
|
||||
endpointSlices, err := client.GetEndpointSlicesForService(namespace, backend.Service.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting endpointslices: %w", err)
|
||||
}
|
||||
|
||||
if !endpointsExists {
|
||||
return nil, errors.New("endpoints not found")
|
||||
}
|
||||
|
||||
for _, subset := range endpoints.Subsets {
|
||||
addresses := map[string]struct{}{}
|
||||
for _, endpointSlice := range endpointSlices {
|
||||
var port int32
|
||||
for _, p := range subset.Ports {
|
||||
if portName == p.Name {
|
||||
port = p.Port
|
||||
for _, p := range endpointSlice.Ports {
|
||||
if portName == *p.Name {
|
||||
port = *p.Port
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
protocol := getProtocol(portSpec, portName, svcConfig)
|
||||
|
||||
for _, addr := range subset.Addresses {
|
||||
hostPort := net.JoinHostPort(addr.IP, strconv.Itoa(int(port)))
|
||||
for _, endpoint := range endpointSlice.Endpoints {
|
||||
if endpoint.Conditions.Ready == nil || !*endpoint.Conditions.Ready {
|
||||
continue
|
||||
}
|
||||
|
||||
svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("%s://%s", protocol, hostPort),
|
||||
})
|
||||
for _, address := range endpoint.Addresses {
|
||||
if _, ok := addresses[address]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
addresses[address] = struct{}{}
|
||||
svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, dynamic.Server{
|
||||
URL: fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(address, strconv.Itoa(int(port)))),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package k8s
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
discoveryv1 "k8s.io/api/discovery/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
|
@ -47,61 +47,54 @@ func objChanged(oldObj, newObj interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
if _, ok := oldObj.(*corev1.Endpoints); ok {
|
||||
return endpointsChanged(oldObj.(*corev1.Endpoints), newObj.(*corev1.Endpoints))
|
||||
if _, ok := oldObj.(*discoveryv1.EndpointSlice); ok {
|
||||
return endpointSliceChanged(oldObj.(*discoveryv1.EndpointSlice), newObj.(*discoveryv1.EndpointSlice))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func endpointsChanged(a, b *corev1.Endpoints) bool {
|
||||
if len(a.Subsets) != len(b.Subsets) {
|
||||
// In some Kubernetes versions leader election is done by updating an endpoint annotation every second,
|
||||
// if there are no changes to the endpoints addresses, ports, and there are no addresses defined for an endpoint
|
||||
// the event can safely be ignored and won't cause unnecessary config reloads.
|
||||
// TODO: check if Kubernetes is still using EndpointSlice for leader election, which seems to not be the case anymore.
|
||||
func endpointSliceChanged(a, b *discoveryv1.EndpointSlice) bool {
|
||||
if len(a.Ports) != len(b.Ports) {
|
||||
return true
|
||||
}
|
||||
|
||||
for i, sa := range a.Subsets {
|
||||
sb := b.Subsets[i]
|
||||
if subsetsChanged(sa, sb) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func subsetsChanged(sa, sb corev1.EndpointSubset) bool {
|
||||
if len(sa.Addresses) != len(sb.Addresses) {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(sa.Ports) != len(sb.Ports) {
|
||||
return true
|
||||
}
|
||||
|
||||
// in Addresses and Ports, we should be able to rely on
|
||||
// these being sorted and able to be compared
|
||||
// they are supposed to be in a canonical format
|
||||
for addr, aaddr := range sa.Addresses {
|
||||
baddr := sb.Addresses[addr]
|
||||
if aaddr.IP != baddr.IP {
|
||||
return true
|
||||
}
|
||||
|
||||
if aaddr.Hostname != baddr.Hostname {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for port, aport := range sa.Ports {
|
||||
bport := sb.Ports[port]
|
||||
for i, aport := range a.Ports {
|
||||
bport := b.Ports[i]
|
||||
if aport.Name != bport.Name {
|
||||
return true
|
||||
}
|
||||
if aport.Port != bport.Port {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if aport.Protocol != bport.Protocol {
|
||||
if len(a.Endpoints) != len(b.Endpoints) {
|
||||
return true
|
||||
}
|
||||
|
||||
for i, ea := range a.Endpoints {
|
||||
eb := b.Endpoints[i]
|
||||
if endpointChanged(ea, eb) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func endpointChanged(a, b discoveryv1.Endpoint) bool {
|
||||
if len(a.Addresses) != len(b.Addresses) {
|
||||
return true
|
||||
}
|
||||
|
||||
for i, aaddr := range a.Addresses {
|
||||
baddr := b.Addresses[i]
|
||||
if aaddr != baddr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,14 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
discoveryv1 "k8s.io/api/discovery/v1"
|
||||
netv1 "k8s.io/api/networking/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func Test_detectChanges(t *testing.T) {
|
||||
portA := int32(80)
|
||||
portB := int32(8080)
|
||||
tests := []struct {
|
||||
name string
|
||||
oldObj interface{}
|
||||
|
@ -21,28 +23,28 @@ func Test_detectChanges(t *testing.T) {
|
|||
want: true,
|
||||
},
|
||||
{
|
||||
name: "With empty endpoints",
|
||||
oldObj: &corev1.Endpoints{},
|
||||
newObj: &corev1.Endpoints{},
|
||||
name: "With empty endpointslice",
|
||||
oldObj: &discoveryv1.EndpointSlice{},
|
||||
newObj: &discoveryv1.EndpointSlice{},
|
||||
},
|
||||
{
|
||||
name: "With old nil",
|
||||
newObj: &corev1.Endpoints{},
|
||||
newObj: &discoveryv1.EndpointSlice{},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "With new nil",
|
||||
oldObj: &corev1.Endpoints{},
|
||||
oldObj: &discoveryv1.EndpointSlice{},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "With same version",
|
||||
oldObj: &corev1.Endpoints{
|
||||
oldObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
newObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
|
@ -50,12 +52,12 @@ func Test_detectChanges(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "With different version",
|
||||
oldObj: &corev1.Endpoints{
|
||||
oldObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
newObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
|
@ -90,7 +92,7 @@ func Test_detectChanges(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "With same annotations",
|
||||
oldObj: &corev1.Endpoints{
|
||||
oldObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
Annotations: map[string]string{
|
||||
|
@ -98,7 +100,7 @@ func Test_detectChanges(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
newObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
Annotations: map[string]string{
|
||||
|
@ -109,7 +111,7 @@ func Test_detectChanges(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "With different annotations",
|
||||
oldObj: &corev1.Endpoints{
|
||||
oldObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
Annotations: map[string]string{
|
||||
|
@ -117,7 +119,7 @@ func Test_detectChanges(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
newObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
Annotations: map[string]string{
|
||||
|
@ -127,384 +129,94 @@ func Test_detectChanges(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "With same subsets",
|
||||
oldObj: &corev1.Endpoints{
|
||||
name: "With same endpoints and ports",
|
||||
oldObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{},
|
||||
Endpoints: []discoveryv1.Endpoint{},
|
||||
Ports: []discoveryv1.EndpointPort{},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
newObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{},
|
||||
Endpoints: []discoveryv1.Endpoint{},
|
||||
Ports: []discoveryv1.EndpointPort{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "With different len of subsets",
|
||||
oldObj: &corev1.Endpoints{
|
||||
name: "With different len of endpoints",
|
||||
oldObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{},
|
||||
Endpoints: []discoveryv1.Endpoint{},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
newObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{}},
|
||||
Endpoints: []discoveryv1.Endpoint{{}},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "With same subsets with same len of addresses",
|
||||
oldObj: &corev1.Endpoints{
|
||||
name: "With different endpoints",
|
||||
oldObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{},
|
||||
Endpoints: []discoveryv1.Endpoint{{
|
||||
Addresses: []string{"10.10.10.10"},
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
newObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "With same subsets with different len of addresses",
|
||||
oldObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{},
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{{}},
|
||||
Endpoints: []discoveryv1.Endpoint{{
|
||||
Addresses: []string{"10.10.10.11"},
|
||||
}},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "With same subsets with same len of ports",
|
||||
oldObj: &corev1.Endpoints{
|
||||
name: "With different len of ports",
|
||||
oldObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{},
|
||||
}},
|
||||
Ports: []discoveryv1.EndpointPort{},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
newObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "With same subsets with different len of ports",
|
||||
oldObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{},
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{{}},
|
||||
}},
|
||||
Ports: []discoveryv1.EndpointPort{{}},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "With same subsets with same len of addresses with same ip",
|
||||
oldObj: &corev1.Endpoints{
|
||||
name: "With different ports",
|
||||
oldObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{{
|
||||
IP: "10.10.10.10",
|
||||
}},
|
||||
Ports: []discoveryv1.EndpointPort{{
|
||||
Port: &portA,
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
newObj: &discoveryv1.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{{
|
||||
IP: "10.10.10.10",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "With same subsets with same len of addresses with different ip",
|
||||
oldObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{{
|
||||
IP: "10.10.10.10",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{{
|
||||
IP: "10.10.10.42",
|
||||
}},
|
||||
Ports: []discoveryv1.EndpointPort{{
|
||||
Port: &portB,
|
||||
}},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "With same subsets with same len of addresses with same hostname",
|
||||
oldObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{{
|
||||
Hostname: "foo",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{{
|
||||
Hostname: "foo",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "With same subsets with same len of addresses with same hostname",
|
||||
oldObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{{
|
||||
Hostname: "foo",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{{
|
||||
Hostname: "bar",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "With same subsets with same len of port with same name",
|
||||
oldObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Name: "foo",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Name: "foo",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "With same subsets with same len of port with different name",
|
||||
oldObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Name: "foo",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Name: "bar",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "With same subsets with same len of port with same port",
|
||||
oldObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Port: 4242,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Port: 4242,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "With same subsets with same len of port with different port",
|
||||
oldObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Port: 4242,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Port: 6969,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "With same subsets with same len of port with same protocol",
|
||||
oldObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Protocol: "HTTP",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Protocol: "HTTP",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "With same subsets with same len of port with different protocol",
|
||||
oldObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Protocol: "HTTP",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Protocol: "TCP",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "With same subsets with same subset",
|
||||
oldObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{{
|
||||
IP: "10.10.10.10",
|
||||
Hostname: "foo",
|
||||
}},
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Name: "bar",
|
||||
Port: 4242,
|
||||
Protocol: "HTTP",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
newObj: &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{{
|
||||
Addresses: []corev1.EndpointAddress{{
|
||||
IP: "10.10.10.10",
|
||||
Hostname: "foo",
|
||||
}},
|
||||
Ports: []corev1.EndpointPort{{
|
||||
Name: "bar",
|
||||
Port: 4242,
|
||||
Protocol: "HTTP",
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue