fix: add support for multiple ingress classes

This commit is contained in:
LandryBe 2021-01-28 15:08:04 +01:00 committed by GitHub
parent 49ec62c757
commit 9a931e4dc9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 175 additions and 71 deletions

View file

@ -56,7 +56,7 @@ func (reh *resourceEventHandler) OnDelete(obj interface{}) {
type Client interface {
WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error)
GetIngresses() []*networkingv1beta1.Ingress
GetIngressClass() (*networkingv1beta1.IngressClass, error)
GetIngressClasses() ([]*networkingv1beta1.IngressClass, 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)
@ -393,9 +393,9 @@ func (c *clientWrapper) GetSecret(namespace, name string) (*corev1.Secret, bool,
return secret, exist, err
}
func (c *clientWrapper) GetIngressClass() (*networkingv1beta1.IngressClass, error) {
func (c *clientWrapper) GetIngressClasses() ([]*networkingv1beta1.IngressClass, error) {
if c.clusterFactory == nil {
return nil, errors.New("failed to find ingressClass: factory not loaded")
return nil, errors.New("cluster factory not loaded")
}
ingressClasses, err := c.clusterFactory.Networking().V1beta1().IngressClasses().Lister().List(labels.Everything())
@ -403,13 +403,14 @@ func (c *clientWrapper) GetIngressClass() (*networkingv1beta1.IngressClass, erro
return nil, err
}
var ics []*networkingv1beta1.IngressClass
for _, ic := range ingressClasses {
if ic.Spec.Controller == traefikDefaultIngressClassController {
return ic, nil
ics = append(ics, ic)
}
}
return nil, nil
return ics, nil
}
// lookupNamespace returns the lookup namespace key for the given namespace.

View file

@ -14,11 +14,11 @@ import (
var _ Client = (*clientMock)(nil)
type clientMock struct {
ingresses []*networkingv1beta1.Ingress
services []*corev1.Service
secrets []*corev1.Secret
endpoints []*corev1.Endpoints
ingressClass *networkingv1beta1.IngressClass
ingresses []*networkingv1beta1.Ingress
services []*corev1.Service
secrets []*corev1.Secret
endpoints []*corev1.Endpoints
ingressClasses []*networkingv1beta1.IngressClass
serverVersion *version.Version
@ -59,7 +59,7 @@ func newClientMock(serverVersion string, paths ...string) clientMock {
}
c.ingresses = append(c.ingresses, ing)
case *networkingv1beta1.IngressClass:
c.ingressClass = o
c.ingressClasses = append(c.ingressClasses, o)
default:
panic(fmt.Sprintf("Unknown runtime object %+v %T", o, o))
}
@ -117,8 +117,8 @@ func (c clientMock) GetSecret(namespace, name string) (*corev1.Secret, bool, err
return nil, false, nil
}
func (c clientMock) GetIngressClass() (*networkingv1beta1.IngressClass, error) {
return c.ingressClass, nil
func (c clientMock) GetIngressClasses() ([]*networkingv1beta1.IngressClass, error) {
return c.ingressClasses, nil
}
func (c clientMock) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) {

View file

@ -8,7 +8,7 @@ spec:
ports:
- name: tchouk
port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1
---
kind: Service
@ -21,4 +21,4 @@ spec:
ports:
- name: tchouk
port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,7 +7,7 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1
---
kind: Service
@ -19,4 +19,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -8,7 +8,7 @@ spec:
ports:
- name: http
port: 8080
clusterIp: "fc00:f853:ccd:e793::1"
clusterIP: "fc00:f853:ccd:e793::1"
type: ClusterIP
---

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -8,4 +8,4 @@ spec:
ports:
- port: 443
targetPort: 8443
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -9,4 +9,4 @@ spec:
- name: https
protocol: ""
port: 8443
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -9,4 +9,4 @@ spec:
- name: https-foo
protocol: ""
port: 8443
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -8,4 +8,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -17,4 +17,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -8,5 +8,5 @@ spec:
ports:
- name: http
port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1
type: ClusterIP

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -10,5 +10,5 @@ spec:
port: 8082
- name: tchouk
port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -10,5 +10,5 @@ spec:
port: 8082
- name: tchouk
port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,7 +7,7 @@ metadata:
spec:
ports:
- port: 8080
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1
type: ExternalName
externalName: traefik.wtf

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -10,5 +10,5 @@ spec:
port: 8082
- name: tchouk
port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,7 +7,7 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1
---
kind: Service
@ -19,4 +19,4 @@ metadata:
spec:
ports:
- port: 8082
clusterIp: 10.1.0.1
clusterIP: 10.1.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -8,4 +8,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -10,5 +10,5 @@ spec:
port: 8082
- name: tchouk
port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -8,7 +8,7 @@ spec:
ports:
- name: http
port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1
type: ClusterIP
---
@ -22,5 +22,5 @@ spec:
ports:
- name: http
port: 80
clusterIp: 10.0.0.2
clusterIP: 10.0.0.2
type: ClusterIP

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -0,0 +1,11 @@
kind: Endpoints
apiVersion: v1
metadata:
name: service1
namespace: testing
subsets:
- addresses:
- ip: 10.10.0.1
ports:
- port: 8080

View file

@ -0,0 +1,30 @@
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: ""
namespace: testing
spec:
ingressClassName: traefik-lb
rules:
- http:
paths:
- path: /bar
backend:
serviceName: service1
servicePort: 80
---
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: ""
namespace: testing
spec:
ingressClassName: traefik-lb2
rules:
- http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 80

View file

@ -0,0 +1,14 @@
apiVersion: networking.k8s.io/v1beta1
kind: IngressClass
metadata:
name: traefik-lb2
spec:
controller: traefik.io/ingress-controller
---
apiVersion: networking.k8s.io/v1beta1
kind: IngressClass
metadata:
name: traefik-lb
spec:
controller: traefik.io/ingress-controller

View file

@ -0,0 +1,10 @@
kind: Service
apiVersion: v1
metadata:
name: service1
namespace: testing
spec:
ports:
- port: 80
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -7,4 +7,4 @@ metadata:
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
clusterIP: 10.0.0.1

View file

@ -190,15 +190,15 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
return conf
}
var ingressClass *networkingv1beta1.IngressClass
var ingressClasses []*networkingv1beta1.IngressClass
if supportsIngressClass(serverVersion) {
ic, err := client.GetIngressClass()
ics, err := client.GetIngressClasses()
if err != nil {
log.FromContext(ctx).Warnf("Failed to find an ingress class: %v", err)
log.FromContext(ctx).Warnf("Failed to list ingress classes: %v", err)
}
ingressClass = ic
ingressClasses = ics
}
ingresses := client.GetIngresses()
@ -207,7 +207,7 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
for _, ingress := range ingresses {
ctx = log.With(ctx, log.Str("ingress", ingress.Name), log.Str("namespace", ingress.Namespace))
if !p.shouldProcessIngress(p.IngressClass, ingress, ingressClass) {
if !p.shouldProcessIngress(ingress, ingressClasses) {
continue
}
@ -351,14 +351,20 @@ func (p *Provider) updateIngressStatus(ing *networkingv1beta1.Ingress, k8sClient
return k8sClient.UpdateIngressStatus(ing, service.Status.LoadBalancer.Ingress)
}
func (p *Provider) shouldProcessIngress(providerIngressClass string, ingress *networkingv1beta1.Ingress, ingressClass *networkingv1beta1.IngressClass) bool {
func (p *Provider) shouldProcessIngress(ingress *networkingv1beta1.Ingress, ingressClasses []*networkingv1beta1.IngressClass) bool {
// configuration through the new kubernetes ingressClass
if ingress.Spec.IngressClassName != nil {
return ingressClass != nil && ingressClass.ObjectMeta.Name == *ingress.Spec.IngressClassName
for _, ic := range ingressClasses {
if *ingress.Spec.IngressClassName == ic.ObjectMeta.Name {
return true
}
}
return false
}
return providerIngressClass == ingress.Annotations[annotationKubernetesIngressClass] ||
len(providerIngressClass) == 0 && ingress.Annotations[annotationKubernetesIngressClass] == traefikDefaultIngressClass
return p.IngressClass == ingress.Annotations[annotationKubernetesIngressClass] ||
len(p.IngressClass) == 0 && ingress.Annotations[annotationKubernetesIngressClass] == traefikDefaultIngressClass
}
func buildHostRule(host string) string {

View file

@ -1061,6 +1061,38 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
},
},
},
{
desc: "v18 Ingress with multiple ingressClasses",
serverVersion: "v1.18",
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{},
HTTP: &dynamic.HTTPConfiguration{
Middlewares: map[string]*dynamic.Middleware{},
Routers: map[string]*dynamic.Router{
"testing-foo": {
Rule: "PathPrefix(`/foo`)",
Service: "testing-service1-80",
},
"testing-bar": {
Rule: "PathPrefix(`/bar`)",
Service: "testing-service1-80",
},
},
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
},
},
},
},
},
},
},
},
{
desc: "v18 Ingress with no pathType",
serverVersion: "v1.18",